#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= # Bestiary by Blizzard # Version: 2.4 # Type: Enemy Catalogue Display # Date: 5.7.2006 # Date v1.1: 18.9.2006 # Date v1.2b: 23.2.2007 # Date v1.3b: 7.7.2007 # Date v2.0b: 12.7.2007 # Date v2.1b: 6.8.2007 # Date v2.2b: 24.9.2007 # Date v2.21b: 8.4.2008 # Date v2.3b: 28.7.2009 # Date v2.4: 23.3.2019 #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= # # This work is licensed under BSD License 2.0: # # #---------------------------------------------------------------------------- # # # # Copyright (c) Boris "Blizzard" Mikić # # All rights reserved. # # # # Redistribution and use in source and binary forms, with or without # # modification, are permitted provided that the following conditions are met: # # # # 1. Redistributions of source code must retain the above copyright notice, # # this list of conditions and the following disclaimer. # # # # 2. Redistributions in binary form must reproduce the above copyright # # notice, this list of conditions and the following disclaimer in the # # documentation and/or other materials provided with the distribution. # # # # 3. Neither the name of the copyright holder nor the names of its # # contributors may be used to endorse or promote products derived from # # this software without specific prior written permission. # # # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # # POSSIBILITY OF SUCH DAMAGE. # # # #---------------------------------------------------------------------------- # # You may use this script for both non-commercial and commercial products # without limitations as long as you fulfill the conditions presented by the # above license. The "complete" way to give credit is to include the license # somewhere in your product (e.g. in the credits screen), but a "simple" way # is also acceptable. The "simple" way to give credit is as follows: # # Bestiary licensed under BSD License 2.0 # Copyright (c) Boris "Blizzard" Mikić # # Alternatively, if your font doesn't support diacritic characters, you may # use this variant: # # Bestiary licensed under BSD License 2.0 # Copyright (c) Boris "Blizzard" Mikic # # In general other similar variants are allowed as long as it is clear who # the creator is (e.g. "Bestiary created by Blizzard" is acceptable). But if # possible, prefer to use one of the two variants listed above. # # If you fail to give credit and/or claim that this work was created by you, # this may result in legal action and/or payment of damages even though this # work is free of charge to use normally. # #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= # # Compatibility: # # 98% compatible with SDK v1.x. 70% compatible with SDK v2.x. May cause # incompatibility issues with exotic CBS-es. WILL corrupt your old savegames. # # # Features: # # - display of full data of enemies # - option to disable different information # - integrated support for my "Advanced Analyze System" # - press SHIFT/ENTER to change the appearance of the Bestiary window # - use LEFT/RIGHT/UP/DOWN to navigate through the information database # # new in v1.1b: # - bugs fixed # # new in v1.2b: # - improved coding (uses less RAM now and processes faster) # # new in v1.3b: # - increased compatibility # # new in v2.0b: # - completely overworked and fixed compatibility issues # # new in v2.1b: # - added custom info possibility # # new in v2.2b: # - rewritten conditions using classic syntax to avoid RGSS conditioning bug # - added SORT_BEASTS option # - improved coding # # new in v2.21b: # - improved coding # # new in v2.3b: # - improved coding # # new in v2.4: # - added new license # - added usage and crediting instructions # # # Instructions: # # - Explanation: # # This script will allow your characters to retrieve information about # enemies during battle and show them in a window. It also has built-in # compatibility for my "Advanced Analyze System" script and allows adding # enemies to it only if enemies were analyzed at least once. This script can # easily be used for Pokémon typed games. # # - Configuration: # # Configure the part below and make one or more skills, that can analyze # enemies. Add the IDs into the array called ANALYZE_IDS and separate them # with commas. If you have one or more scripts using dummy elements (e.g. my # EQUAP Skills, SephirothSpawn's Limit Break, etc.) be sure to include every # dummy element ID in the array called ELM_DUMMIES, also separated by commas. # Below is everything explained, how to set the bestiary up. It has # additional options for rendering single or all enemies "Unknown" and adding # them into the bestiary as such. Later you can use a syntax described below # to enable their information display (e.g. like in Pokémon games, you get # the real info about a pokémon not when you meet it, but when you catch it). # You can use $game_system.bestiary_missing? to check how many enemies were # not added into the Bestiary. If you wish to see how many were added, use # $game_system.beasts.size # # # Important notes: # # You MUST configure the part below if you have scripts that use dummy # elements! Do NOT give your enemies MORE than 11 elements/status effects of # one resistance type (e.g. 12 or more elements, that are absorbed), because # they won't be displayed. # # # If you find any bugs, please report them here: # http://forum.chaos-project.com #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= #:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # START Configuration #:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ELM_DUMMIES = [] # include EVERY dummy element ID, that is used by other scripts STA_DUMMIES = [] # include EVERY dummy status effect ID, that you use EVASION = 'Eva' # word used to display Evasion MAP_BACKGROUND = true # true will show the map background, false won't BESTIARY_SIZE = 999 # change this if to as many NEVER_ADD = [] # include IDs of enemies which will never be added SORT_BEASTS = true # set to false if you don't want all enemies to be sorted by ID # enemy IDs from enemies, that are unknown (e.g. bosses), to make an enemy # known use $game_system.enable(ENEMY_ID) through the event command # "Call Script" to enable the display of information if $override_bestiary UNKNOWN = [4] # overrides the commands further below else UNKNOWN = [] # DO NOT TOUCH THIS end # every enemy is initially unknown (e.g. for Pokémon games), so you don't have # to fill the array above with all the IDs of your enemy database ALL_UNKNOWN = false # If a display below is disabled, the appropriate part above will be overriden. # The values below can also be changed during gameplay by just calling the # "Call script" event command and changing the values like below # DO NOT SET EVERYTHING TO true! THIS WILL BUG YOUR BESTIARY! # set to true to disable display of basic info DISABLE_BEAST_BASIC = false # set to true to disable display of basic stats DISABLE_BEAST_STATS = false # set to true to disable display of extended stats DISABLE_BEAST_EXTSTATS = false # set to true to disable display of extreme element weakness DISABLE_BEAST_XTRWEAK = false # set to true to disable display of element weakness DISABLE_BEAST_WEAK = false # set to true to disable display of element resistance DISABLE_BEAST_RESIST = false # set to true to disable display of element nullification DISABLE_BEAST_NULLIFY = false # set to true to disable display of element absorbtion DISABLE_BEAST_ABSORB = false # set to true to disable display of extreme status effect weakness DISABLE_BEAST_XTRWEAK_S = false # set to true to disable display of status effect weakness DISABLE_BEAST_WEAK_S = false # set to true to disable display of status effect resistance DISABLE_BEAST_RESIST_S = false # set to true to disable display of status effect nullification DISABLE_BEAST_NULLIFY_S = false # set to true to disable display of status effect absorbtion DISABLE_BEAST_ABSORB_S = false # set to false to enable custom display DISABLE_BEAST_CUSTOM = false #:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # END Configuration #:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: if $DUMMY_ELEMENTS == nil $DUMMY_ELEMENTS = ELM_DUMMIES.clone else $DUMMY_ELEMENTS |= ELM_DUMMIES end ELM_DUMMIES = nil if $DUMMY_STATES == nil $DUMMY_STATES = STA_DUMMIES.clone else $DUMMY_STATES |= STA_DUMMIES end STA_DUMMIES = nil $bestiary_enabled = 2.4 #============================================================================== # Game_System #============================================================================== class Game_System attr_accessor :window_mode attr_accessor :known def get_bestiary_info(id) return get_analyze_info(id) if $override_bestiary_info case id #:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # START Custom Beast Info Database # # Use following template to add custom information about monsters: # # when ID then return "STRING" # # ID is the enemy ID and STRING is a string with the information that should be # displayed. Type all the information into one string, the script will slice # the text by itself. Note that special characters like a " (double quote) # need the use of the escape character \ (backslash). If you get and error # with your string or the character doesn't appear right on the screen, try to # use the escape character (i.e. for a " it would be \" instead of just "). # The backslash itself needs an escape character (i.e. \\). #:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: when 1 then return "Until now I believed there is no such thing as a ghost. It's hard to not believe in something that is trying to kill you." when 2 then return "These creatures can be found in swamps and marshes. They are said to be able to have the ability to turn anything they glaze at into stone. If this rumor is true, these creatures can be considered as part of the family of \"Gorgons\"." #:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # END Custom Beast Info Database #:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: end return 'Unknown' end alias init_beast_later initialize def initialize init_beast_later @window_mode, @beasts, @known = 0, [], [] end def beasts return ($bestiary_override ? @analyzed : @beasts) - NEVER_ADD end def add_beast(beast) unless @beasts.include?(beast) @beasts.push(beast) @beasts.sort! if SORT_BEASTS end end def bestiary_missing? return (BESTIARY_SIZE - @beasts.size) end def enable(id) $game_system.known.push(id) unless $game_system.known.include?(id) return end end #============================================================================== # RPG::Enemy #============================================================================== class RPG::Enemy def known return ($game_system.known.include?(self.id)) if ALL_UNKNOWN return (!UNKNOWN.include?(self.id)) end end #============================================================================== # Window_Base #============================================================================== class Window_Base def draw_bestiary_battler(enemy, w, h) bitmap = RPG::Cache.battler(enemy.battler_name, enemy.battler_hue) bitmap_w = bitmap.width / 2 bitmap_h = bitmap.height / 2 src_rect = Rect.new(0, 0, bitmap.width, bitmap.height) self.contents.blt(w/2 - bitmap_w, h/2 - bitmap_h, bitmap, src_rect, 192) end end #============================================================================== # Bitmap #============================================================================== class Bitmap def slice_text(text, width) words = text.split(' ') return words if words.size == 1 result, current_text = [], words.shift words.each_index {|i| if self.text_size("#{current_text} #{words[i]}").width > width result.push(current_text) current_text = words[i] else current_text = "#{current_text} #{words[i]}" end result.push(current_text) if i >= words.size - 1} return result end end #============================================================================== # Window_Beast #============================================================================== class Window_Beast < Window_Base attr_accessor :mode def initialize super(0, 0, 576, 416) @index_enemy = 0 @index_page = 0 @d = [DISABLE_BEAST_BASIC, DISABLE_BEAST_STATS, DISABLE_BEAST_EXTSTATS, DISABLE_BEAST_XTRWEAK, DISABLE_BEAST_WEAK, DISABLE_BEAST_RESIST, DISABLE_BEAST_NULLIFY, DISABLE_BEAST_ABSORB, DISABLE_BEAST_XTRWEAK_S, DISABLE_BEAST_WEAK_S, DISABLE_BEAST_RESIST_S, DISABLE_BEAST_NULLIFY_S, DISABLE_BEAST_ABSORB_S, DISABLE_BEAST_CUSTOM] @pages = 14 - ((0..13).find_all {|i| @d[i]}).size @mode = $game_system.window_mode @enemies = [] for id in ($override_bestiary ? $game_system.analyzed : $game_system.beasts) @enemies.push($data_enemies[id]) if id != nil end self.contents = Bitmap.new(width - 32, height - 32) if $fontface != nil self.contents.font.name = $fontface self.contents.font.size = $fontsize elsif $defaultfonttype != nil self.contents.font.name = $defaultfonttype self.contents.font.size = $defaultfontsize end self.x = 320 - self.width / 2 self.y = 240 - self.height / 2 refresh end def update return if @enemies.size == 0 if Input.trigger?(Input::RIGHT) $game_system.se_play($data_system.cursor_se) @index_enemy = (@index_enemy + 1) % @enemies.size refresh elsif Input.trigger?(Input::LEFT) $game_system.se_play($data_system.cursor_se) @index_enemy = (@index_enemy + @enemies.size - 1) % @enemies.size refresh elsif Input.trigger?(Input::DOWN) $game_system.se_play($data_system.cursor_se) @index_page = (@index_page + 1) % @pages refresh elsif Input.trigger?(Input::UP) $game_system.se_play($data_system.cursor_se) @index_page = (@index_page + @pages - 1) % @pages refresh end end def refresh self.contents.clear x = y = 0 ox = x + 64 enemy = @enemies[@index_enemy] if enemy == nil self.contents.draw_text(0, 64, 544, 32, 'Bestiary is empty', 1) return end self.contents.draw_text(0, 0, 544, 32, "#{enemy.id}. #{enemy.name}", 1) draw_bestiary_battler(enemy, self.width, self.height) if enemy.known case @index_page when (0 - ((0..0).find_all {|i| @d[i]}).size) if enemy.item_id > 0 drop = $data_items[enemy.item_id] t = "#{drop.name} (#{enemy.treasure_prob}% chance)" elsif enemy.weapon_id > 0 drop = $data_weapons[enemy.weapon_id] t = "#{drop.name} (#{enemy.treasure_prob}% chance)" elsif enemy.armor_id > 0 drop = $data_armors[enemy.armor_id] t = "#{drop.name} (#{enemy.treasure_prob}% chance)" end self.contents.draw_text(x, 32, 128, 32, $data_system.words.hp) self.contents.draw_text(x, 96, 128, 32, $data_system.words.sp) self.contents.draw_text(x, 160, 128, 32, 'EXP') self.contents.draw_text(x, 224, 128, 32, $data_system.words.gold) self.contents.draw_text(x, 288, 128, 32, 'Drops') self.contents.draw_text(ox, 64, 256, 32, enemy.maxhp.to_s) self.contents.draw_text(ox, 128, 256, 32, enemy.maxsp.to_s) self.contents.draw_text(ox, 192, 256, 32, enemy.exp.to_s) self.contents.draw_text(ox, 256, 256, 32, enemy.gold.to_s) self.contents.draw_text(ox, 320, 256, 32, (drop != nil ? t : 'nothing')) when (1 - ((0..1).find_all {|i| @d[i]}).size) self.contents.draw_text(x, 32, 128, 32, $data_system.words.str) self.contents.draw_text(x, 96, 128, 32, $data_system.words.dex) self.contents.draw_text(x, 160, 128, 32, $data_system.words.agi) self.contents.draw_text(x, 224, 128, 32, $data_system.words.int) self.contents.draw_text(ox, 64, 256, 32, enemy.str.to_s) self.contents.draw_text(ox, 128, 256, 32, enemy.dex.to_s) self.contents.draw_text(ox, 256, 256, 32, enemy.agi.to_s) self.contents.draw_text(ox, 192, 256, 32, enemy.int.to_s) when (2 - ((0..2).find_all {|i| @d[i]}).size) self.contents.draw_text(x, 32, 128, 32, $data_system.words.atk) self.contents.draw_text(x, 96, 128, 32, $data_system.words.pdef) self.contents.draw_text(x, 160, 128, 32, $data_system.words.mdef) self.contents.draw_text(x, 224, 128, 32, EVASION) self.contents.draw_text(ox, 64, 256, 32, enemy.atk.to_s) self.contents.draw_text(ox, 128, 256, 32, enemy.pdef.to_s) self.contents.draw_text(ox, 192, 256, 32, enemy.mdef.to_s) self.contents.draw_text(ox, 256, 256, 32, enemy.eva.to_s) when (3 - ((0..3).find_all {|i| @d[i]}).size) self.contents.draw_text(x, 32, 544, 32, 'Extremely efficient elements:') draw_elements(enemy, x, 1) when (4 - ((0..4).find_all {|i| @d[i]}).size) self.contents.draw_text(x, 32, 544, 32, 'Efficient elements:') draw_elements(enemy, x, 2) when (5 - ((0..5).find_all {|i| @d[i]}).size) self.contents.draw_text(x, 32, 544, 32, 'Elemental resistances:') draw_elements(enemy, x, 4) when (6 - ((0..6).find_all {|i| @d[i]}).size) self.contents.draw_text(x, 32, 544, 32, 'Elemental nullifications:') draw_elements(enemy, x, 5) when (7 - ((0..7).find_all {|i| @d[i]}).size) self.contents.draw_text(x, 32, 544, 32, 'Elemental absorbtions:') draw_elements(enemy, x, 6) when (8 - ((0..8).find_all {|i| @d[i]}).size) self.contents.draw_text(x, 32, 544, 32, 'Extremely efficient status effects:') draw_states(enemy, x, 1) when (9 - ((0..9).find_all {|i| @d[i]}).size) self.contents.draw_text(x, 32, 544, 32, 'Efficient status effects:') draw_states(enemy, x, 2) when (10 - ((0..10).find_all {|i| @d[i]}).size) self.contents.draw_text(x, 32, 544, 32, 'Status effect resistances:') draw_states(enemy, x, 4) when (11 - ((0..11).find_all {|i| @d[i]}).size) self.contents.draw_text(x, 32, 544, 32, 'Strong status effect resistances:') draw_states(enemy, x, 5) when (12 - ((0..12).find_all {|i| @d[i]}).size) self.contents.draw_text(x, 32, 544, 32, 'Status effect immunities:') draw_states(enemy, x, 6) when (13 - ((0..13).find_all {|i| @d[i]}).size) self.contents.draw_text(x, 32, 544, 32, 'Informations:') draw_info(enemy, x) end else self.contents.draw_text(0, 64, 544, 32, 'Unknown', 1) end end def draw_elements(enemy, x, index) elements = [] (1...$data_system.elements.size).each {|id| if !$DUMMY_ELEMENTS.include?(id) && index == $data_enemies[@enemies[@index_enemy].id].element_ranks[id] elements.push($data_system.elements[id]) end} elements = ['Nothing'] if elements.size == 0 elements.each_index {|i| self.contents.draw_text(x, 64 + i * 32, 544, 32, elements[i])} end def draw_states(enemy, x, index) states = [] (1...$data_states.size).each {|id| if !$DUMMY_STATES.include?(id) && index == $data_enemies[@enemies[@index_enemy].id].state_ranks[id] states.push($data_states[id].name) end} states = ['Nothing'] if states.size == 0 states.each_index {|i| self.contents.draw_text(x, 64 + i * 32, 544, 32, states[i])} end def draw_info(enemy, x) text = self.contents.slice_text($game_system.get_bestiary_info(enemy.id), 528) text.each_index {|i| self.contents.draw_text(x, 64 + i*32, 544, 32, text[i])} end end #============================================================================== # Scene_Bestiary #============================================================================== class Scene_Bestiary def main @spriteset = Spriteset_Map.new if MAP_BACKGROUND @beast_window = Window_Beast.new Graphics.transition loop do Graphics.update Input.update update break if $scene != self end Graphics.freeze @spriteset.dispose if MAP_BACKGROUND @beast_window.dispose end def update @beast_window.update if MAP_BACKGROUND && (Input.trigger?(Input::A) || Input.trigger?(Input::C)) Graphics.freeze $game_system.se_play($data_system.cursor_se) case @beast_window.mode when 0 then @beast_window.back_opacity = 128 when 1 then @beast_window.opacity = 0 when 2 then @beast_window.opacity = @beast_window.back_opacity = 255 end $game_system.window_mode = ($game_system.window_mode+1) % 3 @beast_window.mode = $game_system.window_mode Graphics.transition(5) end if Input.trigger?(Input::B) $game_system.se_play($data_system.cancel_se) $scene = Scene_Map.new end end end #============================================================================== # Scene_Battle #============================================================================== class Scene_Battle alias update_beast_later update def update if @log == nil && !$override_bestiary @log = true $game_troop.enemies.each {|enemy| $game_system.add_beast(enemy.id)} end update_beast_later end end