Merge branch 'dev'

This commit is contained in:
Maruno17
2022-05-19 23:23:50 +01:00
406 changed files with 234045 additions and 104268 deletions

1
.gitignore vendored
View File

@@ -17,6 +17,7 @@ RGSS*.dll
.vscode/
*.code-workspace
.idea/
*.mkproj
# Operating system generated files & folders
.DS_Store

160
.rubocop.yml Normal file
View File

@@ -0,0 +1,160 @@
AllCops:
TargetRubyVersion: "3.0"
NewCops: enable
#===============================================================================
# Layout
#===============================================================================
# We don't need empty lines in methods to separate "return if"s from later code.
Layout/EmptyLineAfterGuardClause:
Enabled: false
# Extra whitespace often helps to make code more presentable.
Layout/ExtraSpacing:
AllowForAlignment: true
AllowBeforeTrailingComments: true
# In a hash with multiple values (one per line), prefer the => to be lined up
# and text to otherwise be left-aligned.
Layout/HashAlignment:
EnforcedHashRocketStyle: table
EnforcedColonStyle: table
# This means hashes and arrays are written the same way, rather than hashes
# needing to be written like { foo => bar } while arrays are like [foo, bar].
Layout/SpaceInsideHashLiteralBraces:
EnforcedStyle: no_space
#===============================================================================
# Lint
#===============================================================================
# Some methods and blocks will have unused arguments. That's fine.
Lint/UnusedBlockArgument:
Enabled: false
Lint/UnusedMethodArgument:
Enabled: false
#===============================================================================
# Metrics
#===============================================================================
# Yes, Essentials has classes/modules/methods that are too big and complex.
# That's just how it is.
Metrics:
Enabled: false
#===============================================================================
# Naming
#===============================================================================
# This cop forbids class/module names with underscores in them. Having
# underscores isn't the end of the world.
Naming/ClassAndModuleCamelCase:
Enabled: false
# Script files are given names that look reasonable in the list of script
# sections in RMXP, and are all numbered. They won't be camel_case.
Naming/FileName:
Enabled: false
#===============================================================================
# Security
#===============================================================================
# Script event conditions and script switches are eval'd, amongst other things.
Security/Eval:
Enabled: false
# Plenty of things are loaded via Marshal.
Security/MarshalLoad:
Enabled: false
#===============================================================================
# Style
#===============================================================================
# List the attr_reader/writer/accessor variables however you want.
Style/AccessorGrouping:
Enabled: false
# The assign_to_condition style looks awful, indenting loads of lines and
# increasing the separation between variable and value being assigned to it.
Style/ConditionalAssignment:
EnforcedStyle: assign_inside_condition
# Check with yard instead.
Style/Documentation:
Enabled: false
# It's a choice between format and sprintf. We already make use of sprintf and
# the translatable _ISPRINTF, so...
Style/FormatString:
EnforcedStyle: sprintf
# String literals are not frozen by default, which makes this comment a
# pointless bit of boilerplate that we neither need nor want.
Style/FrozenStringLiteralComment:
Enabled: false
# RMXP and Essentials use lots of global variables.
Style/GlobalVars:
Enabled: false
# Mixing the styles within a hash just looks silly.
Style/HashSyntax:
EnforcedStyle: no_mixed_keys
# unless just adds mental gymnastics trying to figure out what it actually
# means. I much prefer if !something.
Style/NegatedIf:
Enabled: false
# .zero?, .positive? and .negative? are more wordy than == 0, > 0 and < 0. They
# also aren't consistent with other value comparisons, e.g. x > 42.
Style/NumericPredicate:
EnforcedStyle: comparison
# Following this just means that calls to an affected method need to know what
# that method calls its parameters, which is ridiculous. Keep things short and
# simple.
Style/OptionalBooleanParameter:
Enabled: false
# has_key? and has_value? are far more readable than key? and value?
Style/PreferredHashMethods:
Enabled: false
# Explicit returns help to show whether a method returns a value.
Style/RedundantReturn:
Enabled: false
# Enforcing the names of variables? To single letter ones? Just no.
Style/SingleLineBlockParams:
Enabled: false
# Single line methods use up less space, and they're easier to list next to each
# other and see that they behave similarly.
Style/SingleLineMethods:
Enabled: false
# Single quotes being faster is hardly measurable and only affects parse time.
# Enforcing double quotes reduces the times where you need to change them
# when introducing an interpolation or an apostrophe. Use single quotes only if
# their semantics are needed.
Style/StringLiterals:
EnforcedStyle: double_quotes
# This cop requires arrays of symbols/text to be written like %i[a b c]. We
# don't need that nonsense. ["a", "b", "c"] is clearer and introduces no
# additional syntax to confuse people.
Style/SymbolArray:
EnforcedStyle: brackets
Style/WordArray:
EnforcedStyle: brackets
# Patentheses around the condition in a ternary operator helps to differentiate
# it from the true/false results.
Style/TernaryParentheses:
EnforcedStyle: require_parentheses

View File

@@ -1,12 +1,12 @@
#==============================================================================#
# Pokémon Essentials #
# Version 19.1.dev #
# Version 20 #
# https://github.com/Maruno17/pokemon-essentials #
#==============================================================================#
module Settings
# The version of your game. It has to adhere to the MAJOR.MINOR.PATCH format.
GAME_VERSION = '1.0.0'
GAME_VERSION = "1.0.0"
# The generation that the battle system follows. Used throughout the battle
# scripts, and also by some other settings which are used in and out of battle
@@ -14,38 +14,10 @@ module Settings
# Note that this isn't perfect. Essentials doesn't accurately replicate every
# single generation's mechanics. It's considered to be good enough. Only
# generations 5 and later are reasonably supported.
MECHANICS_GENERATION = 7
MECHANICS_GENERATION = 8
#=============================================================================
# The default screen width (at a scale of 1.0).
SCREEN_WIDTH = 512
# The default screen height (at a scale of 1.0).
SCREEN_HEIGHT = 384
# The default screen scale factor. Possible values are 0.5, 1.0, 1.5 and 2.0.
SCREEN_SCALE = 1.0
#=============================================================================
# The maximum level Pokémon can reach.
MAXIMUM_LEVEL = 100
# The level of newly hatched Pokémon.
EGG_LEVEL = 1
# The odds of a newly generated Pokémon being shiny (out of 65536).
SHINY_POKEMON_CHANCE = (MECHANICS_GENERATION >= 6) ? 16 : 8
# The odds of a wild Pokémon/bred egg having Pokérus (out of 65536).
POKERUS_CHANCE = 3
# Whether a bred baby Pokémon can inherit any TM/HM moves from its father. It
# can never inherit TM/HM moves from its mother.
BREEDING_CAN_INHERIT_MACHINE_MOVES = (MECHANICS_GENERATION <= 5)
# Whether a bred baby Pokémon can inherit egg moves from its mother. It can
# always inherit egg moves from its father.
BREEDING_CAN_INHERIT_EGG_MOVES_FROM_MOTHER = (MECHANICS_GENERATION >= 6)
#=============================================================================
# The amount of money the player starts the game with.
INITIAL_MONEY = 3000
# The maximum amount of money the player can have.
MAX_MONEY = 999_999
# The maximum number of Game Corner coins the player can have.
@@ -58,25 +30,21 @@ module Settings
MAX_PLAYER_NAME_SIZE = 10
# The maximum number of Pokémon that can be in the party.
MAX_PARTY_SIZE = 6
#=============================================================================
# A set of arrays each containing a trainer type followed by a Global Variable
# number. If the variable isn't set to 0, then all trainers with the
# associated trainer type will be named as whatever is in that variable.
RIVAL_NAMES = [
[:RIVAL1, 12],
[:RIVAL2, 12],
[:CHAMPION, 12]
]
# The maximum level Pokémon can reach.
MAXIMUM_LEVEL = 100
# The level of newly hatched Pokémon.
EGG_LEVEL = 1
# The odds of a newly generated Pokémon being shiny (out of 65536).
SHINY_POKEMON_CHANCE = (MECHANICS_GENERATION >= 6) ? 16 : 8
# Whether super shininess is enabled (uses a different shiny animation).
SUPER_SHINY = (MECHANICS_GENERATION >= 8)
# The odds of a wild Pokémon/bred egg having Pokérus (out of 65536).
POKERUS_CHANCE = 3
#=============================================================================
# Whether outdoor maps should be shaded according to the time of day.
TIME_SHADING = true
#=============================================================================
# Whether poisoned Pokémon will lose HP while walking around in the field.
POISON_IN_FIELD = (MECHANICS_GENERATION <= 4)
# Whether poisoned Pokémon will faint while walking around in the field
@@ -94,9 +62,26 @@ module Settings
# The ID of the common event that runs when the player stops fishing (runs
# instead of showing the reeling in animation).
FISHING_END_COMMON_EVENT = -1
#=============================================================================
# Whether Pokémon in the Day Care gain Exp for each step the player takes.
# This is true for the Day Care and false for the Pokémon Nursery, both of
# which use the same code in Essentials.
DAY_CARE_POKEMON_GAIN_EXP_FROM_WALKING = (MECHANICS_GENERATION <= 6)
# Whether two Pokémon in the Day Care can learn egg moves from each other if
# they are the same species.
DAY_CARE_POKEMON_CAN_SHARE_EGG_MOVES = (MECHANICS_GENERATION >= 8)
# Whether a bred baby Pokémon can inherit any TM/TR/HM moves from its father.
# It can never inherit TM/TR/HM moves from its mother.
BREEDING_CAN_INHERIT_MACHINE_MOVES = (MECHANICS_GENERATION <= 5)
# Whether a bred baby Pokémon can inherit egg moves from its mother. It can
# always inherit egg moves from its father.
BREEDING_CAN_INHERIT_EGG_MOVES_FROM_MOTHER = (MECHANICS_GENERATION >= 6)
# Whether the Pokédex entry of a newly owned species will be shown after it
# hatches from an egg, after it evolves and after obtaining it from a trade,
# in addition to after catching it in battle.
SHOW_NEW_SPECIES_POKEDEX_ENTRY_MORE_OFTEN = (MECHANICS_GENERATION >= 7)
# Whether you get 1 Premier Ball for every 10 of any kind of Poké Ball bought
# at once (true), or 1 Premier Ball for buying 10+ Poké Balls (false).
MORE_BONUS_PREMIER_BALLS = (MECHANICS_GENERATION >= 8)
# The number of steps allowed before a Safari Zone game is over (0=infinite).
SAFARI_STEPS = 600
# The number of seconds a Bug Catching Contest lasts for (0=infinite).
@@ -104,13 +89,60 @@ module Settings
#=============================================================================
# Pairs of map IDs, where the location signpost isn't shown when moving from
# one of the maps in a pair to the other (and vice versa). Useful for single
# long routes/towns that are spread over multiple maps.
# e.g. [4,5,16,17,42,43] will be map pairs 4,5 and 16,17 and 42,43.
# Moving between two maps that have the exact same name won't show the
# location signpost anyway, so you don't need to list those maps here.
NO_SIGNPOSTS = []
# If a move taught by a TM/HM/TR replaces another move, this setting is
# whether the machine's move retains the replaced move's PP (true), or whether
# the machine's move has full PP (false).
TAUGHT_MACHINES_KEEP_OLD_PP = (MECHANICS_GENERATION == 5)
# Whether the Move Relearner can also teach egg moves that the Pokémon knew
# when it hatched and moves that the Pokémon was once taught by a TR. Moves
# from the Pokémon's level-up moveset of the same or a lower level than the
# Pokémon can always be relearned.
MOVE_RELEARNER_CAN_TEACH_MORE_MOVES = (MECHANICS_GENERATION >= 6)
# Whether various HP-healing items heal the amounts they do in Gen 7+ (true)
# or in earlier Generations (false).
REBALANCED_HEALING_ITEM_AMOUNTS = (MECHANICS_GENERATION >= 7)
# Whether Rage Candy Bar acts as a Full Heal (true) or a Potion (false).
RAGE_CANDY_BAR_CURES_STATUS_PROBLEMS = (MECHANICS_GENERATION >= 7)
# Whether vitamins can add EVs no matter how many that stat already has in it
# (true), or whether they can't make that stat's EVs greater than 100 (false).
NO_VITAMIN_EV_CAP = (MECHANICS_GENERATION >= 8)
# Whether Rare Candy can be used on a Pokémon that is already at its maximum
# level if it is able to evolve by level-up (if so, triggers that evolution).
RARE_CANDY_USABLE_AT_MAX_LEVEL = (MECHANICS_GENERATION >= 8)
# Whether the player can choose how many of an item to use at once on a
# Pokémon. This applies to Exp-changing items (Rare Candy, Exp Candies) and
# EV-changing items (vitamins, feathers, EV-lowering berries).
USE_MULTIPLE_STAT_ITEMS_AT_ONCE = (MECHANICS_GENERATION >= 8)
#=============================================================================
# Whether Repel uses the level of the first Pokémon in the party regardless of
# its HP (true), or it uses the level of the first unfainted Pokémon (false).
REPEL_COUNTS_FAINTED_POKEMON = (MECHANICS_GENERATION >= 6)
# Whether more abilities affect whether wild Pokémon appear, which Pokémon
# they are, etc.
MORE_ABILITIES_AFFECT_WILD_ENCOUNTERS = (MECHANICS_GENERATION >= 8)
# Whether the Black/White Flutes will raise/lower the levels of wild Pokémon
# respectively (true), or will lower/raise the wild encounter rate
# respectively (false).
FLUTES_CHANGE_WILD_ENCOUNTER_LEVELS = (MECHANICS_GENERATION >= 6)
# Whether shiny wild Pokémon are more likely to appear if the player has
# previously defeated/caught lots of other Pokémon of the same species.
HIGHER_SHINY_CHANCES_WITH_NUMBER_BATTLED = (MECHANICS_GENERATION >= 8)
# Whether overworld weather can set the default terrain effect in battle.
# Storm weather sets Electric Terrain, and fog weather sets Misty Terrain.
OVERWORLD_WEATHER_SETS_BATTLE_TERRAIN = (MECHANICS_GENERATION >= 8)
#=============================================================================
# A set of arrays each containing a trainer type followed by a Game Variable
# number. If the Variable isn't set to 0, then all trainers with the
# associated trainer type will be named as whatever is in that Variable.
RIVAL_NAMES = [
[:RIVAL1, 12],
[:RIVAL2, 12],
[:CHAMPION, 12]
]
#=============================================================================
@@ -135,34 +167,9 @@ module Settings
#=============================================================================
# If a move taught by a TM/HM/TR replaces another move, this setting is
# whether the machine's move retains the replaced move's PP (true), or whether
# the machine's move has full PP (false).
TAUGHT_MACHINES_KEEP_OLD_PP = (MECHANICS_GENERATION == 5)
# Whether the Black/White Flutes will raise/lower the levels of wild Pokémon
# respectively (true), or will lower/raise the wild encounter rate
# respectively (false).
FLUTES_CHANGE_WILD_ENCOUNTER_LEVELS = (MECHANICS_GENERATION >= 6)
# Whether Repel uses the level of the first Pokémon in the party regardless of
# its HP (true), or it uses the level of the first unfainted Pokémon (false).
REPEL_COUNTS_FAINTED_POKEMON = (MECHANICS_GENERATION >= 6)
# Whether Rage Candy Bar acts as a Full Heal (true) or a Potion (false).
RAGE_CANDY_BAR_CURES_STATUS_PROBLEMS = (MECHANICS_GENERATION >= 7)
#=============================================================================
# The name of the person who created the Pokémon storage system.
def self.storage_creator_name
return _INTL("Bill")
end
# The number of boxes in Pokémon storage.
NUM_STORAGE_BOXES = 30
#=============================================================================
# The names of each pocket of the Bag. Ignore the first entry ("").
# The names of each pocket of the Bag.
def self.bag_pocket_names
return ["",
return [
_INTL("Items"),
_INTL("Medicine"),
_INTL("Poké Balls"),
@@ -173,14 +180,20 @@ module Settings
_INTL("Key Items")
]
end
# The maximum number of slots per pocket (-1 means infinite number). Ignore
# the first number (0).
BAG_MAX_POCKET_SIZE = [0, -1, -1, -1, -1, -1, -1, -1, -1]
# The maximum number of slots per pocket (-1 means infinite number).
BAG_MAX_POCKET_SIZE = [-1, -1, -1, -1, -1, -1, -1, -1]
# Whether each pocket in turn auto-sorts itself by item ID number.
BAG_POCKET_AUTO_SORT = [false, false, false, true, true, false, false, false]
# The maximum number of items each slot in the Bag can hold.
BAG_MAX_PER_SLOT = 999
# Whether each pocket in turn auto-sorts itself by item ID number. Ignore the
# first entry (the 0).
BAG_POCKET_AUTO_SORT = [0, false, false, false, true, true, false, false, false]
#=============================================================================
# The number of boxes in Pokémon storage.
NUM_STORAGE_BOXES = 40
# Whether putting a Pokémon into Pokémon storage will heal it. IF false, they
# are healed by the Recover All: Entire Party event command (at Poké Centers).
HEAL_STORED_POKEMON = (MECHANICS_GENERATION >= 8)
#=============================================================================
@@ -189,16 +202,16 @@ module Settings
# Dex list to view if more than one is available (false).
USE_CURRENT_REGION_DEX = false
# The names of the Pokédex lists, in the order they are defined in the PBS
# file "regionaldexes.txt". The last name is for the National Dex and is added
# onto the end of this array (remember that you don't need to use it). This
# array's order is also the order of $Trainer.pokedex.unlocked_dexes, which
# records which Dexes have been unlocked (the first is unlocked by default).
# If an entry is just a name, then the region map shown in the Area page while
# viewing that Dex list will be the region map of the region the player is
# currently in. The National Dex entry should always behave like this.
# If an entry is of the form [name, number], then the number is a region
# number. That region's map will appear in the Area page while viewing that
# Dex list, no matter which region the player is currently in.
# file "regional_dexes.txt". The last name is for the National Dex and is
# added onto the end of this array (remember that you don't need to use it).
# This array's order is also the order of $player.pokedex.unlocked_dexes,
# which records which Dexes have been unlocked (the first is unlocked by
# default). If an entry is just a name, then the region map shown in the Area
# page while viewing that Dex list will be the region map of the region the
# player is currently in. The National Dex entry should always behave like
# this. If an entry is of the form [name, number], then the number is a region
# number, and that region's map will appear in the Area page while viewing
# that Dex list, no matter which region the player is currently in.
def self.pokedex_names
return [
[_INTL("Kanto Pokédex"), 0],
@@ -231,6 +244,20 @@ module Settings
[0, 52, 20, 14, "mapHiddenFaraday", false]
]
# Whether the player can use Fly while looking at the Town Map. This is only
# allowed if the player can use Fly normally.
CAN_FLY_FROM_TOWN_MAP = true
#=============================================================================
# Pairs of map IDs, where the location signpost isn't shown when moving from
# one of the maps in a pair to the other (and vice versa). Useful for single
# long routes/towns that are spread over multiple maps.
# e.g. [4,5,16,17,42,43] will be map pairs 4,5 and 16,17 and 42,43.
# Moving between two maps that have the exact same name won't show the
# location signpost anyway, so you don't need to list those maps here.
NO_SIGNPOSTS = []
#=============================================================================
# A list of maps used by roaming Pokémon. Each map has an array of other maps
@@ -297,6 +324,10 @@ module Settings
# The Game Switch which, while ON, makes all Pokémon created considered to be
# met via a fateful encounter.
FATEFUL_ENCOUNTER_SWITCH = 32
# The Game Switch which, while ON, disables the effect of the Pokémon Box Link
# and prevents the player from accessing Pokémon storage via the party screen
# with it.
DISABLE_BOX_LINK_SWITCH = 35
#=============================================================================
@@ -323,6 +354,15 @@ module Settings
#=============================================================================
# The default screen width (at a scale of 1.0).
SCREEN_WIDTH = 512
# The default screen height (at a scale of 1.0).
SCREEN_HEIGHT = 384
# The default screen scale factor. Possible values are 0.5, 1.0, 1.5 and 2.0.
SCREEN_SCALE = 1.0
#=============================================================================
# An array of available languages in the game, and their corresponding message
# file in the Data folder. Edit only if you have 2 or more languages to choose
# from.
@@ -393,6 +433,6 @@ end
# DO NOT EDIT THESE!
module Essentials
VERSION = "19.1.dev"
VERSION = "20"
ERROR_TEXT = ""
end

View File

@@ -7,18 +7,16 @@ module PBDebug
rescue
PBDebug.log("")
PBDebug.log("**Exception: #{$!.message}")
PBDebug.log("#{$!.backtrace.inspect}")
PBDebug.log($!.backtrace.inspect.to_s)
PBDebug.log("")
# if $INTERNAL
pbPrintException($!)
# end
pbPrintException($!) # if $INTERNAL
PBDebug.flush
end
end
def self.flush
if $DEBUG && $INTERNAL && @@log.length > 0
File.open("Data/debuglog.txt", "a+b") { |f| f.write("#{@@log}") }
File.open("Data/debuglog.txt", "a+b") { |f| f.write(@@log.to_s) }
end
@@log.clear
end
@@ -26,9 +24,7 @@ module PBDebug
def self.log(msg)
if $DEBUG && $INTERNAL
@@log.push("#{msg}\r\n")
# if @@log.length>1024
PBDebug.flush
# end
PBDebug.flush # if @@log.length > 1024
end
end

View File

@@ -1,26 +1,23 @@
# To use the console, use the executable explicitly built
# with the console enabled on Windows. On Linux and macOS,
# just launch the executable directly from a terminal.
# To use the console, use the executable explicitly built with the console
# enabled on Windows. On Linux and macOS, just launch the executable directly
# from a terminal.
module Console
def self.setup_console
return unless $DEBUG
echoln "GPU Cache Max: #{Bitmap.max_size}"
echoln "--------------------------------"
echoln "-------------------------------------------------------------------------------"
echoln "#{System.game_title} Output Window"
echoln "--------------------------------"
echoln "If you are seeing this window, you are running"
echoln "#{System.game_title} in Debug Mode. This means"
echoln "that you're either playing a Debug Version, or"
echoln "you are playing from within RPG Maker XP."
echoln "-------------------------------------------------------------------------------"
echoln "If you can see this window, you are running the game in Debug Mode. This means"
echoln "that you're either playing a debug version of the game, or you're playing from"
echoln "within RPG Maker XP."
echoln ""
echoln "Closing this window will close the game. If"
echoln "you want to get rid of this window, run the"
echoln "program from the Shell, or download a Release"
echoln "version."
echoln "Closing this window will close the game. If you want to get rid of this window,"
echoln "run the program from the Shell, or download a release version of the game."
echoln ""
echoln "--------------------------------"
echoln "-------------------------------------------------------------------------------"
echoln "Debug Output:"
echoln "--------------------------------"
echoln "-------------------------------------------------------------------------------"
echoln ""
end
@@ -44,9 +41,187 @@ module Kernel
end
def echoln(string)
echo(string)
echo("\r\n")
echo string
echo "\r\n"
end
end
Console.setup_console
#===============================================================================
# Console message formatting
#===============================================================================
module Console
module_function
#-----------------------------------------------------------------------------
# echo string into console (example shorthand for common options)
#-----------------------------------------------------------------------------
# heading 1
def echo_h1(msg)
echoln markup_style("*** #{msg} ***", text: :brown)
echoln ""
end
# heading 2
def echo_h2(msg, **options)
echoln markup_style(msg, **options)
echoln ""
end
# heading 3
def echo_h3(msg)
echoln markup(msg)
echoln ""
end
# list item
def echo_li(msg, pad = 0, color = :brown)
echo markup_style(" -> ", text: color)
pad = (pad - msg.length) > 0 ? "." * (pad - msg.length) : ""
echo markup(msg + pad)
end
# list item with line break after
def echoln_li(msg, pad = 0, color = :brown)
self.echo_li(msg, pad, color)
echoln ""
end
# paragraph with markup
def echo_p(msg)
echoln markup(msg)
end
# warning message
def echo_warn(msg)
echoln markup_style("WARNING: #{msg}", text: :yellow)
end
# error message
def echo_error(msg)
echoln markup_style("ERROR: #{msg}", text: :light_red)
end
# status output
def echo_status(status)
if status
echoln markup_style("OK", text: :green)
else
echoln markup_style("FAIL", text: :red)
end
end
# completion output
def echo_done(status)
if status
echoln markup_style("done", text: :green)
else
echoln markup_style("error", text: :red)
end
end
#-----------------------------------------------------------------------------
# Markup options
#-----------------------------------------------------------------------------
def string_colors
{
default: "38", black: "30", red: "31", green: "32", brown: "33",
blue: "34", purple: "35", cyan: "36", gray: "37",
dark_gray: "1;30", light_red: "1;31", light_green: "1;32", yellow: "1;33",
light_blue: "1;34", light_purple: "1;35", light_cyan: "1;36", white: "1;37"
}
end
def background_colors
{
default: "0", black: "40", red: "41", green: "42", brown: "43",
blue: "44", purple: "45", cyan: "46", gray: "47",
dark_gray: "100", light_red: "101", light_green: "102", yellow: "103",
light_blue: "104", light_purple: "105", light_cyan: "106", white: "107"
}
end
def font_options
{
bold: "1", dim: "2", italic: "3", underline: "4", reverse: "7",
hidden: "8"
}
end
# Text markup that turns text between them a certain color
def markup_colors
{
"`" => :cyan, '"' => :purple, "'" => :purple, "$" => :green, "~" => :red
}
end
def markup_options
{
"__" => :underline, "*" => :bold, "|" => :italic
}
end
# apply console coloring
def markup_style(string, text: :default, bg: :default, **options)
# get colors
code_text = string_colors[text]
code_bg = background_colors[bg]
# get options
options_pool = options.select { |key, val| font_options.key?(key) && val }
markup_pool = options_pool.keys.map { |opt| font_options[opt] }.join(";").squeeze
# return formatted string
"\e[#{code_bg};#{markup_pool};#{code_text}m#{string}\e[0m".squeeze(";")
end
#-----------------------------------------------------------------------------
# Perform markup on text
#-----------------------------------------------------------------------------
def markup_all_options
@markup_all_options ||= markup_colors.merge(markup_options)
end
def markup_component(string, component, key, options)
# trim inner markup content
l = key.length
trimmed = component[l...-l]
# merge markup options
options[trimmed] = {} unless options[trimmed]
options[trimmed].deep_merge!({}.tap do |new_opt|
new_opt[:text] = markup_colors[key] if markup_colors.key?(key)
new_opt[markup_options[key]] = true if markup_options.key?(key)
end)
# remove markup from input string
string.gsub!(component, trimmed)
# return output
return string, options
end
def markup_breakdown(string, options = {})
# iterate through all options
markup_all_options.each_key do |key|
# ensure escape
key_char = key.chars.map { |c| "\\#{c}" }.join
# define regex
regex = "#{key_char}.*?#{key_char}"
# go through matches
string.scan(/#{regex}/).each do |component|
return *markup_breakdown(*markup_component(string, component, key, options))
end
end
# return output
return string, options
end
def markup(string)
# get a breakdown of all markup options
string, options = markup_breakdown(string)
# iterate through each option and apply
options.each do |key, opt|
string.gsub!(key, markup_style(key, **opt))
end
# return string
return string
end
end

View File

@@ -4,12 +4,23 @@
class Reset < Exception
end
class EventScriptError < Exception
attr_accessor :event_message
def initialize(message)
super(nil)
@event_message = message
end
end
def pbGetExceptionMessage(e, _script = "")
return e.event_message.dup if e.is_a?(EventScriptError) # Message with map/event ID generated elsewhere
emessage = e.message.dup
emessage.force_encoding(Encoding::UTF_8)
if e.is_a?(Hangup)
case e
when Hangup
emessage = "The script is taking too long. The game will restart."
elsif e.is_a?(Errno::ENOENT)
when Errno::ENOENT
filename = emessage.sub("No such file or directory - ", "")
emessage = "File #{filename} not found."
end
@@ -18,27 +29,26 @@ def pbGetExceptionMessage(e,_script="")
end
def pbPrintException(e)
emessage = ""
if $EVENTHANGUPMSG && $EVENTHANGUPMSG!=""
emessage = $EVENTHANGUPMSG # Message with map/event ID generated elsewhere
$EVENTHANGUPMSG = nil
else
emessage = pbGetExceptionMessage(e)
end
# begin message formatting
message = "[Pokémon Essentials version #{Essentials::VERSION}]\r\n"
message += "#{Essentials::ERROR_TEXT}\r\n" # For third party scripts to add to
if !e.is_a?(EventScriptError)
message += "Exception: #{e.class}\r\n"
message += "Message: #{emessage}\r\n"
message += "Message: "
end
message += emessage
# show last 10/25 lines of backtrace
message += "\r\nBacktrace:\r\n"
btrace = ""
if !e.is_a?(EventScriptError)
message += "\r\n\r\nBacktrace:\r\n"
backtrace_text = ""
if e.backtrace
maxlength = ($INTERNAL) ? 25 : 10
e.backtrace[0, maxlength].each { |i| btrace += "#{i}\r\n" }
e.backtrace[0, maxlength].each { |i| backtrace_text += "#{i}\r\n" }
end
backtrace_text.gsub!(/Section(\d+)/) { $RGSS_SCRIPTS[$1.to_i][1] } rescue nil
message += backtrace_text
end
btrace.gsub!(/Section(\d+)/) { $RGSS_SCRIPTS[$1.to_i][1] } rescue nil
message += btrace
# output to log
errorlog = "errorlog.txt"
errorlog = RTP.getSaveFileName("errorlog.txt") if (Object.const_defined?(:RTP) rescue false)
@@ -55,7 +65,7 @@ def pbPrintException(e)
print("#{message}\r\nThis exception was logged in #{errorlogline}.\r\nHold Ctrl when closing this message to copy it to the clipboard.")
# Give a ~500ms coyote time to start holding Control
t = System.delta
until (System.delta - t) >= 500000
until (System.delta - t) >= 500_000
Input.update
if Input.press?(Input::CTRL)
Input.clipboard = message

View File

@@ -8,15 +8,14 @@ module Deprecation
# @param removal_version [String] version the method is removed in
# @param alternative [String] preferred alternative method
def warn_method(method_name, removal_version = nil, alternative = nil)
text = _INTL('WARN: usage of deprecated method "{1}" or its alias.', method_name)
text = _INTL('Usage of deprecated method "{1}" or its alias.', method_name)
unless removal_version.nil?
text += _INTL("\nThe method is slated to be"\
" removed in Essentials {1}.", removal_version)
text += "\r\n" + _INTL("The method is slated to be removed in Essentials {1}.", removal_version)
end
unless alternative.nil?
text += _INTL("\nUse \"{1}\" instead.", alternative)
text += "\r\n" + _INTL("Use \"{1}\" instead.", alternative)
end
echoln text
Console.echo_warn text
end
end
@@ -41,11 +40,11 @@ class Module
raise ArgumentError, "#{class_name} does not have method #{aliased_method} defined"
end
delimiter = class_method ? '.' : '#'
delimiter = class_method ? "." : "#"
target.define_method(name) do |*args, **kvargs|
alias_name = format('%s%s%s', class_name, delimiter, name)
aliased_method_name = format('%s%s%s', class_name, delimiter, aliased_method)
alias_name = sprintf("%s%s%s", class_name, delimiter, name)
aliased_method_name = sprintf("%s%s%s", class_name, delimiter, aliased_method)
Deprecation.warn_method(alias_name, removal_in, aliased_method_name)
method(aliased_method).call(*args, **kvargs)
end

View File

@@ -1,20 +1,31 @@
# Using mkxp-z v2.2.0 - https://gitlab.com/mkxp-z/mkxp-z/-/releases/v2.2.0
# Using mkxp-z v2.3.1 - https://gitlab.com/mkxp-z/mkxp-z/-/releases/v2.3.1
$VERBOSE = nil
Font.default_shadow = false if Font.respond_to?(:default_shadow)
Graphics.frame_rate = 40
Encoding.default_internal = Encoding::UTF_8
Encoding.default_external = Encoding::UTF_8
def pbSetWindowText(string)
System.set_window_title(string || System.game_title)
end
class Bitmap
attr_accessor :text_offset_y
alias mkxp_draw_text draw_text unless method_defined?(:mkxp_draw_text)
def draw_text(x, y, width, height, text, align = 0)
def draw_text(x, y, width, height = nil, text = "", align = 0)
if x.is_a?(Rect)
x.y -= (@text_offset_y || 0)
# rect, string & alignment
mkxp_draw_text(x, y, width)
else
y -= (@text_offset_y || 0)
height = text_size(text).height
mkxp_draw_text(x, y, width, height, text, align)
end
end
end
module Graphics
def self.delta_s

View File

@@ -9,7 +9,7 @@ class Dir
files = []
filters = [filters] if !filters.is_a?(Array)
self.chdir(dir) do
for filter in filters
filters.each do |filter|
self.glob(filter) { |f| files.push(full ? (dir + "/" + f) : f) }
end
end
@@ -22,7 +22,7 @@ class Dir
# sets variables for starting
files = []
subfolders = []
for file in self.get(dir, filters, full)
self.get(dir, filters, full).each do |file|
# engages in recursion to read the entire file tree
if self.safe?(file) # Is a directory
subfolders += self.all(file, filters, full)
@@ -43,6 +43,42 @@ class Dir
return ret
end
#-----------------------------------------------------------------------------
# Creates all the required directories for filename path
#-----------------------------------------------------------------------------
def self.create(path)
path.gsub!("\\", "/") # Windows compatibility
# get path tree
dirs = path.split("/")
full = ""
for dir in dirs
full += dir + "/"
# creates directories
self.mkdir(full) if !self.safe?(full)
end
end
#-----------------------------------------------------------------------------
# Generates entire folder tree from a certain directory
#-----------------------------------------------------------------------------
def self.all_dirs(dir)
# sets variables for starting
dirs = []
for file in self.get(dir, "*", true)
# engages in recursion to read the entire folder tree
dirs += self.all_dirs(file) if self.safe?(file)
end
# returns all found directories
return dirs.length > 0 ? (dirs + [dir]) : [dir]
end
#-----------------------------------------------------------------------------
# Deletes all the files in a directory and all the sub directories (allows for non-empty dirs)
#-----------------------------------------------------------------------------
def self.delete_all(dir)
# delete all files in dir
self.all(dir).each { |f| File.delete(f) }
# delete all dirs in dir
self.all_dirs(dir).each { |f| Dir.delete(f) }
end
#-----------------------------------------------------------------------------
end
@@ -56,7 +92,15 @@ class File
#-----------------------------------------------------------------------------
def self.safe?(file)
ret = false
self.open(file, 'rb') { ret = true } rescue nil
self.open(file, "rb") { ret = true } rescue nil
return ret
end
#-----------------------------------------------------------------------------
# Checks for existing .rxdata file
#-----------------------------------------------------------------------------
def self.safeData?(file)
ret = false
ret = (load_data(file) ? true : false) rescue false
return ret
end
#-----------------------------------------------------------------------------
@@ -108,8 +152,8 @@ end
def pbResolveAudioSE(file)
return nil if !file
if RTP.exists?("Audio/SE/"+file,["",".wav",".mp3",".ogg"])
return RTP.getPath("Audio/SE/"+file,["",".wav",".mp3",".ogg"])
if RTP.exists?("Audio/SE/" + file, ["", ".wav", ".ogg"]) # ".mp3"
return RTP.getPath("Audio/SE/" + file, ["", ".wav", ".ogg"]) # ".mp3"
end
return nil
end
@@ -157,7 +201,7 @@ def canonicalize(c)
pos = -1
ret = []
retstr = ""
for x in csplit
csplit.each do |x|
if x == ".."
if pos >= 0
ret.delete_at(pos)
@@ -168,7 +212,7 @@ def canonicalize(c)
pos += 1
end
end
for i in 0...ret.length
ret.length.times do |i|
retstr += "/" if i > 0
retstr += ret[i]
end
@@ -184,7 +228,7 @@ module RTP
return false if nil_or_empty?(filename)
eachPathFor(filename) { |path|
return true if safeExists?(path)
for ext in extensions
extensions.each do |ext|
return true if safeExists?(path + ext)
end
}
@@ -196,14 +240,14 @@ module RTP
end
def self.getAudioPath(filename)
return self.getPath(filename,["",".mp3",".wav",".wma",".mid",".ogg",".midi"])
return self.getPath(filename, ["", ".wav", ".wma", ".mid", ".ogg", ".midi"]) # ".mp3"
end
def self.getPath(filename, extensions = [])
return filename if nil_or_empty?(filename)
eachPathFor(filename) { |path|
return path if safeExists?(path)
for ext in extensions
extensions.each do |ext|
file = path + ext
return file if safeExists?(file)
end
@@ -240,8 +284,6 @@ module RTP
yield ".".gsub(/[\/\\]/, "/").gsub(/[\/\\]$/, "") + "/"
end
private
def self.getSaveFileName(fileName)
File.join(getSaveFolder, fileName)
end
@@ -260,15 +302,15 @@ end
module FileTest
Image_ext = ['.png', '.gif'] # '.jpg', '.jpeg', '.bmp',
Audio_ext = ['.mp3', '.mid', '.midi', '.ogg', '.wav', '.wma']
IMAGE_EXTENSIONS = [".png", ".gif"] # ".jpg", ".jpeg", ".bmp",
AUDIO_EXTENSIONS = [".mid", ".midi", ".ogg", ".wav", ".wma"] # ".mp3"
def self.audio_exist?(filename)
return RTP.exists?(filename,Audio_ext)
return RTP.exists?(filename, AUDIO_EXTENSIONS)
end
def self.image_exist?(filename)
return RTP.exists?(filename,Image_ext)
return RTP.exists?(filename, IMAGE_EXTENSIONS)
end
end
@@ -277,7 +319,7 @@ end
# Used to determine whether a data file exists (rather than a graphics or
# audio file). Doesn't check RTP, but does check encrypted archives.
# Note: pbGetFileChar checks anything added in MKXP's RTP setting,
# NOTE: pbGetFileChar checks anything added in MKXP's RTP setting,
# and matching mount points added through System.mount
def pbRgssExists?(filename)
if safeExists?("./Game.rgssad")
@@ -291,7 +333,7 @@ end
# Opens an IO, even if the file is in an encrypted archive.
# Doesn't check RTP for the file.
# Note: load_data checks anything added in MKXP's RTP setting,
# NOTE: load_data checks anything added in MKXP's RTP setting,
# and matching mount points added through System.mount
def pbRgssOpen(file, mode = nil)
# File.open("debug.txt","ab") { |fw| fw.write([file,mode,Time.now.to_f].inspect+"\r\n") }
@@ -320,7 +362,7 @@ def pbGetFileChar(file)
canon_file = canonicalize(file)
if !safeExists?("./Game.rgssad")
return nil if !safeExists?(canon_file)
return nil if file.last == '/' # Is a directory
return nil if file.last == "/" # Is a directory
begin
File.open(canon_file, "rb") { |f| return f.read(1) } # read one byte
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES, Errno::EISDIR
@@ -338,13 +380,13 @@ end
def pbTryString(x)
ret = pbGetFileChar(x)
return (ret!=nil && ret!="") ? x : nil
return nil_or_empty?(ret) ? nil : x
end
# Gets the contents of a file. Doesn't check RTP, but does check
# encrypted archives.
# Note: load_data will check anything added in MKXP's RTP setting,
# NOTE: load_data will check anything added in MKXP's RTP setting,
# and matching mount points added through System.mount
def pbGetFileString(file)
file = canonicalize(file)
@@ -380,7 +422,7 @@ class StringInput
f = super
yield f
ensure
f.close if f
f&.close
end
else
super
@@ -403,7 +445,7 @@ class StringInput
end
def close
raise IOError, 'closed stream' if @closed
raise IOError, "closed stream" if @closed
@pos = nil
@closed = true
end
@@ -411,7 +453,7 @@ class StringInput
def closed?; @closed; end
def pos
raise IOError, 'closed stream' if @closed
raise IOError, "closed stream" if @closed
[@pos, @string.size].min
end
@@ -422,7 +464,7 @@ class StringInput
def pos=(value); seek(value); end
def seek(offset, whence = IO::SEEK_SET)
raise IOError, 'closed stream' if @closed
raise IOError, "closed stream" if @closed
case whence
when IO::SEEK_SET then @pos = offset
when IO::SEEK_CUR then @pos += offset
@@ -436,12 +478,12 @@ class StringInput
end
def eof?
raise IOError, 'closed stream' if @closed
raise IOError, "closed stream" if @closed
@pos > @string.size
end
def each(&block)
raise IOError, 'closed stream' if @closed
raise IOError, "closed stream" if @closed
begin
@string.each(&block)
ensure
@@ -450,8 +492,9 @@ class StringInput
end
def gets
raise IOError, 'closed stream' if @closed
if idx = @string.index(?\n, @pos)
raise IOError, "closed stream" if @closed
idx = @string.index("\n", @pos)
if idx
idx += 1 # "\n".size
line = @string[@pos...idx]
@pos = idx
@@ -465,7 +508,7 @@ class StringInput
end
def getc
raise IOError, 'closed stream' if @closed
raise IOError, "closed stream" if @closed
ch = @string[@pos]
@pos += 1
@pos += 1 if @pos == @string.size
@@ -473,7 +516,7 @@ class StringInput
end
def read(len = nil)
raise IOError, 'closed stream' if @closed
raise IOError, "closed stream" if @closed
if !len
return nil if eof?
rest = @string[@pos...@string.size]
@@ -485,8 +528,6 @@ class StringInput
@pos += 1 if @pos == @string.size
str
end
def read_all; read(); end
alias read_all read
alias sysread read
end

View File

@@ -67,7 +67,7 @@ module FileInputMixin
self.pos = 0
offset = fgetdw >> 3
return 0 if index >= offset
self.pos = index * 8 + 4
self.pos = (index * 8) + 4
return fgetdw
end
@@ -137,7 +137,7 @@ class StringInput
end
def each_byte
while !eof?
until eof?
yield getc
end
end

View File

@@ -6,16 +6,16 @@
def pbPostData(url, postdata, filename = nil, depth = 0)
if url[/^http:\/\/([^\/]+)(.*)$/]
host = $1
path = $2
path = "/" if path.length==0
# path = $2
# path = "/" if path.length == 0
userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14"
body = postdata.map { |key, value|
keyString = key.to_s
valueString = value.to_s
keyString.gsub!(/[^a-zA-Z0-9_\.\-]/n) { |s| sprintf('%%%02x', s[0]) }
valueString.gsub!(/[^a-zA-Z0-9_\.\-]/n) { |s| sprintf('%%%02x', s[0]) }
keyString.gsub!(/[^a-zA-Z0-9_\.\-]/n) { |s| sprintf("%%%02x", s[0]) }
valueString.gsub!(/[^a-zA-Z0-9_\.\-]/n) { |s| sprintf("%%%02x", s[0]) }
next "#{keyString}=#{valueString}"
}.join('&')
}.join("&")
ret = HTTPLite.post_body(
url,
body,

View File

@@ -2,7 +2,7 @@
# class Object
#===============================================================================
class Object
alias full_inspect inspect
alias full_inspect inspect unless method_defined?(:full_inspect)
def inspect
return "#<#{self.class}>"
@@ -23,32 +23,21 @@ end
#===============================================================================
class String
def starts_with_vowel?
return ['a', 'e', 'i', 'o', 'u'].include?(self[0, 1].downcase)
return ["a", "e", "i", "o", "u"].include?(self[0, 1].downcase)
end
def first(n = 1)
return self[0...n]
end
def first(n = 1); return self[0...n]; end
def last(n = 1)
return self[-n..-1] || self
end
def last(n = 1); return self[-n..-1] || self; end
def blank?
blank = true
s = self.scan(/./)
for l in s
blank = false if l != ""
end
return blank
end
def blank?; return self.strip.empty?; end
def cut(bitmap, width)
string = self
width -= bitmap.text_size("...").width
string_width = 0
text = []
for char in string.scan(/./)
string.scan(/./).each do |char|
wdh = bitmap.text_size(char).width
next if (wdh + string_width) > width
string_width += wdh
@@ -56,11 +45,15 @@ class String
end
text.push("...") if text.length < string.length
new_string = ""
for char in text
text.each do |char|
new_string += char
end
return new_string
end
def numeric?
return !self[/^[+-]?([0-9]+)(?:\.[0-9]+)?$/].nil?
end
end
#===============================================================================
@@ -100,6 +93,29 @@ class Array
end
end
#===============================================================================
# class Hash
#===============================================================================
class Hash
def deep_merge(hash)
merged_hash = self.clone
merged_hash.deep_merge!(hash) if hash.is_a?(Hash)
return merged_hash
end
def deep_merge!(hash)
# failsafe
return unless hash.is_a?(Hash)
hash.each do |key, val|
if self[key].is_a?(Hash)
self[key].deep_merge!(val)
else
self[key] = val
end
end
end
end
#===============================================================================
# module Enumerable
#===============================================================================
@@ -111,6 +127,144 @@ module Enumerable
end
end
#===============================================================================
# class File
#===============================================================================
class File
# Copies the source file to the destination path.
def self.copy(source, destination)
data = ""
t = Time.now
File.open(source, "rb") do |f|
loop do
r = f.read(4096)
break if !r
if Time.now - t > 1
Graphics.update
t = Time.now
end
data += r
end
end
File.delete(destination) if File.file?(destination)
f = File.new(destination, "wb")
f.write data
f.close
end
# Copies the source to the destination and deletes the source.
def self.move(source, destination)
File.copy(source, destination)
File.delete(source)
end
end
#===============================================================================
# class Color
#===============================================================================
class Color
# alias for old constructor
alias init_original initialize unless self.private_method_defined?(:init_original)
# New constructor, accepts RGB values as well as a hex number or string value.
def initialize(*args)
pbPrintException("Wrong number of arguments! At least 1 is needed!") if args.length < 1
if args.length == 1
if args.first.is_a?(Fixnum)
hex = args.first.to_s(16)
elsif args.first.is_a?(String)
try_rgb_format = args.first.split(",")
return init_original(*try_rgb_format.map(&:to_i)) if try_rgb_format.length.between?(3, 4)
hex = args.first.delete("#")
end
pbPrintException("Wrong type of argument given!") if !hex
r = hex[0...2].to_i(16)
g = hex[2...4].to_i(16)
b = hex[4...6].to_i(16)
elsif args.length == 3
r, g, b = *args
end
return init_original(r, g, b) if r && g && b
return init_original(*args)
end
# Returns this color as a hex string like "#RRGGBB".
def to_hex
r = sprintf("%02X", self.red)
g = sprintf("%02X", self.green)
b = sprintf("%02X", self.blue)
return ("#" + r + g + b).upcase
end
# Returns this color as a 24-bit color integer.
def to_i
return self.to_hex.delete("#").to_i(16)
end
# Converts the provided hex string/24-bit integer to RGB values.
def self.hex_to_rgb(hex)
hex = hex.delete("#") if hex.is_a?(String)
hex = hex.to_s(16) if hex.is_a?(Numeric)
r = hex[0...2].to_i(16)
g = hex[2...4].to_i(16)
b = hex[4...6].to_i(16)
return r, g, b
end
# Parses the input as a Color and returns a Color object made from it.
def self.parse(color)
case color
when Color
return color
when String, Numeric
return Color.new(color)
end
# returns nothing if wrong input
return nil
end
# Returns color object for some commonly used colors
def self.red; return Color.new(255, 0, 0); end
def self.green; return Color.new( 0, 255, 0); end
def self.blue; return Color.new( 0, 0, 255); end
def self.black; return Color.new( 0, 0, 0); end
def self.white; return Color.new(255, 255, 255); end
def self.yellow; return Color.new(255, 255, 0); end
def self.magenta; return Color.new(255, 0, 255); end
def self.teal; return Color.new( 0, 255, 255); end
def self.orange; return Color.new(255, 155, 0); end
def self.purple; return Color.new(155, 0, 255); end
def self.brown; return Color.new(112, 72, 32); end
end
#===============================================================================
# Wrap code blocks in a class which passes data accessible as instance variables
# within the code block.
#
# wrapper = CallbackWrapper.new { puts @test }
# wrapper.set(test: "Hi")
# wrapper.execute #=> "Hi"
#===============================================================================
class CallbackWrapper
@params = {}
def initialize(&block)
@code_block = block
end
def execute(given_block = nil, *args)
execute_block = given_block || @code_block
@params.each do |key, value|
args.instance_variable_set("@#{key.to_s}", value)
end
args.instance_eval(&execute_block)
end
def set(params = {})
@params = params
end
end
#===============================================================================
# Kernel methods
#===============================================================================

View File

@@ -24,7 +24,7 @@ def pbSetTextMessages
begin
t = Time.now.to_i
texts = []
for script in $RGSS_SCRIPTS
$RGSS_SCRIPTS.each do |script|
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
@@ -34,8 +34,8 @@ def pbSetTextMessages
end
if safeExists?("Data/PluginScripts.rxdata")
plugin_scripts = load_data("Data/PluginScripts.rxdata")
for plugin in plugin_scripts
for script in plugin[2]
plugin_scripts.each do |plugin|
plugin[2].each do |script|
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
@@ -50,7 +50,7 @@ def pbSetTextMessages
commonevents = load_data("Data/CommonEvents.rxdata")
items = []
choices = []
for event in commonevents.compact
commonevents.compact.each do |event|
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
@@ -58,7 +58,7 @@ def pbSetTextMessages
begin
neednewline = false
lastitem = ""
for j in 0...event.list.size
event.list.size.times do |j|
list = event.list[j]
if neednewline && list.code != 401
if lastitem != ""
@@ -69,16 +69,16 @@ def pbSetTextMessages
neednewline = false
end
if list.code == 101
lastitem+="#{list.parameters[0]}"
lastitem += list.parameters[0].to_s
neednewline = true
elsif list.code == 102
for k in 0...list.parameters[0].length
list.parameters[0].length.times do |k|
choices.push(list.parameters[0][k])
end
neednewline = false
elsif list.code == 401
lastitem += " " if lastitem != ""
lastitem+="#{list.parameters[0]}"
lastitem += list.parameters[0].to_s
neednewline = true
elsif list.code == 355 || list.code == 655
pbAddScriptTexts(items, list.parameters[0])
@@ -86,21 +86,19 @@ def pbSetTextMessages
pbAddScriptTexts(items, list.parameters[1])
elsif list.code == 209
route = list.parameters[1]
for k in 0...route.list.size
route.list.size.times do |k|
if route.list[k].code == 45
pbAddScriptTexts(items, route.list[k].parameters[0])
end
end
end
end
if neednewline
if lastitem!=""
if neednewline && lastitem != ""
items.push(lastitem)
lastitem = ""
end
end
end
end
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
@@ -110,12 +108,7 @@ def pbSetTextMessages
items.concat(choices)
MessageTypes.setMapMessagesAsHash(0, items)
mapinfos = pbLoadMapInfos
mapnames=[]
for id in mapinfos.keys
mapnames[id]=mapinfos[id].name
end
MessageTypes.setMessages(MessageTypes::MapNames,mapnames)
for id in mapinfos.keys
mapinfos.each_key do |id|
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
@@ -125,16 +118,16 @@ def pbSetTextMessages
map = load_data(filename)
items = []
choices = []
for event in map.events.values
map.events.each_value do |event|
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
end
begin
for i in 0...event.pages.size
event.pages.size.times do |i|
neednewline = false
lastitem = ""
for j in 0...event.pages[i].list.size
event.pages[i].list.size.times do |j|
list = event.pages[i].list[j]
if neednewline && list.code != 401
if lastitem != ""
@@ -145,16 +138,16 @@ def pbSetTextMessages
neednewline = false
end
if list.code == 101
lastitem+="#{list.parameters[0]}"
lastitem += list.parameters[0].to_s
neednewline = true
elsif list.code == 102
for k in 0...list.parameters[0].length
list.parameters[0].length.times do |k|
choices.push(list.parameters[0][k])
end
neednewline = false
elsif list.code == 401
lastitem += " " if lastitem != ""
lastitem+="#{list.parameters[0]}"
lastitem += list.parameters[0].to_s
neednewline = true
elsif list.code == 355 || list.code == 655
pbAddScriptTexts(items, list.parameters[0])
@@ -162,22 +155,20 @@ def pbSetTextMessages
pbAddScriptTexts(items, list.parameters[1])
elsif list.code == 209
route = list.parameters[1]
for k in 0...route.list.size
route.list.size.times do |k|
if route.list[k].code == 45
pbAddScriptTexts(items, route.list[k].parameters[0])
end
end
end
end
if neednewline
if lastitem!=""
if neednewline && lastitem != ""
items.push(lastitem)
lastitem = ""
end
end
end
end
end
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
@@ -215,7 +206,7 @@ def pbEachIntlSection(file)
sectionname = $~[1]
havesection = true
else
if sectionname==nil
if sectionname.nil?
raise _INTL("Expected a section at the beginning of the file (line {1})", lineno)
end
lastsection.push(line.gsub(/\s+$/, ""))
@@ -259,12 +250,13 @@ def pbGetText(infile)
else
intlhash = OrderedHash.new
itemlength = 2
if section.length%2!=0
if section.length.odd?
raise _INTL("Section {1} has an odd number of entries (section was recognized as a hash because its first line is not a number)", name)
end
end
i = 0
loop do break unless i<section.length
loop do
break unless i < section.length
if itemlength == 3
if !section[i][/^\d+$/]
raise _INTL("Expected a number in section {1}, got {2} instead", name, section[i])
@@ -316,7 +308,7 @@ class OrderedHash < Hash
def inspect
str = "{"
for i in 0...@keys.length
@keys.length.times do |i|
str += ", " if i > 0
str += @keys[i].inspect + "=>" + self[@keys[i]].inspect
end
@@ -324,7 +316,7 @@ class OrderedHash < Hash
return str
end
alias :to_s :inspect
alias to_s inspect
def []=(key, value)
oldvalue = self[key]
@@ -334,7 +326,7 @@ class OrderedHash < Hash
@keys |= []
@keys -= [key]
end
return super(key,value)
super(key, value)
end
def self._load(string)
@@ -342,7 +334,7 @@ class OrderedHash < Hash
keysvalues = Marshal.load(string)
keys = keysvalues[0]
values = keysvalues[1]
for i in 0...keys.length
keys.length.times do |i|
ret[keys[i]] = values[i]
end
return ret
@@ -350,7 +342,7 @@ class OrderedHash < Hash
def _dump(_depth = 100)
values = []
for key in @keys
@keys.each do |key|
values.push(self[key])
end
return Marshal.dump([@keys, values])
@@ -416,9 +408,10 @@ class Messages
def self.writeObject(f, msgs, secname, origMessages = nil)
return if !msgs
if msgs.is_a?(Array)
case msgs
when Array
f.write("[#{secname}]\r\n")
for j in 0...msgs.length
msgs.length.times do |j|
next if nil_or_empty?(msgs[j])
value = Messages.normalizeValue(msgs[j])
origValue = ""
@@ -431,10 +424,10 @@ class Messages
f.write(origValue + "\r\n")
f.write(value + "\r\n")
end
elsif msgs.is_a?(OrderedHash)
when OrderedHash
f.write("[#{secname}]\r\n")
keys = msgs.keys
for key in keys
keys.each do |key|
next if nil_or_empty?(msgs[key])
value = Messages.normalizeValue(msgs[key])
valkey = Messages.normalizeValue(key)
@@ -459,12 +452,12 @@ class Messages
f.write("# To localize this text for a particular language, please\r\n")
f.write("# translate every second line of this file.\r\n")
if origMessages.messages[0]
for i in 0...origMessages.messages[0].length
origMessages.messages[0].length.times do |i|
msgs = origMessages.messages[0][i]
Messages.writeObject(f, msgs, "Map#{i}", origMessages)
end
end
for i in 1...origMessages.messages.length
(1...origMessages.messages.length).each do |i|
msgs = origMessages.messages[i]
Messages.writeObject(f, msgs, i, origMessages)
end
@@ -474,7 +467,7 @@ class Messages
def setMessages(type, array)
@messages = [] if !@messages
arr = []
for i in 0...array.length
array.length.times do |i|
arr[i] = (array[i]) ? array[i] : ""
end
@messages[type] = arr
@@ -483,7 +476,7 @@ class Messages
def addMessages(type, array)
@messages = [] if !@messages
arr = (@messages[type]) ? @messages[type] : []
for i in 0...array.length
array.length.times do |i|
arr[i] = (array[i]) ? array[i] : (arr[i]) ? arr[i] : ""
end
@messages[type] = arr
@@ -491,7 +484,7 @@ class Messages
def self.createHash(_type, array)
arr = OrderedHash.new
for i in 0...array.length
array.length.times do |i|
if array[i]
key = Messages.stringToKey(array[i])
arr[key] = array[i]
@@ -502,7 +495,7 @@ class Messages
def self.addToHash(_type, array, hash)
hash = OrderedHash.new if !hash
for i in 0...array.length
array.length.times do |i|
if array[i]
key = Messages.stringToKey(array[i])
hash[key] = array[i]
@@ -627,6 +620,7 @@ module MessageTypes
ScriptTexts = 24
RibbonNames = 25
RibbonDescriptions = 26
StorageCreator = 27
@@messages = Messages.new
@@messagesFallback = Messages.new("Data/messages.dat", true)
@@ -740,8 +734,8 @@ def _INTL(*arg)
string = arg[0]
end
string = string.clone
for i in 1...arg.length
string.gsub!(/\{#{i}\}/,"#{arg[i]}")
(1...arg.length).each do |i|
string.gsub!(/\{#{i}\}/, arg[i].to_s)
end
return string
end
@@ -756,7 +750,7 @@ def _ISPRINTF(*arg)
string = arg[0]
end
string = string.clone
for i in 1...arg.length
(1...arg.length).each do |i|
string.gsub!(/\{#{i}\:([^\}]+?)\}/) { |m|
next sprintf("%" + $1, arg[i])
}
@@ -764,15 +758,15 @@ def _ISPRINTF(*arg)
return string
end
def _I(str)
return _MAPINTL($game_map.map_id,str)
def _I(str, *arg)
return _MAPINTL($game_map.map_id, str, *arg)
end
def _MAPINTL(mapid, *arg)
string = MessageTypes.getFromMapHash(mapid, arg[0])
string = string.clone
for i in 1...arg.length
string.gsub!(/\{#{i}\}/,"#{arg[i]}")
(1...arg.length).each do |i|
string.gsub!(/\{#{i}\}/, arg[i].to_s)
end
return string
end
@@ -780,7 +774,7 @@ end
def _MAPISPRINTF(mapid, *arg)
string = MessageTypes.getFromMapHash(mapid, arg[0])
string = string.clone
for i in 1...arg.length
(1...arg.length).each do |i|
string.gsub!(/\{#{i}\:([^\}]+?)\}/) { |m|
next sprintf("%" + $1, arg[i])
}

View File

@@ -1,8 +1,8 @@
#==============================================================================#
# Plugin Manager #
# by Marin #
# support for external plugin scripts by Luka S.J. #
# tweaked by Maruno #
# Support for external plugin scripts by Luka S.J. #
# Tweaked by Maruno #
#------------------------------------------------------------------------------#
# Provides a simple interface that allows plugins to require dependencies #
# at specific versions, and to specify incompatibilities between plugins. #
@@ -12,152 +12,92 @@
#------------------------------------------------------------------------------#
# Usage: #
# #
# A Pokémon Essentials plugin should register itself using the PluginManager. #
# The simplest way to do so, for a plugin without dependencies, is as follows: #
# Each plugin should have its own folder in the "Plugins" folder found in the #
# main directory. The "Plugins" folder is similar in concept to the "PBS" #
# folder, in that its contents are compiled and recorded as existing. The #
# plugin's script file(s) are placed in its folder - they must be .rb files. #
# #
# A plugin's folder must also contain a "meta.txt" file. This file is what #
# makes Essentials recognise that the plugin exists, and contains important #
# information about the plugin; if this file does not exist, the folder's #
# contents are ignored. Each line in this file is a property. #
# #
# Required lines: #
# #
# Name = Simple Extension The plugin's name #
# Version = 1.0 The plugin's version #
# Essentials = 19.1,20 Compatible version(s) of Essentials #
# Link = https://reliccastle.com/link-to-the-plugin/ #
# Credits = Luka S.J.,Maruno,Marin One or more names #
# #
# A plugin's version should be in the format X or X.Y or X.Y.Z, where X/Y/Z #
# are numbers. You can also use Xa, Xb, Xc, Ya, etc. What matters is that you #
# use version numbers consistently for your plugin. A later version will be #
# alphanumerically higher than an older version. #
# #
# Plugins can interact with each other in several ways, such as requiring #
# another one to exist or by clashing with each other. These interactions are #
# known as dependencies and conflicts. The lines below are all optional, and #
# go in "meta.txt" to define how your plugin works (or doesn't work) with #
# others. You can have multiples of each of these lines. #
# #
# Requires = Basic Plugin Must have this plugin (any version) #
# Requires = Useful Utils,1.1 Must have this plugin/min. version #
# Exact = Scene Tweaks,2 Must have this plugin/version #
# Optional = Extended Windows,1.2 If this plugin exists, load it first #
# Conflicts = Complex Extension Incompatible plugin #
# #
# A plugin that depends on another one ("Requires"/"Exact"/"Optional") will #
# make that other plugin be loaded first. The "Optional" line is for a plugin #
# which isn't necessary, but if it does exist in the same project, it must be #
# at the given version or higher. #
# #
# When plugins are compiled, their scripts are stored in the file #
# "PluginScripts.rxdata" in the "Data" folder. Dependencies defined above will #
# ensure that they are loaded in a suitable order. Scripts within a plugin are #
# loaded alphanumerically, going through subfolders depth-first. #
# #
# The "Plugins" folder should be deleted when the game is released. Scripts in #
# there are compiled, but any other files used by a plugin (graphics/audio) #
# should go into other folders and not the plugin's folder. #
# #
#------------------------------------------------------------------------------#
# The code behind plugins: #
# #
# When a plugin's "meta.txt" file is read, its contents are registered in the #
# PluginManager. A simple example of registering a plugin is as follows: #
# #
# PluginManager.register({ #
# :name => "Basic Plugin", #
# :version => "1.0", #
# :essentials => "20", #
# :link => "https://reliccastle.com/link-to-the-plugin/", #
# :credits => "Marin" #
# :credits => ["Marin"] #
# }) #
# #
# The link portion here is optional, but recommended. This will be shown in #
# the error message if the PluginManager detects that this plugin needs to be #
# updated. #
# The :link value is optional, but recommended. This will be shown in the #
# message if the PluginManager detects that this plugin needs to be updated. #
# #
# A plugin's version should be in the format X.Y.Z, but the number of digits #
# you use does not matter. You can also use Xa, Xb, Xc, Ya, etc. #
# What matters is that you use it consistently, so that it can be compared. #
# #
# IF there are multiple people to credit, their names should be in an array. #
# If there is only one credit, it does not need an array: #
# #
# :credits => "Marin" #
# :credits => ["Marin", "Maruno"], #
# #
# #
# #
# Dependency: #
# #
# A plugin can require another plugin to be installed in order to work. For #
# example, the "Simple Extension" plugin depends on the above "Basic Plugin" #
# like so: #
# Here is the same example but also with dependencies and conflicts: #
# #
# PluginManager.register({ #
# :name => "Simple Extension", #
# :name => "Basic Plugin", #
# :version => "1.0", #
# :essentials => "20", #
# :link => "https://reliccastle.com/link-to-the-plugin/", #
# :credits => ["Marin", "Maruno"], #
# :dependencies => ["Basic Plugin"] #
# :credits => ["Marin"], #
# :dependencies => ["Basic Plugin", #
# ["Useful Utils", "1.1"], #
# [:exact, "Scene Tweaks", "2"], #
# [:optional, "Extended Windows", "1.2"], #
# ], #
# :incompatibilities => ["Simple Extension"] #
# }) #
# #
# If there are multiple dependencies, they should be listed in an array. If #
# there is only one dependency, it does not need an array: #
# #
# :dependencies => "Basic Plugin" #
# #
# To require a minimum version of a dependency plugin, you should turn the #
# dependency's name into an array which contains the name and the version #
# (both as strings). For example, to require "Basic Plugin" version 1.2 or #
# higher, you would write: #
# #
# :dependencies => [ #
# ["Basic Plugin", "1.2"] #
# ] #
# #
# To require a specific version (no higher and no lower) of a dependency #
# plugin, you should add the :exact flag as the first thing in the array for #
# that dependency: #
# #
# :dependencies => [ #
# [:exact, "Basic Plugin", "1.2"] #
# ] #
# #
# If your plugin can work without another plugin, but it is incompatible with #
# an old version of that other plugin, you should list it as an optional #
# dependency. If that other plugin is present in a game, then this optional #
# dependency will check whether it meets the minimum version required for your #
# plugin. Write it in the same way as any other dependency as described above, #
# but use the :optional flag instead. #
# #
# :dependencies => [ #
# [:optional, "QoL Improvements", "1.1"] #
# ] #
# #
# The :optional_exact flag is a combination of :optional and :exact. #
# #
# #
# #
# Incompatibility: #
# #
# If your plugin is known to be incompatible with another plugin, you should #
# list that other plugin as such. Only one of the two plugins needs to list #
# that it is incompatible with the other. #
# #
# PluginManager.register({ #
# :name => "QoL Improvements", #
# :version => "1.0", #
# :link => "https://reliccastle.com/link-to-the-plugin/", #
# :credits => "Marin", #
# :incompatibilities => [ #
# "Simple Extension" #
# ] #
# }) #
# #
#------------------------------------------------------------------------------#
# Plugin folder: #
# #
# The Plugin folder is treated like the PBS folder, but for script files for #
# plugins. Each plugin has its own folder within the Plugin folder. Each #
# plugin must have a meta.txt file in its folder, which contains information #
# about that plugin. Folders without this meta.txt file are ignored. #
# #
# Scripts must be in .rb files. You should not put any other files into a #
# plugin's folder except for script files and meta.txt. #
# #
# When the game is compiled, scripts in these folders are read and converted #
# into a usable format, and saved in the file Data/PluginScripts.rxdata. #
# Script files are loaded in order of their name and subfolder, so it is wise #
# to name script files "001_first script.rb", "002_second script.rb", etc. to #
# ensure they are loaded in the correct order. #
# #
# When the game is compressed for distribution, the Plugin folder and all its #
# contents should be deleted (like the PBS folder), because its contents will #
# be unused (they will have been compiled into the PluginScripts.rxdata file). #
# #
# The contents of meta.txt are as follows: #
# #
# Name = Simple Extension #
# Version = 1.0 #
# Requires = Basic Plugin #
# Requires = Useful Utilities,1.1 #
# Conflicts = Complex Extension #
# Conflicts = Extended Windows #
# Link = https://reliccastle.com/link-to-the-plugin/ #
# Credits = Luka S.J.,Maruno,Marin #
# #
# These lines are related to what is described above. You can have multiple #
# "Requires" and "Conflicts" lines, each listing a single other plugin that is #
# either a dependency or a conflict respectively. #
# #
# Examples of the "Requires" line: #
# #
# Requires = Basic Plugin #
# Requires = Basic Plugin,1.1 #
# Requires = Basic Plugin,1.1,exact #
# Requires = Basic Plugin,1.1,optional #
# Exact = Basic Plugin,1.1 #
# Optional = Basic Plugin,1.1 #
# #
# The "Exact" and "Optional" lines are equivalent to the "Requires" lines #
# that contain those keywords. #
# #
# There is also a "Scripts" line, which lists one or more script files that #
# should be loaded first. You can have multiple "Scripts" lines. However, you #
# can achieve the same effect by simply naming your script files in #
# alphanumeric order to make them load in a particular order, so the "Scripts" #
# line should not be necessary. #
# The example dependencies/conflict are the same as the examples shown above #
# for lines in "meta.txt". :optional_exact is a combination of :exact and #
# :optional, and there is no way to make use of its combined functionality via #
# "meta.txt". #
# #
#------------------------------------------------------------------------------#
# Please give credit when using this. #
@@ -172,21 +112,20 @@ module PluginManager
def self.register(options)
name = nil
version = nil
essentials = nil
link = nil
dependencies = nil
incompats = nil
credits = []
order = [:name, :version, :link, :dependencies, :incompatibilities, :credits]
order = [:name, :version, :essentials, :link, :dependencies, :incompatibilities, :credits]
# Ensure it first reads the plugin's name, which is used in error reporting,
# by sorting the keys
keys = options.keys.sort do |a, b|
idx_a = order.index(a)
idx_a = order.size if idx_a == -1
idx_b = order.index(b)
idx_b = order.size if idx_b == -1
idx_a = order.index(a) || order.size
idx_b = order.index(b) || order.size
next idx_a <=> idx_b
end
for key in keys
keys.each do |key|
value = options[key]
case key
when :name # Plugin name
@@ -202,6 +141,8 @@ module PluginManager
self.error("Plugin version must be a string.")
end
version = value
when :essentials
essentials = value
when :link # Plugin website
if nil_or_empty?(value)
self.error("Plugin link must be a non-empty string.")
@@ -210,12 +151,13 @@ module PluginManager
when :dependencies # Plugin dependencies
dependencies = value
dependencies = [dependencies] if !dependencies.is_a?(Array) || !dependencies[0].is_a?(Array)
for dep in value
if dep.is_a?(String) # "plugin name"
value.each do |dep|
case dep
when String # "plugin name"
if !self.installed?(dep)
self.error("Plugin '#{name}' requires plugin '#{dep}' to be installed above it.")
end
elsif dep.is_a?(Array)
when Array
case dep.size
when 1 # ["plugin name"]
if dep[0].is_a?(String)
@@ -236,7 +178,8 @@ module PluginManager
if self.installed?(dep_name) # Have plugin but lower version
msg = "Plugin '#{name}' requires plugin '#{dep_name}' version #{dep_version} or higher, " +
"but the installed version is #{self.version(dep_name)}."
if dep_link = self.link(dep_name)
dep_link = self.link(dep_name)
if dep_link
msg += "\r\nCheck #{dep_link} for an update to plugin '#{dep_name}'."
end
self.error(msg)
@@ -278,7 +221,8 @@ module PluginManager
msg = "Plugin '#{name}' requires plugin '#{dep_name}', if installed, to be version #{dep_version}"
msg << " or higher" if !exact
msg << ", but the installed version was #{self.version(dep_name)}."
if dep_link = self.link(dep_name)
dep_link = self.link(dep_name)
if dep_link
msg << "\r\nCheck #{dep_link} for an update to plugin '#{dep_name}'."
end
self.error(msg)
@@ -288,16 +232,16 @@ module PluginManager
msg = "Plugin '#{name}' requires plugin '#{dep_name}' to be version #{dep_version}"
msg << " or later" if !exact
msg << ", but the installed version was #{self.version(dep_name)}."
if dep_link = self.link(dep_name)
dep_link = self.link(dep_name)
if dep_link
msg << "\r\nCheck #{dep_link} for an update to plugin '#{dep_name}'."
end
self.error(msg)
else # Don't have plugin
msg = "Plugin '#{name}' requires plugin '#{dep_name}' version #{dep_version} "
msg << "or later " if !exact
msg << "to be installed above it."
self.error(msg)
end
self.error(msg)
end
end
end
@@ -305,7 +249,7 @@ module PluginManager
when :incompatibilities # Plugin incompatibilities
incompats = value
incompats = [incompats] if !incompats.is_a?(Array)
for incompat in incompats
incompats.each do |incompat|
if self.installed?(incompat)
self.error("Plugin '#{name}' is incompatible with '#{incompat}'. " +
"They cannot both be used at the same time.")
@@ -314,11 +258,11 @@ module PluginManager
when :credits # Plugin credits
value = [value] if value.is_a?(String)
if value.is_a?(Array)
for entry in value
if !entry.is_a?(String)
self.error("Plugin '#{name}'s credits array contains a non-string value.")
else
value.each do |entry|
if entry.is_a?(String)
credits << entry
else
self.error("Plugin '#{name}'s credits array contains a non-string value.")
end
end
else
@@ -328,8 +272,8 @@ module PluginManager
self.error("Invalid plugin registry key '#{key}'.")
end
end
for plugin in @@Plugins.values
if plugin[:incompatibilities] && plugin[:incompatibilities].include?(name)
@@Plugins.each_value do |plugin|
if plugin[:incompatibilities]&.include?(name)
self.error("Plugin '#{plugin[:name]}' is incompatible with '#{name}'. " +
"They cannot both be used at the same time.")
end
@@ -338,6 +282,7 @@ module PluginManager
@@Plugins[name] = {
:name => name,
:version => version,
:essentials => essentials,
:link => link,
:dependencies => dependencies,
:incompatibilities => incompats,
@@ -350,8 +295,8 @@ module PluginManager
def self.error(msg)
Graphics.update
t = Thread.new do
echoln "Plugin Error:\r\n#{msg}"
p "Plugin Error: #{msg}"
Console.echo_error "Plugin Error:\r\n#{msg}"
print("Plugin Error:\r\n#{msg}")
Thread.exit
end
while t.status
@@ -408,21 +353,25 @@ module PluginManager
# -1 if v1 is lower than v2
#-----------------------------------------------------------------------------
def self.compare_versions(v1, v2)
d1 = v1.split("")
d1 = v1.chars
d1.insert(0, "0") if d1[0] == "." # Turn ".123" into "0.123"
while d1[-1] == "."; d1 = d1[0..-2]; end # Turn "123." into "123"
d2 = v2.split("")
while d1[-1] == "." # Turn "123." into "123"
d1 = d1[0..-2]
end
d2 = v2.chars
d2.insert(0, "0") if d2[0] == "." # Turn ".123" into "0.123"
while d2[-1] == "."; d2 = d2[0..-2]; end # Turn "123." into "123"
for i in 0...[d1.size, d2.size].max # Compare each digit in turn
while d2[-1] == "." # Turn "123." into "123"
d2 = d2[0..-2]
end
[d1.size, d2.size].max.times do |i| # Compare each digit in turn
c1 = d1[i]
c2 = d2[i]
if c1
return 1 if !c2
return 1 if c1.to_i(16) > c2.to_i(16)
return -1 if c1.to_i(16) < c2.to_i(16)
else
return -1 if c2
elsif c2
return -1
end
end
return 0
@@ -431,25 +380,17 @@ module PluginManager
# formats the error message
#-----------------------------------------------------------------------------
def self.pluginErrorMsg(name, script)
e = $!
# begin message formatting
message = "[Pokémon Essentials version #{Essentials::VERSION}]\r\n"
message += "#{Essentials::ERROR_TEXT}\r\n" # For third party scripts to add to
message += "Error in Plugin [#{name}]:\r\n"
message += "#{$!.class} occurred.\r\n"
# go through message content
for line in $!.message.split("\r\n")
next if nil_or_empty?(line)
n = line[/\d+/]
err = line.split(":")[-1].strip
lms = line.split(":")[0].strip
err.gsub!(n, "") if n
err = err.capitalize if err.is_a?(String) && !err.empty?
linum = n ? "Line #{n}: " : ""
message += "#{linum}#{err}: #{lms}\r\n"
end
message += "Error in Plugin: [#{name}]\r\n"
message += "Exception: #{e.class}\r\n"
message += "Message: "
message += e.message
# show last 10 lines of backtrace
message += "\r\nBacktrace:\r\n"
$!.backtrace[0, 10].each { |i| message += "#{i}\r\n" }
message += "\r\n\r\nBacktrace:\r\n"
e.backtrace[0, 10].each { |i| message += "#{i}\r\n" }
# output to log
errorlog = "errorlog.txt"
errorlog = RTP.getSaveFileName("errorlog.txt") if (Object.const_defined?(:RTP) rescue false)
@@ -466,7 +407,7 @@ module PluginManager
print("#{message}\r\nThis exception was logged in #{errorlogline}.\r\nHold Ctrl when closing this message to copy it to the clipboard.")
# Give a ~500ms coyote time to start holding Control
t = System.delta
until (System.delta - t) >= 500000
until (System.delta - t) >= 500_000
Input.update
if Input.press?(Input::CTRL)
Input.clipboard = message
@@ -487,11 +428,14 @@ module PluginManager
raise _INTL("Bad line syntax (expected syntax like XXX=YYY)\r\n{1}", FileLineData.linereport)
end
property = $~[1].upcase
data = $~[2].split(',')
data = $~[2].split(",")
data.each_with_index { |value, i| data[i] = value.strip }
# begin formatting data hash
case property
when 'REQUIRES'
when "ESSENTIALS"
meta[:essentials] = [] if !meta[:essentials]
data.each { |ver| meta[:essentials].push(ver) }
when "REQUIRES"
meta[:dependencies] = [] if !meta[:dependencies]
if data.length < 2 # No version given, just push name of plugin dependency
meta[:dependencies].push(data[0])
@@ -501,23 +445,23 @@ module PluginManager
else # Push dependency type, name and version of plugin dependency
meta[:dependencies].push([data[2].downcase.to_sym, data[0], data[1]])
end
when 'EXACT'
when "EXACT"
next if data.length < 2 # Exact dependencies must have a version given; ignore if not
meta[:dependencies] = [] if !meta[:dependencies]
meta[:dependencies].push([:exact, data[0], data[1]])
when 'OPTIONAL'
when "OPTIONAL"
next if data.length < 2 # Optional dependencies must have a version given; ignore if not
meta[:dependencies] = [] if !meta[:dependencies]
meta[:dependencies].push([:optional, data[0], data[1]])
when 'CONFLICTS'
when "CONFLICTS"
meta[:incompatibilities] = [] if !meta[:incompatibilities]
data.each { |value| meta[:incompatibilities].push(value) if value && !value.empty? }
when 'SCRIPTS'
when "SCRIPTS"
meta[:scripts] = [] if !meta[:scripts]
data.each { |scr| meta[:scripts].push(scr) }
when 'CREDITS'
when "CREDITS"
meta[:credits] = data
when 'LINK', 'WEBSITE'
when "LINK", "WEBSITE"
meta[:link] = data[0]
else
meta[property.downcase.to_sym] = data[0]
@@ -527,7 +471,7 @@ module PluginManager
# be loaded (files listed in the meta file are loaded first)
meta[:scripts] = [] if !meta[:scripts]
# get all script files from plugin Dir
for fl in Dir.all(dir)
Dir.all(dir).each do |fl|
next if !fl.include?(".rb")
meta[:scripts].push(fl.gsub("#{dir}/", ""))
end
@@ -555,7 +499,7 @@ module PluginManager
return nil if !meta[name] || !meta[name][:dependencies]
og = [name] if !og
# go through all dependencies
for dname in meta[name][:dependencies]
meta[name][:dependencies].each do |dname|
# clean the name to a simple string
dname = dname[0] if dname.is_a?(Array) && dname.length == 2
dname = dname[1] if dname.is_a?(Array) && dname.length == 3
@@ -572,10 +516,10 @@ module PluginManager
#-----------------------------------------------------------------------------
def self.sortLoadOrder(order, plugins)
# go through the load order
for o in order
order.each do |o|
next if !plugins[o] || !plugins[o][:dependencies]
# go through all dependencies
for dname in plugins[o][:dependencies]
plugins[o][:dependencies].each do |dname|
optional = false
# clean the name to a simple string
if dname.is_a?(Array)
@@ -604,7 +548,7 @@ module PluginManager
order = []
# Find all plugin folders that have a meta.txt and add them to the list of
# plugins.
for dir in self.listAll
self.listAll.each do |dir|
# skip if there is no meta file
next if !safeExists?(dir + "/meta.txt")
ndx = order.length
@@ -632,14 +576,14 @@ module PluginManager
return false if !$DEBUG || safeExists?("Game.rgssad")
return true if !safeExists?("Data/PluginScripts.rxdata")
Input.update
return true if Input.press?(Input::CTRL)
return true if Input.press?(Input::SHIFT) || Input.press?(Input::CTRL)
# analyze whether or not to push recompile
mtime = File.mtime("Data/PluginScripts.rxdata")
for o in order
order.each do |o|
# go through all the registered plugin scripts
scr = plugins[o][:scripts]
dir = plugins[o][:dir]
for sc in scr
scr.each do |sc|
return true if File.mtime("#{dir}/#{sc}") > mtime
end
return true if File.mtime("#{dir}/meta.txt") > mtime
@@ -650,18 +594,18 @@ module PluginManager
# Check if plugins need compiling
#-----------------------------------------------------------------------------
def self.compilePlugins(order, plugins)
echo 'Compiling plugin scripts...'
Console.echo_li "Compiling plugin scripts..."
scripts = []
# go through the entire order one by one
for o in order
order.each do |o|
# save name, metadata and scripts array
meta = plugins[o].clone
meta.delete(:scripts)
meta.delete(:dir)
dat = [o, meta, []]
# iterate through each file to deflate
for file in plugins[o][:scripts]
File.open("#{plugins[o][:dir]}/#{file}", 'rb') do |f|
plugins[o][:scripts].each do |file|
File.open("#{plugins[o][:dir]}/#{file}", "rb") do |f|
dat[2].push([file, Zlib::Deflate.deflate(f.read)])
end
end
@@ -669,16 +613,17 @@ module PluginManager
scripts.push(dat)
end
# save to main `PluginScripts.rxdata` file
File.open("Data/PluginScripts.rxdata", 'wb') { |f| Marshal.dump(scripts, f) }
File.open("Data/PluginScripts.rxdata", "wb") { |f| Marshal.dump(scripts, f) }
# collect garbage
GC.start
echoln ' done.'
echoln ''
Console.echo_done(true)
echoln "" if scripts.length == 0
end
#-----------------------------------------------------------------------------
# Check if plugins need compiling
#-----------------------------------------------------------------------------
def self.runPlugins
Console.echo_h1 "Checking plugins"
# get the order of plugins to interpret
order, plugins = self.getPluginOrder
# compile if necessary
@@ -686,13 +631,16 @@ module PluginManager
# load plugins
scripts = load_data("Data/PluginScripts.rxdata")
echoed_plugins = []
for plugin in scripts
scripts.each do |plugin|
# get the required data
name, meta, script = plugin
if !meta[:essentials] || !meta[:essentials].include?(Essentials::VERSION)
Console.echo_warn "Plugin '#{name}' may not be compatible with Essentials v#{Essentials::VERSION}. Trying to load anyway."
end
# register plugin
self.register(meta)
# go through each script and interpret
for scr in script
script.each do |scr|
# turn code into plaintext
code = Zlib::Inflate.inflate(scr[1]).force_encoding(Encoding::UTF_8)
# get rid of tabs
@@ -703,7 +651,7 @@ module PluginManager
# try to run the code
begin
eval(code, TOPLEVEL_BINDING, fname)
echoln "Loaded plugin: #{name}" if !echoed_plugins.include?(name)
Console.echoln_li "Loaded plugin: '#{name}' (ver. #{meta[:version]})" if !echoed_plugins.include?(name)
echoed_plugins.push(name)
rescue Exception # format error message to display
self.pluginErrorMsg(name, sname)
@@ -711,7 +659,27 @@ module PluginManager
end
end
end
echoln '' if !echoed_plugins.empty?
if scripts.length > 0
echoln ""
Console.echo_h2("Successfully loaded #{scripts.length} plugin(s)", text: :green)
else
Console.echo_h2("No plugins found", text: :green)
end
end
#-----------------------------------------------------------------------------
# Get plugin dir from name based on meta entries
#-----------------------------------------------------------------------------
def self.findDirectory(name)
# go through the plugins folder
Dir.get("Plugins").each do |dir|
next if !Dir.safe?(dir)
next if !safeExists?(dir + "/meta.txt")
# read meta
meta = self.readMeta(dir, "meta.txt")
return dir if meta[:name] == name
end
# return nil if no plugin dir found
return nil
end
#-----------------------------------------------------------------------------
end

View File

@@ -6,14 +6,12 @@ class SpriteAnimation
@sprite = sprite
end
%w[
x y ox oy viewport flash src_rect opacity tone
].each_with_index do |s, _i|
["x", "y", "ox", "oy", "viewport", "flash", "src_rect", "opacity", "tone"].each do |def_name|
eval <<-__END__
def #{s}(*arg)
@sprite.#{s}(*arg)
end
def #{def_name}(*arg) # def x(*arg)
@sprite.#{def_name}(*arg) # @sprite.x(*arg)
end # end
__END__
end
@@ -30,7 +28,7 @@ class SpriteAnimation
def animation(animation, hit, height = 3)
dispose_animation
@_animation = animation
return if @_animation == nil
return if @_animation.nil?
@_animation_hit = hit
@_animation_height = height
@_animation_duration = @_animation.frame_max
@@ -66,7 +64,7 @@ class SpriteAnimation
return if animation == @_loop_animation
dispose_loop_animation
@_loop_animation = animation
return if @_loop_animation == nil
return if @_loop_animation.nil?
@_loop_animation_index = 0
fr = 20
if @_animation.name[/\[\s*(\d+?)\s*\]\s*$/]
@@ -92,15 +90,15 @@ class SpriteAnimation
end
def dispose_animation
return if @_animation_sprites == nil
return if @_animation_sprites.nil?
sprite = @_animation_sprites[0]
if sprite != nil
if sprite
@@_reference_count[sprite.bitmap] -= 1
if @@_reference_count[sprite.bitmap] == 0
sprite.bitmap.dispose
end
end
for sprite in @_animation_sprites
@_animation_sprites.each do |sprite|
sprite.dispose
end
@_animation_sprites = nil
@@ -108,15 +106,15 @@ class SpriteAnimation
end
def dispose_loop_animation
return if @_loop_animation_sprites == nil
return if @_loop_animation_sprites.nil?
sprite = @_loop_animation_sprites[0]
if sprite != nil
if sprite
@@_reference_count[sprite.bitmap] -= 1
if @@_reference_count[sprite.bitmap] == 0
sprite.bitmap.dispose
end
end
for sprite in @_loop_animation_sprites
@_loop_animation_sprites.each do |sprite|
sprite.dispose
end
@_loop_animation_sprites = nil
@@ -124,7 +122,7 @@ class SpriteAnimation
end
def active?
return @_loop_animation_sprites != nil || @_animation_sprites != nil
return @_loop_animation_sprites || @_animation_sprites
end
def effect?
@@ -132,7 +130,7 @@ class SpriteAnimation
end
def update
if @_animation != nil
if @_animation
quick_update = true
if Graphics.frame_count % @_animation_frame_skip == 0
@_animation_duration -= 1
@@ -140,7 +138,7 @@ class SpriteAnimation
end
update_animation(quick_update)
end
if @_loop_animation != nil
if @_loop_animation
quick_update = (Graphics.frame_count % @_loop_animation_frame_skip != 0)
update_loop_animation(quick_update)
if !quick_update
@@ -160,7 +158,7 @@ class SpriteAnimation
position = @_animation.position
animation_set_sprites(@_animation_sprites, cell_data, position, quick_update)
return if quick_update
for timing in @_animation.timings
@_animation.timings.each do |timing|
next if timing.frame != frame_index
animation_process_timing(timing, @_animation_hit)
end
@@ -172,7 +170,7 @@ class SpriteAnimation
position = @_loop_animation.position
animation_set_sprites(@_loop_animation_sprites, cell_data, position, quick_update)
return if quick_update
for timing in @_loop_animation.timings
@_loop_animation.timings.each do |timing|
next if timing.frame != frame_index
animation_process_timing(timing, true)
end
@@ -182,21 +180,21 @@ class SpriteAnimation
sprite_x = 320
sprite_y = 240
if position == 3
if self.viewport != nil
if self.viewport
sprite_x = self.viewport.rect.width / 2
sprite_y = self.viewport.rect.height - 160
end
else
sprite_x = self.x - self.ox + self.src_rect.width / 2
sprite_x = self.x - self.ox + (self.src_rect.width / 2)
sprite_y = self.y - self.oy
sprite_y += self.src_rect.height / 2 if position == 1
sprite_y += self.src_rect.height if position == 2
end
for i in 0..15
16.times do |i|
sprite = sprites[i]
pattern = cell_data[i, 0]
if sprite == nil || pattern == nil || pattern == -1
sprite.visible = false if sprite != nil
if sprite.nil? || pattern.nil? || pattern == -1
sprite.visible = false if sprite
next
end
sprite.x = sprite_x + cell_data[i, 1]
@@ -206,8 +204,8 @@ class SpriteAnimation
sprite.src_rect.set(pattern % 5 * 192, pattern / 5 * 192, 192, 192)
case @_animation_height
when 0 then sprite.z = 1
when 1 then sprite.z = sprite.y+32+15
when 2 then sprite.z = sprite.y+32+32+17
when 1 then sprite.z = sprite.y + (Game_Map::TILE_HEIGHT * 3 / 2) + 1
when 2 then sprite.z = sprite.y + (Game_Map::TILE_HEIGHT * 3) + 1
else sprite.z = 2000
end
sprite.ox = 96
@@ -234,9 +232,7 @@ class SpriteAnimation
when 1
self.flash(timing.flash_color, timing.flash_duration * 2)
when 2
if self.viewport != nil
self.viewport.flash(timing.flash_color, timing.flash_duration * 2)
end
self.viewport.flash(timing.flash_color, timing.flash_duration * 2) if self.viewport
when 3
self.flash(nil, timing.flash_duration * 2)
end
@@ -246,30 +242,22 @@ class SpriteAnimation
def x=(x)
sx = x - self.x
return if sx == 0
if @_animation_sprites != nil
for i in 0..15
@_animation_sprites[i].x += sx
end
end
if @_loop_animation_sprites != nil
for i in 0..15
@_loop_animation_sprites[i].x += sx
if @_animation_sprites
16.times { |i| @_animation_sprites[i].x += sx }
end
if @_loop_animation_sprites
16.times { |i| @_loop_animation_sprites[i].x += sx }
end
end
def y=(y)
sy = y - self.y
return if sy == 0
if @_animation_sprites != nil
for i in 0..15
@_animation_sprites[i].y += sy
end
end
if @_loop_animation_sprites != nil
for i in 0..15
@_loop_animation_sprites[i].y += sy
if @_animation_sprites
16.times { |i| @_animation_sprites[i].y += sy }
end
if @_loop_animation_sprites
16.times { |i| @_loop_animation_sprites[i].y += sy }
end
end
end
@@ -370,14 +358,14 @@ module RPG
@_damage_sprite.ox = 80
@_damage_sprite.oy = 20
@_damage_sprite.x = self.x
@_damage_sprite.y = self.y - self.oy / 2
@_damage_sprite.y = self.y - (self.oy / 2)
@_damage_sprite.z = 3000
@_damage_duration = 40
end
def pushAnimation(array, anim)
for i in 0...array.length
next if array[i] && array[i].active?
array.length.times do |i|
next if array[i]&.active?
array[i] = anim
return
end
@@ -397,7 +385,7 @@ module RPG
end
def dispose_damage
return if @_damage_sprite == nil
return if @_damage_sprite.nil?
@_damage_sprite.bitmap.dispose
@_damage_sprite.dispose
@_damage_sprite = nil
@@ -405,15 +393,15 @@ module RPG
end
def dispose_animation
for a in @animations
a.dispose_animation if a
@animations.each do |a|
a&.dispose_animation
end
@animations.clear
end
def dispose_loop_animation
for a in @loopAnimations
a.dispose_loop_animation if a
@loopAnimations.each do |a|
a&.dispose_loop_animation
end
@loopAnimations.clear
end
@@ -440,7 +428,7 @@ module RPG
return true if @_escape_duration > 0
return true if @_collapse_duration > 0
return true if @_damage_duration > 0
for a in @animations
@animations.each do |a|
return true if a.effect?
end
return false
@@ -450,7 +438,7 @@ module RPG
super
if @_whiten_duration > 0
@_whiten_duration -= 1
self.color.alpha = 128 - (16 - @_whiten_duration) * 10
self.color.alpha = 128 - ((16 - @_whiten_duration) * 10)
end
if @_appear_duration > 0
@_appear_duration -= 1
@@ -458,11 +446,11 @@ module RPG
end
if @_escape_duration > 0
@_escape_duration -= 1
self.opacity = 256 - (32 - @_escape_duration) * 10
self.opacity = 256 - ((32 - @_escape_duration) * 10)
end
if @_collapse_duration > 0
@_collapse_duration -= 1
self.opacity = 256 - (48 - @_collapse_duration) * 6
self.opacity = 256 - ((48 - @_collapse_duration) * 6)
end
if @_damage_duration > 0
@_damage_duration -= 1
@@ -476,15 +464,15 @@ module RPG
when 28..33
@_damage_sprite.y += 4
end
@_damage_sprite.opacity = 256 - (12 - @_damage_duration) * 32
@_damage_sprite.opacity = 256 - ((12 - @_damage_duration) * 32)
if @_damage_duration == 0
dispose_damage
end
end
for a in @animations
@animations.each do |a|
a.update
end
for a in @loopAnimations
@loopAnimations.each do |a|
a.update
end
if @_blink
@@ -500,32 +488,32 @@ module RPG
end
def update_animation
for a in @animations
a.update_animation if a && a.active?
@animations.each do |a|
a.update_animation if a&.active?
end
end
def update_loop_animation
for a in @loopAnimations
a.update_loop_animation if a && a.active?
@loopAnimations.each do |a|
a.update_loop_animation if a&.active?
end
end
def x=(x)
for a in @animations
@animations.each do |a|
a.x = x if a
end
for a in @loopAnimations
@loopAnimations.each do |a|
a.x = x if a
end
super
end
def y=(y)
for a in @animations
@animations.each do |a|
a.y = y if a
end
for a in @loopAnimations
@loopAnimations.each do |a|
a.y = y if a
end
super

View File

@@ -1,15 +1,25 @@
module Settings
# Whether a move's physical/special category depends on the move itself as in
# newer Gens (true), or on its type as in older Gens (false).
MOVE_CATEGORY_PER_MOVE = (MECHANICS_GENERATION >= 4)
# Whether turn order is recalculated after a Pokémon Mega Evolves.
RECALCULATE_TURN_ORDER_AFTER_MEGA_EVOLUTION = (MECHANICS_GENERATION >= 7)
# Whether turn order is recalculated after a Pokémon's Speed stat changes.
RECALCULATE_TURN_ORDER_AFTER_SPEED_CHANGES = (MECHANICS_GENERATION >= 8)
# Whether any Pokémon (originally owned by the player or foreign) can disobey
# the player's commands if the Pokémon is too high a level compared to the
# number of Gym Badges the player has.
ANY_HIGH_LEVEL_POKEMON_CAN_DISOBEY = false
# Whether foreign Pokémon can disobey the player's commands if the Pokémon is
# too high a level compared to the number of Gym Badges the player has.
FOREIGN_HIGH_LEVEL_POKEMON_CAN_DISOBEY = true
# Whether a move's physical/special category depends on the move itself as in
# newer Gens (true), or on its type as in older Gens (false).
MOVE_CATEGORY_PER_MOVE = (MECHANICS_GENERATION >= 4)
# Whether critical hits do 1.5x damage and have 4 stages (true), or they do 2x
# damage and have 5 stages as in Gen 5 (false). Also determines whether
# critical hit rate can be copied by Transform/Psych Up.
NEW_CRITICAL_HIT_RATE_MECHANICS = (MECHANICS_GENERATION >= 6)
#=============================================================================
# Whether several effects apply relating to a Pokémon's type:
# * Electric-type immunity to paralysis
# * Ghost-type immunity to being trapped
@@ -18,9 +28,6 @@ module Settings
MORE_TYPE_EFFECTS = (MECHANICS_GENERATION >= 6)
# Whether weather caused by an ability lasts 5 rounds (true) or forever (false).
FIXED_DURATION_WEATHER_FROM_ABILITY = (MECHANICS_GENERATION >= 6)
#=============================================================================
# Whether X items (X Attack, etc.) raise their stat by 2 stages (true) or 1
# (false).
X_STAT_ITEMS_RAISE_BY_TWO_STAGES = (MECHANICS_GENERATION >= 7)
@@ -33,6 +40,18 @@ module Settings
#=============================================================================
# Whether Pokémon with high happiness will gain more Exp from battles, have a
# chance of avoiding/curing negative effects by themselves, resisting
# fainting, etc.
AFFECTION_EFFECTS = false
# Whether a Pokémon's happiness is limited to 179, and can only be increased
# further with friendship-raising berries. Related to AFFECTION_EFFECTS by
# default as affection effects only start applying above a happiness of 179.
# Also lowers the happiness evolution threshold to 160.
APPLY_HAPPINESS_SOFT_CAP = AFFECTION_EFFECTS
#=============================================================================
# The minimum number of badges required to boost each stat of a player's
# Pokémon by 1.1x, in battle only.
NUM_BADGES_BOOST_ATTACK = (MECHANICS_GENERATION >= 4) ? 999 : 1
@@ -43,9 +62,6 @@ module Settings
#=============================================================================
# An array of items which act as Mega Rings for the player (NPCs don't need a
# Mega Ring item, just a Mega Stone held by their Pokémon).
MEGA_RINGS = [:MEGARING, :MEGABRACELET, :MEGACUFF, :MEGACHARM]
# The Game Switch which, while ON, prevents all Pokémon in battle from Mega
# Evolving even if they otherwise could.
NO_MEGA_EVOLUTION = 34
@@ -60,6 +76,9 @@ module Settings
# that much Exp (false). This also applies to Exp gained via the Exp Share
# (held item version) being distributed to all Exp Share holders.
SPLIT_EXP_BETWEEN_GAINERS = (MECHANICS_GENERATION <= 5)
# Whether a Pokémon holding a Power item gains 8 (true) or 4 (false) EVs in
# the relevant stat.
MORE_EVS_FROM_POWER_ITEMS = (MECHANICS_GENERATION >= 7)
# Whether the critical capture mechanic applies. Note that its calculation is
# based on a total of 600+ species (i.e. that many species need to be caught
# to provide the greatest critical capture chance of 2.5x), and there may be
@@ -67,6 +86,13 @@ module Settings
ENABLE_CRITICAL_CAPTURES = (MECHANICS_GENERATION >= 5)
# Whether Pokémon gain Exp for capturing a Pokémon.
GAIN_EXP_FOR_CAPTURE = (MECHANICS_GENERATION >= 6)
# Whether the player is asked what to do with a newly caught Pokémon if their
# party is full. If true, the player can toggle whether they are asked this in
# the Options screen.
NEW_CAPTURE_CAN_REPLACE_PARTY_MEMBER = (MECHANICS_GENERATION >= 7)
#=============================================================================
# The Game Switch which, whie ON, prevents the player from losing money if
# they lose a battle (they can still gain money from trainers for winning).
NO_MONEY_LOSS = 33

View File

@@ -6,9 +6,9 @@
module SaveData
# Contains the file path of the save file.
FILE_PATH = if File.directory?(System.data_directory)
System.data_directory + '/Game.rxdata'
System.data_directory + "/Game.rxdata"
else
'./Game.rxdata'
"./Game.rxdata"
end
# @return [Boolean] whether the save file exists
@@ -45,7 +45,7 @@ module SaveData
save_data = get_data_from_file(file_path)
save_data = to_hash_format(save_data) if save_data.is_a?(Array)
if !save_data.empty? && run_conversions(save_data)
File.open(file_path, 'wb') { |file| Marshal.dump(save_data, file) }
File.open(file_path, "wb") { |file| Marshal.dump(save_data, file) }
end
return save_data
end
@@ -57,14 +57,14 @@ module SaveData
def self.save_to_file(file_path)
validate file_path => String
save_data = self.compile_save_hash
File.open(file_path, 'wb') { |file| Marshal.dump(save_data, file) }
File.open(file_path, "wb") { |file| Marshal.dump(save_data, file) }
end
# Deletes the save file (and a possible .bak backup file if one exists)
# @raise [Error::ENOENT]
def self.delete_file
File.delete(FILE_PATH)
File.delete(FILE_PATH + '.bak') if File.file?(FILE_PATH + '.bak')
File.delete(FILE_PATH + ".bak") if File.file?(FILE_PATH + ".bak")
end
# Converts the pre-v19 format data to the new format.
@@ -85,12 +85,12 @@ module SaveData
# already exists in {FILE_PATH}.
def self.move_old_windows_save
return if File.file?(FILE_PATH)
game_title = System.game_title.gsub(/[^\w ]/, '_')
home = ENV['HOME'] || ENV['HOMEPATH']
game_title = System.game_title.gsub(/[^\w ]/, "_")
home = ENV["HOME"] || ENV["HOMEPATH"]
return if home.nil?
old_location = File.join(home, 'Saved Games', game_title)
old_location = File.join(home, "Saved Games", game_title)
return unless File.directory?(old_location)
old_file = File.join(old_location, 'Game.rxdata')
old_file = File.join(old_location, "Game.rxdata")
return unless File.file?(old_file)
File.move(old_file, FILE_PATH)
end

View File

@@ -114,21 +114,21 @@ module SaveData
# Requires a block with the loaded value as its parameter.
# @see SaveData.register
def load_value(&block)
raise ArgumentError, 'No block given to load_value' unless block_given?
raise ArgumentError, "No block given to load_value" unless block_given?
@load_proc = block
end
# Defines what is saved into save data. Requires a block.
# @see SaveData.register
def save_value(&block)
raise ArgumentError, 'No block given to save_value' unless block_given?
raise ArgumentError, "No block given to save_value" unless block_given?
@save_proc = block
end
# If present, defines what the value is set to at the start of a new game.
# @see SaveData.register
def new_game_value(&block)
raise ArgumentError, 'No block given to new_game_value' unless block_given?
raise ArgumentError, "No block given to new_game_value" unless block_given?
@new_game_value_proc = block
end
@@ -142,7 +142,7 @@ module SaveData
# save format. Requires a block with the old format array as its parameter.
# @see SaveData.register
def from_old_format(&block)
raise ArgumentError, 'No block given to from_old_format' unless block_given?
raise ArgumentError, "No block given to from_old_format" unless block_given?
@old_format_get_proc = block
end
@@ -181,11 +181,11 @@ module SaveData
# new_game_value { Bar.new }
# end
# @param id [Symbol] value id
# @yieldself [Value]
# @yield the block of code to be saved as a Value
def self.register(id, &block)
validate id => Symbol
unless block_given?
raise ArgumentError, 'No block given to SaveData.register'
raise ArgumentError, "No block given to SaveData.register"
end
@values << Value.new(id, &block)
end

View File

@@ -112,7 +112,7 @@ module SaveData
# @see SaveData.register_conversion
def to_value(value_id, &block)
validate value_id => Symbol
raise ArgumentError, 'No block given to to_value' unless block_given?
raise ArgumentError, "No block given to to_value" unless block_given?
if @value_procs[value_id].is_a?(Proc)
raise "Multiple to_value definitions in conversion #{@id} for #{value_id}"
end
@@ -122,7 +122,7 @@ module SaveData
# Defines a conversion to the entire save data.
# @see SaveData.register_conversion
def to_all(&block)
raise ArgumentError, 'No block given to to_all' unless block_given?
raise ArgumentError, "No block given to to_all" unless block_given?
if @all_proc.is_a?(Proc)
raise "Multiple to_all definitions in conversion #{@id}"
end
@@ -152,11 +152,11 @@ module SaveData
# save_data[:new_value] = Foo.new
# end
# end
# @yield self [Conversion]
# @yield the block of code to be saved as a Conversion
def self.register_conversion(id, &block)
validate id => Symbol
unless block_given?
raise ArgumentError, 'No block given to SaveData.register_conversion'
raise ArgumentError, "No block given to SaveData.register_conversion"
end
conversion = Conversion.new(id, &block)
@conversions[conversion.trigger_type][conversion.version] ||= []
@@ -168,8 +168,8 @@ module SaveData
def self.get_conversions(save_data)
conversions_to_run = []
versions = {
essentials: save_data[:essentials_version] || '18.1',
game: save_data[:game_version] || '0.0.0'
essentials: save_data[:essentials_version] || "18.1",
game: save_data[:game_version] || "0.0.0"
}
[:essentials, :game].each do |trigger_type|
# Ensure the versions are sorted from lowest to highest
@@ -194,14 +194,15 @@ module SaveData
validate save_data => Hash
conversions_to_run = self.get_conversions(save_data)
return false if conversions_to_run.none?
File.open(SaveData::FILE_PATH + '.bak', 'wb') { |f| Marshal.dump(save_data, f) }
echoln "Running #{conversions_to_run.length} conversions..."
File.open(SaveData::FILE_PATH + ".bak", "wb") { |f| Marshal.dump(save_data, f) }
Console.echo_h1 "Running #{conversions_to_run.length} save file conversions"
conversions_to_run.each do |conversion|
echo "#{conversion.title}..."
Console.echo_li "#{conversion.title}..."
conversion.run(save_data)
echoln ' done.'
Console.echo_done(true)
end
echoln '' if conversions_to_run.length > 0
echoln "" if conversions_to_run.length > 0
Console.echo_h2("All save file conversions applied successfully", text: :green)
save_data[:essentials_version] = Essentials::VERSION
save_data[:game_version] = Settings::GAME_VERSION
return true

View File

@@ -2,11 +2,11 @@
SaveData.register(:player) do
ensure_class :Player
save_value { $Trainer }
load_value { |value| $Trainer = value }
save_value { $player }
load_value { |value| $player = $Trainer = value }
new_game_value {
trainer_type = nil # Get the first defined trainer type as a placeholder
GameData::TrainerType.each { |t| trainer_type = t.id; break }
# Get the first defined trainer type as a placeholder
trainer_type = GameData::TrainerType.keys.first
Player.new("Unnamed", trainer_type)
}
from_old_format { |old_format| old_format[0] }
@@ -72,8 +72,8 @@ end
SaveData.register(:map_factory) do
ensure_class :PokemonMapFactory
save_value { $MapFactory }
load_value { |value| $MapFactory = value }
save_value { $map_factory }
load_value { |value| $map_factory = $MapFactory = value }
from_old_format { |old_format| old_format[9] }
end
@@ -103,8 +103,8 @@ end
SaveData.register(:bag) do
ensure_class :PokemonBag
save_value { $PokemonBag }
load_value { |value| $PokemonBag = value }
save_value { $bag }
load_value { |value| $bag = $PokemonBag = value }
new_game_value { PokemonBag.new }
from_old_format { |old_format| old_format[13] }
end
@@ -121,7 +121,7 @@ SaveData.register(:essentials_version) do
load_in_bootup
ensure_class :String
save_value { Essentials::VERSION }
load_value { |value| $SaveVersion = value }
load_value { |value| $save_engine_version = value }
new_game_value { Essentials::VERSION }
from_old_format { |old_format| old_format[15] }
end
@@ -130,6 +130,14 @@ SaveData.register(:game_version) do
load_in_bootup
ensure_class :String
save_value { Settings::GAME_VERSION }
load_value { |value| $game_version = value }
load_value { |value| $save_game_version = value }
new_game_value { Settings::GAME_VERSION }
end
SaveData.register(:stats) do
load_in_bootup
ensure_class :GameStats
save_value { $stats }
load_value { |value| $stats = value }
new_game_value { GameStats.new }
end

View File

@@ -1,242 +1,350 @@
# Contains conversions defined in Essentials by default.
#===============================================================================
# Conversions required to support backwards compatibility with old save files
# (within reason).
#===============================================================================
SaveData.register_conversion(:v19_define_versions) do
essentials_version 19
display_title 'Adding game version and Essentials version to save data'
to_all do |save_data|
unless save_data.has_key?(:essentials_version)
save_data[:essentials_version] = Essentials::VERSION
end
unless save_data.has_key?(:game_version)
save_data[:game_version] = Settings::GAME_VERSION
end
end
end
SaveData.register_conversion(:v19_convert_PokemonSystem) do
essentials_version 19
display_title 'Updating PokemonSystem class'
to_all do |save_data|
new_system = PokemonSystem.new
new_system.textspeed = save_data[:pokemon_system].textspeed || new_system.textspeed
new_system.battlescene = save_data[:pokemon_system].battlescene || new_system.battlescene
new_system.battlestyle = save_data[:pokemon_system].battlestyle || new_system.battlestyle
new_system.frame = save_data[:pokemon_system].frame || new_system.frame
new_system.textskin = save_data[:pokemon_system].textskin || new_system.textskin
new_system.screensize = save_data[:pokemon_system].screensize || new_system.screensize
new_system.language = save_data[:pokemon_system].language || new_system.language
new_system.runstyle = save_data[:pokemon_system].runstyle || new_system.runstyle
new_system.bgmvolume = save_data[:pokemon_system].bgmvolume || new_system.bgmvolume
new_system.sevolume = save_data[:pokemon_system].sevolume || new_system.sevolume
new_system.textinput = save_data[:pokemon_system].textinput || new_system.textinput
save_data[:pokemon_system] = new_system
end
end
SaveData.register_conversion(:v19_convert_player) do
essentials_version 19
display_title 'Converting player trainer class'
to_all do |save_data|
next if save_data[:player].is_a?(Player)
# Conversion of the party is handled in PokeBattle_Trainer.convert
save_data[:player] = PokeBattle_Trainer.convert(save_data[:player])
end
end
SaveData.register_conversion(:v19_move_global_data_to_player) do
essentials_version 19
display_title 'Moving some global metadata data to player'
to_all do |save_data|
global = save_data[:global_metadata]
player = save_data[:player]
player.character_ID = global.playerID
global.playerID = nil
global.pokedexUnlocked.each_with_index do |value, i|
if value
player.pokedex.unlock(i)
else
player.pokedex.lock(i)
end
end
player.coins = global.coins
global.coins = nil
player.soot = global.sootsack
global.sootsack = nil
player.has_running_shoes = global.runningShoes
global.runningShoes = nil
player.seen_storage_creator = global.seenStorageCreator
global.seenStorageCreator = nil
player.has_snag_machine = global.snagMachine
global.snagMachine = nil
player.seen_purify_chamber = global.seenPurifyChamber
global.seenPurifyChamber = nil
end
end
SaveData.register_conversion(:v19_convert_global_metadata) do
essentials_version 19
display_title 'Adding encounter version variable to global metadata'
# Planted berries accidentally weren't converted in v19 to change their
# numerical IDs to symbolic IDs (for the berry planted and for mulch laid down).
# Since item numerical IDs no longer exist, this conversion needs to have a list
# of them in order to convert planted berry data properly.
SaveData.register_conversion(:v20_fix_planted_berry_numerical_ids) do
essentials_version 20
display_title "Fixing berry plant IDs data"
to_value :global_metadata do |global|
global.bridge ||= 0
global.encounter_version ||= 0
if global.pcItemStorage
global.pcItemStorage.items.each_with_index do |slot, i|
item_data = GameData::Item.try_get(slot[0])
if item_data
slot[0] = item_data.id
else
global.pcItemStorage.items[i] = nil
berry_conversion = {
389 => :CHERIBERRY,
390 => :CHESTOBERRY,
391 => :PECHABERRY,
392 => :RAWSTBERRY,
393 => :ASPEARBERRY,
394 => :LEPPABERRY,
395 => :ORANBERRY,
396 => :PERSIMBERRY,
397 => :LUMBERRY,
398 => :SITRUSBERRY,
399 => :FIGYBERRY,
400 => :WIKIBERRY,
401 => :MAGOBERRY,
402 => :AGUAVBERRY,
403 => :IAPAPABERRY,
404 => :RAZZBERRY,
405 => :BLUKBERRY,
406 => :NANABBERRY,
407 => :WEPEARBERRY,
408 => :PINAPBERRY,
409 => :POMEGBERRY,
410 => :KELPSYBERRY,
411 => :QUALOTBERRY,
412 => :HONDEWBERRY,
413 => :GREPABERRY,
414 => :TAMATOBERRY,
415 => :CORNNBERRY,
416 => :MAGOSTBERRY,
417 => :RABUTABERRY,
418 => :NOMELBERRY,
419 => :SPELONBERRY,
420 => :PAMTREBERRY,
421 => :WATMELBERRY,
422 => :DURINBERRY,
423 => :BELUEBERRY,
424 => :OCCABERRY,
425 => :PASSHOBERRY,
426 => :WACANBERRY,
427 => :RINDOBERRY,
428 => :YACHEBERRY,
429 => :CHOPLEBERRY,
430 => :KEBIABERRY,
431 => :SHUCABERRY,
432 => :COBABERRY,
433 => :PAYAPABERRY,
434 => :TANGABERRY,
435 => :CHARTIBERRY,
436 => :KASIBBERRY,
437 => :HABANBERRY,
438 => :COLBURBERRY,
439 => :BABIRIBERRY,
440 => :CHILANBERRY,
441 => :LIECHIBERRY,
442 => :GANLONBERRY,
443 => :SALACBERRY,
444 => :PETAYABERRY,
445 => :APICOTBERRY,
446 => :LANSATBERRY,
447 => :STARFBERRY,
448 => :ENIGMABERRY,
449 => :MICLEBERRY,
450 => :CUSTAPBERRY,
451 => :JABOCABERRY,
452 => :ROWAPBERRY
}
mulch_conversion = {
59 => :GROWTHMULCH,
60 => :DAMPMULCH,
61 => :STABLEMULCH,
62 => :GOOEYMULCH
}
global.eventvars.each_value do |var|
next if !var || !var.is_a?(Array)
next if var.length < 6 || var.length > 8 # Neither old nor new berry plant
if !var[1].is_a?(Symbol) # Planted berry item
var[1] = berry_conversion[var[1]] || :ORANBERRY
end
end
global.pcItemStorage.items.compact!
end
if global.mailbox
global.mailbox.each_with_index do |mail, i|
global.mailbox[i] = PokemonMail.convert(mail) if mail
end
end
global.phoneNumbers.each do |contact|
contact[1] = GameData::TrainerType.get(contact[1]).id if contact && contact.length == 8
end
if global.partner
global.partner[0] = GameData::TrainerType.get(global.partner[0]).id
global.partner[3].each_with_index do |pkmn, i|
global.partner[3][i] = PokeBattle_Pokemon.convert(pkmn) if pkmn
end
end
if global.daycare
global.daycare.each do |slot|
slot[0] = PokeBattle_Pokemon.convert(slot[0]) if slot && slot[0]
end
end
if global.roamPokemon
global.roamPokemon.each_with_index do |pkmn, i|
global.roamPokemon[i] = PokeBattle_Pokemon.convert(pkmn) if pkmn && pkmn != true
end
end
global.purifyChamber.sets.each do |set|
set.shadow = PokeBattle_Pokemon.convert(set.shadow) if set.shadow
set.list.each_with_index do |pkmn, i|
set.list[i] = PokeBattle_Pokemon.convert(pkmn) if pkmn
end
end
if global.hallOfFame
global.hallOfFame.each do |team|
next if !team
team.each_with_index do |pkmn, i|
team[i] = PokeBattle_Pokemon.convert(pkmn) if pkmn
end
end
end
if global.triads
global.triads.items.each do |card|
card[0] = GameData::Species.get(card[0]).id if card && card[0] && card[0] != 0
if var[7] && !var[7].is_a?(Symbol) # Mulch
var[7] = mulch_conversion[var[7]]
end
end
end
end
SaveData.register_conversion(:v19_1_fix_phone_contacts) do
essentials_version 19.1
display_title 'Fixing phone contacts data'
#===============================================================================
SaveData.register_conversion(:v20_refactor_planted_berries_data) do
essentials_version 20
display_title "Updating berry plant data format"
to_value :global_metadata do |global|
global.phoneNumbers.each do |contact|
contact[1] = GameData::TrainerType.get(contact[1]).id if contact && contact.length == 8
if global.eventvars
global.eventvars.each_pair do |key, value|
next if !value || !value.is_a?(Array)
case value.length
when 6 # Old berry plant data
data = BerryPlantData.new
if value[1].is_a?(Symbol)
plant_data = GameData::BerryPlant.get(value[1])
data.new_mechanics = false
data.berry_id = value[1]
data.time_alive = value[0] * plant_data.hours_per_stage * 3600
data.time_last_updated = value[3]
data.growth_stage = value[0]
data.replant_count = value[5]
data.watered_this_stage = value[2]
data.watering_count = value[4]
end
global.eventvars[key] = data
when 7, 8 # New berry plant data
data = BerryPlantData.new
if value[1].is_a?(Symbol)
data.new_mechanics = true
data.berry_id = value[1]
data.mulch_id = value[7] if value[7].is_a?(Symbol)
data.time_alive = value[2]
data.time_last_updated = value[3]
data.growth_stage = value[0]
data.replant_count = value[5]
data.moisture_level = value[4]
data.yield_penalty = value[6]
end
global.eventvars[key] = data
end
end
end
end
end
SaveData.register_conversion(:v19_convert_bag) do
essentials_version 19
display_title 'Converting item IDs in Bag'
#===============================================================================
SaveData.register_conversion(:v20_refactor_follower_data) do
essentials_version 20
display_title "Updating follower data format"
to_value :global_metadata do |global|
# NOTE: dependentEvents is still defined in class PokemonGlobalMetadata just
# for the sake of this conversion. It will be removed in future.
if global.dependentEvents && global.dependentEvents.length > 0
global.followers = []
global.dependentEvents.each do |follower|
data = FollowerData.new(follower[0], follower[1], "reflection",
follower[2], follower[3], follower[4],
follower[5], follower[6], follower[7])
data.name = follower[8]
data.common_event_id = follower[9]
global.followers.push(data)
end
end
global.dependentEvents = nil
end
end
#===============================================================================
SaveData.register_conversion(:v20_refactor_day_care_variables) do
essentials_version 20
display_title "Refactoring Day Care variables"
to_value :global_metadata do |global|
global.instance_eval do
@day_care = DayCare.new if @day_care.nil?
if !@daycare.nil?
@daycare.each do |old_slot|
if !old_slot[0]
old_slot[0] = Pokemon.new(:MANAPHY, 50)
old_slot[1] = 4
end
next if !old_slot[0]
@day_care.slots.each do |slot|
next if slot.filled?
slot.instance_eval do
@pokemon = old_slot[0]
@initial_level = old_slot[1]
if @pokemon && @pokemon.markings.is_a?(Integer)
markings = []
6.times { |i| markings[i] = ((@pokemon.markings & (1 << i)) == 0) ? 0 : 1 }
@pokemon.markings = markings
end
end
end
end
@day_care.egg_generated = ((@daycareEgg.is_a?(Numeric) && @daycareEgg > 0) || @daycareEgg == true)
@day_care.step_counter = @daycareEggSteps
@daycare = nil
@daycareEgg = nil
@daycareEggSteps = nil
end
end
end
end
#===============================================================================
SaveData.register_conversion(:v20_rename_bag_variables) do
essentials_version 20
display_title "Renaming Bag variables"
to_value :bag do |bag|
bag.instance_eval do
for pocket in self.pockets
pocket.each_with_index do |item, i|
next if !item || !item[0] || item[0] == 0
item_data = GameData::Item.try_get(item[0])
if item_data
item[0] = item_data.id
else
pocket[i] = nil
if !@lastpocket.nil?
@last_viewed_pocket = @lastpocket
@lastPocket = nil
end
if !@choices.nil?
@last_pocket_selections = @choices.clone
@choices = nil
end
pocket.compact!
if !@registeredItems.nil?
@registered_items = @registeredItems || []
@registeredItems = nil
end
self.registeredIndex # Just to ensure this data exists
self.registeredItems.each_with_index do |item, i|
next if !item
if item == 0
self.registeredItems[i] = nil
else
item_data = GameData::Item.try_get(item)
if item_data
self.registeredItems[i] = item_data.id
else
self.registeredItems[i] = nil
end
end
end
self.registeredItems.compact!
end # bag.instance_eval
end # to_value
end
SaveData.register_conversion(:v19_convert_game_variables) do
essentials_version 19
display_title 'Converting classes of things in Game Variables'
to_all do |save_data|
variables = save_data[:variables]
for i in 0..5000
value = variables[i]
next if value.nil?
if value.is_a?(Array)
value.each_with_index do |value2, j|
if value2.is_a?(PokeBattle_Pokemon)
value[j] = PokeBattle_Pokemon.convert(value2)
end
end
elsif value.is_a?(PokeBattle_Pokemon)
variables[i] = PokeBattle_Pokemon.convert(value)
elsif value.is_a?(PokemonBag)
SaveData.run_single_conversions(value, :bag, save_data)
if !@registeredIndex.nil?
@ready_menu_selection = @registeredIndex || [0, 0, 1]
@registeredIndex = nil
end
end
end
end
SaveData.register_conversion(:v19_convert_storage) do
essentials_version 19
display_title 'Converting classes of Pokémon in storage'
to_value :storage_system do |storage|
storage.instance_eval do
for box in 0...self.maxBoxes
for i in 0...self.maxPokemon(box)
self[box, i] = PokeBattle_Pokemon.convert(self[box, i]) if self[box, i]
end
end
self.unlockedWallpapers # Just to ensure this data exists
end # storage.instance_eval
end # to_value
end
#===============================================================================
SaveData.register_conversion(:v19_convert_game_player) do
essentials_version 19
display_title 'Converting game player character'
to_value :game_player do |game_player|
game_player.width = 1
game_player.height = 1
game_player.sprite_size = [Game_Map::TILE_WIDTH, Game_Map::TILE_HEIGHT]
game_player.pattern_surf ||= 0
game_player.lock_pattern ||= false
game_player.move_speed = game_player.move_speed
SaveData.register_conversion(:v20_increment_player_character_id) do
essentials_version 20
display_title "Incrementing player character ID"
to_value :player do |player|
player.character_ID += 1
end
end
SaveData.register_conversion(:v19_convert_game_screen) do
essentials_version 19
display_title 'Converting game screen'
#===============================================================================
SaveData.register_conversion(:v20_add_pokedex_records) do
essentials_version 20
display_title "Adding more Pokédex records"
to_value :player do |player|
player.pokedex.instance_eval do
@caught_counts = {} if @caught_counts.nil?
@defeated_counts = {} if @defeated_counts.nil?
@seen_eggs = {} if @seen_eggs.nil?
@seen_forms.each_value do |sp|
next if !sp || sp[0][0].is_a?(Array) # Already converted to include shininess
sp[0] = [sp[0], []]
sp[1] = [sp[1], []]
end
end
end
end
#===============================================================================
SaveData.register_conversion(:v20_add_new_default_options) do
essentials_version 20
display_title "Updating Options to include new settings"
to_value :pokemon_system do |option|
option.givenicknames = 0 if option.givenicknames.nil?
option.sendtoboxes = 0 if option.sendtoboxes.nil?
end
end
#===============================================================================
SaveData.register_conversion(:v20_fix_default_weather_type) do
essentials_version 20
display_title "Fixing weather type 0 in effect"
to_value :game_screen do |game_screen|
game_screen.weather(game_screen.weather_type, game_screen.weather_max, 0)
game_screen.instance_eval do
@weather_type = :None if @weather_type == 0
end
end
end
#===============================================================================
SaveData.register_conversion(:v20_add_stats) do
essentials_version 20
display_title "Adding stats to save data"
to_all do |save_data|
unless save_data.has_key?(:stats)
save_data[:stats] = GameStats.new
save_data[:stats].play_time = save_data[:frame_count].to_f / Graphics.frame_rate
save_data[:stats].play_sessions = 1
save_data[:stats].time_last_saved = save_data[:stats].play_time
end
end
end
#===============================================================================
SaveData.register_conversion(:v20_convert_pokemon_markings) do
essentials_version 20
display_title "Updating format of Pokémon markings"
to_all do |save_data|
# Create a lambda function that updates a Pokémon's markings
update_markings = lambda do |pkmn|
return if !pkmn || !pkmn.markings.is_a?(Integer)
markings = []
6.times { |i| markings[i] = ((pkmn.markings & (1 << i)) == 0) ? 0 : 1 }
pkmn.markings = markings
end
# Party Pokémon
save_data[:player].party.each { |pkmn| update_markings.call(pkmn) }
# Pokémon storage
save_data[:storage_system].boxes.each do |box|
box.pokemon.each { |pkmn| update_markings.call(pkmn) if pkmn }
end
# NOTE: Pokémon in the Day Care have their markings converted above.
# Partner trainer
if save_data[:global_metadata].partner
save_data[:global_metadata].partner[3].each { |pkmn| update_markings.call(pkmn) }
end
# Roaming Pokémon
if save_data[:global_metadata].roamPokemon
save_data[:global_metadata].roamPokemon.each { |pkmn| update_markings.call(pkmn) }
end
# Purify Chamber
save_data[:global_metadata].purifyChamber.sets.each do |set|
set.list.each { |pkmn| update_markings.call(pkmn) }
update_markings.call(set.shadow) if set.shadow
end
# Hall of Fame records
if save_data[:global_metadata].hallOfFame
save_data[:global_metadata].hallOfFame.each do |team|
next if !team
team.each { |pkmn| update_markings.call(pkmn) }
end
end
# Pokémon stored in Game Variables for some reason
variables = save_data[:variables]
(0..5000).each do |i|
value = variables[i]
case value
when Array
value.each { |value2| update_markings.call(value2) if value2.is_a?(Pokemon) }
when Pokemon
update_markings.call(value)
end
end
end
end

View File

@@ -2,18 +2,17 @@
module Game
# Initializes various global variables and loads the game data.
def self.initialize
$PokemonTemp = PokemonTemp.new
$game_temp = Game_Temp.new
$game_system = Game_System.new
$data_animations = load_data('Data/Animations.rxdata')
$data_tilesets = load_data('Data/Tilesets.rxdata')
$data_common_events = load_data('Data/CommonEvents.rxdata')
$data_system = load_data('Data/System.rxdata')
$data_animations = load_data("Data/Animations.rxdata")
$data_tilesets = load_data("Data/Tilesets.rxdata")
$data_common_events = load_data("Data/CommonEvents.rxdata")
$data_system = load_data("Data/System.rxdata")
pbLoadBattleAnimations
GameData.load_all
map_file = format('Data/Map%03d.rxdata', $data_system.start_map_id)
map_file = sprintf("Data/Map%03d.rxdata", $data_system.start_map_id)
if $data_system.start_map_id == 0 || !pbRgssExists?(map_file)
raise _INTL('No starting position was set in the map editor.')
raise _INTL("No starting position was set in the map editor.")
end
end
@@ -32,21 +31,22 @@ module Game
# Set language (and choose language if there is no save file)
if Settings::LANGUAGES.length >= 2
$PokemonSystem.language = pbChooseLanguage if save_data.empty?
pbLoadMessages('Data/' + Settings::LANGUAGES[$PokemonSystem.language][1])
pbLoadMessages("Data/" + Settings::LANGUAGES[$PokemonSystem.language][1])
end
end
# Called when starting a new game. Initializes global variables
# and transfers the player into the map scene.
def self.start_new
if $game_map && $game_map.events
if $game_map&.events
$game_map.events.each_value { |event| event.clear_starting }
end
$game_temp.common_event_id = 0 if $game_temp
$PokemonTemp.begunNewGame = true
$game_temp.begun_new_game = true
$scene = Scene_Map.new
SaveData.load_new_game_values
$MapFactory = PokemonMapFactory.new($data_system.start_map_id)
$stats.play_sessions += 1
$map_factory = PokemonMapFactory.new($data_system.start_map_id)
$game_player.moveto($data_system.start_x, $data_system.start_y)
$game_player.refresh
$PokemonEncounters = PokemonEncounters.new
@@ -61,6 +61,7 @@ module Game
def self.load(save_data)
validate save_data => Hash
SaveData.load_all_values(save_data)
$stats.play_sessions += 1
self.load_map
pbAutoplayOnSave
$game_map.update
@@ -70,31 +71,31 @@ module Game
# Loads and validates the map. Called when loading a saved game.
def self.load_map
$game_map = $MapFactory.map
$game_map = $map_factory.map
magic_number_matches = ($game_system.magic_number == $data_system.magic_number)
if !magic_number_matches || $PokemonGlobal.safesave
if pbMapInterpreterRunning?
pbMapInterpreter.setup(nil, 0)
end
begin
$MapFactory.setup($game_map.map_id)
$map_factory.setup($game_map.map_id)
rescue Errno::ENOENT
if $DEBUG
pbMessage(_INTL('Map {1} was not found.', $game_map.map_id))
pbMessage(_INTL("Map {1} was not found.", $game_map.map_id))
map = pbWarpToMap
exit unless map
$MapFactory.setup(map[0])
$map_factory.setup(map[0])
$game_player.moveto(map[1], map[2])
else
raise _INTL('The map was not found. The game cannot continue.')
raise _INTL("The map was not found. The game cannot continue.")
end
end
$game_player.center($game_player.x, $game_player.y)
else
$MapFactory.setMapChanged($game_map.map_id)
$map_factory.setMapChanged($game_map.map_id)
end
if $game_map.events.nil?
raise _INTL('The map is corrupt. The game cannot continue.')
raise _INTL("The map is corrupt. The game cannot continue.")
end
$PokemonEncounters = PokemonEncounters.new
$PokemonEncounters.setup($game_map.map_id)
@@ -111,6 +112,7 @@ module Game
$PokemonGlobal.safesave = safe
$game_system.save_count += 1
$game_system.magic_number = $data_system.magic_number
$stats.set_time_last_saved
begin
SaveData.save_to_file(save_file)
Graphics.frame_reset

View File

@@ -5,35 +5,38 @@
#===============================================================================
class Scene_Map
attr_reader :spritesetGlobal
attr_reader :map_renderer
def spriteset
for i in @spritesets.values
def spriteset(map_id = -1)
return @spritesets[map_id] if map_id > 0 && @spritesets[map_id]
@spritesets.each_value do |i|
return i if i.map == $game_map
end
return @spritesets.values[0]
end
def createSpritesets
@map_renderer = TilemapRenderer.new(Spriteset_Map.viewport)
@spritesetGlobal = Spriteset_Global.new
@spritesets = {}
for map in $MapFactory.maps
$map_factory.maps.each do |map|
@spritesets[map.map_id] = Spriteset_Map.new(map)
end
$MapFactory.setSceneStarted(self)
$map_factory.setSceneStarted(self)
updateSpritesets
end
def createSingleSpriteset(map)
temp = $scene.spriteset.getAnimations
@spritesets[map] = Spriteset_Map.new($MapFactory.maps[map])
@spritesets[map] = Spriteset_Map.new($map_factory.maps[map])
$scene.spriteset.restoreAnimations(temp)
$MapFactory.setSceneStarted(self)
$map_factory.setSceneStarted(self)
updateSpritesets
end
def disposeSpritesets
return if !@spritesets
for i in @spritesets.keys
@spritesets.each_key do |i|
next if !@spritesets[i]
@spritesets[i].dispose
@spritesets[i] = nil
@@ -42,6 +45,8 @@ class Scene_Map
@spritesets = {}
@spritesetGlobal.dispose
@spritesetGlobal = nil
@map_renderer.dispose
@map_renderer = nil
end
def autofade(mapid)
@@ -50,26 +55,25 @@ class Scene_Map
return if !playingBGM && !playingBGS
map = load_data(sprintf("Data/Map%03d.rxdata", mapid))
if playingBGM && map.autoplay_bgm
if (PBDayNight.isNight? rescue false)
pbBGMFade(0.8) if playingBGM.name!=map.bgm.name && playingBGM.name!=map.bgm.name+"_n"
else
pbBGMFade(0.8) if playingBGM.name!=map.bgm.name
if (PBDayNight.isNight? && FileTest.audio_exist?("Audio/BGM/" + map.bgm.name + "_n") &&
playingBGM.name != map.bgm.name + "_n") || playingBGM.name != map.bgm.name
pbBGMFade(0.8)
end
end
if playingBGS && map.autoplay_bgs
pbBGMFade(0.8) if playingBGS.name!=map.bgs.name
if playingBGS && map.autoplay_bgs && playingBGS.name != map.bgs.name
pbBGMFade(0.8)
end
Graphics.frame_reset
end
def transfer_player(cancelVehicles=true)
def transfer_player(cancel_swimming = true)
$game_temp.player_transferring = false
pbCancelVehicles($game_temp.player_new_map_id) if cancelVehicles
pbCancelVehicles($game_temp.player_new_map_id, cancel_swimming)
autofade($game_temp.player_new_map_id)
pbBridgeOff
@spritesetGlobal.playersprite.clearShadows
if $game_map.map_id != $game_temp.player_new_map_id
$MapFactory.setup($game_temp.player_new_map_id)
$map_factory.setup($game_temp.player_new_map_id)
end
$game_player.moveto($game_temp.player_new_x, $game_temp.player_new_y)
case $game_temp.player_new_direction
@@ -79,13 +83,14 @@ class Scene_Map
when 8 then $game_player.turn_up
end
$game_player.straighten
$game_temp.followers.map_transfer_followers
$game_map.update
disposeSpritesets
RPG::Cache.clear
createSpritesets
if $game_temp.transition_processing
$game_temp.transition_processing = false
Graphics.transition(20)
Graphics.transition
end
$game_map.autoplay
Graphics.frame_reset
@@ -111,60 +116,62 @@ class Scene_Map
end
def miniupdate
$PokemonTemp.miniupdate = true
$game_temp.in_mini_update = true
loop do
updateMaps
$game_player.update
updateMaps
$game_system.update
$game_screen.update
break unless $game_temp.player_transferring
transfer_player
transfer_player(false)
break if $game_temp.transition_processing
end
updateSpritesets
$PokemonTemp.miniupdate = false
$game_temp.in_mini_update = false
end
def updateMaps
for map in $MapFactory.maps
$map_factory.maps.each do |map|
map.update
end
$MapFactory.updateMaps(self)
$map_factory.updateMaps(self)
end
def updateSpritesets
@spritesets = {} if !@spritesets
$map_factory.maps.each do |map|
@spritesets[map.map_id] = Spriteset_Map.new(map) if !@spritesets[map.map_id]
end
keys = @spritesets.keys.clone
for i in keys
if !$MapFactory.hasMap?(i)
@spritesets[i].dispose if @spritesets[i]
keys.each do |i|
if $map_factory.hasMap?(i)
@spritesets[i].update
else
@spritesets[i]&.dispose
@spritesets[i] = nil
@spritesets.delete(i)
else
@spritesets[i].update
end
end
@spritesetGlobal.update
for map in $MapFactory.maps
@spritesets[map.map_id] = Spriteset_Map.new(map) if !@spritesets[map.map_id]
end
Events.onMapUpdate.trigger(self)
pbDayNightTint(@map_renderer)
@map_renderer.update
EventHandlers.trigger(:on_frame_update)
end
def update
loop do
updateMaps
pbMapInterpreter.update
$game_player.update
updateMaps
$game_system.update
$game_screen.update
break unless $game_temp.player_transferring
transfer_player
transfer_player(false)
break if $game_temp.transition_processing
end
updateSpritesets
if $game_temp.to_title
$game_temp.to_title = false
if $game_temp.title_screen_calling
$game_temp.title_screen_calling = false
SaveData.mark_values_as_unloaded
$scene = pbCallTitle
return
@@ -172,7 +179,7 @@ class Scene_Map
if $game_temp.transition_processing
$game_temp.transition_processing = false
if $game_temp.transition_name == ""
Graphics.transition(20)
Graphics.transition
else
Graphics.transition(40, "Graphics/Transitions/" + $game_temp.transition_name)
end
@@ -180,15 +187,15 @@ class Scene_Map
return if $game_temp.message_window_showing
if !pbMapInterpreterRunning?
if Input.trigger?(Input::USE)
$PokemonTemp.hiddenMoveEventCalling = true
elsif Input.trigger?(Input::BACK)
$game_temp.interact_calling = true
elsif Input.trigger?(Input::ACTION)
unless $game_system.menu_disabled || $game_player.moving?
$game_temp.menu_calling = true
$game_temp.menu_beep = true
end
elsif Input.trigger?(Input::SPECIAL)
unless $game_player.moving?
$PokemonTemp.keyItemCalling = true
$game_temp.ready_menu_calling = true
end
elsif Input.press?(Input::F9)
$game_temp.debug_calling = true if $DEBUG
@@ -199,21 +206,21 @@ class Scene_Map
call_menu
elsif $game_temp.debug_calling
call_debug
elsif $PokemonTemp.keyItemCalling
$PokemonTemp.keyItemCalling = false
elsif $game_temp.ready_menu_calling
$game_temp.ready_menu_calling = false
$game_player.straighten
pbUseKeyItem
elsif $PokemonTemp.hiddenMoveEventCalling
$PokemonTemp.hiddenMoveEventCalling = false
elsif $game_temp.interact_calling
$game_temp.interact_calling = false
$game_player.straighten
Events.onAction.trigger(self)
EventHandlers.trigger(:on_player_interact)
end
end
end
def main
createSpritesets
Graphics.transition(20)
Graphics.transition
loop do
Graphics.update
Input.update
@@ -222,8 +229,8 @@ class Scene_Map
end
Graphics.freeze
disposeSpritesets
if $game_temp.to_title
Graphics.transition(20)
if $game_temp.title_screen_calling
Graphics.transition
Graphics.freeze
end
end

View File

@@ -22,7 +22,7 @@ class Interpreter
def inspect
str = super.chop
str << format(' @event_id: %d>', @event_id)
str << sprintf(" @event_id: %d>", @event_id)
return str
end
@@ -35,6 +35,9 @@ class Interpreter
@child_interpreter = nil # child interpreter
@branch = {} # branch data
@buttonInput = false
@hidden_choices = []
@renamed_choices = []
end_follower_overrides
end
#-----------------------------------------------------------------------------
# * Event Setup
@@ -59,7 +62,7 @@ class Interpreter
return
end
# Check all map events for one that wants to start, and set it up
for event in $game_map.events.values
$game_map.events.each_value do |event|
next if !event.starting
if event.trigger < 3 # Isn't autorun or parallel processing
event.lock
@@ -69,7 +72,7 @@ class Interpreter
return
end
# Check all common events for one that is autorun, and set it up
for common_event in $data_common_events.compact
$data_common_events.compact.each do |common_event|
next if common_event.trigger != 1 || !$game_switches[common_event.switch_id]
setup(common_event.list, 0)
return
@@ -77,7 +80,7 @@ class Interpreter
end
def running?
return @list != nil
return !@list.nil?
end
#-----------------------------------------------------------------------------
# * Frame Update
@@ -92,7 +95,7 @@ class Interpreter
end
# If this interpreter's map isn't the current map or connected to it,
# forget this interpreter's event ID
if $game_map.map_id != @map_id && !$MapFactory.areConnected?($game_map.map_id, @map_id)
if $game_map.map_id != @map_id && !$map_factory.areConnected?($game_map.map_id, @map_id)
@event_id = 0
end
# Update child interpreter if one exists
@@ -106,7 +109,10 @@ class Interpreter
# Do nothing if any event or the player is in the middle of a move route
if @move_route_waiting
return if $game_player.move_route_forcing
for event in $game_map.events.values
$game_map.events.each_value do |event|
return if event.move_route_forcing
end
$game_temp.followers.each_follower do |event, follower|
return if event.move_route_forcing
end
@move_route_waiting = false
@@ -138,55 +144,42 @@ class Interpreter
return result
rescue Exception
e = $!
raise if e.is_a?(SystemExit) || "#{e.class}" == "Reset"
raise if e.is_a?(SystemExit) || e.class.to_s == "Reset"
event = get_self
s = "Backtrace:\r\n"
# Gather text for error message
message = pbGetExceptionMessage(e)
backtrace_text = ""
if e.is_a?(SyntaxError)
script.each_line { |line|
line.gsub!(/\s+$/, "")
if line[/^\s*\(/]
message += "\r\n***Line '#{line}' shouldn't begin with '('. Try\r\n"
message += "putting the '(' at the end of the previous line instead,\r\n"
message += "or using 'extendtext.exe'."
end
if line[/\:\:\s*$/]
message += "\r\n***Line '#{line}' can't end with '::'. Try putting\r\n"
message += "the next word on the same line, e.g. 'PBSpecies:" + ":MEW'"
message += "\r\n***Line '#{line}' shouldn't begin with '('. Try putting the '('\r\n"
message += "at the end of the previous line instead, or using 'extendtext.exe'."
end
}
else
for bt in e.backtrace[0, 10]
s += bt + "\r\n"
backtrace_text += "\r\n"
backtrace_text += "Backtrace:"
e.backtrace[0, 10].each { |i| backtrace_text += "\r\n#{i}" }
backtrace_text.gsub!(/Section(\d+)/) { $RGSS_SCRIPTS[$1.to_i][1] } rescue nil
backtrace_text += "\r\n"
end
s.gsub!(/Section(\d+)/) { $RGSS_SCRIPTS[$1.to_i][1] }
end
message = "Exception: #{e.class}\r\nMessage: " + message + "\r\n"
message += "\r\n***Full script:\r\n#{script}\r\n"
if event && $game_map
# Assemble error message
err = "Script error in Interpreter\r\n"
if $game_map
map_name = ($game_map.name rescue nil) || "???"
err = "Script error in event #{event.id} (coords #{event.x},#{event.y}), map #{$game_map.map_id} (#{map_name}):\r\n"
err += "#{message}\r\n#{s}"
if e.is_a?(Hangup)
$EVENTHANGUPMSG = err
raise
end
elsif $game_map
map_name = ($game_map.name rescue nil) || "???"
err = "Script error in map #{$game_map.map_id} (#{map_name}):\r\n"
err += "#{message}\r\n#{s}"
if e.is_a?(Hangup)
$EVENTHANGUPMSG = err
raise
end
if event
err = "Script error in event #{event.id} (coords #{event.x},#{event.y}), map #{$game_map.map_id} (#{map_name})\r\n"
else
err = "Script error in interpreter:\r\n#{message}\r\n#{s}"
if e.is_a?(Hangup)
$EVENTHANGUPMSG = err
raise
err = "Script error in Common Event, map #{$game_map.map_id} (#{map_name})\r\n"
end
end
raise err
err += "Exception: #{e.class}\r\n"
err += "Message: #{message}\r\n\r\n"
err += "***Full script:\r\n#{script}" # \r\n"
err += backtrace_text
# Raise error
raise EventScriptError.new(err)
end
end
#-----------------------------------------------------------------------------
@@ -221,13 +214,13 @@ class Interpreter
# * Freezes all events on the map (for use at the beginning of common events)
#-----------------------------------------------------------------------------
def pbGlobalLock
$game_map.events.values.each { |event| event.minilock }
$game_map.events.each_value { |event| event.minilock }
end
#-----------------------------------------------------------------------------
# * Unfreezes all events on the map (for use at the end of common events)
#-----------------------------------------------------------------------------
def pbGlobalUnlock
$game_map.events.values.each { |event| event.unlock }
$game_map.events.each_value { |event| event.unlock }
end
#-----------------------------------------------------------------------------
# * Gets the next index in the interpreter, ignoring certain commands between messages
@@ -281,12 +274,30 @@ class Interpreter
temp_index += 1
end
end
def follower_move_route(id = nil)
@follower_move_route = true
@follower_move_route_id = id
end
def follower_animation(id = nil)
@follower_animation = true
@follower_animation_id = id
end
def end_follower_overrides
@follower_move_route = false
@follower_move_route_id = nil
@follower_animation = false
@follower_animation_id = nil
end
#-----------------------------------------------------------------------------
# * Various methods to be used in a script event command.
#-----------------------------------------------------------------------------
# Helper function that shows a picture in a script.
def pbShowPicture(number, name, origin, x, y, zoomX = 100, zoomY = 100, opacity = 255, blendType = 0)
number = number + ($game_temp.in_battle ? 50 : 0)
number += ($game_temp.in_battle ? 50 : 0)
$game_screen.pictures[number].show(name, origin, x, y, zoomX, zoomY, opacity, blendType)
end
@@ -295,7 +306,7 @@ class Interpreter
def pbEraseThisEvent
if $game_map.events[@event_id]
$game_map.events[@event_id].erase
$PokemonMap.addErasedEvent(@event_id) if $PokemonMap
$PokemonMap&.addErasedEvent(@event_id)
end
@index += 1
return true
@@ -325,8 +336,8 @@ class Interpreter
mapid = @map_id if mapid < 0
old_value = $game_self_switches[[mapid, eventid, switch_name]]
$game_self_switches[[mapid, eventid, switch_name]] = value
if value != old_value && $MapFactory.hasMap?(mapid)
$MapFactory.getMap(mapid, false).need_refresh = true
if value != old_value && $map_factory.hasMap?(mapid)
$map_factory.getMap(mapid, false).need_refresh = true
end
end
@@ -368,7 +379,7 @@ class Interpreter
end
def pbGetPokemon(id)
return $Trainer.party[pbGet(id)]
return $player.party[pbGet(id)]
end
def pbSetEventTime(*arg)
@@ -377,7 +388,7 @@ class Interpreter
time = time.to_i
pbSetSelfSwitch(@event_id, "A", true)
$PokemonGlobal.eventvars[[@map_id, @event_id]] = time
for otherevt in arg
arg.each do |otherevt|
pbSetSelfSwitch(otherevt, "A", true)
$PokemonGlobal.eventvars[[@map_id, otherevt]] = time
end
@@ -391,13 +402,14 @@ class Interpreter
# Apply strict version of passable, which treats tiles that are passable
# only from certain directions as fully impassible
return if !event.can_move_in_direction?($game_player.direction, true)
$stats.strength_push_count += 1
case $game_player.direction
when 2 then event.move_down
when 4 then event.move_left
when 6 then event.move_right
when 8 then event.move_up
end
$PokemonMap.addMovedEvent(@event_id) if $PokemonMap
$PokemonMap&.addMovedEvent(@event_id)
if old_x != event.x || old_y != event.y
$game_player.lock
loop do
@@ -426,14 +438,14 @@ class Interpreter
return true if $DEBUG && !GameData::TrainerType.exists?(symbol)
tr_type = GameData::TrainerType.get(symbol).id
pbGlobalLock
pbPlayTrainerIntroME(tr_type)
pbPlayTrainerIntroBGM(tr_type)
return true
end
def pbTrainerEnd
pbGlobalUnlock
event = get_self
event.erase_route if event
event&.erase_route
end
def setPrice(item, buy_price = -1, sell_price = -1)
@@ -442,8 +454,8 @@ class Interpreter
$game_temp.mart_prices[item][0] = buy_price if buy_price > 0
if sell_price >= 0 # 0=can't sell
$game_temp.mart_prices[item][1] = sell_price * 2
else
$game_temp.mart_prices[item][1] = buy_price if buy_price > 0
elsif buy_price > 0
$game_temp.mart_prices[item][1] = buy_price
end
end

View File

@@ -126,6 +126,7 @@ class Interpreter
#-----------------------------------------------------------------------------
def command_end
@list = nil
end_follower_overrides
# If main map event and event ID are valid, unlock event
if @main && @event_id > 0 && $game_map.events[@event_id]
$game_map.events[@event_id].unlock
@@ -158,7 +159,7 @@ class Interpreter
return false if $game_temp.message_window_showing
message = @list[@index].parameters[0]
message_end = ""
commands = nil
choices = nil
number_input_variable = nil
number_input_max_digits = nil
# Check the next command(s) for things to add on to this text
@@ -174,8 +175,8 @@ class Interpreter
when 101 # Show Text
message_end = "\1"
when 102 # Show Choices
commands = @list[next_index].parameters
@index = next_index
choices = setup_choices(@list[@index].parameters)
when 103 # Input Number
number_input_variable = @list[next_index].parameters[0]
number_input_max_digits = @list[next_index].parameters[1]
@@ -185,15 +186,11 @@ class Interpreter
end
# Translate the text
message = _MAPINTL($game_map.map_id, message)
# Display the text, with commands/number choosing if appropriate
# Display the text, with choices/number choosing if appropriate
@message_waiting = true # Lets parallel process events work while a message is displayed
if commands
cmd_texts = []
for cmd in commands[0]
cmd_texts.push(_MAPINTL($game_map.map_id, cmd))
end
command = pbMessage(message + message_end, cmd_texts, commands[1])
@branch[@list[@index].indent] = command
if choices
command = pbMessage(message + message_end, choices[0], choices[1])
@branch[@list[@index].indent] = choices[2][command] || command
elsif number_input_variable
params = ChooseNumberParams.new
params.setMaxDigits(number_input_max_digits)
@@ -210,17 +207,93 @@ class Interpreter
# * Show Choices
#-----------------------------------------------------------------------------
def command_102
choices = setup_choices(@list[@index].parameters)
@message_waiting = true
command = pbShowCommands(nil, @list[@index].parameters[0], @list[@index].parameters[1])
command = pbShowCommands(nil, choices[0], choices[1])
@message_waiting = false
@branch[@list[@index].indent] = command
@branch[@list[@index].indent] = choices[2][command] || command
Input.update # Must call Input.update again to avoid extra triggers
return true
end
def setup_choices(params)
# Get initial options
choices = params[0].clone
cancel_index = params[1]
# Clone @list so the original isn't modified
@list = Marshal.load(Marshal.dump(@list))
# Get more choices
@choice_branch_index = 4
ret = add_more_choices(choices, cancel_index, @index + 1, @list[@index].indent)
# Rename choices
ret[0].each_with_index { |choice, i| ret[0][i] = @renamed_choices[i] if @renamed_choices[i] }
@renamed_choices.clear
# Remove hidden choices
ret[2] = Array.new(ret[0].length) { |i| i }
@hidden_choices.each_with_index do |condition, i|
next if !condition
ret[0][i] = nil
ret[2][i] = nil
end
ret[0].compact!
ret[2].compact!
@hidden_choices.clear
# Translate choices
ret[0].map! { |ch| _MAPINTL($game_map.map_id, ch) }
return ret
end
def add_more_choices(choices, cancel_index, choice_index, indent)
# Find index of next command after the current Show Choices command
loop do
break if @list[choice_index].indent == indent && ![402, 403, 404].include?(@list[choice_index].code)
choice_index += 1
end
next_cmd = @list[choice_index]
# If the next command isn't another Show Choices, we're done
return [choices, cancel_index] if next_cmd.code != 102
# Add more choices
old_length = choices.length
choices += next_cmd.parameters[0]
# Update cancel option
if next_cmd.parameters[1] == 5 # Branch
cancel_index = choices.length + 1
@choice_branch_index = cancel_index - 1
elsif next_cmd.parameters[1] > 0 # A choice
cancel_index = old_length + next_cmd.parameters[1]
@choice_branch_index = -1
end
# Update first Show Choices command to include all options and result of cancelling
@list[@index].parameters[0] = choices
@list[@index].parameters[1] = cancel_index
# Find the "When" lines for this Show Choices command and update their index parameter
temp_index = choice_index + 1
loop do
break if @list[temp_index].indent == indent && ![402, 403, 404].include?(@list[temp_index].code)
if @list[temp_index].code == 402 && @list[temp_index].indent == indent
@list[temp_index].parameters[0] += old_length
end
temp_index += 1
end
# Delete the "Show Choices" line
@list.delete(next_cmd)
# Find more choices to add
return add_more_choices(choices, cancel_index, choice_index + 1, indent)
end
def hide_choice(number, condition = true)
@hidden_choices[number - 1] = condition
end
def rename_choice(number, new_name, condition = true)
return if !condition || nil_or_empty?(new_name)
@renamed_choices[number - 1] = new_name
end
#-----------------------------------------------------------------------------
# * When [**]
#-----------------------------------------------------------------------------
def command_402
# @parameters[0] is 0/1/2/3 for Choice 1/2/3/4 respectively
if @branch[@list[@index].indent] == @parameters[0]
@branch.delete(@list[@index].indent)
return true
@@ -231,7 +304,8 @@ class Interpreter
# * When Cancel
#-----------------------------------------------------------------------------
def command_403
if @branch[@list[@index].indent] == 4
# @parameters[0] is 4 for "Branch"
if @branch[@list[@index].indent] == @choice_branch_index
@branch.delete(@list[@index].indent)
return true
end
@@ -271,7 +345,7 @@ class Interpreter
Input.update
pbUpdateSceneMap
# Check for input and break if there is one
for i in 1..18
(1..18).each do |i|
ret = i if Input.trigger?(i)
end
break if ret != 0
@@ -343,7 +417,7 @@ class Interpreter
character = get_character(@parameters[1])
result = (character.direction == @parameters[2]) if character
when 7 # gold
gold = $Trainer.money
gold = $player.money
result = (@parameters[2] == 0) ? (gold >= @parameters[1]) : (gold <= @parameters[1])
# when 8, 9, 10 # item, weapon, armor
when 11 # button
@@ -413,8 +487,8 @@ class Interpreter
#-----------------------------------------------------------------------------
def command_116
if @event_id > 0
$game_map.events[@event_id].erase if $game_map.events[@event_id]
$PokemonMap.addErasedEvent(@event_id) if $PokemonMap
$game_map.events[@event_id]&.erase
$PokemonMap&.addErasedEvent(@event_id)
end
@index += 1
return false
@@ -459,7 +533,7 @@ class Interpreter
#-----------------------------------------------------------------------------
def command_121
should_refresh = false
for i in @parameters[0]..@parameters[1]
(@parameters[0]..@parameters[1]).each do |i|
next if $game_switches[i] == (@parameters[2] == 0)
$game_switches[i] = (@parameters[2] == 0)
should_refresh = true
@@ -496,8 +570,8 @@ class Interpreter
when 7 # other
case @parameters[4]
when 0 then value = $game_map.map_id # map ID
when 1 then value = $Trainer.pokemon_party.length # party members
when 2 then value = $Trainer.money # gold
when 1 then value = $player.pokemon_party.length # party members
when 2 then value = $player.money # gold
# when 3 # steps
when 4 then value = Graphics.frame_count / Graphics.frame_rate # play time
when 5 then value = $game_system.timer / Graphics.frame_rate # timer
@@ -505,29 +579,29 @@ class Interpreter
end
end
# Apply value and operation to all specified game variables
for i in @parameters[0]..@parameters[1]
(@parameters[0]..@parameters[1]).each do |i|
case @parameters[2]
when 0 # set
next if $game_variables[i] == value
$game_variables[i] = value
when 1 # add
next if $game_variables[i] >= 99999999
next if $game_variables[i] >= 99_999_999
$game_variables[i] += value
when 2 # subtract
next if $game_variables[i] <= -99999999
next if $game_variables[i] <= -99_999_999
$game_variables[i] -= value
when 3 # multiply
next if value == 1
$game_variables[i] *= value
when 4 # divide
next if value == 1 || value == 0
next if [0, 1].include?(value)
$game_variables[i] /= value
when 5 # remainder
next if value == 1 || value == 0
next if [0, 1].include?(value)
$game_variables[i] %= value
end
$game_variables[i] = 99999999 if $game_variables[i] > 99999999
$game_variables[i] = -99999999 if $game_variables[i] < -99999999
$game_variables[i] = 99_999_999 if $game_variables[i] > 99_999_999
$game_variables[i] = -99_999_999 if $game_variables[i] < -99_999_999
$game_map.need_refresh = true
end
return true
@@ -560,7 +634,7 @@ class Interpreter
def command_125
value = (@parameters[1] == 0) ? @parameters[2] : $game_variables[@parameters[2]]
value = -value if @parameters[0] == 1 # Decrease
$Trainer.money += value
$player.money += value
return true
end
@@ -572,7 +646,7 @@ class Interpreter
# * Change Windowskin
#-----------------------------------------------------------------------------
def command_131
for i in 0...Settings::SPEECH_WINDOWSKINS.length
Settings::SPEECH_WINDOWSKINS.length.times do |i|
next if Settings::SPEECH_WINDOWSKINS[i] != @parameters[0]
$PokemonSystem.textskin = i
MessageConfig.pbSetSpeechFrame("Graphics/Windowskins/" + Settings::SPEECH_WINDOWSKINS[i])
@@ -590,10 +664,7 @@ class Interpreter
#-----------------------------------------------------------------------------
# * Change Battle End ME
#-----------------------------------------------------------------------------
def command_133
($PokemonGlobal.nextBattleME = @parameters[0]) ? @parameters[0].clone : nil
return true
end
def command_133; command_dummy; end
#-----------------------------------------------------------------------------
# * Change Save Access
#-----------------------------------------------------------------------------
@@ -630,13 +701,12 @@ class Interpreter
$game_temp.player_new_map_id = @parameters[1]
$game_temp.player_new_x = @parameters[2]
$game_temp.player_new_y = @parameters[3]
$game_temp.player_new_direction = @parameters[4]
else # Appoint with variables
$game_temp.player_new_map_id = $game_variables[@parameters[1]]
$game_temp.player_new_x = $game_variables[@parameters[2]]
$game_temp.player_new_y = $game_variables[@parameters[3]]
$game_temp.player_new_direction = @parameters[4]
end
$game_temp.player_new_direction = @parameters[4]
@index += 1
# If transition happens with a fade, do the fade
if @parameters[5] == 0
@@ -654,9 +724,10 @@ class Interpreter
character = get_character(@parameters[0])
return true if character.nil?
# Move the character
if @parameters[1] == 0 # Direct appointment
case @parameters[1]
when 0 # Direct appointment
character.moveto(@parameters[2], @parameters[3])
elsif @parameters[1] == 1 # Appoint with variables
when 1 # Appoint with variables
character.moveto($game_variables[@parameters[2]], $game_variables[@parameters[3]])
else # Exchange with another event
character2 = get_character(@parameters[2])
@@ -726,6 +797,11 @@ class Interpreter
#-----------------------------------------------------------------------------
def command_207
character = get_character(@parameters[0])
if @follower_animation
character = Followers.get(@follower_animation_id)
@follower_animation = false
@follower_animation_id = nil
end
return true if character.nil?
character.animation_id = @parameters[1]
return true
@@ -742,6 +818,11 @@ class Interpreter
#-----------------------------------------------------------------------------
def command_209
character = get_character(@parameters[0])
if @follower_move_route
character = Followers.get(@follower_move_route_id)
@follower_move_route = false
@follower_move_route_id = nil
end
return true if character.nil?
character.force_move_route(@parameters[1])
return true
@@ -931,18 +1012,19 @@ class Interpreter
# * Name Input Processing
#-----------------------------------------------------------------------------
def command_303
if $Trainer
$Trainer.name = pbEnterPlayerName(_INTL("Your name?"), 1, @parameters[1], $Trainer.name)
if $player
$player.name = pbEnterPlayerName(_INTL("Your name?"), 1, @parameters[1], $player.name)
return true
end
if $game_actors && $data_actors && $data_actors[@parameters[0]] != nil
if $game_actors && $data_actors && $data_actors[@parameters[0]]
$game_temp.battle_abort = true
pbFadeOutIn {
sscene = PokemonEntryScene.new
sscreen = PokemonEntry.new(sscene)
$game_actors[@parameters[0]].name = sscreen.pbStartScreen(
_INTL("Enter {1}'s name.", $game_actors[@parameters[0]].name),
1, @parameters[1], $game_actors[@parameters[0]].name)
1, @parameters[1], $game_actors[@parameters[0]].name
)
}
end
return true
@@ -955,7 +1037,13 @@ class Interpreter
# * Recover All
#-----------------------------------------------------------------------------
def command_314
$Trainer.heal_party if @parameters[0] == 0
if @parameters[0] == 0
if Settings::HEAL_STORED_POKEMON # No need to heal stored Pokémon
$player.heal_party
else
pbEachPokemon { |pkmn, box| pkmn.heal } # Includes party Pokémon
end
end
return true
end
@@ -1006,7 +1094,7 @@ class Interpreter
# * Return to Title Screen
#-----------------------------------------------------------------------------
def command_354
$game_temp.to_title = true
$game_temp.title_screen_calling = true
return false
end
#-----------------------------------------------------------------------------

View File

@@ -13,21 +13,15 @@ class Event
end
# Removes an event handler procedure from the event.
def -(method)
for i in 0...@callbacks.length
next if @callbacks[i]!=method
@callbacks.delete_at(i)
break
end
def -(other)
@callbacks.delete(other)
return self
end
# Adds an event handler procedure from the event.
def +(method)
for i in 0...@callbacks.length
return self if @callbacks[i]==method
end
@callbacks.push(method)
def +(other)
return self if @callbacks.include?(other)
@callbacks.push(other)
return self
end
@@ -45,7 +39,7 @@ class Event
# proc { |sender,arg0,arg1,...| }
def trigger(*arg)
arglist = arg[1, arg.length]
for callback in @callbacks
@callbacks.each do |callback|
if callback.arity > 2 && arg.length == callback.arity
# Retrofitted for callbacks that take three or more arguments
callback.call(*arg)
@@ -59,14 +53,45 @@ class Event
# by the code where the event occurred. The first argument is the sender of
# the event, the other arguments are the event's parameters.
def trigger2(*arg)
for callback in @callbacks
@callbacks.each do |callback|
callback.call(*arg)
end
end
end
#===============================================================================
#
# Same as class Event, but each registered proc has a name (a symbol) so it can
# be referenced individually.
#===============================================================================
class NamedEvent
def initialize
@callbacks = {}
end
# Adds an event handler procedure from the event.
def add(key, proc)
@callbacks[key] = proc if !@callbacks.has_key?(key)
end
# Removes an event handler procedure from the event.
def remove(key)
@callbacks.delete(key)
end
# Clears the event of event handlers.
def clear
@callbacks.clear
end
# Triggers the event and calls all its event handlers. Normally called only
# by the code where the event occurred.
def trigger(*args)
@callbacks.each_value { |callback| callback.call(*args) }
end
end
#===============================================================================
# Unused.
#===============================================================================
class HandlerHash
def initialize(mod)
@@ -89,7 +114,7 @@ class HandlerHash
return ret if ret
mod = Object.const_get(@mod) rescue nil
return nil if !mod
for key in mod.constants
mod.constants.each do |key|
next if mod.const_get(key) != sym
ret = key.to_sym
@symbolCache[sym] = ret
@@ -118,7 +143,7 @@ class HandlerHash
def copy(src, *dests)
handler = self[src]
if handler
for dest in dests
dests.each do |dest|
self.add(dest, handler)
end
end
@@ -131,7 +156,7 @@ class HandlerHash
symbol = toSymbol(sym)
ret = @hash[symbol] if symbol && @hash[symbol] # Symbol or string
unless ret
for addif in @addIfs
@addIfs.each do |addif|
return addif[1] if addif[0].call(id)
end
end
@@ -150,7 +175,8 @@ end
#===============================================================================
# A stripped-down version of class HandlerHash which only deals with symbols and
# doesn't care about whether those symbols actually relate to a defined thing.
# doesn't care about whether those symbols are defined as constants in a class
# or module.
#===============================================================================
class HandlerHash2
def initialize
@@ -161,19 +187,12 @@ class HandlerHash2
def [](sym)
sym = sym.id if !sym.is_a?(Symbol) && sym.respond_to?("id")
return @hash[sym] if sym && @hash[sym]
for add_if in @add_ifs
@add_ifs.each do |add_if|
return add_if[1] if add_if[0].call(sym)
end
return nil
end
def addIf(conditionProc, handler = nil, &handlerBlock)
if ![Proc, Hash].include?(handler.class) && !block_given?
raise ArgumentError, "addIf call for #{self.class.name} has no valid handler (#{handler.inspect} was given)"
end
@add_ifs.push([conditionProc, handler || handlerBlock])
end
def add(sym, handler = nil, &handlerBlock)
if ![Proc, Hash].include?(handler.class) && !block_given?
raise ArgumentError, "#{self.class.name} for #{sym.inspect} has no valid handler (#{handler.inspect} was given)"
@@ -181,12 +200,21 @@ class HandlerHash2
@hash[sym] = handler || handlerBlock if sym
end
def addIf(conditionProc, handler = nil, &handlerBlock)
if ![Proc, Hash].include?(handler.class) && !block_given?
raise ArgumentError, "addIf call for #{self.class.name} has no valid handler (#{handler.inspect} was given)"
end
@add_ifs.push([conditionProc, handler || handlerBlock])
end
def copy(src, *dests)
handler = self[src]
return if !handler
for dest in dests
self.add(dest, handler)
dests.each { |dest| add(dest, handler) }
end
def remove(key)
@hash.delete(key)
end
def clear
@@ -196,7 +224,7 @@ class HandlerHash2
def trigger(sym, *args)
sym = sym.id if !sym.is_a?(Symbol) && sym.respond_to?("id")
handler = self[sym]
return (handler) ? handler.call(sym, *args) : nil
return handler&.call(sym, *args)
end
end
@@ -206,7 +234,6 @@ end
#===============================================================================
class HandlerHashBasic
def initialize
@ordered_keys = []
@hash = {}
@addIfs = []
end
@@ -215,23 +242,18 @@ class HandlerHashBasic
ret = nil
ret = @hash[entry] if entry && @hash[entry]
unless ret
for addif in @addIfs
@addIfs.each do |addif|
return addif[1] if addif[0].call(entry)
end
end
return ret
end
def each
@ordered_keys.each { |key| yield key, @hash[key] }
end
def add(entry, handler = nil, &handlerBlock)
if ![Proc, Hash].include?(handler.class) && !block_given?
raise ArgumentError, "#{self.class.name} for #{entry.inspect} has no valid handler (#{handler.inspect} was given)"
end
return if !entry || entry.empty?
@ordered_keys.push(entry) if !@ordered_keys.include?(entry)
@hash[entry] = handler || handlerBlock
end
@@ -245,17 +267,28 @@ class HandlerHashBasic
def copy(src, *dests)
handler = self[src]
return if !handler
dests.each { |dest| self.add(dest, handler) }
dests.each { |dest| add(dest, handler) }
end
def remove(key)
@hash.delete(key)
end
def clear
@hash.clear
@ordered_keys.clear
end
def each
@hash.each_pair { |key, value| yield key, value }
end
def keys
return @hash.keys.clone
end
def trigger(entry, *args)
handler = self[entry]
return (handler) ? handler.call(*args) : nil
return handler&.call(*args)
end
end

View File

@@ -0,0 +1,123 @@
#===============================================================================
# This module stores events that can happen during the game. A procedure can
# subscribe to an event by adding itself to the event. It will then be called
# whenever the event occurs. Existing events are:
#-------------------------------------------------------------------------------
# :on_game_map_setup - When a Game_Map is set up. Typically changes map data.
# :on_new_spriteset_map - When a Spriteset_Map is created. Adds more things to
# show in the overworld.
# :on_frame_update - Once per frame. Various frame/time counters.
# :on_leave_map - When leaving a map. End weather/expired effects.
# :on_enter_map - Upon entering a new map. Set up new effects, end expired
# effects.
# :on_map_or_spriteset_change - Upon entering a new map or when spriteset was
# made. Show things on-screen.
#-------------------------------------------------------------------------------
# :on_player_change_direction - When the player turns in a different direction.
# :on_leave_tile - When any event or the player starts to move from a tile.
# :on_step_taken - When any event or the player finishes a step.
# :on_player_step_taken - When the player finishes a step/ends surfing, except
# as part of a move route. Step-based counters.
# :on_player_step_taken_can_transfer - When the player finishes a step/ends
# surfing, except as part of a move route. Step-based effects that can
# transfer the player elsewhere.
# :on_player_interact - When the player presses the Use button in the
# overworld.
#-------------------------------------------------------------------------------
# :on_trainer_load - When an NPCTrainer is generated (to battle against or as
# a registered partner). Various modifications to that trainer and their
# Pokémon.
# :on_wild_species_chosen - When a species/level have been chosen for a wild
# encounter. Changes the species/level (e.g. roamer, Poké Radar chain).
# :on_wild_pokemon_created - When a Pokemon object has been created for a wild
# encounter. Various modifications to that Pokémon.
# :on_calling_wild_battle - When a wild battle is called. Prevents that wild
# battle and instead starts a different kind of battle (e.g. Safari Zone).
# :on_start_battle - Just before a battle starts. Memorize/reset information
# about party Pokémon, which is used after battle for evolution checks.
# :on_end_battle - Just after a battle ends. Evolution checks, Pickup/Honey
# Gather, blacking out.
# :on_wild_battle_end - After a wild battle. Updates Poké Radar chain info.
#===============================================================================
module EventHandlers
@@events = {}
# Add a named callback for the given event.
def self.add(event, key, proc)
@@events[event] = NamedEvent.new if !@@events.has_key?(event)
@@events[event].add(key, proc)
end
# Remove a named callback from the given event.
def self.remove(event, key)
@@events[event]&.remove(key)
end
# Clear all callbacks for the given event.
def self.clear(key)
@@events[key]&.clear
end
# Trigger all callbacks from an Event if it has been defined.
def self.trigger(event, *args)
return @@events[event]&.trigger(*args)
end
end
#===============================================================================
# This module stores the contents of various menus. Each command in a menu is a
# hash of data (containing its name, relative order, code to run when chosen,
# etc.).
# Menus that use this module are:
#-------------------------------------------------------------------------------
# Pause menu
# Party screen main interact menu
# Pokégear main menu
# Options screen
# PC main menu
# Various debug menus (main, Pokémon, battle, battle Pokémon)
#===============================================================================
module MenuHandlers
@@handlers = {}
def self.add(menu, option, hash)
@@handlers[menu] = HandlerHashBasic.new if !@@handlers.has_key?(menu)
@@handlers[menu].add(option, hash)
end
def self.remove(menu, option)
@@handlers[menu]&.remove(option)
end
def self.clear(menu)
@@handlers[menu]&.clear
end
def self.each(menu)
return if !@@handlers.has_key?(menu)
@@handlers[menu].each { |option, hash| yield option, hash }
end
def self.each_available(menu, *args)
return if !@@handlers.has_key?(menu)
options = @@handlers[menu]
keys = options.keys
sorted_keys = keys.sort_by { |option| options[option]["order"] || keys.index(option) }
sorted_keys.each do |option|
hash = options[option]
next if hash["condition"] && !hash["condition"].call(*args)
if hash["name"].is_a?(Proc)
name = hash["name"].call
else
name = _INTL(hash["name"])
end
yield option, hash, name
end
end
def self.call(menu, option, function, *args)
option_hash = @@handlers[menu][option]
return nil if !option_hash || !option_hash[function]
return option_hash[function].call(*args)
end
end

View File

@@ -1,172 +0,0 @@
#===============================================================================
# This module stores events that can happen during the game. A procedure can
# subscribe to an event by adding itself to the event. It will then be called
# whenever the event occurs.
#===============================================================================
module Events
@@OnMapCreate = Event.new
@@OnMapUpdate = Event.new
@@OnMapChange = Event.new
@@OnMapChanging = Event.new
@@OnMapSceneChange = Event.new
@@OnSpritesetCreate = Event.new
@@OnAction = Event.new
@@OnStepTaken = Event.new
@@OnLeaveTile = Event.new
@@OnStepTakenFieldMovement = Event.new
@@OnStepTakenTransferPossible = Event.new
@@OnStartBattle = Event.new
@@OnEndBattle = Event.new
@@OnWildPokemonCreate = Event.new
@@OnWildBattleOverride = Event.new
@@OnWildBattleEnd = Event.new
@@OnTrainerPartyLoad = Event.new
@@OnChangeDirection = Event.new
# Fires whenever a map is created. Event handler receives two parameters: the
# map (RPG::Map) and the tileset (RPG::Tileset)
def self.onMapCreate; @@OnMapCreate; end
def self.onMapCreate=(v); @@OnMapCreate = v; end
# Fires each frame during a map update.
def self.onMapUpdate; @@OnMapUpdate; end
def self.onMapUpdate=(v); @@OnMapUpdate = v; end
# Fires whenever one map is about to change to a different one. Event handler
# receives the new map ID and the Game_Map object representing the new map.
# When the event handler is called, $game_map still refers to the old map.
def self.onMapChanging; @@OnMapChanging; end
def self.onMapChanging=(v); @@OnMapChanging = v; end
# Fires whenever the player moves to a new map. Event handler receives the old
# map ID or 0 if none. Also fires when the first map of the game is loaded
def self.onMapChange; @@OnMapChange; end
def self.onMapChange=(v); @@OnMapChange = v; end
# Fires whenever the map scene is regenerated and soon after the player moves
# to a new map.
# Parameters:
# e[0] - Scene_Map object.
# e[1] - Whether the player just moved to a new map (either true or false). If
# false, some other code had called $scene.createSpritesets to
# regenerate the map scene without transferring the player elsewhere
def self.onMapSceneChange; @@OnMapSceneChange; end
def self.onMapSceneChange=(v); @@OnMapSceneChange = v; end
# Fires whenever a spriteset is created.
# Parameters:
# e[0] - Spriteset being created. e[0].map is the map associated with the
# spriteset (not necessarily the current map).
# e[1] - Viewport used for tilemap and characters
def self.onSpritesetCreate; @@OnSpritesetCreate; end
def self.onSpritesetCreate=(v); @@OnSpritesetCreate = v; end
# Triggers when the player presses the Action button on the map.
def self.onAction; @@OnAction; end
def self.onAction=(v); @@OnAction = v; end
# Fires whenever the player takes a step.
def self.onStepTaken; @@OnStepTaken; end
def self.onStepTaken=(v); @@OnStepTaken = v; end
# Fires whenever the player or another event leaves a tile.
# Parameters:
# e[0] - Event that just left the tile.
# e[1] - Map ID where the tile is located (not necessarily
# the current map). Use "$MapFactory.getMap(e[1])" to
# get the Game_Map object corresponding to that map.
# e[2] - X-coordinate of the tile
# e[3] - Y-coordinate of the tile
def self.onLeaveTile; @@OnLeaveTile; end
def self.onLeaveTile=(v); @@OnLeaveTile = v; end
# Fires whenever the player or another event enters a tile.
# Parameters:
# e[0] - Event that just entered a tile.
def self.onStepTakenFieldMovement; @@OnStepTakenFieldMovement; end
def self.onStepTakenFieldMovement=(v); @@OnStepTakenFieldMovement = v; end
# Fires whenever the player takes a step. The event handler may possibly move
# the player elsewhere.
# Parameters:
# e[0] - Array that contains a single boolean value. If an event handler moves
# the player to a new map, it should set this value to true. Other
# event handlers should check this parameter's value.
def self.onStepTakenTransferPossible; @@OnStepTakenTransferPossible; end
def self.onStepTakenTransferPossible=(v); @@OnStepTakenTransferPossible = v; end
def self.onStartBattle; @@OnStartBattle; end
def self.onStartBattle=(v); @@OnStartBattle = v; end
def self.onEndBattle; @@OnEndBattle; end
def self.onEndBattle=(v); @@OnEndBattle = v; end
# Triggers whenever a wild Pokémon is created
# Parameters:
# e[0] - Pokémon being created
def self.onWildPokemonCreate; @@OnWildPokemonCreate; end
def self.onWildPokemonCreate=(v); @@OnWildPokemonCreate = v; end
# Triggers at the start of a wild battle. Event handlers can provide their
# own wild battle routines to override the default behavior.
def self.onWildBattleOverride; @@OnWildBattleOverride; end
def self.onWildBattleOverride=(v); @@OnWildBattleOverride = v; end
# Triggers whenever a wild Pokémon battle ends
# Parameters:
# e[0] - Pokémon species
# e[1] - Pokémon level
# e[2] - Battle result (1-win, 2-loss, 3-escaped, 4-caught, 5-draw)
def self.onWildBattleEnd; @@OnWildBattleEnd; end
def self.onWildBattleEnd=(v); @@OnWildBattleEnd = v; end
# Triggers whenever an NPC trainer's Pokémon party is loaded
# Parameters:
# e[0] - Trainer
# e[1] - Items possessed by the trainer
# e[2] - Party
def self.onTrainerPartyLoad; @@OnTrainerPartyLoad; end
def self.onTrainerPartyLoad=(v); @@OnTrainerPartyLoad = v; end
# Fires whenever the player changes direction.
def self.onChangeDirection; @@OnChangeDirection; end
def self.onChangeDirection=(v); @@OnChangeDirection = v; end
end
#===============================================================================
#
#===============================================================================
def pbOnSpritesetCreate(spriteset,viewport)
Events.onSpritesetCreate.trigger(nil,spriteset,viewport)
end
#===============================================================================
# This module stores encounter-modifying events that can happen during the game.
# A procedure can subscribe to an event by adding itself to the event. It will
# then be called whenever the event occurs.
#===============================================================================
module EncounterModifier
@@procs = []
@@procsEnd = []
def self.register(p)
@@procs.push(p)
end
def self.registerEncounterEnd(p)
@@procsEnd.push(p)
end
def self.trigger(encounter)
for prc in @@procs
encounter = prc.call(encounter)
end
return encounter
end
def self.triggerEncounterEnd()
for prc in @@procsEnd
prc.call()
end
end
end

View File

@@ -17,6 +17,7 @@ class Game_Screen
attr_reader :weather_type # weather type
attr_reader :weather_max # max number of weather sprites
attr_accessor :weather_duration # ticks in which the weather should fade in
#-----------------------------------------------------------------------------
# * Object Initialization
#-----------------------------------------------------------------------------
@@ -35,10 +36,10 @@ class Game_Screen
@shake_direction = 1
@shake = 0
@pictures = [nil]
for i in 1..100
(1..100).each do |i|
@pictures.push(Game_Picture.new(i))
end
@weather_type = 0
@weather_type = :None
@weather_max = 0.0
@weather_duration = 0
end
@@ -96,15 +97,15 @@ class Game_Screen
end
if @fadein_duration && @fadein_duration >= 1
d = @fadein_duration
@brightness = (@brightness*(d-1)+255)/d
@brightness = ((@brightness * (d - 1)) + 255) / d
@fadein_duration -= 1
end
if @tone_duration >= 1
d = @tone_duration
@tone.red = (@tone.red*(d-1)+@tone_target.red)/d
@tone.green = (@tone.green*(d-1)+@tone_target.green)/d
@tone.blue = (@tone.blue*(d-1)+@tone_target.blue)/d
@tone.gray = (@tone.gray*(d-1)+@tone_target.gray)/d
@tone.red = ((@tone.red * (d - 1)) + @tone_target.red) / d
@tone.green = ((@tone.green * (d - 1)) + @tone_target.green) / d
@tone.blue = ((@tone.blue * (d - 1)) + @tone_target.blue) / d
@tone.gray = ((@tone.gray * (d - 1)) + @tone_target.gray) / d
@tone_duration -= 1
end
if @flash_duration >= 1
@@ -124,11 +125,11 @@ class Game_Screen
@shake_duration -= 1 if @shake_duration >= 1
end
if $game_temp.in_battle
for i in 51..100
(51..100).each do |i|
@pictures[i].update
end
else
for i in 1..50
(1..50).each do |i|
@pictures[i].update
end
end
@@ -140,8 +141,8 @@ end
#===============================================================================
def pbToneChangeAll(tone, duration)
$game_screen.start_tone_change(tone, duration * Graphics.frame_rate / 20)
for picture in $game_screen.pictures
picture.start_tone_change(tone,duration*Graphics.frame_rate/20) if picture
$game_screen.pictures.each do |picture|
picture&.start_tone_change(tone, duration * Graphics.frame_rate / 20)
end
end

View File

@@ -5,51 +5,86 @@
# Refer to "$game_temp" for the instance of this class.
#===============================================================================
class Game_Temp
attr_accessor :message_window_showing # message window showing
attr_accessor :common_event_id # common event ID
attr_accessor :in_battle # in-battle flag
attr_accessor :battle_abort # battle flag: interrupt
attr_accessor :battleback_name # battleback file name
attr_accessor :in_menu # menu is open
attr_accessor :menu_beep # menu: play sound effect flag
# Flags requesting something to happen
attr_accessor :menu_calling # menu calling flag
attr_accessor :ready_menu_calling # ready menu calling flag
attr_accessor :debug_calling # debug calling flag
attr_accessor :interact_calling # EventHandlers.trigger(:on_player_interact) flag
attr_accessor :battle_abort # battle flag: interrupt (unused)
attr_accessor :title_screen_calling # return to title screen flag
attr_accessor :common_event_id # common event ID to start
# Flags indicating something is happening
attr_accessor :in_menu # menu is open
attr_accessor :in_storage # in-Pokémon storage flag
attr_accessor :in_battle # in-battle flag
attr_accessor :message_window_showing # message window showing
attr_accessor :ending_surf # jumping off surf base flag
attr_accessor :surf_base_coords # [x, y] while jumping on/off, or nil
attr_accessor :in_mini_update # performing mini update flag
# Battle
attr_accessor :battleback_name # battleback file name
attr_accessor :force_single_battle # force next battle to be 1v1 flag
attr_accessor :waiting_trainer # [trainer, event ID] or nil
attr_accessor :last_battle_record # record of actions in last recorded battle
# Player transfers
attr_accessor :player_transferring # player place movement flag
attr_accessor :player_new_map_id # player destination: map ID
attr_accessor :player_new_x # player destination: x-coordinate
attr_accessor :player_new_y # player destination: y-coordinate
attr_accessor :player_new_direction # player destination: direction
attr_accessor :fly_destination # [map ID, x, y] or nil
# Transitions
attr_accessor :transition_processing # transition processing flag
attr_accessor :transition_name # transition file name
attr_accessor :to_title # return to title screen flag
attr_accessor :fadestate # for sprite hashes
attr_accessor :background_bitmap
attr_accessor :fadestate # for sprite hashes
# Other
attr_accessor :begun_new_game # new game flag (true fron new game until saving)
attr_accessor :menu_beep # menu: play sound effect flag
attr_accessor :menu_last_choice # pause menu: index of last selection
attr_accessor :memorized_bgm # set when trainer intro BGM is played
attr_accessor :memorized_bgm_position # set when trainer intro BGM is played
attr_accessor :darkness_sprite # DarknessSprite or nil
attr_accessor :mart_prices
#-----------------------------------------------------------------------------
# * Object Initialization
#-----------------------------------------------------------------------------
def initialize
@message_window_showing = false
@common_event_id = 0
@in_battle = false
@battle_abort = false
@battleback_name = ''
@in_menu = false
@menu_beep = false
# Flags requesting something to happen
@menu_calling = false
@ready_menu_calling = false
@debug_calling = false
@interact_calling = false
@battle_abort = false
@title_screen_calling = false
@common_event_id = 0
# Flags indicating something is happening
@in_menu = false
@in_storage = false
@in_battle = false
@message_window_showing = false
@ending_surf = false
@in_mini_update = false
# Battle
@battleback_name = ""
@force_single_battle = false
# Player transfers
@player_transferring = false
@player_new_map_id = 0
@player_new_x = 0
@player_new_y = 0
@player_new_direction = 0
# Transitions
@transition_processing = false
@transition_name = ""
@to_title = false
@fadestate = 0
@background_bitmap = nil
@message_window_showing = false
@transition_processing = false
# Other
@begun_new_game = false
@menu_beep = false
@memorized_bgm = nil
@memorized_bgm_position = 0
@menu_last_choice = 0
@mart_prices = {}
end

View File

@@ -16,7 +16,7 @@ class Game_Switches
# switch_id : switch ID
#-----------------------------------------------------------------------------
def [](switch_id)
return @data[switch_id] if switch_id <= 5000 && @data[switch_id] != nil
return @data[switch_id] if switch_id <= 5000 && @data[switch_id]
return false
end
#-----------------------------------------------------------------------------

View File

@@ -16,7 +16,7 @@ class Game_SelfSwitches
# key : key
#-----------------------------------------------------------------------------
def [](key)
return (@data[key]==true) ? true : false
return @data[key] == true
end
#-----------------------------------------------------------------------------
# * Set Self Switch

View File

@@ -61,11 +61,10 @@ class Game_System
def bgm_play_internal(bgm, position) # :nodoc:
@bgm_position = position if !@bgm_paused
@playing_bgm = (bgm==nil) ? nil : bgm.clone
if bgm!=nil && bgm.name!=""
if FileTest.audio_exist?("Audio/BGM/"+bgm.name)
bgm_play_internal2("Audio/BGM/"+bgm.name,
bgm.volume,bgm.pitch,@bgm_position) if !@defaultBGM
@playing_bgm = bgm&.clone
if bgm && bgm.name != ""
if !@defaultBGM && FileTest.audio_exist?("Audio/BGM/" + bgm.name)
bgm_play_internal2("Audio/BGM/" + bgm.name, bgm.volume, bgm.pitch, @bgm_position)
end
else
@bgm_position = position if !@bgm_paused
@@ -132,12 +131,11 @@ class Game_System
def setDefaultBGM(bgm, volume = 80, pitch = 100)
bgm = RPG::AudioFile.new(bgm, volume, pitch) if bgm.is_a?(String)
if bgm!=nil && bgm.name!=""
@defaultBGM = nil
if bgm && bgm.name != ""
self.bgm_play(bgm)
@defaultBGM = bgm.clone
else
@defaultBGM = nil
self.bgm_play(@playing_bgm)
end
end
@@ -146,7 +144,7 @@ class Game_System
def me_play(me)
me = RPG::AudioFile.new(me) if me.is_a?(String)
if me!=nil && me.name!=""
if me && me.name != ""
if FileTest.audio_exist?("Audio/ME/" + me.name)
vol = me.volume
vol *= $PokemonSystem.bgmvolume / 100.0
@@ -162,8 +160,8 @@ class Game_System
################################################################################
def bgs_play(bgs)
@playing_bgs = (bgs==nil) ? nil : bgs.clone
if bgs!=nil && bgs.name!=""
@playing_bgs = (bgs.nil?) ? nil : bgs.clone
if bgs && bgs.name != ""
if FileTest.audio_exist?("Audio/BGS/" + bgs.name)
vol = bgs.volume
vol *= $PokemonSystem.sevolume / 100.0
@@ -230,7 +228,7 @@ class Game_System
def se_play(se)
se = RPG::AudioFile.new(se) if se.is_a?(String)
if se!=nil && se.name!="" && FileTest.audio_exist?("Audio/SE/"+se.name)
if se && se.name != "" && FileTest.audio_exist?("Audio/SE/" + se.name)
vol = se.volume
vol *= $PokemonSystem.sevolume / 100.0
vol = vol.to_i
@@ -248,36 +246,30 @@ class Game_System
return (@battle_bgm) ? @battle_bgm : $data_system.battle_bgm
end
def battle_bgm=(battle_bgm)
@battle_bgm = battle_bgm
end
attr_writer :battle_bgm
def battle_end_me
return (@battle_end_me) ? @battle_end_me : $data_system.battle_end_me
end
def battle_end_me=(battle_end_me)
@battle_end_me = battle_end_me
end
attr_writer :battle_end_me
################################################################################
def windowskin_name
if @windowskin_name==nil
if @windowskin_name.nil?
return $data_system.windowskin_name
else
return @windowskin_name
end
end
def windowskin_name=(windowskin_name)
@windowskin_name = windowskin_name
end
attr_writer :windowskin_name
def update
@timer -= 1 if @timer_working && @timer > 0
if Input.trigger?(Input::SPECIAL) && pbCurrentEventCommentInput(1, "Cut Scene")
event = @map_interpreter.get_character(0)
event = @map_interpreter.get_self
@map_interpreter.pbSetSelfSwitch(event.id, "A", true)
@map_interpreter.command_end
event.start

View File

@@ -20,6 +20,7 @@ class Game_Picture
attr_reader :blend_type # blend method
attr_reader :tone # color tone
attr_reader :angle # rotation angle
#-----------------------------------------------------------------------------
# * Object Initialization
# number : picture number
@@ -65,7 +66,7 @@ class Game_Picture
@zoom_x = zoom_x.to_f
@zoom_y = zoom_y.to_f
@opacity = opacity.to_f
@blend_type = blend_type ? blend_type : 0
@blend_type = blend_type || 0
@duration = 0
@target_x = @x
@target_y = @y
@@ -97,7 +98,7 @@ class Game_Picture
@target_zoom_x = zoom_x.to_f
@target_zoom_y = zoom_y.to_f
@target_opacity = opacity.to_f
@blend_type = blend_type ? blend_type : 0
@blend_type = blend_type || 0
end
#-----------------------------------------------------------------------------
# * Change Rotation Speed
@@ -130,19 +131,19 @@ class Game_Picture
def update
if @duration >= 1
d = @duration
@x = (@x * (d - 1) + @target_x) / d
@y = (@y * (d - 1) + @target_y) / d
@zoom_x = (@zoom_x * (d - 1) + @target_zoom_x) / d
@zoom_y = (@zoom_y * (d - 1) + @target_zoom_y) / d
@opacity = (@opacity * (d - 1) + @target_opacity) / d
@x = ((@x * (d - 1)) + @target_x) / d
@y = ((@y * (d - 1)) + @target_y) / d
@zoom_x = ((@zoom_x * (d - 1)) + @target_zoom_x) / d
@zoom_y = ((@zoom_y * (d - 1)) + @target_zoom_y) / d
@opacity = ((@opacity * (d - 1)) + @target_opacity) / d
@duration -= 1
end
if @tone_duration >= 1
d = @tone_duration
@tone.red = (@tone.red * (d - 1) + @tone_target.red) / d
@tone.green = (@tone.green * (d - 1) + @tone_target.green) / d
@tone.blue = (@tone.blue * (d - 1) + @tone_target.blue) / d
@tone.gray = (@tone.gray * (d - 1) + @tone_target.gray) / d
@tone.red = ((@tone.red * (d - 1)) + @tone_target.red) / d
@tone.green = ((@tone.green * (d - 1)) + @tone_target.green) / d
@tone.blue = ((@tone.blue * (d - 1)) + @tone_target.blue) / d
@tone.gray = ((@tone.gray * (d - 1)) + @tone_target.gray) / d
@tone_duration -= 1
end
if @rotate_speed != 0

View File

@@ -57,13 +57,13 @@ class Game_Map
self.display_x = 0
self.display_y = 0
@need_refresh = false
Events.onMapCreate.trigger(self,map_id,@map,tileset)
EventHandlers.trigger(:on_game_map_setup, map_id, @map, tileset)
@events = {}
for i in @map.events.keys
@map.events.each_key do |i|
@events[i] = Game_Event.new(@map_id, @map.events[i], self)
end
@common_events = {}
for i in 1...$data_common_events.size
(1...$data_common_events.size).each do |i|
@common_events[i] = Game_CommonEvent.new(i)
end
@scroll_direction = 2
@@ -95,43 +95,42 @@ class Game_Map
def encounter_list; return @map.encounter_list; end
def encounter_step; return @map.encounter_step; end
def data; return @map.data; end
def tileset_id; return @map.tileset_id; end
def bgm; return @map.bgm; end
def name
ret = pbGetMessage(MessageTypes::MapNames,@map_id)
ret.gsub!(/\\PN/,$Trainer.name) if $Trainer
return ret
return pbGetMapNameFromId(@map_id)
end
def metadata
return GameData::MapMetadata.try_get(@map_id)
end
#-----------------------------------------------------------------------------
# Returns the name of this map's BGM. If it's night time, returns the night
# version of the BGM (if it exists).
#-----------------------------------------------------------------------------
def bgm_name
if PBDayNight.isNight? && FileTest.audio_exist?("Audio/BGM/" + @map.bgm.name + "_n")
return @map.bgm.name + "_n"
end
return @map.bgm.name
end
#-----------------------------------------------------------------------------
# * Autoplays background music
# Plays music called "[normal BGM]_n" if it's night time and it exists
#-----------------------------------------------------------------------------
def autoplayAsCue
if @map.autoplay_bgm
if PBDayNight.isNight? && FileTest.audio_exist?("Audio/BGM/"+ @map.bgm.name+ "_n")
pbCueBGM(@map.bgm.name+"_n",1.0,@map.bgm.volume,@map.bgm.pitch)
else
pbCueBGM(@map.bgm,1.0)
end
end
if @map.autoplay_bgs
pbBGSPlay(@map.bgs)
end
pbCueBGM(bgm_name, 1.0, @map.bgm.volume, @map.bgm.pitch) if @map.autoplay_bgm
pbBGSPlay(@map.bgs) if @map.autoplay_bgs
end
#-----------------------------------------------------------------------------
# * Plays background music
# Plays music called "[normal BGM]_n" if it's night time and it exists
#-----------------------------------------------------------------------------
def autoplay
if @map.autoplay_bgm
if PBDayNight.isNight? && FileTest.audio_exist?("Audio/BGM/"+ @map.bgm.name+ "_n")
pbBGMPlay(@map.bgm.name+"_n",@map.bgm.volume,@map.bgm.pitch)
else
pbBGMPlay(@map.bgm)
end
end
if @map.autoplay_bgs
pbBGSPlay(@map.bgs)
end
pbBGMPlay(bgm_name, @map.bgm.volume, @map.bgm.pitch) if @map.autoplay_bgm
pbBGSPlay(@map.bgs) if @map.autoplay_bgs
end
def valid?(x, y)
@@ -144,8 +143,8 @@ class Game_Map
def passable?(x, y, d, self_event = nil)
return false if !valid?(x, y)
bit = (1 << (d / 2 - 1)) & 0x0f
for event in events.values
bit = (1 << ((d / 2) - 1)) & 0x0f
events.each_value do |event|
next if event.tile_id <= 0
next if event == self_event
next if !event.at_coordinate?(x, y)
@@ -183,14 +182,14 @@ class Game_Map
newy -= 1
end
return false if !valid?(newx, newy)
for i in [2, 1, 0]
[2, 1, 0].each do |i|
tile_id = data[x, y, i]
terrain = GameData::TerrainTag.try_get(@terrain_tags[tile_id])
# If already on water, only allow movement to another water tile
if self_event != nil && terrain.can_surf_freely
for j in [2, 1, 0]
if self_event && terrain.can_surf_freely
[2, 1, 0].each do |j|
facing_tile_id = data[newx, newy, j]
return false if facing_tile_id == nil
return false if facing_tile_id.nil?
facing_terrain = GameData::TerrainTag.try_get(@terrain_tags[facing_tile_id])
if facing_terrain.id != :None && !facing_terrain.ignore_passability
return facing_terrain.can_surf_freely
@@ -200,29 +199,28 @@ class Game_Map
# Can't walk onto ice
elsif terrain.ice
return false
elsif self_event != nil && self_event.x == x && self_event.y == y
elsif self_event && self_event.x == x && self_event.y == y
# Can't walk onto ledges
for j in [2, 1, 0]
[2, 1, 0].each do |j|
facing_tile_id = data[newx, newy, j]
return false if facing_tile_id == nil
return false if facing_tile_id.nil?
facing_terrain = GameData::TerrainTag.try_get(@terrain_tags[facing_tile_id])
return false if facing_terrain.ledge
break if facing_terrain.id != :None && !facing_terrain.ignore_passability
end
end
next if terrain&.ignore_passability
# Regular passability checks
if !terrain || !terrain.ignore_passability
passage = @passages[tile_id]
return false if passage & bit != 0 || passage & 0x0f == 0x0f
return true if @priorities[tile_id] == 0
end
end
return true
end
def playerPassable?(x, y, d, self_event = nil)
bit = (1 << (d / 2 - 1)) & 0x0f
for i in [2, 1, 0]
bit = (1 << ((d / 2) - 1)) & 0x0f
[2, 1, 0].each do |i|
tile_id = data[x, y, i]
terrain = GameData::TerrainTag.try_get(@terrain_tags[tile_id])
passage = @passages[tile_id]
@@ -238,12 +236,11 @@ class Game_Map
return (passage & bit == 0 && passage & 0x0f != 0x0f)
end
end
next if terrain&.ignore_passability
# Regular passability checks
if !terrain || !terrain.ignore_passability
return false if passage & bit != 0 || passage & 0x0f == 0x0f
return true if @priorities[tile_id] == 0
end
end
return true
end
@@ -251,14 +248,14 @@ class Game_Map
# event there, and the tile is fully passable in all directions)
def passableStrict?(x, y, d, self_event = nil)
return false if !valid?(x, y)
for event in events.values
events.each_value do |event|
next if event == self_event || event.tile_id < 0 || event.through
next if !event.at_coordinate?(x, y)
next if GameData::TerrainTag.try_get(@terrain_tags[event.tile_id]).ignore_passability
return false if @passages[event.tile_id] & 0x0f != 0
return true if @priorities[event.tile_id] == 0
end
for i in [2, 1, 0]
[2, 1, 0].each do |i|
tile_id = data[x, y, i]
next if GameData::TerrainTag.try_get(@terrain_tags[tile_id]).ignore_passability
return false if @passages[tile_id] & 0x0f != 0
@@ -268,7 +265,7 @@ class Game_Map
end
def bush?(x, y)
for i in [2, 1, 0]
[2, 1, 0].each do |i|
tile_id = data[x, y, i]
return false if GameData::TerrainTag.try_get(@terrain_tags[tile_id]).bridge &&
$PokemonGlobal.bridge > 0
@@ -278,7 +275,7 @@ class Game_Map
end
def deepBush?(x, y)
for i in [2, 1, 0]
[2, 1, 0].each do |i|
tile_id = data[x, y, i]
terrain = GameData::TerrainTag.try_get(@terrain_tags[tile_id])
return false if terrain.bridge && $PokemonGlobal.bridge > 0
@@ -288,7 +285,7 @@ class Game_Map
end
def counter?(x, y)
for i in [2, 1, 0]
[2, 1, 0].each do |i|
tile_id = data[x, y, i]
passage = @passages[tile_id]
return true if passage & 0x80 == 0x80
@@ -298,7 +295,7 @@ class Game_Map
def terrain_tag(x, y, countBridge = false)
if valid?(x, y)
for i in [2, 1, 0]
[2, 1, 0].each do |i|
tile_id = data[x, y, i]
terrain = GameData::TerrainTag.try_get(@terrain_tags[tile_id])
next if terrain.id == :None || terrain.ignore_passability
@@ -311,7 +308,7 @@ class Game_Map
# Unused.
def check_event(x, y)
for event in self.events.values
self.events.each_value do |event|
return event.id if event.at_coordinate?(x, y)
end
end
@@ -319,21 +316,21 @@ class Game_Map
def display_x=(value)
return if @display_x == value
@display_x = value
if GameData::MapMetadata.exists?(self.map_id) && GameData::MapMetadata.get(self.map_id).snap_edges
max_x = (self.width - Graphics.width*1.0/TILE_WIDTH) * REAL_RES_X
if metadata&.snap_edges
max_x = (self.width - (Graphics.width.to_f / TILE_WIDTH)) * REAL_RES_X
@display_x = [0, [@display_x, max_x].min].max
end
$MapFactory.setMapsInRange if $MapFactory
$map_factory&.setMapsInRange
end
def display_y=(value)
return if @display_y == value
@display_y = value
if GameData::MapMetadata.exists?(self.map_id) && GameData::MapMetadata.get(self.map_id).snap_edges
max_y = (self.height - Graphics.height*1.0/TILE_HEIGHT) * REAL_RES_Y
if metadata&.snap_edges
max_y = (self.height - (Graphics.height.to_f / TILE_HEIGHT)) * REAL_RES_Y
@display_y = [0, [@display_y, max_y].min].max
end
$MapFactory.setMapsInRange if $MapFactory
$map_factory&.setMapsInRange
end
def scroll_up(distance)
@@ -354,7 +351,7 @@ class Game_Map
def start_scroll(direction, distance, speed)
@scroll_direction = direction
if direction==2 || direction==8 # down or up
if [2, 8].include?(direction) # down or up
@scroll_rest = distance * REAL_RES_Y
else
@scroll_rest = distance * REAL_RES_X
@@ -375,18 +372,26 @@ class Game_Map
end
def start_fog_opacity_change(opacity, duration)
@fog_opacity_target = opacity*1.0
@fog_opacity_target = opacity.to_f
@fog_opacity_duration = duration
if @fog_opacity_duration == 0
@fog_opacity = @fog_opacity_target
end
end
def set_tile(x, y, layer, id = 0)
self.data[x, y, layer] = id
end
def erase_tile(x, y, layer)
set_tile(x, y, layer, 0)
end
def refresh
for event in @events.values
@events.each_value do |event|
event.refresh
end
for common_event in @common_events.values
@common_events.each_value do |common_event|
common_event.refresh
end
@need_refresh = false
@@ -394,11 +399,11 @@ class Game_Map
def update
# refresh maps if necessary
if $MapFactory
for i in $MapFactory.maps
if $map_factory
$map_factory.maps.each do |i|
i.refresh if i.need_refresh
end
$MapFactory.setCurrentMap
$map_factory.setCurrentMap
end
# If scrolling
if @scroll_rest > 0
@@ -413,11 +418,11 @@ class Game_Map
@scroll_rest -= distance
end
# Only update events that are on-screen
for event in @events.values
@events.each_value do |event|
event.update
end
# Update common events
for common_event in @common_events.values
@common_events.each_value do |common_event|
common_event.update
end
# Update fog
@@ -426,15 +431,15 @@ class Game_Map
if @fog_tone_duration >= 1
d = @fog_tone_duration
target = @fog_tone_target
@fog_tone.red = (@fog_tone.red * (d - 1) + target.red) / d
@fog_tone.green = (@fog_tone.green * (d - 1) + target.green) / d
@fog_tone.blue = (@fog_tone.blue * (d - 1) + target.blue) / d
@fog_tone.gray = (@fog_tone.gray * (d - 1) + target.gray) / d
@fog_tone.red = ((@fog_tone.red * (d - 1)) + target.red) / d
@fog_tone.green = ((@fog_tone.green * (d - 1)) + target.green) / d
@fog_tone.blue = ((@fog_tone.blue * (d - 1)) + target.blue) / d
@fog_tone.gray = ((@fog_tone.gray * (d - 1)) + target.gray) / d
@fog_tone_duration -= 1
end
if @fog_opacity_duration >= 1
d = @fog_opacity_duration
@fog_opacity = (@fog_opacity * (d - 1) + @fog_opacity_target) / d
@fog_opacity = ((@fog_opacity * (d - 1)) + @fog_opacity_target) / d
@fog_opacity_duration -= 1
end
end

View File

@@ -81,19 +81,34 @@ class Interpreter
if $game_map.scrolling?
return false
elsif !$game_map.valid?(x, y)
print 'Map Autoscroll: given x,y is invalid'
print "Map Autoscroll: given x,y is invalid"
return command_skip
elsif !(1..6).include?(speed)
print 'Map Autoscroll: invalid speed (1-6 only)'
print "Map Autoscroll: invalid speed (1-6 only)"
return command_skip
end
center_x = (Graphics.width/2 - Game_Map::TILE_WIDTH/2) * 4 # X coordinate in the center of the screen
center_y = (Graphics.height/2 - Game_Map::TILE_HEIGHT/2) * 4 # Y coordinate in the center of the screen
max_x = ($game_map.width - Graphics.width*1.0/Game_Map::TILE_WIDTH) * 4 * Game_Map::TILE_WIDTH
max_y = ($game_map.height - Graphics.height*1.0/Game_Map::TILE_HEIGHT) * 4 * Game_Map::TILE_HEIGHT
count_x = ($game_map.display_x - [0,[x*Game_Map::REAL_RES_X-center_x,max_x].min].max)/Game_Map::REAL_RES_X
count_y = ($game_map.display_y - [0,[y*Game_Map::REAL_RES_Y-center_y,max_y].min].max)/Game_Map::REAL_RES_Y
if !@diag
center_x = ((Graphics.width / 2) - (Game_Map::TILE_WIDTH / 2)) * 4 # X coordinate in the center of the screen
center_y = ((Graphics.height / 2) - (Game_Map::TILE_HEIGHT / 2)) * 4 # Y coordinate in the center of the screen
max_x = ($game_map.width - (Graphics.width.to_f / Game_Map::TILE_WIDTH)) * 4 * Game_Map::TILE_WIDTH
max_y = ($game_map.height - (Graphics.height.to_f / Game_Map::TILE_HEIGHT)) * 4 * Game_Map::TILE_HEIGHT
count_x = ($game_map.display_x - [0, [(x * Game_Map::REAL_RES_X) - center_x, max_x].min].max) / Game_Map::REAL_RES_X
count_y = ($game_map.display_y - [0, [(y * Game_Map::REAL_RES_Y) - center_y, max_y].min].max) / Game_Map::REAL_RES_Y
if @diag
@diag = false
dir = nil
if count_x != 0 && count_y != 0
return false
elsif count_x > 0
dir = 4
elsif count_x < 0
dir = 6
elsif count_y > 0
dir = 8
elsif count_y < 0
dir = 2
end
count = count_x == 0 ? count_y.abs : count_x.abs
else
@diag = true
dir = nil
if count_x > 0
@@ -110,28 +125,9 @@ class Interpreter
end
end
count = [count_x.abs, count_y.abs].min
else
@diag = false
dir = nil
if count_x != 0 && count_y != 0
return false
elsif count_x > 0
dir = 4
elsif count_x < 0
dir = 6
elsif count_y > 0
dir = 8
elsif count_y < 0
dir = 2
end
count = count_x != 0 ? count_x.abs : count_y.abs
end
$game_map.start_scroll(dir, count, speed) if dir != nil
if @diag
return false
else
return true
end
$game_map.start_scroll(dir, count, speed) if dir
return !@diag
end
#-----------------------------------------------------------------------------
@@ -148,20 +144,20 @@ end
class Game_Map
def scroll_downright(distance)
@display_x = [@display_x + distance,
(self.width - Graphics.width*1.0/TILE_WIDTH) * REAL_RES_X].min
(self.width - (Graphics.width.to_f / TILE_WIDTH)) * REAL_RES_X].min
@display_y = [@display_y + distance,
(self.height - Graphics.height*1.0/TILE_HEIGHT) * REAL_RES_Y].min
(self.height - (Graphics.height.to_f / TILE_HEIGHT)) * REAL_RES_Y].min
end
def scroll_downleft(distance)
@display_x = [@display_x - distance, 0].max
@display_y = [@display_y + distance,
(self.height - Graphics.height*1.0/TILE_HEIGHT) * REAL_RES_Y].min
(self.height - (Graphics.height.to_f / TILE_HEIGHT)) * REAL_RES_Y].min
end
def scroll_upright(distance)
@display_x = [@display_x + distance,
(self.width - Graphics.width*1.0/TILE_WIDTH) * REAL_RES_X].min
(self.width - (Graphics.width.to_f / TILE_WIDTH)) * REAL_RES_X].min
@display_y = [@display_y - distance, 0].max
end

View File

@@ -31,28 +31,28 @@ class PokemonMapFactory
return @maps[@mapIndex] if @maps[@mapIndex]
raise "No maps in save file... (mapIndex=#{@mapIndex})" if @maps.length == 0
if @maps[0]
echoln("Using next map, may be incorrect (mapIndex=#{@mapIndex}, length=#{@maps.length})")
echoln "Using next map, may be incorrect (mapIndex=#{@mapIndex}, length=#{@maps.length})"
return @maps[0]
end
raise "No maps in save file... (all maps empty; mapIndex=#{@mapIndex})"
end
def hasMap?(id)
for map in @maps
@maps.each do |map|
return true if map.map_id == id
end
return false
end
def getMapIndex(id)
for i in 0...@maps.length
@maps.length.times do |i|
return i if @maps[i].map_id == id
end
return -1
end
def getMap(id, add = true)
for map in @maps
@maps.each do |map|
return map if map.map_id == id
end
map = Game_Map.new
@@ -67,9 +67,7 @@ class PokemonMapFactory
def getNewMap(playerX, playerY)
id = $game_map.map_id
conns = MapFactoryHelper.getMapConnections
if conns[id]
for conn in conns[id]
MapFactoryHelper.eachConnectionForMap(id) do |conn|
mapidB = nil
newx = 0
newy = 0
@@ -88,7 +86,6 @@ class PokemonMapFactory
return [getMap(mapidB), newx, newy]
end
end
end
return nil
end
@@ -117,13 +114,11 @@ class PokemonMapFactory
return if @fixup
@fixup = true
id = $game_map.map_id
conns = MapFactoryHelper.getMapConnections
if conns[id]
for conn in conns[id]
MapFactoryHelper.eachConnectionForMap(id) do |conn|
if conn[0] == id
mapA = getMap(conn[0])
newdispx = (conn[4] - conn[1]) * Game_Map::REAL_RES_X + mapA.display_x
newdispy = (conn[5] - conn[2]) * Game_Map::REAL_RES_Y + mapA.display_y
newdispx = ((conn[4] - conn[1]) * Game_Map::REAL_RES_X) + mapA.display_x
newdispy = ((conn[5] - conn[2]) * Game_Map::REAL_RES_Y) + mapA.display_y
if hasMap?(conn[3]) || MapFactoryHelper.mapInRangeById?(conn[3], newdispx, newdispy)
mapB = getMap(conn[3])
mapB.display_x = newdispx if mapB.display_x != newdispx
@@ -131,8 +126,8 @@ class PokemonMapFactory
end
else
mapA = getMap(conn[3])
newdispx = (conn[1] - conn[4]) * Game_Map::REAL_RES_X + mapA.display_x
newdispy = (conn[2] - conn[5]) * Game_Map::REAL_RES_Y + mapA.display_y
newdispx = ((conn[1] - conn[4]) * Game_Map::REAL_RES_X) + mapA.display_x
newdispy = ((conn[2] - conn[5]) * Game_Map::REAL_RES_Y) + mapA.display_y
if hasMap?(conn[0]) || MapFactoryHelper.mapInRangeById?(conn[0], newdispx, newdispy)
mapB = getMap(conn[0])
mapB.display_x = newdispx if mapB.display_x != newdispx
@@ -140,21 +135,20 @@ class PokemonMapFactory
end
end
end
end
@fixup = false
end
def setMapChanging(newID, newMap)
Events.onMapChanging.trigger(self,newID,newMap)
EventHandlers.trigger(:on_leave_map, newID, newMap)
end
def setMapChanged(prevMap)
Events.onMapChange.trigger(self,prevMap)
EventHandlers.trigger(:on_enter_map, prevMap)
@mapChanged = true
end
def setSceneStarted(scene)
Events.onMapSceneChange.trigger(self,scene,@mapChanged)
EventHandlers.trigger(:on_map_or_spriteset_change, scene, @mapChanged)
@mapChanged = false
end
@@ -180,15 +174,15 @@ class PokemonMapFactory
return false unless map.passable?(x, y, 0, thisEvent)
end
# Check passability of event(s) in that spot
for event in map.events.values
map.events.each_value do |event|
next if event == thisEvent || !event.at_coordinate?(x, y)
return false if !event.through && event.character_name != ""
end
# Check passability of player
if !thisEvent.is_a?(Game_Player)
if $game_map.map_id == mapID && $game_player.x == x && $game_player.y == y
return false if !$game_player.through && $game_player.character_name != ""
end
if !thisEvent.is_a?(Game_Player) &&
$game_map.map_id == mapID && $game_player.x == x && $game_player.y == y &&
!$game_player.through && $game_player.character_name != ""
return false
end
return true
end
@@ -201,13 +195,13 @@ class PokemonMapFactory
return false if !map.valid?(x, y)
return true if thisEvent.through
if thisEvent == $game_player
if !($DEBUG && Input.press?(Input::CTRL))
return false if !map.passableStrict?(x,y,0,thisEvent)
if !($DEBUG && Input.press?(Input::CTRL)) && !map.passableStrict?(x, y, 0, thisEvent)
return false
end
else
return false if !map.passableStrict?(x,y,0,thisEvent)
elsif !map.passableStrict?(x, y, 0, thisEvent)
return false
end
for event in map.events.values
map.events.each_value do |event|
next if event == thisEvent || !event.at_coordinate?(x, y)
return false if !event.through && event.character_name != ""
end
@@ -234,33 +228,28 @@ class PokemonMapFactory
def areConnected?(mapID1, mapID2)
return true if mapID1 == mapID2
conns = MapFactoryHelper.getMapConnections
if conns[mapID1]
for conn in conns[mapID1]
MapFactoryHelper.eachConnectionForMap(mapID1) do |conn|
return true if conn[0] == mapID2 || conn[3] == mapID2
end
end
return false
end
# Returns the coordinate change to go from this position to other position
def getRelativePos(thisMapID, thisX, thisY, otherMapID, otherX, otherY)
if thisMapID == otherMapID # Both events share the same map
return [otherX - thisX, otherY - thisY]
end
conns = MapFactoryHelper.getMapConnections
if conns[thisMapID]
for conn in conns[thisMapID]
MapFactoryHelper.eachConnectionForMap(thisMapID) do |conn|
if conn[0] == otherMapID
posX = thisX + conn[1] - conn[4] + otherX
posY = thisY + conn[2] - conn[5] + otherY
posX = conn[4] - conn[1] + otherX - thisX
posY = conn[5] - conn[2] + otherY - thisY
return [posX, posY]
elsif conn[1] == otherMapID
posX = thisX + conn[4] - conn[1] + otherX
posY = thisY + conn[5] - conn[2] + otherY
elsif conn[3] == otherMapID
posX = conn[1] - conn[4] + otherX - thisX
posY = conn[2] - conn[5] + otherY - thisY
return [posX, posY]
end
end
end
return [0, 0]
end
@@ -269,15 +258,14 @@ class PokemonMapFactory
# the array (3,-4), because (5-2=3) and (1-5=-4).
def getThisAndOtherEventRelativePos(thisEvent, otherEvent)
return [0, 0] if !thisEvent || !otherEvent
return getRelativePos(
thisEvent.map.map_id,thisEvent.x,thisEvent.y,
return getRelativePos(thisEvent.map.map_id, thisEvent.x, thisEvent.y,
otherEvent.map.map_id, otherEvent.x, otherEvent.y)
end
def getThisAndOtherPosRelativePos(thisEvent, otherMapID, otherX, otherY)
return [0, 0] if !thisEvent
return getRelativePos(
thisEvent.map.map_id,thisEvent.x,thisEvent.y,otherMapID,otherX,otherY)
return getRelativePos(thisEvent.map.map_id, thisEvent.x, thisEvent.y,
otherMapID, otherX, otherY)
end
# Unused
@@ -289,12 +277,12 @@ class PokemonMapFactory
# NOTE: Assumes the event is 1x1 tile in size. Only returns one tile.
def getFacingTile(direction = nil, event = nil, steps = 1)
event = $game_player if event==nil
event = $game_player if event.nil?
return [0, 0, 0] if !event
x = event.x
y = event.y
id = event.map.map_id
direction = event.direction if direction==nil
direction = event.direction if direction.nil?
return getFacingTileFromPos(id, x, y, direction, steps)
end
@@ -330,9 +318,7 @@ class PokemonMapFactory
def getRealTilePos(mapID, x, y)
id = mapID
return [id, x, y] if getMapNoAdd(id).valid?(x, y)
conns = MapFactoryHelper.getMapConnections
if conns[id]
for conn in conns[id]
MapFactoryHelper.eachConnectionForMap(id) do |conn|
if conn[0] == id
newX = x + conn[4] - conn[1]
newY = y + conn[5] - conn[2]
@@ -349,7 +335,6 @@ class PokemonMapFactory
return [conn[0], newX, newY]
end
end
end
return nil
end
@@ -381,31 +366,21 @@ class PokemonMapFactory
def updateMaps(scene)
updateMapsInternal
$MapFactory.setSceneStarted(scene) if @mapChanged
$map_factory.setSceneStarted(scene) if @mapChanged
end
def updateMapsInternal
return if $game_player.moving?
if !MapFactoryHelper.hasConnections?($game_map.map_id)
return if @maps.length == 1
for i in 0...@maps.length
@maps[i] = nil if $game_map.map_id!=@maps[i].map_id
end
@maps.compact!
@maps.delete_if { |map| $game_map.map_id != map.map_id }
@mapIndex = getMapIndex($game_map.map_id)
return
end
setMapsInRange
deleted = false
for i in 0...@maps.length
next if MapFactoryHelper.mapInRange?(@maps[i])
@maps[i] = nil
deleted = true
end
if deleted
@maps.compact!
@mapIndex = getMapIndex($game_map.map_id)
end
old_num_maps = @maps.length
@maps.delete_if { |map| !MapFactoryHelper.mapInRange?(map) }
@mapIndex = getMapIndex($game_map.map_id) if @maps.length != old_num_maps
end
end
@@ -465,6 +440,12 @@ module MapFactoryHelper
return conns[id] ? true : false
end
def self.eachConnectionForMap(id)
conns = MapFactoryHelper.getMapConnections
return if !conns[id]
conns[id].each { |conn| yield conn }
end
# Gets the height and width of the map with id
def self.getMapDims(id)
# Create cache if doesn't exist
@@ -485,7 +466,7 @@ module MapFactoryHelper
# Returns the X or Y coordinate of an edge on the map with id.
# Considers the special strings "N","W","E","S"
def self.getMapEdge(id, edge)
return 0 if edge=="N" || edge=="W"
return 0 if ["N", "W"].include?(edge)
dims = getMapDims(id) # Get dimensions
return dims[0] if edge == "E"
return dims[1] if edge == "S"
@@ -498,8 +479,8 @@ module MapFactoryHelper
dispy = map.display_y
return false if dispx >= (map.width + range) * Game_Map::REAL_RES_X
return false if dispy >= (map.height + range) * Game_Map::REAL_RES_Y
return false if dispx <= -(Graphics.width + range * Game_Map::TILE_WIDTH) * Game_Map::X_SUBPIXELS
return false if dispy <= -(Graphics.height + range * Game_Map::TILE_HEIGHT) * Game_Map::Y_SUBPIXELS
return false if dispx <= -(Graphics.width + (range * Game_Map::TILE_WIDTH)) * Game_Map::X_SUBPIXELS
return false if dispy <= -(Graphics.height + (range * Game_Map::TILE_HEIGHT)) * Game_Map::Y_SUBPIXELS
return true
end
@@ -508,8 +489,8 @@ module MapFactoryHelper
dims = MapFactoryHelper.getMapDims(id)
return false if dispx >= (dims[0] + range) * Game_Map::REAL_RES_X
return false if dispy >= (dims[1] + range) * Game_Map::REAL_RES_Y
return false if dispx <= -(Graphics.width + range * Game_Map::TILE_WIDTH) * Game_Map::X_SUBPIXELS
return false if dispy <= -(Graphics.height + range * Game_Map::TILE_HEIGHT) * Game_Map::Y_SUBPIXELS
return false if dispx <= -(Graphics.width + (range * Game_Map::TILE_WIDTH)) * Game_Map::X_SUBPIXELS
return false if dispy <= -(Graphics.height + (range * Game_Map::TILE_HEIGHT)) * Game_Map::Y_SUBPIXELS
return true
end
end
@@ -519,8 +500,8 @@ end
#===============================================================================
# Unused
def updateTilesets
maps = $MapFactory.maps
for map in maps
map.updateTileset if map
maps = $map_factory.maps
maps.each do |map|
map&.updateTileset
end
end

View File

@@ -6,13 +6,15 @@ class Game_Character
attr_reader :y
attr_reader :real_x
attr_reader :real_y
attr_writer :x_offset # In pixels, positive shifts sprite to the right
attr_writer :y_offset # In pixels, positive shifts sprite down
attr_accessor :width
attr_accessor :height
attr_accessor :sprite_size
attr_reader :tile_id
attr_accessor :character_name
attr_accessor :character_hue
attr_reader :opacity
attr_accessor :opacity
attr_reader :blend_type
attr_accessor :direction
attr_accessor :pattern
@@ -35,6 +37,8 @@ class Game_Character
@y = 0
@real_x = 0
@real_y = 0
@x_offset = 0
@y_offset = 0
@width = 1
@height = 1
@sprite_size = [Game_Map::TILE_WIDTH, Game_Map::TILE_HEIGHT]
@@ -73,10 +77,14 @@ class Game_Character
@bob_height = 0
@wait_count = 0
@moved_this_frame = false
@moveto_happened = false
@locked = false
@prelock_direction = 0
end
def x_offset; return @x_offset || 0; end
def y_offset; return @y_offset || 0; end
def at_coordinate?(check_x, check_y)
return check_x >= @x && check_x < @x + @width &&
check_y > @y - @height && check_y <= @y
@@ -88,8 +96,8 @@ class Game_Character
end
def each_occupied_tile
for i in @x...(@x + @width)
for j in (@y - @height + 1)..@y
(@x...(@x + @width)).each do |i|
((@y - @height + 1)..@y).each do |j|
yield i, j
end
end
@@ -142,7 +150,7 @@ class Game_Character
# 4 => 64 # 1.6 seconds
# 5 => 30 # 0.75 seconds
# 6 => 0 # 0 seconds, i.e. continuous movement
self.move_frequency_real = (40 - val * 2) * (6 - val)
self.move_frequency_real = (40 - (val * 2)) * (6 - val)
end
def move_frequency_real
@@ -199,19 +207,30 @@ class Game_Character
def calculate_bush_depth
if @tile_id > 0 || @always_on_top || jumping?
@bush_depth = 0
else
deep_bush = regular_bush = false
return
end
xbehind = @x + (@direction == 4 ? 1 : @direction == 6 ? -1 : 0)
ybehind = @y + (@direction == 8 ? 1 : @direction == 2 ? -1 : 0)
this_map = (self.map.valid?(@x, @y)) ? [self.map, @x, @y] : $MapFactory.getNewMap(@x, @y)
if this_map[0].deepBush?(this_map[1], this_map[2]) && self.map.deepBush?(xbehind, ybehind)
this_map = (self.map.valid?(@x, @y)) ? [self.map, @x, @y] : $map_factory&.getNewMap(@x, @y)
behind_map = (self.map.valid?(xbehind, ybehind)) ? [self.map, xbehind, ybehind] : $map_factory&.getNewMap(xbehind, ybehind)
if this_map && this_map[0].deepBush?(this_map[1], this_map[2]) &&
(!behind_map || behind_map[0].deepBush?(behind_map[1], behind_map[2]))
@bush_depth = Game_Map::TILE_HEIGHT
elsif !moving? && this_map[0].bush?(this_map[1], this_map[2])
elsif this_map && this_map[0].bush?(this_map[1], this_map[2]) && !moving?
@bush_depth = 12
else
@bush_depth = 0
end
end
def fullPattern
case self.direction
when 2 then return self.pattern
when 4 then return self.pattern + 4
when 6 then return self.pattern + 8
when 8 then return self.pattern + 12
end
return 0
end
#=============================================================================
@@ -229,12 +248,13 @@ class Game_Character
return false unless self.map.passable?(x, y, d, self)
return false unless self.map.passable?(new_x, new_y, 10 - d, self)
end
for event in self.map.events.values
self.map.events.each_value do |event|
next if self == event || !event.at_coordinate?(new_x, new_y) || event.through
return false if self != $game_player || event.character_name != ""
end
if $game_player.x == new_x && $game_player.y == new_y
return false if !$game_player.through && @character_name != ""
if $game_player.x == new_x && $game_player.y == new_y &&
!$game_player.through && @character_name != ""
return false
end
return true
end
@@ -243,24 +263,24 @@ class Game_Character
case dir
when 2, 8 # Down, up
y_diff = (dir == 8) ? @height - 1 : 0
for i in start_x...(start_x + @width)
(start_x...(start_x + @width)).each do |i|
return false if !passable?(i, start_y - y_diff, dir, strict)
end
return true
when 4, 6 # Left, right
x_diff = (dir == 6) ? @width - 1 : 0
for i in (start_y - @height + 1)..start_y
((start_y - @height + 1)..start_y).each do |i|
return false if !passable?(start_x + x_diff, i, dir, strict)
end
return true
when 1, 3 # Down diagonals
# Treated as moving down first and then horizontally, because that
# describes which tiles the character's feet touch
for i in start_x...(start_x + @width)
(start_x...(start_x + @width)).each do |i|
return false if !passable?(i, start_y, 2, strict)
end
x_diff = (dir == 3) ? @width - 1 : 0
for i in (start_y - @height + 1)..start_y
((start_y - @height + 1)..start_y).each do |i|
return false if !passable?(start_x + x_diff, i + 1, dir + 3, strict)
end
return true
@@ -268,12 +288,12 @@ class Game_Character
# Treated as moving horizontally first and then up, because that describes
# which tiles the character's feet touch
x_diff = (dir == 9) ? @width - 1 : 0
for i in (start_y - @height + 1)..start_y
((start_y - @height + 1)..start_y).each do |i|
return false if !passable?(start_x + x_diff, i, dir - 3, strict)
end
x_offset = (dir == 9) ? 1 : -1
for i in start_x...(start_x + @width)
return false if !passable?(i + x_offset, start_y - @height + 1, 8, strict)
x_tile_offset = (dir == 9) ? 1 : -1
(start_x...(start_x + @width)).each do |i|
return false if !passable?(i + x_tile_offset, start_y - @height + 1, 8, strict)
end
return true
end
@@ -288,13 +308,14 @@ class Game_Character
# Screen position of the character
#=============================================================================
def screen_x
ret = ((@real_x - self.map.display_x) / Game_Map::X_SUBPIXELS).round
ret = ((@real_x.to_f - self.map.display_x) / Game_Map::X_SUBPIXELS).round
ret += @width * Game_Map::TILE_WIDTH / 2
ret += self.x_offset
return ret
end
def screen_y_ground
ret = ((@real_y - self.map.display_y) / Game_Map::Y_SUBPIXELS).round
ret = ((@real_y.to_f - self.map.display_y) / Game_Map::Y_SUBPIXELS).round
ret += Game_Map::TILE_HEIGHT
return ret
end
@@ -307,8 +328,9 @@ class Game_Character
else
jump_fraction = ((@jump_distance_left / @jump_distance) - 0.5).abs # 0.5 to 0 to 0.5
end
ret += @jump_peak * (4 * jump_fraction**2 - 1)
ret += @jump_peak * ((4 * (jump_fraction**2)) - 1)
end
ret += self.y_offset
return ret
end
@@ -317,7 +339,7 @@ class Game_Character
z = screen_y_ground
if @tile_id > 0
begin
return z + self.map.priorities[@tile_id] * 32
return z + (self.map.priorities[@tile_id] * 32)
rescue
raise "Event's graphic is an out-of-range tile (event #{@id}, map #{self.map.map_id})"
end
@@ -345,7 +367,7 @@ class Game_Character
end
def force_move_route(move_route)
if @original_move_route == nil
if @original_move_route.nil?
@original_move_route = @move_route
@original_move_route_index = @move_route_index
end
@@ -363,6 +385,7 @@ class Game_Character
@real_x = @x * Game_Map::REAL_RES_X
@real_y = @y * Game_Map::REAL_RES_Y
@prelock_direction = 0
@moveto_happened = true
calculate_bush_depth
triggerLeaveTile
end
@@ -370,7 +393,7 @@ class Game_Character
def triggerLeaveTile
if @oldX && @oldY && @oldMap &&
(@oldX != self.x || @oldY != self.y || @oldMap != self.map.map_id)
Events.onLeaveTile.trigger(self,self,@oldMap,@oldX,@oldY)
EventHandlers.trigger(:on_leave_tile, self, @oldMap, @oldX, @oldY)
end
@oldX = self.x
@oldY = self.y
@@ -394,8 +417,8 @@ class Game_Character
end
def move_type_toward_player
sx = @x + @width / 2.0 - ($game_player.x + $game_player.width / 2.0)
sy = @y - @height / 2.0 - ($game_player.y - $game_player.height / 2.0)
sx = @x + (@width / 2.0) - ($game_player.x + ($game_player.width / 2.0))
sy = @y - (@height / 2.0) - ($game_player.y - ($game_player.height / 2.0))
if sx.abs + sy.abs >= 20
move_random
return
@@ -620,13 +643,15 @@ class Game_Character
def move_random_range(xrange = -1, yrange = -1)
dirs = [] # 0=down, 1=left, 2=right, 3=up
if xrange < 0
dirs.push(1); dirs.push(2)
dirs.push(1)
dirs.push(2)
elsif xrange > 0
dirs.push(1) if @x > @original_x - xrange
dirs.push(2) if @x < @original_x + xrange
end
if yrange < 0
dirs.push(0); dirs.push(3)
dirs.push(0)
dirs.push(3)
elsif yrange > 0
dirs.push(0) if @y < @original_y + yrange
dirs.push(3) if @y > @original_y - yrange
@@ -649,8 +674,8 @@ class Game_Character
end
def move_toward_player
sx = @x + @width / 2.0 - ($game_player.x + $game_player.width / 2.0)
sy = @y - @height / 2.0 - ($game_player.y - $game_player.height / 2.0)
sx = @x + (@width / 2.0) - ($game_player.x + ($game_player.width / 2.0))
sy = @y - (@height / 2.0) - ($game_player.y - ($game_player.height / 2.0))
return if sx == 0 && sy == 0
abs_sx = sx.abs
abs_sy = sy.abs
@@ -671,8 +696,8 @@ class Game_Character
end
def move_away_from_player
sx = @x + @width / 2.0 - ($game_player.x + $game_player.width / 2.0)
sy = @y - @height / 2.0 - ($game_player.y - $game_player.height / 2.0)
sx = @x + (@width / 2.0) - ($game_player.x + ($game_player.width / 2.0))
sy = @y - (@height / 2.0) - ($game_player.y - ($game_player.height / 2.0))
return if sx == 0 && sy == 0
abs_sx = sx.abs
abs_sy = sy.abs
@@ -724,7 +749,7 @@ class Game_Character
end
@x = @x + x_plus
@y = @y + y_plus
real_distance = Math::sqrt(x_plus * x_plus + y_plus * y_plus)
real_distance = Math.sqrt((x_plus * x_plus) + (y_plus * y_plus))
distance = [1, real_distance].max
@jump_peak = distance * Game_Map::TILE_HEIGHT * 3 / 8 # 3/4 of tile for ledge jumping
@jump_distance = [x_plus.abs * Game_Map::REAL_RES_X, y_plus.abs * Game_Map::REAL_RES_Y].max
@@ -736,9 +761,6 @@ class Game_Character
@jump_count = Game_Map::REAL_RES_X / jump_speed_real # Number of frames to jump one tile
end
@stop_count = 0
if self.is_a?(Game_Player)
$PokemonTemp.dependentEvents.pbMoveDependentEvents
end
triggerLeaveTile
end
@@ -814,8 +836,8 @@ class Game_Character
end
def turn_toward_player
sx = @x + @width / 2.0 - ($game_player.x + $game_player.width / 2.0)
sy = @y - @height / 2.0 - ($game_player.y - $game_player.height / 2.0)
sx = @x + (@width / 2.0) - ($game_player.x + ($game_player.width / 2.0))
sy = @y - (@height / 2.0) - ($game_player.y - ($game_player.height / 2.0))
return if sx == 0 && sy == 0
if sx.abs > sy.abs
(sx > 0) ? turn_left : turn_right
@@ -825,8 +847,8 @@ class Game_Character
end
def turn_away_from_player
sx = @x + @width / 2.0 - ($game_player.x + $game_player.width / 2.0)
sy = @y - @height / 2.0 - ($game_player.y - $game_player.height / 2.0)
sx = @x + (@width / 2.0) - ($game_player.x + ($game_player.width / 2.0))
sy = @y - (@height / 2.0) - ($game_player.y - ($game_player.height / 2.0))
return if sx == 0 && sy == 0
if sx.abs > sy.abs
(sx > 0) ? turn_right : turn_left
@@ -841,6 +863,8 @@ class Game_Character
def update
@moved_last_frame = @moved_this_frame
@stopped_last_frame = @stopped_this_frame
@moved_this_frame = false
@stopped_this_frame = false
if !$game_temp.in_menu
# Update command
update_command
@@ -905,12 +929,11 @@ class Game_Character
end
# End of a step, so perform events that happen at this time
if !jumping? && !moving?
Events.onStepTakenFieldMovement.trigger(self, self)
EventHandlers.trigger(:on_step_taken, self)
calculate_bush_depth
@stopped_this_frame = true
elsif !@moved_last_frame || @stopped_last_frame # Started a new step
calculate_bush_depth
@stopped_this_frame = false
end
# Increment animation counter
@anime_count += 1 if @walk_anime || @step_anime
@@ -920,8 +943,6 @@ class Game_Character
def update_stop
@anime_count += 1 if @step_anime
@stop_count += 1 if !@starting && !lock?
@moved_this_frame = false
@stopped_this_frame = false
end
def update_pattern

View File

@@ -99,7 +99,7 @@ class Game_Event < Game_Character
return $PokemonGlobal.eventvars[[@map_id, @event.id]].to_i
end
def expired?(secs=86400)
def expired?(secs = 86_400)
ontime = self.variable
time = pbGetTimeNow
return ontime && (time.to_i > ontime + secs)
@@ -109,8 +109,8 @@ class Game_Event < Game_Character
ontime = self.variable.to_i
return false if !ontime
now = pbGetTimeNow
elapsed=(now.to_i-ontime)/86400
elapsed+=1 if (now.to_i-ontime)%86400>(now.hour*3600+now.min*60+now.sec)
elapsed = (now.to_i - ontime) / 86_400
elapsed += 1 if (now.to_i - ontime) % 86_400 > ((now.hour * 3600) + (now.min * 60) + now.sec)
return elapsed >= days
end
@@ -141,12 +141,12 @@ class Game_Event < Game_Character
def pbCheckEventTriggerAfterTurning
return if $game_system.map_interpreter.running? || @starting
if @event.name[/trainer\((\d+)\)/i]
return if @trigger != 2 # Event touch
return if !@event.name[/(?:sight|trainer)\((\d+)\)/i]
distance = $~[1].to_i
if @trigger==2 && pbEventCanReachPlayer?(self,$game_player,distance)
start if !jumping? && !over_trigger?
end
end
return if !pbEventCanReachPlayer?(self, $game_player, distance)
return if jumping? || over_trigger?
start
end
def check_event_trigger_touch(dir)
@@ -168,11 +168,12 @@ class Game_Event < Game_Character
end
def check_event_trigger_auto
if @trigger == 2 # Event touch
if at_coordinate?($game_player.x, $game_player.y)
start if !jumping? && over_trigger?
case @trigger
when 2 # Event touch
if at_coordinate?($game_player.x, $game_player.y) && !jumping? && over_trigger?
start
end
elsif @trigger == 3 # Autorun
when 3 # Autorun
start
end
end
@@ -180,7 +181,7 @@ class Game_Event < Game_Character
def refresh
new_page = nil
unless @erased
for page in @event.pages.reverse
@event.pages.reverse.each do |page|
c = page.condition
next if c.switch1_valid && !switchIsOn?(c.switch1_id)
next if c.switch2_valid && !switchIsOn?(c.switch2_id)
@@ -196,7 +197,7 @@ class Game_Event < Game_Character
return if new_page == @page
@page = new_page
clear_starting
if @page == nil
if @page.nil?
@tile_id = 0
@character_name = ""
@character_hue = 0
@@ -245,12 +246,12 @@ class Game_Event < Game_Character
def should_update?(recalc = false)
return @to_update if !recalc
return true if @trigger && (@trigger == 3 || @trigger == 4)
return true if @move_route_forcing
return true if @move_route_forcing || @moveto_happened
return true if @event.name[/update/i]
range = 2 # Number of tiles
return false if self.screen_x - @sprite_size[0]/2 > Graphics.width + range * Game_Map::TILE_WIDTH
return false if self.screen_x + @sprite_size[0]/2 < -range * Game_Map::TILE_WIDTH
return false if self.screen_y_ground - @sprite_size[1] > Graphics.height + range * Game_Map::TILE_HEIGHT
return false if self.screen_x - (@sprite_size[0] / 2) > Graphics.width + (range * Game_Map::TILE_WIDTH)
return false if self.screen_x + (@sprite_size[0] / 2) < -range * Game_Map::TILE_WIDTH
return false if self.screen_y_ground - @sprite_size[1] > Graphics.height + (range * Game_Map::TILE_HEIGHT)
return false if self.screen_y_ground < -range * Game_Map::TILE_HEIGHT
return true
end
@@ -258,6 +259,7 @@ class Game_Event < Game_Character
def update
@to_update = should_update?(true)
return if !@to_update
@moveto_happened = false
last_moving = moving?
super
if !moving? && last_moving
@@ -268,7 +270,7 @@ class Game_Event < Game_Character
refresh
end
check_event_trigger_auto
if @interpreter != nil
if @interpreter
unless @interpreter.running?
@interpreter.setup(@list, @event.id, @map_id)
end

View File

@@ -10,8 +10,10 @@ class Game_Player < Game_Character
attr_accessor :charsetData
attr_accessor :encounter_count
SCREEN_CENTER_X = (Settings::SCREEN_WIDTH / 2 - Game_Map::TILE_WIDTH / 2) * Game_Map::X_SUBPIXELS
SCREEN_CENTER_Y = (Settings::SCREEN_HEIGHT / 2 - Game_Map::TILE_HEIGHT / 2) * Game_Map::Y_SUBPIXELS
SCREEN_CENTER_X = ((Settings::SCREEN_WIDTH / 2) - (Game_Map::TILE_WIDTH / 2)) * Game_Map::X_SUBPIXELS
SCREEN_CENTER_Y = ((Settings::SCREEN_HEIGHT / 2) - (Game_Map::TILE_HEIGHT / 2)) * Game_Map::Y_SUBPIXELS
@@bobFrameSpeed = 1.0 / 15
def initialize(*arg)
super(*arg)
@@ -25,60 +27,174 @@ class Game_Player < Game_Character
return $game_map
end
def pbHasDependentEvents?
return $PokemonGlobal.dependentEvents.length>0
def map_id
return $game_map.map_id
end
def screen_z(height = 0)
ret = super
return ret + 1
end
def has_follower?
return $PokemonGlobal.followers.length > 0
end
def can_map_transfer_with_follower?
return $PokemonGlobal.followers.length == 0
end
def can_ride_vehicle_with_follower?
return $PokemonGlobal.followers.length == 0
end
def can_run?
return @move_speed > 3 if @move_route_forcing
return false if $game_temp.in_menu || $game_temp.in_battle ||
$game_temp.message_window_showing || pbMapInterpreterRunning?
return false if !$player.has_running_shoes && !$PokemonGlobal.diving &&
!$PokemonGlobal.surfing && !$PokemonGlobal.bicycle
return false if jumping?
return false if pbTerrainTag.must_walk
return ($PokemonSystem.runstyle == 1) ^ Input.press?(Input::BACK)
end
def set_movement_type(type)
meta = GameData::PlayerMetadata.get($player&.character_ID || 1)
new_charset = nil
case type
when :fishing
new_charset = pbGetPlayerCharset(meta.fish_charset)
when :surf_fishing
new_charset = pbGetPlayerCharset(meta.surf_fish_charset)
when :diving, :diving_fast, :diving_jumping, :diving_stopped
self.move_speed = 3
new_charset = pbGetPlayerCharset(meta.dive_charset)
when :surfing, :surfing_fast, :surfing_jumping, :surfing_stopped
self.move_speed = (type == :surfing_jumping) ? 3 : 4
new_charset = pbGetPlayerCharset(meta.surf_charset)
when :cycling, :cycling_fast, :cycling_jumping, :cycling_stopped
self.move_speed = (type == :cycling_jumping) ? 3 : 5
new_charset = pbGetPlayerCharset(meta.cycle_charset)
when :running
self.move_speed = 4
new_charset = pbGetPlayerCharset(meta.run_charset)
when :ice_sliding
self.move_speed = 4
new_charset = pbGetPlayerCharset(meta.walk_charset)
else # :walking, :jumping, :walking_stopped
self.move_speed = 3
new_charset = pbGetPlayerCharset(meta.walk_charset)
end
@character_name = new_charset if new_charset
end
# Called when the player's character or outfit changes. Assumes the player
# isn't moving.
def refresh_charset
meta = GameData::PlayerMetadata.get($player&.character_ID || 1)
new_charset = nil
if $PokemonGlobal&.diving
new_charset = pbGetPlayerCharset(meta.dive_charset)
elsif $PokemonGlobal&.surfing
new_charset = pbGetPlayerCharset(meta.surf_charset)
elsif $PokemonGlobal&.bicycle
new_charset = pbGetPlayerCharset(meta.cycle_charset)
else
new_charset = pbGetPlayerCharset(meta.walk_charset)
end
@character_name = new_charset if new_charset
end
def bump_into_object
return if @bump_se && @bump_se > 0
pbSEPlay("Player bump")
pbSEPlay("Player bump") if !@move_route_forcing
@bump_se = Graphics.frame_rate / 4
end
def move_generic(dir, turn_enabled = true)
turn_generic(dir, true) if turn_enabled
if !$PokemonTemp.encounterTriggered
if !$game_temp.encounter_triggered
if can_move_in_direction?(dir)
x_offset = (dir == 4) ? -1 : (dir == 6) ? 1 : 0
y_offset = (dir == 8) ? -1 : (dir == 2) ? 1 : 0
return if pbLedge(x_offset, y_offset)
return if pbEndSurf(x_offset, y_offset)
turn_generic(dir, true)
if !$PokemonTemp.encounterTriggered
if !$game_temp.encounter_triggered
@x += x_offset
@y += y_offset
$PokemonTemp.dependentEvents.pbMoveDependentEvents
if $PokemonGlobal&.diving || $PokemonGlobal&.surfing
$stats.distance_surfed += 1
elsif $PokemonGlobal&.bicycle
$stats.distance_cycled += 1
else
$stats.distance_walked += 1
end
$stats.distance_slid_on_ice += 1 if $PokemonGlobal.sliding
increase_steps
end
elsif !check_event_trigger_touch(dir)
bump_into_object
end
end
$PokemonTemp.encounterTriggered = false
$game_temp.encounter_triggered = false
end
def turn_generic(dir, keep_enc_indicator = false)
old_direction = @direction
super(dir)
if @direction != old_direction && !@move_route_forcing && !pbMapInterpreterRunning?
Events.onChangeDirection.trigger(self, self)
$PokemonTemp.encounterTriggered = false if !keep_enc_indicator
EventHandlers.trigger(:on_player_change_direction)
$game_temp.encounter_triggered = false if !keep_enc_indicator
end
end
def pbTriggeredTrainerEvents(triggers,checkIfRunning=true)
def jump(x_plus, y_plus)
if x_plus != 0 || y_plus != 0
if x_plus.abs > y_plus.abs
(x_plus < 0) ? turn_left : turn_right
else
(y_plus < 0) ? turn_up : turn_down
end
each_occupied_tile { |i, j| return if !passable?(i + x_plus, j + y_plus, 0) }
end
@x = @x + x_plus
@y = @y + y_plus
real_distance = Math.sqrt((x_plus * x_plus) + (y_plus * y_plus))
distance = [1, real_distance].max
@jump_peak = distance * Game_Map::TILE_HEIGHT * 3 / 8 # 3/4 of tile for ledge jumping
@jump_distance = [x_plus.abs * Game_Map::REAL_RES_X, y_plus.abs * Game_Map::REAL_RES_Y].max
@jump_distance_left = 1 # Just needs to be non-zero
if real_distance > 0 # Jumping to somewhere else
if $PokemonGlobal&.diving || $PokemonGlobal&.surfing
$stats.distance_surfed += x_plus.abs + y_plus.abs
elsif $PokemonGlobal&.bicycle
$stats.distance_cycled += x_plus.abs + y_plus.abs
else
$stats.distance_walked += x_plus.abs + y_plus.abs
end
@jump_count = 0
else # Jumping on the spot
@jump_speed_real = nil # Reset jump speed
@jump_count = Game_Map::REAL_RES_X / jump_speed_real # Number of frames to jump one tile
end
@stop_count = 0
triggerLeaveTile
end
def pbTriggeredTrainerEvents(triggers, checkIfRunning = true, trainer_only = false)
result = []
# If event is running
return result if checkIfRunning && $game_system.map_interpreter.running?
# All event loops
for event in $game_map.events.values
next if !event.name[/trainer\((\d+)\)/i]
$game_map.events.each_value do |event|
next if !triggers.include?(event.trigger)
next if !event.name[/trainer\((\d+)\)/i] && (trainer_only || !event.name[/sight\((\d+)\)/i])
distance = $~[1].to_i
# If event coordinates and triggers are consistent
if pbEventCanReachPlayer?(event,self,distance) && triggers.include?(event.trigger)
# If starting determinant is front event (other than jumping)
result.push(event) if !event.jumping? && !event.over_trigger?
end
next if !pbEventCanReachPlayer?(event, self, distance)
next if event.jumping? || event.over_trigger?
result.push(event)
end
return result
end
@@ -88,14 +204,13 @@ class Game_Player < Game_Character
# If event is running
return result if checkIfRunning && $game_system.map_interpreter.running?
# All event loops
for event in $game_map.events.values
$game_map.events.each_value do |event|
next if !triggers.include?(event.trigger)
next if !event.name[/counter\((\d+)\)/i]
distance = $~[1].to_i
# If event coordinates and triggers are consistent
if pbEventFacesPlayer?(event,self,distance) && triggers.include?(event.trigger)
# If starting determinant is front event (other than jumping)
result.push(event) if !event.jumping? && !event.over_trigger?
end
next if !pbEventFacesPlayer?(event, self, distance)
next if event.jumping? || event.over_trigger?
result.push(event)
end
return result
end
@@ -106,14 +221,14 @@ class Game_Player < Game_Character
ret = pbTriggeredTrainerEvents(triggers)
ret.concat(pbTriggeredCounterEvents(triggers))
return false if ret.length == 0
for event in ret
ret.each do |event|
event.start
end
return true
end
def pbTerrainTag(countBridge = false)
return $MapFactory.getTerrainTag(self.map.map_id, @x, @y, countBridge) if $MapFactory
return $map_factory.getTerrainTag(self.map.map_id, @x, @y, countBridge) if $map_factory
return $game_map.terrain_tag(@x, @y, countBridge)
end
@@ -123,7 +238,7 @@ class Game_Player < Game_Character
new_x = @x + (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
new_y = @y + (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
return nil if !$game_map.valid?(new_x, new_y)
for event in $game_map.events.values
$game_map.events.each_value do |event|
next if !event.at_coordinate?(new_x, new_y)
next if event.jumping? || event.over_trigger?
return event
@@ -132,7 +247,7 @@ class Game_Player < Game_Character
if $game_map.counter?(new_x, new_y)
new_x += (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
new_y += (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
for event in $game_map.events.values
$game_map.events.each_value do |event|
next if !event.at_coordinate?(new_x, new_y)
next if event.jumping? || event.over_trigger?
return event
@@ -143,7 +258,7 @@ class Game_Player < Game_Character
def pbFacingTerrainTag(dir = nil)
dir = self.direction if !dir
return $MapFactory.getFacingTerrainTag(dir, self) if $MapFactory
return $map_factory.getFacingTerrainTag(dir, self) if $map_factory
facing = pbFacingTile(dir, self)
return $game_map.terrain_tag(facing[1], facing[2])
end
@@ -162,8 +277,8 @@ class Game_Player < Game_Character
# If coordinates are outside of map
return false if !$game_map.validLax?(new_x, new_y)
if !$game_map.valid?(new_x, new_y)
return false if !$MapFactory
return $MapFactory.isPassableFromEdge?(new_x, new_y)
return false if !$map_factory
return $map_factory.isPassableFromEdge?(new_x, new_y)
end
# If debug mode is ON and Ctrl key was pressed
return true if $DEBUG && Input.press?(Input::CTRL)
@@ -174,8 +289,8 @@ class Game_Player < Game_Character
# * Set Map Display Position to Center of Screen
#-----------------------------------------------------------------------------
def center(x, y)
self.map.display_x = x * Game_Map::REAL_RES_X - SCREEN_CENTER_X
self.map.display_y = y * Game_Map::REAL_RES_Y - SCREEN_CENTER_Y
self.map.display_x = (x * Game_Map::REAL_RES_X) - SCREEN_CENTER_X
self.map.display_y = (y * Game_Map::REAL_RES_Y) - SCREEN_CENTER_Y
end
#-----------------------------------------------------------------------------
@@ -185,9 +300,7 @@ class Game_Player < Game_Character
#-----------------------------------------------------------------------------
def moveto(x, y)
super
# Centering
center(x, y)
# Make encounter count
make_encounter_count
end
@@ -219,7 +332,7 @@ class Game_Player < Game_Character
# If event is running
return result if $game_system.map_interpreter.running?
# All event loops
for event in $game_map.events.values
$game_map.events.each_value do |event|
# If event coordinates and triggers are consistent
next if !event.at_coordinate?(@x, @y)
next if !triggers.include?(event.trigger)
@@ -243,35 +356,32 @@ class Game_Player < Game_Character
new_y = @y + (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
return false if !$game_map.valid?(new_x, new_y)
# All event loops
for event in $game_map.events.values
$game_map.events.each_value do |event|
next if !triggers.include?(event.trigger)
# If event coordinates and triggers are consistent
next if !event.at_coordinate?(new_x, new_y)
next if !triggers.include?(event.trigger)
# If starting determinant is front event (other than jumping)
next if event.jumping? || event.over_trigger?
event.start
result = true
end
# If fitting event is not found
if result == false
# If front tile is a counter
if $game_map.counter?(new_x, new_y)
if result == false && $game_map.counter?(new_x, new_y)
# Calculate coordinates of 1 tile further away
new_x += (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
new_y += (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
return false if !$game_map.valid?(new_x, new_y)
# All event loops
for event in $game_map.events.values
$game_map.events.each_value do |event|
next if !triggers.include?(event.trigger)
# If event coordinates and triggers are consistent
next if !event.at_coordinate?(new_x, new_y)
next if !triggers.include?(event.trigger)
# If starting determinant is front event (other than jumping)
next if event.jumping? || event.over_trigger?
event.start
result = true
end
end
end
return result
end
@@ -284,11 +394,11 @@ class Game_Player < Game_Character
# All event loops
x_offset = (dir == 4) ? -1 : (dir == 6) ? 1 : 0
y_offset = (dir == 8) ? -1 : (dir == 2) ? 1 : 0
for event in $game_map.events.values
$game_map.events.each_value do |event|
next if ![1, 2].include?(event.trigger) # Player touch, event touch
# If event coordinates and triggers are consistent
next if !event.at_coordinate?(@x + x_offset, @y + y_offset)
if event.name[/trainer\((\d+)\)/i]
if event.name[/(?:sight|trainer)\((\d+)\)/i]
distance = $~[1].to_i
next if !pbEventCanReachPlayer?(event, self, distance)
elsif event.name[/counter\((\d+)\)/i]
@@ -312,14 +422,18 @@ class Game_Player < Game_Character
super
update_screen_position(last_real_x, last_real_y)
# Update dependent events
$PokemonTemp.dependentEvents.updateDependentEvents
if (!@moved_last_frame || @stopped_last_frame ||
(@stopped_this_frame && $PokemonGlobal.sliding)) && (moving? || jumping?)
$game_temp.followers.move_followers
end
$game_temp.followers.update
# Count down the time between allowed bump sounds
@bump_se -= 1 if @bump_se && @bump_se > 0
# Finish up dismounting from surfing
if $PokemonTemp.endSurf && !moving?
if $game_temp.ending_surf && !moving?
pbCancelVehicles
$PokemonTemp.surfJump = nil
$PokemonTemp.endSurf = false
$game_temp.surf_base_coords = nil
$game_temp.ending_surf = false
end
update_event_triggering
end
@@ -327,7 +441,7 @@ class Game_Player < Game_Character
def update_command_new
dir = Input.dir4
unless pbMapInterpreterRunning? || $game_temp.message_window_showing ||
$PokemonTemp.miniupdate || $game_temp.in_menu
$game_temp.in_mini_update || $game_temp.in_menu
# Move player in the direction the directional button is being pressed
if @moved_last_frame ||
(dir > 0 && dir == @lastdir && Graphics.frame_count - @lastdirframe > Graphics.frame_rate / 20)
@@ -351,6 +465,64 @@ class Game_Player < Game_Character
@lastdir = dir
end
def update_move
if !@moved_last_frame || @stopped_last_frame # Started a new step
if pbTerrainTag.ice
set_movement_type(:ice_sliding)
else#if !@move_route_forcing
faster = can_run?
if $PokemonGlobal&.diving
set_movement_type((faster) ? :diving_fast : :diving)
elsif $PokemonGlobal&.surfing
set_movement_type((faster) ? :surfing_fast : :surfing)
elsif $PokemonGlobal&.bicycle
set_movement_type((faster) ? :cycling_fast : :cycling)
else
set_movement_type((faster) ? :running : :walking)
end
end
if jumping?
if $PokemonGlobal&.diving
set_movement_type(:diving_jumping)
elsif $PokemonGlobal&.surfing
set_movement_type(:surfing_jumping)
elsif $PokemonGlobal&.bicycle
set_movement_type(:cycling_jumping)
else
set_movement_type(:jumping) # Walking speed/charset while jumping
end
end
end
super
end
def update_stop
if @stopped_last_frame
if $PokemonGlobal&.diving
set_movement_type(:diving_stopped)
elsif $PokemonGlobal&.surfing
set_movement_type(:surfing_stopped)
elsif $PokemonGlobal&.bicycle
set_movement_type(:cycling_stopped)
else
set_movement_type(:walking_stopped)
end
end
super
end
def update_pattern
if $PokemonGlobal&.surfing || $PokemonGlobal&.diving
p = ((Graphics.frame_count % 60) * @@bobFrameSpeed).floor
@pattern = p if !@lock_pattern
@pattern_surf = p
@bob_height = (p >= 2) ? 2 : 0
else
@bob_height = 0
super
end
end
# Center player on-screen
def update_screen_position(last_real_x, last_real_y)
return if self.map.scrolling? || !(@moved_last_frame || @moved_this_frame)
@@ -362,7 +534,7 @@ class Game_Player < Game_Character
return if moving?
# Try triggering events upon walking into them/in front of them
if @moved_this_frame
$PokemonTemp.dependentEvents.pbTurnDependentEvents
$game_temp.followers.turn_followers
result = pbCheckEventTriggerFromDistance([2])
# Event determinant is via touch of same position event
result |= check_event_trigger_here([1, 2])
@@ -370,7 +542,7 @@ class Game_Player < Game_Character
pbOnStepTaken(result)
end
# Try to manually interact with events
if Input.trigger?(Input::USE) && !$PokemonTemp.miniupdate
if Input.trigger?(Input::USE) && !$game_temp.in_mini_update
# Same position and front event determinant
check_event_trigger_here([0])
check_event_trigger_there([0, 2])
@@ -380,17 +552,18 @@ end
def pbGetPlayerCharset(meta,charset,trainer=nil,force=false)
trainer = $Trainer if !trainer
#===============================================================================
#
#===============================================================================
def pbGetPlayerCharset(charset, trainer = nil, force = false)
trainer = $player if !trainer
outfit = (trainer) ? trainer.outfit : 0
if $game_player && $game_player.charsetData && !force
return nil if $game_player.charsetData[0] == $Trainer.character_ID &&
return nil if !force && $game_player&.charsetData &&
$game_player.charsetData[0] == trainer.character_ID &&
$game_player.charsetData[1] == charset &&
$game_player.charsetData[2] == outfit
end
$game_player.charsetData = [$Trainer.character_ID,charset,outfit] if $game_player
ret = meta[charset]
ret = meta[1] if nil_or_empty?(ret)
$game_player.charsetData = [trainer.character_ID, charset, outfit] if $game_player
ret = charset
if pbResolveBitmap("Graphics/Characters/" + ret + "_" + outfit.to_s)
ret = ret + "_" + outfit.to_s
end
@@ -398,21 +571,20 @@ def pbGetPlayerCharset(meta,charset,trainer=nil,force=false)
end
def pbUpdateVehicle
meta = GameData::Metadata.get_player($Trainer.character_ID)
if meta
charset = 1 # Regular graphic
if $PokemonGlobal.diving; charset = 5 # Diving graphic
elsif $PokemonGlobal.surfing; charset = 3 # Surfing graphic
elsif $PokemonGlobal.bicycle; charset = 2 # Bicycle graphic
end
newCharName = pbGetPlayerCharset(meta,charset)
$game_player.character_name = newCharName if newCharName
if $PokemonGlobal&.diving
$game_player.set_movement_type(:diving)
elsif $PokemonGlobal&.surfing
$game_player.set_movement_type(:surfing)
elsif $PokemonGlobal&.bicycle
$game_player.set_movement_type(:cycling)
else
$game_player.set_movement_type(:walking)
end
end
def pbCancelVehicles(destination=nil)
$PokemonGlobal.surfing = false
$PokemonGlobal.diving = false
def pbCancelVehicles(destination = nil, cancel_swimming = true)
$PokemonGlobal.surfing = false if cancel_swimming
$PokemonGlobal.diving = false if cancel_swimming
$PokemonGlobal.bicycle = false if !destination || !pbCanUseBike?(destination)
pbUpdateVehicle
end
@@ -420,14 +592,13 @@ end
def pbCanUseBike?(map_id)
map_metadata = GameData::MapMetadata.try_get(map_id)
return false if !map_metadata
return true if map_metadata.always_bicycle
val = map_metadata.can_bicycle || map_metadata.outdoor_map
return (val) ? true : false
return map_metadata.always_bicycle || map_metadata.can_bicycle || map_metadata.outdoor_map
end
def pbMountBike
return if $PokemonGlobal.bicycle
$PokemonGlobal.bicycle = true
$stats.cycle_count += 1
pbUpdateVehicle
bike_bgm = GameData::Metadata.get.bicycle_BGM
pbCueBGM(bike_bgm, 0.5) if bike_bgm

View File

@@ -56,7 +56,7 @@ class Game_CommonEvent
def refresh
# Create an interpreter for parallel process if necessary
if self.trigger == 2 && switchIsOn?(self.switch_id)
if @interpreter == nil
if @interpreter.nil?
@interpreter = Interpreter.new
end
else
@@ -67,15 +67,10 @@ class Game_CommonEvent
# * Frame Update
#-----------------------------------------------------------------------------
def update
# If parallel process is valid
if @interpreter != nil
# If not running
unless @interpreter.running?
# Set up event
@interpreter.setup(self.list, 0)
end
return if !@interpreter
# Set up event if interpreter is not running
@interpreter.setup(self.list, 0) if !@interpreter.running?
# Update interpreter
@interpreter.update
end
end
end

View File

@@ -1,102 +0,0 @@
class Game_Player < Game_Character
@@bobFrameSpeed = 1.0/15
def fullPattern
case self.direction
when 2 then return self.pattern
when 4 then return self.pattern + 4
when 6 then return self.pattern + 8
when 8 then return self.pattern + 12
end
return 0
end
def setDefaultCharName(chname,pattern,lockpattern=false)
return if pattern<0 || pattern>=16
@defaultCharacterName = chname
@direction = [2,4,6,8][pattern/4]
@pattern = pattern%4
@lock_pattern = lockpattern
end
def pbCanRun?
return false if $game_temp.in_menu || $game_temp.in_battle ||
@move_route_forcing || $game_temp.message_window_showing ||
pbMapInterpreterRunning?
input = ($PokemonSystem.runstyle == 1) ^ Input.press?(Input::ACTION)
return input && $Trainer.has_running_shoes && !jumping? &&
!$PokemonGlobal.diving && !$PokemonGlobal.surfing &&
!$PokemonGlobal.bicycle && !$game_player.pbTerrainTag.must_walk
end
def pbIsRunning?
return moving? && !@move_route_forcing && pbCanRun?
end
def character_name
@defaultCharacterName = "" if !@defaultCharacterName
return @defaultCharacterName if @defaultCharacterName!=""
if !@move_route_forcing && $Trainer.character_ID>=0
meta = GameData::Metadata.get_player($Trainer.character_ID)
if meta && !$PokemonGlobal.bicycle && !$PokemonGlobal.diving && !$PokemonGlobal.surfing
charset = 1 # Display normal character sprite
if pbCanRun? && (moving? || @wasmoving) && Input.dir4!=0 && meta[4] && meta[4]!=""
charset = 4 # Display running character sprite
end
newCharName = pbGetPlayerCharset(meta,charset)
@character_name = newCharName if newCharName
@wasmoving = moving?
end
end
return @character_name
end
def update_command
if $game_player.pbTerrainTag.ice
self.move_speed = 4 # Sliding on ice
elsif !moving? && !@move_route_forcing && $PokemonGlobal
if $PokemonGlobal.bicycle
self.move_speed = 5 # Cycling
elsif pbCanRun? || $PokemonGlobal.surfing
self.move_speed = 4 # Running, surfing
else
self.move_speed = 3 # Walking, diving
end
end
super
end
def update_pattern
if $PokemonGlobal.surfing || $PokemonGlobal.diving
p = ((Graphics.frame_count%60)*@@bobFrameSpeed).floor
@pattern = p if !@lock_pattern
@pattern_surf = p
@bob_height = (p>=2) ? 2 : 0
else
@bob_height = 0
super
end
end
end
=begin
class Game_Character
alias update_old2 update
def update
if self.is_a?(Game_Event)
if @dependentEvents
for i in 0...@dependentEvents.length
if @dependentEvents[i][0]==$game_map.map_id &&
@dependentEvents[i][1]==self.id
self.move_speed_real = $game_player.move_speed_real
break
end
end
end
end
update_old2
end
end
=end

View File

@@ -0,0 +1,204 @@
#===============================================================================
# Instances of this are stored in @realEvents.
#===============================================================================
class Game_Follower < Game_Event
attr_writer :map
def initialize(event_data)
# Create RPG::Event to base self on
rpg_event = RPG::Event.new(event_data.x, event_data.y)
rpg_event.id = event_data.event_id
rpg_event.name = event_data.event_name
if event_data.common_event_id
# Must setup common event list here and now
common_event = Game_CommonEvent.new(event_data.common_event_id)
rpg_event.pages[0].list = common_event.list
end
# Create self
super(event_data.original_map_id, rpg_event, $map_factory.getMap(event_data.current_map_id))
# Modify self
self.character_name = event_data.character_name
self.character_hue = event_data.character_hue
case event_data.direction
when 2 then turn_down
when 4 then turn_left
when 6 then turn_right
when 8 then turn_up
end
end
#=============================================================================
def move_through(direction)
old_through = @through
@through = true
case direction
when 2 then move_down
when 4 then move_left
when 6 then move_right
when 8 then move_up
end
@through = old_through
end
def move_fancy(direction)
delta_x = (direction == 6) ? 1 : (direction == 4) ? -1 : 0
delta_y = (direction == 2) ? 1 : (direction == 8) ? -1 : 0
new_x = self.x + delta_x
new_y = self.y + delta_y
# Move if new position is the player's, or the new position is passable,
# or self's current position is not passable
if ($game_player.x == new_x && $game_player.y == new_y) ||
location_passable?(new_x, new_y, 10 - direction) ||
!location_passable?(self.x, self.y, direction)
move_through(direction)
end
end
def jump_fancy(direction, leader)
delta_x = (direction == 6) ? 2 : (direction == 4) ? -2 : 0
delta_y = (direction == 2) ? 2 : (direction == 8) ? -2 : 0
half_delta_x = delta_x / 2
half_delta_y = delta_y / 2
if location_passable?(self.x + half_delta_x, self.y + half_delta_y, 10 - direction)
# Can walk over the middle tile normally; just take two steps
move_fancy(direction)
move_fancy(direction)
elsif location_passable?(self.x + delta_x, self.y + delta_y, 10 - direction)
# Can't walk over the middle tile, but can walk over the end tile; jump over
if location_passable?(self.x, self.y, direction)
if leader.jumping?
@jump_speed_real = leader.jump_speed_real
else
# This is doubled because self has to jump 2 tiles in the time it
# takes the leader to move one tile.
@jump_speed_real = leader.move_speed_real * 2
end
jump(delta_x, delta_y)
else
# self's current tile isn't passable; just take two steps ignoring passability
move_through(direction)
move_through(direction)
end
end
end
def fancy_moveto(new_x, new_y, leader)
if self.x - new_x == 1 && self.y == new_y
move_fancy(4)
elsif self.x - new_x == -1 && self.y == new_y
move_fancy(6)
elsif self.x == new_x && self.y - new_y == 1
move_fancy(8)
elsif self.x == new_x && self.y - new_y == -1
move_fancy(2)
elsif self.x - new_x == 2 && self.y == new_y
jump_fancy(4, leader)
elsif self.x - new_x == -2 && self.y == new_y
jump_fancy(6, leader)
elsif self.x == new_x && self.y - new_y == 2
jump_fancy(8, leader)
elsif self.x == new_x && self.y - new_y == -2
jump_fancy(2, leader)
elsif self.x != new_x || self.y != new_y
moveto(new_x, new_y)
end
end
#=============================================================================
def turn_towards_leader(leader)
pbTurnTowardEvent(self, leader)
end
def follow_leader(leader, instant = false, leaderIsTrueLeader = true)
maps_connected = $map_factory.areConnected?(leader.map.map_id, self.map.map_id)
target = nil
# Get the target tile that self wants to move to
if maps_connected
behind_direction = 10 - leader.direction
target = $map_factory.getFacingTile(behind_direction, leader)
if target && $map_factory.getTerrainTag(target[0], target[1], target[2]).ledge
# Get the tile above the ledge (where the leader jumped from)
target = $map_factory.getFacingTileFromPos(target[0], target[1], target[2], behind_direction)
end
target = [leader.map.map_id, leader.x, leader.y] if !target
else
# Map transfer to an unconnected map
target = [leader.map.map_id, leader.x, leader.y]
end
# Move self to the target
if self.map.map_id != target[0]
vector = $map_factory.getRelativePos(target[0], 0, 0, self.map.map_id, @x, @y)
@map = $map_factory.getMap(target[0])
# NOTE: Can't use moveto because vector is outside the boundaries of the
# map, and moveto doesn't allow setting invalid coordinates.
@x = vector[0]
@y = vector[1]
@real_x = @x * Game_Map::REAL_RES_X
@real_y = @y * Game_Map::REAL_RES_Y
end
if instant || !maps_connected
moveto(target[1], target[2])
else
fancy_moveto(target[1], target[2], leader)
end
end
#=============================================================================
def update_move
was_jumping = jumping?
super
if was_jumping && !jumping?
spriteset = $scene.spriteset(map_id)
spriteset&.addUserAnimation(Settings::DUST_ANIMATION_ID, self.x, self.y, true, 1)
end
end
#=============================================================================
private
def location_passable?(x, y, direction)
this_map = self.map
return false if !this_map || !this_map.valid?(x, y)
return true if @through
passed_tile_checks = false
bit = (1 << ((direction / 2) - 1)) & 0x0f
# Check all events for ones using tiles as graphics, and see if they're passable
this_map.events.each_value do |event|
next if event.tile_id < 0 || event.through || !event.at_coordinate?(x, y)
tile_data = GameData::TerrainTag.try_get(this_map.terrain_tags[event.tile_id])
next if tile_data.ignore_passability
next if tile_data.bridge && $PokemonGlobal.bridge == 0
return false if tile_data.ledge
passage = this_map.passages[event.tile_id] || 0
return false if passage & bit != 0
passed_tile_checks = true if (tile_data.bridge && $PokemonGlobal.bridge > 0) ||
(this_map.priorities[event.tile_id] || -1) == 0
break if passed_tile_checks
end
# Check if tiles at (x, y) allow passage for followe
if !passed_tile_checks
[2, 1, 0].each do |i|
tile_id = this_map.data[x, y, i] || 0
next if tile_id == 0
tile_data = GameData::TerrainTag.try_get(this_map.terrain_tags[tile_id])
next if tile_data.ignore_passability
next if tile_data.bridge && $PokemonGlobal.bridge == 0
return false if tile_data.ledge
passage = this_map.passages[tile_id] || 0
return false if passage & bit != 0
break if tile_data.bridge && $PokemonGlobal.bridge > 0
break if (this_map.priorities[tile_id] || -1) == 0
end
end
# Check all events on the map to see if any are in the way
this_map.events.each_value do |event|
next if !event.at_coordinate?(x, y)
return false if !event.through && event.character_name != ""
end
return true
end
end

View File

@@ -1,563 +0,0 @@
class PokemonTemp
attr_writer :dependentEvents
def dependentEvents
@dependentEvents = DependentEvents.new if !@dependentEvents
return @dependentEvents
end
end
def pbRemoveDependencies()
$PokemonTemp.dependentEvents.removeAllEvents()
pbDeregisterPartner() rescue nil
end
def pbAddDependency(event)
$PokemonTemp.dependentEvents.addEvent(event)
end
def pbRemoveDependency(event)
$PokemonTemp.dependentEvents.removeEvent(event)
end
def pbAddDependency2(eventID, eventName, commonEvent)
$PokemonTemp.dependentEvents.addEvent($game_map.events[eventID],eventName,commonEvent)
end
# Gets the Game_Character object associated with a dependent event.
def pbGetDependency(eventName)
return $PokemonTemp.dependentEvents.getEventByName(eventName)
end
def pbRemoveDependency2(eventName)
$PokemonTemp.dependentEvents.removeEventByName(eventName)
end
class PokemonGlobalMetadata
attr_writer :dependentEvents
def dependentEvents
@dependentEvents = [] if !@dependentEvents
return @dependentEvents
end
end
def pbTestPass(follower,x,y,_direction=nil)
return $MapFactory.isPassableStrict?(follower.map.map_id,x,y,follower)
end
# Same map only
def moveThrough(follower,direction)
oldThrough=follower.through
follower.through=true
case direction
when 2 then follower.move_down
when 4 then follower.move_left
when 6 then follower.move_right
when 8 then follower.move_up
end
follower.through=oldThrough
end
# Same map only
def moveFancy(follower,direction)
deltaX=(direction == 6 ? 1 : (direction == 4 ? -1 : 0))
deltaY=(direction == 2 ? 1 : (direction == 8 ? -1 : 0))
newX = follower.x + deltaX
newY = follower.y + deltaY
# Move if new position is the player's, or the new position is passable,
# or the current position is not passable
if ($game_player.x==newX && $game_player.y==newY) ||
pbTestPass(follower,newX,newY,0) ||
!pbTestPass(follower,follower.x,follower.y,0)
oldThrough=follower.through
follower.through=true
case direction
when 2 then follower.move_down
when 4 then follower.move_left
when 6 then follower.move_right
when 8 then follower.move_up
end
follower.through=oldThrough
end
end
# Same map only
def jumpFancy(follower,direction,leader)
deltaX=(direction == 6 ? 2 : (direction == 4 ? -2 : 0))
deltaY=(direction == 2 ? 2 : (direction == 8 ? -2 : 0))
halfDeltaX=(direction == 6 ? 1 : (direction == 4 ? -1 : 0))
halfDeltaY=(direction == 2 ? 1 : (direction == 8 ? -1 : 0))
middle=pbTestPass(follower,follower.x+halfDeltaX,follower.y+halfDeltaY,0)
ending=pbTestPass(follower,follower.x+deltaX, follower.y+deltaY, 0)
if middle
moveFancy(follower,direction)
moveFancy(follower,direction)
elsif ending
if pbTestPass(follower,follower.x,follower.y,0)
if leader.jumping?
follower.jump_speed_real = leader.jump_speed_real * Graphics.frame_rate / 40.0
else
follower.jump_speed_real = leader.move_speed_real * Graphics.frame_rate / 20.0
end
follower.jump(deltaX,deltaY)
else
moveThrough(follower,direction)
moveThrough(follower,direction)
end
end
end
def pbFancyMoveTo(follower,newX,newY,leader)
if follower.x-newX==-1 && follower.y==newY
moveFancy(follower,6)
elsif follower.x-newX==1 && follower.y==newY
moveFancy(follower,4)
elsif follower.y-newY==-1 && follower.x==newX
moveFancy(follower,2)
elsif follower.y-newY==1 && follower.x==newX
moveFancy(follower,8)
elsif follower.x-newX==-2 && follower.y==newY
jumpFancy(follower,6,leader)
elsif follower.x-newX==2 && follower.y==newY
jumpFancy(follower,4,leader)
elsif follower.y-newY==-2 && follower.x==newX
jumpFancy(follower,2,leader)
elsif follower.y-newY==2 && follower.x==newX
jumpFancy(follower,8,leader)
elsif follower.x!=newX || follower.y!=newY
follower.moveto(newX,newY)
end
end
class DependentEvents
attr_reader :lastUpdate
def createEvent(eventData)
rpgEvent = RPG::Event.new(eventData[3],eventData[4])
rpgEvent.id = eventData[1]
if eventData[9]
# Must setup common event list here and now
commonEvent = Game_CommonEvent.new(eventData[9])
rpgEvent.pages[0].list = commonEvent.list
end
newEvent = Game_Event.new(eventData[0],rpgEvent,$MapFactory.getMap(eventData[2]))
newEvent.character_name = eventData[6]
newEvent.character_hue = eventData[7]
case eventData[5] # direction
when 2 then newEvent.turn_down
when 4 then newEvent.turn_left
when 6 then newEvent.turn_right
when 8 then newEvent.turn_up
end
return newEvent
end
def initialize
# Original map, Event ID, Current map, X, Y, Direction
events=$PokemonGlobal.dependentEvents
@realEvents=[]
@lastUpdate=-1
for event in events
@realEvents.push(createEvent(event))
end
end
def pbEnsureEvent(event, newMapID)
events=$PokemonGlobal.dependentEvents
for i in 0...events.length
# Check original map ID and original event ID
if events[i][0]==event.map_id && events[i][1]==event.id
# Change current map ID
events[i][2]=newMapID
newEvent=createEvent(events[i])
# Replace event
@realEvents[i]=newEvent
@lastUpdate+=1
return i
end
end
return -1
end
def pbFollowEventAcrossMaps(leader,follower,instant=false,leaderIsTrueLeader=true)
d=leader.direction
areConnected=$MapFactory.areConnected?(leader.map.map_id,follower.map.map_id)
# Get the rear facing tile of leader
facingDirection=10-d
if !leaderIsTrueLeader && areConnected
relativePos=$MapFactory.getThisAndOtherEventRelativePos(leader,follower)
# Assumes leader and follower are both 1x1 tile in size
if (relativePos[1]==0 && relativePos[0]==2) # 2 spaces to the right of leader
facingDirection=6
elsif (relativePos[1]==0 && relativePos[0]==-2) # 2 spaces to the left of leader
facingDirection=4
elsif relativePos[1]==-2 && relativePos[0]==0 # 2 spaces above leader
facingDirection=8
elsif relativePos[1]==2 && relativePos[0]==0 # 2 spaces below leader
facingDirection=2
end
end
facings=[facingDirection] # Get facing from behind
# facings.push([0,0,4,0,8,0,2,0,6][d]) # Get right facing
# facings.push([0,0,6,0,2,0,8,0,4][d]) # Get left facing
if !leaderIsTrueLeader
facings.push(d) # Get forward facing
end
mapTile=nil
if areConnected
bestRelativePos=-1
oldthrough=follower.through
follower.through=false
for i in 0...facings.length
facing=facings[i]
tile=$MapFactory.getFacingTile(facing,leader)
# Assumes leader is 1x1 tile in size
passable=tile && $MapFactory.isPassableStrict?(tile[0],tile[1],tile[2],follower)
if i==0 && !passable && tile &&
$MapFactory.getTerrainTag(tile[0],tile[1],tile[2]).ledge
# If the tile isn't passable and the tile is a ledge,
# get tile from further behind
tile=$MapFactory.getFacingTileFromPos(tile[0],tile[1],tile[2],facing)
passable=tile && $MapFactory.isPassableStrict?(tile[0],tile[1],tile[2],follower)
end
if passable
relativePos=$MapFactory.getThisAndOtherPosRelativePos(
follower,tile[0],tile[1],tile[2])
# Assumes follower is 1x1 tile in size
distance=Math.sqrt(relativePos[0]*relativePos[0]+relativePos[1]*relativePos[1])
if bestRelativePos==-1 || bestRelativePos>distance
bestRelativePos=distance
mapTile=tile
end
if i==0 && distance<=1 # Prefer behind if tile can move up to 1 space
break
end
end
end
follower.through=oldthrough
else
tile=$MapFactory.getFacingTile(facings[0],leader)
# Assumes leader is 1x1 tile in size
passable=tile && $MapFactory.isPassableStrict?(tile[0],tile[1],tile[2],follower)
mapTile=passable ? mapTile : nil
end
if mapTile && follower.map.map_id==mapTile[0]
# Follower is on same map
newX=mapTile[1]
newY=mapTile[2]
deltaX=(d == 6 ? -1 : d == 4 ? 1 : 0)
deltaY=(d == 2 ? -1 : d == 8 ? 1 : 0)
posX = newX + deltaX
posY = newY + deltaY
follower.move_speed=leader.move_speed # sync movespeed
if (follower.x-newX==-1 && follower.y==newY) ||
(follower.x-newX==1 && follower.y==newY) ||
(follower.y-newY==-1 && follower.x==newX) ||
(follower.y-newY==1 && follower.x==newX)
if instant
follower.moveto(newX,newY)
else
pbFancyMoveTo(follower,newX,newY,leader)
end
elsif (follower.x-newX==-2 && follower.y==newY) ||
(follower.x-newX==2 && follower.y==newY) ||
(follower.y-newY==-2 && follower.x==newX) ||
(follower.y-newY==2 && follower.x==newX)
if instant
follower.moveto(newX,newY)
else
pbFancyMoveTo(follower,newX,newY,leader)
end
elsif follower.x!=posX || follower.y!=posY
if instant
follower.moveto(newX,newY)
else
pbFancyMoveTo(follower,posX,posY,leader)
pbFancyMoveTo(follower,newX,newY,leader)
end
end
else
if !mapTile
# Make current position into leader's position
mapTile=[leader.map.map_id,leader.x,leader.y]
end
if follower.map.map_id==mapTile[0]
# Follower is on same map as leader
follower.moveto(leader.x,leader.y)
else
# Follower will move to different map
events=$PokemonGlobal.dependentEvents
eventIndex=pbEnsureEvent(follower,mapTile[0])
if eventIndex>=0
newFollower=@realEvents[eventIndex]
newEventData=events[eventIndex]
newFollower.moveto(mapTile[1],mapTile[2])
newEventData[3]=mapTile[1]
newEventData[4]=mapTile[2]
end
end
end
end
def debugEcho
self.eachEvent { |e,d|
echoln d
echoln [e.map_id,e.map.map_id,e.id]
}
end
def pbMapChangeMoveDependentEvents
events=$PokemonGlobal.dependentEvents
updateDependentEvents
leader=$game_player
for i in 0...events.length
event=@realEvents[i]
pbFollowEventAcrossMaps(leader,event,true,i==0)
# Update X and Y for this event
events[i][3]=event.x
events[i][4]=event.y
events[i][5]=event.direction
# Set leader to this event
leader=event
end
end
def pbMoveDependentEvents
events=$PokemonGlobal.dependentEvents
updateDependentEvents
leader=$game_player
for i in 0...events.length
event=@realEvents[i]
pbFollowEventAcrossMaps(leader,event,false,i==0)
# Update X and Y for this event
events[i][3]=event.x
events[i][4]=event.y
events[i][5]=event.direction
# Set leader to this event
leader=event
end
end
def pbTurnDependentEvents
events=$PokemonGlobal.dependentEvents
updateDependentEvents
leader=$game_player
for i in 0...events.length
event=@realEvents[i]
pbTurnTowardEvent(event,leader)
# Update direction for this event
events[i][5]=event.direction
# Set leader to this event
leader=event
end
end
def eachEvent
events=$PokemonGlobal.dependentEvents
for i in 0...events.length
yield @realEvents[i],events[i]
end
end
def updateDependentEvents
events=$PokemonGlobal.dependentEvents
return if events.length==0
for i in 0...events.length
event=@realEvents[i]
next if !@realEvents[i]
event.transparent=$game_player.transparent
if event.jumping? || event.moving? ||
!($game_player.jumping? || $game_player.moving?)
event.update
elsif !event.starting
event.set_starting
event.update
event.clear_starting
end
events[i][3]=event.x
events[i][4]=event.y
events[i][5]=event.direction
end
# Check event triggers
if Input.trigger?(Input::USE) && !$game_temp.in_menu && !$game_temp.in_battle &&
!$game_player.move_route_forcing && !$game_temp.message_window_showing &&
!pbMapInterpreterRunning?
# Get position of tile facing the player
facingTile=$MapFactory.getFacingTile()
# Assumes player is 1x1 tile in size
self.eachEvent { |e,d|
next if !d[9]
if e.at_coordinate?($game_player.x, $game_player.y)
# On same position
if !e.jumping? && (!e.respond_to?("over_trigger") || e.over_trigger?)
if e.list.size>1
# Start event
$game_map.refresh if $game_map.need_refresh
e.lock
pbMapInterpreter.setup(e.list,e.id,e.map.map_id)
end
end
elsif facingTile && e.map.map_id==facingTile[0] &&
e.at_coordinate?(facingTile[1], facingTile[2])
# On facing tile
if !e.jumping? && (!e.respond_to?("over_trigger") || !e.over_trigger?)
if e.list.size>1
# Start event
$game_map.refresh if $game_map.need_refresh
e.lock
pbMapInterpreter.setup(e.list,e.id,e.map.map_id)
end
end
end
}
end
end
def removeEvent(event)
events=$PokemonGlobal.dependentEvents
mapid=$game_map.map_id
for i in 0...events.length
if events[i][2]==mapid && # Refer to current map
events[i][0]==event.map_id && # Event's map ID is original ID
events[i][1]==event.id
events[i]=nil
@realEvents[i]=nil
@lastUpdate+=1
end
end
events.compact!
@realEvents.compact!
end
def getEventByName(name)
events=$PokemonGlobal.dependentEvents
for i in 0...events.length
if events[i] && events[i][8]==name # Arbitrary name given to dependent event
return @realEvents[i]
end
end
return nil
end
def removeAllEvents
events=$PokemonGlobal.dependentEvents
events.clear
@realEvents.clear
@lastUpdate+=1
end
def removeEventByName(name)
events=$PokemonGlobal.dependentEvents
for i in 0...events.length
if events[i] && events[i][8]==name # Arbitrary name given to dependent event
events[i]=nil
@realEvents[i]=nil
@lastUpdate+=1
end
end
events.compact!
@realEvents.compact!
end
def addEvent(event,eventName=nil,commonEvent=nil)
return if !event
events=$PokemonGlobal.dependentEvents
for i in 0...events.length
if events[i] && events[i][0]==$game_map.map_id && events[i][1]==event.id
# Already exists
return
end
end
# Original map ID, original event ID, current map ID,
# event X, event Y, event direction,
# event's filename,
# event's hue, event's name, common event ID
eventData=[
$game_map.map_id,event.id,$game_map.map_id,
event.x,event.y,event.direction,
event.character_name.clone,
event.character_hue,eventName,commonEvent
]
newEvent=createEvent(eventData)
events.push(eventData)
@realEvents.push(newEvent)
@lastUpdate+=1
event.erase
end
end
class DependentEventSprites
def initialize(viewport,map)
@disposed=false
@sprites=[]
@map=map
@viewport=viewport
refresh
@lastUpdate=nil
end
def refresh
for sprite in @sprites
sprite.dispose
end
@sprites.clear
$PokemonTemp.dependentEvents.eachEvent { |event,data|
if data[0]==@map.map_id # Check original map
@map.events[data[1]].erase
end
if data[2]==@map.map_id # Check current map
@sprites.push(Sprite_Character.new(@viewport,event))
end
}
end
def update
if $PokemonTemp.dependentEvents.lastUpdate!=@lastUpdate
refresh
@lastUpdate=$PokemonTemp.dependentEvents.lastUpdate
end
for sprite in @sprites
sprite.update
end
end
def dispose
return if @disposed
for sprite in @sprites
sprite.dispose
end
@sprites.clear
@disposed=true
end
def disposed?
@disposed
end
end
Events.onSpritesetCreate += proc { |_sender,e|
spriteset = e[0] # Spriteset being created
viewport = e[1] # Viewport used for tilemap and characters
map = spriteset.map # Map associated with the spriteset (not necessarily the current map)
spriteset.addUserSprite(DependentEventSprites.new(viewport,map))
}
Events.onMapSceneChange += proc { |_sender,e|
mapChanged = e[1]
if mapChanged
$PokemonTemp.dependentEvents.pbMapChangeMoveDependentEvents
end
}

View File

@@ -0,0 +1,435 @@
#===============================================================================
# Data saved in $PokemonGlobal.followers.
#===============================================================================
class FollowerData
attr_accessor :original_map_id
attr_accessor :event_id
attr_accessor :event_name
attr_accessor :current_map_id
attr_accessor :x, :y
attr_accessor :direction
attr_accessor :character_name, :character_hue
attr_accessor :name
attr_accessor :common_event_id
attr_accessor :visible
attr_accessor :invisible_after_transfer
def initialize(original_map_id, event_id, event_name, current_map_id, x, y,
direction, character_name, character_hue)
@original_map_id = original_map_id
@event_id = event_id
@event_name = event_name
@current_map_id = current_map_id
@x = x
@y = y
@direction = direction
@character_name = character_name
@character_hue = character_hue
@name = nil
@common_event_id = nil
@visible = true
@invisible_after_transfer = false
end
def visible?
return @visible && !@invisible_after_transfer
end
def interact(event)
return if !event || event.list.size <= 1
return if !@common_event_id
# Start event
$game_map.refresh if $game_map.need_refresh
event.lock
pbMapInterpreter.setup(event.list, event.id, event.map.map_id)
end
end
#===============================================================================
# Permanently stores data of follower events (i.e. in save files).
#===============================================================================
class PokemonGlobalMetadata
attr_accessor :dependentEvents # Deprecated
attr_writer :followers
def followers
@followers = [] if !@followers
return @followers
end
end
#===============================================================================
# Stores Game_Follower instances just for the current play session.
#===============================================================================
class Game_Temp
attr_writer :followers
def followers
@followers = Game_FollowerFactory.new if !@followers
return @followers
end
end
#===============================================================================
#
#===============================================================================
class Game_FollowerFactory
attr_reader :last_update
def initialize
@events = []
$PokemonGlobal.followers.each do |follower|
@events.push(create_follower_object(follower))
end
@last_update = -1
end
#=============================================================================
def add_follower(event, name = nil, common_event_id = nil)
return if !event
followers = $PokemonGlobal.followers
if followers.any? { |data| data.original_map_id == $game_map.map_id && data.event_id == event.id }
return # Event is already dependent
end
eventData = FollowerData.new($game_map.map_id, event.id, event.name,
$game_map.map_id, event.x, event.y, event.direction,
event.character_name.clone, event.character_hue)
eventData.name = name
eventData.common_event_id = common_event_id
newEvent = create_follower_object(eventData)
followers.push(eventData)
@events.push(newEvent)
@last_update += 1
end
def remove_follower_by_event(event)
followers = $PokemonGlobal.followers
map_id = $game_map.map_id
followers.each_with_index do |follower, i|
next if follower.current_map_id != map_id
next if follower.original_map_id != event.map_id
next if follower.event_id != event.id
followers[i] = nil
@events[i] = nil
@last_update += 1
end
followers.compact!
@events.compact!
end
def remove_follower_by_name(name)
followers = $PokemonGlobal.followers
followers.each_with_index do |follower, i|
next if follower.name != name
followers[i] = nil
@events[i] = nil
@last_update += 1
end
followers.compact!
@events.compact!
end
def remove_all_followers
$PokemonGlobal.followers.clear
@events.clear
@last_update += 1
end
def get_follower_by_index(index = 0)
@events.each_with_index { |event, i| return event if i == index }
return nil
end
def get_follower_by_name(name)
each_follower { |event, follower| return event if follower&.name == name }
return nil
end
def each_follower
$PokemonGlobal.followers.each_with_index { |follower, i| yield @events[i], follower }
end
#=============================================================================
def turn_followers
leader = $game_player
$PokemonGlobal.followers.each_with_index do |follower, i|
event = @events[i]
event.turn_towards_leader(leader)
follower.direction = event.direction
leader = event
end
end
def move_followers
leader = $game_player
$PokemonGlobal.followers.each_with_index do |follower, i|
event = @events[i]
event.follow_leader(leader, false, (i == 0))
follower.x = event.x
follower.y = event.y
follower.current_map_id = event.map.map_id
follower.direction = event.direction
leader = event
end
end
def map_transfer_followers
$PokemonGlobal.followers.each_with_index do |follower, i|
event = @events[i]
event.map = $game_map
event.moveto($game_player.x, $game_player.y)
event.direction = $game_player.direction
event.opacity = 255
follower.x = event.x
follower.y = event.y
follower.current_map_id = event.map.map_id
follower.direction = event.direction
follower.invisible_after_transfer = true
end
end
def follow_into_door
# Setting an event's move route also makes it start along that move route,
# so we need to record all followers' current positions first before setting
# any move routes
follower_pos = []
follower_pos.push([$game_player.map.map_id, $game_player.x, $game_player.y])
$PokemonGlobal.followers.each_with_index do |follower, i|
event = @events[i]
follower_pos.push([event.map.map_id, event.x, event.y])
end
# Calculate and set move route from each follower to player
move_route = []
$PokemonGlobal.followers.each_with_index do |follower, i|
event = @events[i]
leader = follower_pos[i]
vector = $map_factory.getRelativePos(event.map.map_id, event.x, event.y,
leader[0], leader[1], leader[2])
if vector[0] != 0
move_route.prepend((vector[0] > 0) ? PBMoveRoute::Right : PBMoveRoute::Left)
elsif vector[1] != 0
move_route.prepend((vector[1] > 0) ? PBMoveRoute::Down : PBMoveRoute::Up)
end
pbMoveRoute(event, move_route + [PBMoveRoute::Opacity, 0])
end
end
# Used when coming out of a door.
def hide_followers
$PokemonGlobal.followers.each_with_index do |follower, i|
event = @events[i]
event.opacity = 0
end
end
# Used when coming out of a door. Makes all followers invisible until the
# player starts moving.
def put_followers_on_player
$PokemonGlobal.followers.each_with_index do |follower, i|
event = @events[i]
event.moveto($game_player.x, $game_player.y)
event.opacity = 255
follower.x = event.x
follower.y = event.y
follower.invisible_after_transfer = true
end
end
#=============================================================================
def update
followers = $PokemonGlobal.followers
return if followers.length == 0
# Update all followers
leader = $game_player
player_moving = $game_player.moving? || $game_player.jumping?
followers.each_with_index do |follower, i|
event = @events[i]
next if !@events[i]
if follower.invisible_after_transfer && player_moving
follower.invisible_after_transfer = false
event.turn_towards_leader($game_player)
end
event.move_speed = leader.move_speed
event.transparent = !follower.visible?
if $PokemonGlobal.sliding
event.straighten
event.walk_anime = false
else
event.walk_anime = true
end
if event.jumping? || event.moving? || !player_moving
event.update
elsif !event.starting
event.set_starting
event.update
event.clear_starting
end
follower.direction = event.direction
leader = event
end
# Check event triggers
if Input.trigger?(Input::USE) && !$game_temp.in_menu && !$game_temp.in_battle &&
!$game_player.move_route_forcing && !$game_temp.message_window_showing &&
!pbMapInterpreterRunning?
# Get position of tile facing the player
facing_tile = $map_factory.getFacingTile
# Assumes player is 1x1 tile in size
each_follower do |event, follower|
if event.at_coordinate?($game_player.x, $game_player.y) # Underneath player
next if !event.over_trigger?
elsif facing_tile && event.map.map_id == facing_tile[0] &&
event.at_coordinate?(facing_tile[1], facing_tile[2]) # On facing tile
next if event.over_trigger?
else # Somewhere else
next
end
next if event.jumping?
follower.interact(event)
end
end
end
#=============================================================================
private
def create_follower_object(event_data)
return Game_Follower.new(event_data)
end
end
#===============================================================================
#
#===============================================================================
class FollowerSprites
def initialize(viewport)
@viewport = viewport
@sprites = []
@last_update = nil
@disposed = false
end
def dispose
return if @disposed
@sprites.each { |sprite| sprite.dispose }
@sprites.clear
@disposed = true
end
def disposed?
return @disposed
end
def refresh
@sprites.each { |sprite| sprite.dispose }
@sprites.clear
$game_temp.followers.each_follower do |event, follower|
@sprites.push(Sprite_Character.new(@viewport, event))
end
end
def update
if $game_temp.followers.last_update != @last_update
refresh
@last_update = $game_temp.followers.last_update
end
@sprites.each { |sprite| sprite.update }
end
end
#===============================================================================
# Helper module for adding/removing/getting followers.
#===============================================================================
module Followers
module_function
# @param event_id [Integer] ID of the event on the current map to be added as a follower
# @param name [String] identifier name of the follower to be added
# @param common_event_id [Integer] ID of the Common Event triggered when interacting with this follower
def add(event_id, name, common_event_id)
$game_temp.followers.add_follower($game_map.events[event_id], name, common_event_id)
end
# @param event [Game_Event] map event to be added as a follower
def add_event(event)
$game_temp.followers.add_follower(event)
end
# @param name [String] identifier name of the follower to be removed
def remove(name)
$game_temp.followers.remove_follower_by_name(name)
end
# @param event [Game_Event] map event to be removed as a follower
def remove_event(event)
$game_temp.followers.remove_follower_by_event(event)
end
# Removes all followers.
def clear
$game_temp.followers.remove_all_followers
pbDeregisterPartner rescue nil
end
# @param name [String, nil] name of the follower to get, or nil for the first follower
# @return [Game_Follower, nil] follower object
def get(name = nil)
return $game_temp.followers.get_follower_by_name(name) if name
return $game_temp.followers.get_follower_by_index
end
def follow_into_door
$game_temp.followers.follow_into_door
end
def hide_followers
$game_temp.followers.hide_followers
end
def put_followers_on_player
$game_temp.followers.put_followers_on_player
end
end
#===============================================================================
# Deprecated methods
#===============================================================================
# @deprecated This method is slated to be removed in v21.
def pbAddDependency2(event_id, name, common_event_id)
Deprecation.warn_method("pbAddDependency2", "v21", "Followers.add(event_id, name, common_event_id)")
Followers.add(event_id, name, common_event_id)
end
# @deprecated This method is slated to be removed in v21.
def pbAddDependency(event)
Deprecation.warn_method("pbAddDependency", "v21", "Followers.add_event(event)")
Followers.add_event(event)
end
# @deprecated This method is slated to be removed in v21.
def pbRemoveDependency2(name)
Deprecation.warn_method("pbRemoveDependency2", "v21", "Followers.remove(name)")
Followers.remove(name)
end
# @deprecated This method is slated to be removed in v21.
def pbRemoveDependency(event)
Deprecation.warn_method("pbRemoveDependency", "v21", "Followers.remove_event(event)")
Followers.remove_event(event)
end
# @deprecated This method is slated to be removed in v21.
def pbRemoveDependencies
Deprecation.warn_method("pbRemoveDependencies", "v21", "Followers.clear")
Followers.clear
end
# @deprecated This method is slated to be removed in v21.
def pbGetDependency(name)
Deprecation.warn_method("pbGetDependency", "v21", "Followers.get(name)")
Followers.get(name)
end

View File

@@ -0,0 +1,198 @@
#===============================================================================
# Stored in $stats
#===============================================================================
class GameStats
# Travel
attr_accessor :distance_walked, :distance_cycled, :distance_surfed # surfed includes diving
attr_accessor :distance_slid_on_ice # Also counted in distance_walked
attr_accessor :cycle_count, :surf_count, :dive_count
# Field actions
attr_accessor :fly_count, :cut_count, :flash_count
attr_accessor :rock_smash_count, :rock_smash_battles
attr_accessor :headbutt_count, :headbutt_battles
attr_accessor :strength_push_count # Number of shoves, not the times Strength was used
attr_accessor :waterfall_count, :waterfalls_descended
# Items
attr_accessor :repel_count
attr_accessor :itemfinder_count
attr_accessor :fishing_count, :fishing_battles
attr_accessor :poke_radar_count, :poke_radar_longest_chain
attr_accessor :berry_plants_picked, :max_yield_berry_plants
attr_accessor :berries_planted
# NPCs
attr_accessor :poke_center_count
attr_accessor :revived_fossil_count
attr_accessor :lottery_prize_count # Times won any prize at all
# Pokémon
attr_accessor :eggs_hatched
attr_accessor :evolution_count, :evolutions_cancelled
attr_accessor :trade_count
attr_accessor :moves_taught_by_item, :moves_taught_by_tutor, :moves_taught_by_reminder
attr_accessor :day_care_deposits, :day_care_levels_gained
attr_accessor :pokerus_infections
attr_accessor :shadow_pokemon_purified
# Battles
attr_accessor :wild_battles_won, :wild_battles_lost # Lost includes fled from
attr_accessor :trainer_battles_won, :trainer_battles_lost
attr_accessor :total_exp_gained
attr_accessor :battle_money_gained, :battle_money_lost
attr_accessor :blacked_out_count
attr_accessor :mega_evolution_count
attr_accessor :failed_poke_ball_count
# Currency
attr_accessor :money_spent_at_marts
attr_accessor :money_earned_at_marts
attr_accessor :mart_items_bought, :premier_balls_earned
attr_accessor :drinks_bought, :drinks_won # From vending machines
attr_accessor :coins_won, :coins_lost # Not bought, not spent
attr_accessor :battle_points_won, :battle_points_spent # Currently unused
attr_accessor :soot_collected
# Special stats
attr_accessor :gym_leader_attempts # An array of integers
attr_accessor :times_to_get_badges # An array of times in seconds
attr_accessor :elite_four_attempts
attr_accessor :hall_of_fame_entry_count # See also Game Variable 13
attr_accessor :time_to_enter_hall_of_fame # In seconds
attr_accessor :safari_pokemon_caught, :most_captures_per_safari_game
attr_accessor :bug_contest_count, :bug_contest_wins
# Play
attr_accessor :play_time # In seconds
attr_accessor :play_sessions
attr_accessor :time_last_saved # In seconds
def initialize
# Travel
@distance_walked = 0
@distance_cycled = 0
@distance_surfed = 0
@distance_slid_on_ice = 0
@cycle_count = 0
@surf_count = 0
@dive_count = 0
# Field actions
@fly_count = 0
@cut_count = 0
@flash_count = 0
@rock_smash_count = 0
@rock_smash_battles = 0
@headbutt_count = 0
@headbutt_battles = 0
@strength_push_count = 0
@waterfall_count = 0
@waterfalls_descended = 0
# Items
@repel_count = 0
@itemfinder_count = 0
@fishing_count = 0
@fishing_battles = 0
@poke_radar_count = 0
@poke_radar_longest_chain = 0
@berry_plants_picked = 0
@max_yield_berry_plants = 0
@berries_planted = 0
# NPCs
@poke_center_count = 0 # Incremented in Poké Center nurse events
@revived_fossil_count = 0 # Incremented in fossil reviver events
@lottery_prize_count = 0 # Incremented in lottery NPC events
# Pokémon
@eggs_hatched = 0
@evolution_count = 0
@evolutions_cancelled = 0
@trade_count = 0
@moves_taught_by_item = 0
@moves_taught_by_tutor = 0
@moves_taught_by_reminder = 0
@day_care_deposits = 0
@day_care_levels_gained = 0
@pokerus_infections = 0
@shadow_pokemon_purified = 0
# Battles
@wild_battles_won = 0
@wild_battles_lost = 0
@trainer_battles_won = 0
@trainer_battles_lost = 0
@total_exp_gained = 0
@battle_money_gained = 0
@battle_money_lost = 0
@blacked_out_count = 0
@mega_evolution_count = 0
@failed_poke_ball_count = 0
# Currency
@money_spent_at_marts = 0
@money_earned_at_marts = 0
@mart_items_bought = 0
@premier_balls_earned = 0
@drinks_bought = 0 # Incremented in vending machine events
@drinks_won = 0 # Incremented in vending machine events
@coins_won = 0
@coins_lost = 0
@battle_points_won = 0
@battle_points_spent = 0
@soot_collected = 0
# Special stats
@gym_leader_attempts = [0] * 50 # Incremented in Gym Leader events (50 is arbitrary but suitably large)
@times_to_get_badges = [] # Set with set_time_to_badge(number) in Gym Leader events
@elite_four_attempts = 0 # Incremented in door event leading to the first E4 member
@hall_of_fame_entry_count = 0 # Incremented in Hall of Fame event
@time_to_enter_hall_of_fame = 0 # Set with set_time_to_hall_of_fame in Hall of Fame event
@safari_pokemon_caught = 0
@most_captures_per_safari_game = 0
@bug_contest_count = 0
@bug_contest_wins = 0
# Play
@play_time = 0
@play_sessions = 0
@time_last_saved = 0
end
def distance_moved
return @distance_walked + @distance_cycled + @distance_surfed
end
def caught_pokemon_count
return 0 if !$player
ret = 0
GameData::Species.each_species { |sp| ret += $player.pokedex.caught_count(sp) }
return ret
end
def save_count
return $game_system&.save_count || 0
end
def set_time_to_badge(number)
@times_to_get_badges[number] = @play_time
end
def set_time_to_hall_of_fame
@time_to_enter_hall_of_fame = @play_time
end
def play_time_per_session
return @play_time / @play_sessions
end
def set_time_last_saved
@time_last_saved = @play_time
end
def time_since_last_save
return @play_time - @time_last_saved
end
end
#===============================================================================
#
#===============================================================================
module Graphics
unless defined?(update_stats_play_time)
class << Graphics
alias update_stats_play_time update
end
end
def self.update
update_stats_play_time
$stats.play_time += self.delta_s if $stats && $PokemonEncounters
end
end

View File

@@ -7,11 +7,11 @@ class Sprite_Picture
end
def dispose
@sprite.dispose if @sprite
@sprite&.dispose
end
def update
@sprite.update if @sprite
@sprite&.update
# If picture file name is different from current one
if @picture_name != @picture.name
# Remember file name to instance variables
@@ -27,7 +27,7 @@ class Sprite_Picture
if @picture_name == ""
# Set sprite to invisible
if @sprite
@sprite.dispose if @sprite
@sprite&.dispose
@sprite = nil
end
return

View File

@@ -7,7 +7,7 @@ class Sprite_Timer
end
def dispose
@timer.dispose if @timer
@timer&.dispose
@timer = nil
@disposed = true
end
@@ -38,8 +38,8 @@ class Sprite_Timer
@timer.text = _ISPRINTF("<ac>{1:02d}:{2:02d}", min, sec)
end
@timer.update
else
@timer.visible=false if @timer
elsif @timer
@timer.visible = false
end
end
end

View File

@@ -8,7 +8,7 @@ class BushBitmap
end
def dispose
@bitmaps.each { |b| b.dispose if b }
@bitmaps.each { |b| b&.dispose }
end
def bitmap
@@ -28,7 +28,7 @@ class BushBitmap
ret = Bitmap.new(bitmap.width, bitmap.height)
charheight = ret.height / 4
cy = charheight - depth - 2
for i in 0...4
4.times do |i|
y = i * charheight
if cy >= 0
ret.blt(0, y, bitmap, Rect.new(0, y, ret.width, cy))
@@ -80,13 +80,13 @@ class Sprite_Character < RPG::Sprite
end
def dispose
@bushbitmap.dispose if @bushbitmap
@bushbitmap&.dispose
@bushbitmap = nil
@charbitmap.dispose if @charbitmap
@charbitmap&.dispose
@charbitmap = nil
@reflection.dispose if @reflection
@reflection&.dispose
@reflection = nil
@surfbase.dispose if @surfbase
@surfbase&.dispose
@surfbase = nil
super
end
@@ -102,12 +102,12 @@ class Sprite_Character < RPG::Sprite
@character_name = @character.character_name
@character_hue = @character.character_hue
@oldbushdepth = @character.bush_depth
@charbitmap&.dispose
if @tile_id >= 384
@charbitmap.dispose if @charbitmap
@charbitmap = pbGetTileBitmap(@character.map.tileset_name, @tile_id,
@character_hue, @character.width, @character.height)
@charbitmapAnimated = false
@bushbitmap.dispose if @bushbitmap
@bushbitmap&.dispose
@bushbitmap = nil
@spriteoffset = false
@cw = Game_Map::TILE_WIDTH * @character.width
@@ -115,21 +115,20 @@ class Sprite_Character < RPG::Sprite
self.src_rect.set(0, 0, @cw, @ch)
self.ox = @cw / 2
self.oy = @ch
@character.sprite_size = [@cw, @ch]
else
@charbitmap.dispose if @charbitmap
@charbitmap = AnimatedBitmap.new(
'Graphics/Characters/' + @character_name, @character_hue)
RPG::Cache.retain('Graphics/Characters/', @character_name, @character_hue) if @character == $game_player
"Graphics/Characters/" + @character_name, @character_hue
)
RPG::Cache.retain("Graphics/Characters/", @character_name, @character_hue) if @character == $game_player
@charbitmapAnimated = true
@bushbitmap.dispose if @bushbitmap
@bushbitmap&.dispose
@bushbitmap = nil
@spriteoffset = @character_name[/offset/i]
@cw = @charbitmap.width / 4
@ch = @charbitmap.height / 4
self.ox = @cw / 2
@character.sprite_size = [@cw, @ch]
end
@character.sprite_size = [@cw, @ch]
end
@charbitmap.update if @charbitmapAnimated
bushdepth = @character.bush_depth
@@ -157,17 +156,14 @@ class Sprite_Character < RPG::Sprite
self.x = @character.screen_x
self.y = @character.screen_y
self.z = @character.screen_z(@ch)
# self.zoom_x = Game_Map::TILE_WIDTH / 32.0
# self.zoom_y = Game_Map::TILE_HEIGHT / 32.0
self.opacity = @character.opacity
self.blend_type = @character.blend_type
# self.bush_depth = @character.bush_depth
if @character.animation_id != 0
animation = $data_animations[@character.animation_id]
animation(animation, true)
@character.animation_id = 0
end
@reflection.update if @reflection
@surfbase.update if @surfbase
@reflection&.update
@surfbase&.update
end
end

View File

@@ -8,12 +8,10 @@ class Sprite_Reflection
@event = event
@height = 0
@fixedheight = false
if @event && @event!=$game_player
if @event.name[/reflection\((\d+)\)/i]
if @event && @event != $game_player && @event.name[/reflection\((\d+)\)/i]
@height = $~[1].to_i || 0
@fixedheight = true
end
end
@viewport = viewport
@disposed = false
update
@@ -21,7 +19,7 @@ class Sprite_Reflection
def dispose
if !@disposed
@sprite.dispose if @sprite
@sprite&.dispose
@sprite = nil
@disposed = true
end
@@ -57,12 +55,13 @@ class Sprite_Reflection
y += @height * 16
width = @rsprite.src_rect.width
height = @rsprite.src_rect.height
@sprite.x = x+width/2
@sprite.y = y+height+height/2
@sprite.x = x + (width / 2)
@sprite.y = y + height + (height / 2)
@sprite.ox = width / 2
@sprite.oy = height/2-2 # Hard-coded 2 pixel shift up
@sprite.oy = (height / 2) - 2 # Hard-coded 2 pixel shift up
@sprite.oy -= @rsprite.character.bob_height * 2
@sprite.z = -50 # Still water is -100, map is 0 and above
@sprite.z += 1 if @event == $game_player
@sprite.zoom_x = @rsprite.zoom_x
@sprite.zoom_y = @rsprite.zoom_y
frame = (Graphics.frame_count % 40) / 10

View File

@@ -21,7 +21,7 @@ class Sprite_SurfBase
def dispose
return if @disposed
@sprite.dispose if @sprite
@sprite&.dispose
@sprite = nil
@surfbitmap.dispose
@divebitmap.dispose
@@ -62,9 +62,9 @@ class Sprite_SurfBase
sx = @event.pattern_surf * cw
sy = ((@event.direction - 2) / 2) * ch
@sprite.src_rect.set(sx, sy, cw, ch)
if $PokemonTemp.surfJump
@sprite.x = ($PokemonTemp.surfJump[0]*Game_Map::REAL_RES_X-@event.map.display_x+3)/4+(Game_Map::TILE_WIDTH/2)
@sprite.y = ($PokemonTemp.surfJump[1]*Game_Map::REAL_RES_Y-@event.map.display_y+3)/4+(Game_Map::TILE_HEIGHT/2)+16
if $game_temp.surf_base_coords
@sprite.x = ((($game_temp.surf_base_coords[0] * Game_Map::REAL_RES_X) - @event.map.display_x + 3) / 4) + (Game_Map::TILE_WIDTH / 2)
@sprite.y = ((($game_temp.surf_base_coords[1] * Game_Map::REAL_RES_Y) - @event.map.display_y + 3) / 4) + (Game_Map::TILE_HEIGHT / 2) + 16
else
@sprite.x = @rsprite.x
@sprite.y = @rsprite.y

View File

@@ -1,12 +1,14 @@
class Spriteset_Global
attr_reader :playersprite
@@viewport2 = Viewport.new(0, 0, Settings::SCREEN_WIDTH, Settings::SCREEN_HEIGHT)
@@viewport2.z = 200
def initialize
@follower_sprites = FollowerSprites.new(Spriteset_Map.viewport)
@playersprite = Sprite_Character.new(Spriteset_Map.viewport, $game_player)
@picture_sprites = []
for i in 1..100
(1..100).each do |i|
@picture_sprites.push(Sprite_Picture.new(@@viewport2, $game_screen.pictures[i]))
end
@timer_sprite = Sprite_Timer.new
@@ -14,15 +16,18 @@ class Spriteset_Global
end
def dispose
@follower_sprites.dispose
@follower_sprites = nil
@playersprite.dispose
@picture_sprites.each { |sprite| sprite.dispose }
@timer_sprite.dispose
@playersprite = nil
@picture_sprites.each { |sprite| sprite.dispose }
@picture_sprites.clear
@timer_sprite.dispose
@timer_sprite = nil
end
def update
@follower_sprites.update
@playersprite.update
@picture_sprites.each { |sprite| sprite.update }
@timer_sprite.update

View File

@@ -1,3 +1,4 @@
# Unused
class ClippableSprite < Sprite_Character
def initialize(viewport, event, tilemap)
@tilemap = tilemap
@@ -8,22 +9,22 @@ class ClippableSprite < Sprite_Character
def update
super
@_src_rect = self.src_rect
tmright = @tilemap.map_data.xsize*Game_Map::TILE_WIDTH-@tilemap.ox
echoln("x=#{self.x},ox=#{self.ox},tmright=#{tmright},tmox=#{@tilemap.ox}")
tmright = (@tilemap.map_data.xsize * Game_Map::TILE_WIDTH) - @tilemap.ox
echoln "x=#{self.x},ox=#{self.ox},tmright=#{tmright},tmox=#{@tilemap.ox}"
if @tilemap.ox - self.ox < -self.x
# clipped on left
diff = -self.x - @tilemap.ox + self.ox
self.src_rect = Rect.new(@_src_rect.x + diff, @_src_rect.y,
@_src_rect.width - diff, @_src_rect.height)
echoln("clipped out left: #{diff} #{@tilemap.ox-self.ox} #{self.x}")
echoln "clipped out left: #{diff} #{@tilemap.ox - self.ox} #{self.x}"
elsif tmright - self.ox < self.x
# clipped on right
diff = self.x - tmright + self.ox
self.src_rect = Rect.new(@_src_rect.x, @_src_rect.y,
@_src_rect.width - diff, @_src_rect.height)
echoln("clipped out right: #{diff} #{tmright+self.ox} #{self.x}")
echoln "clipped out right: #{diff} #{tmright + self.ox} #{self.x}"
else
echoln("-not- clipped out left: #{diff} #{@tilemap.ox-self.ox} #{self.x}")
echoln "-not- clipped out left: #{diff} #{@tilemap.ox - self.ox} #{self.x}"
end
end
end
@@ -32,7 +33,7 @@ end
class Spriteset_Map
attr_reader :map
attr_accessor :tilemap
@@viewport0 = Viewport.new(0, 0, Settings::SCREEN_WIDTH, Settings::SCREEN_HEIGHT) # Panorama
@@viewport0.z = -100
@@viewport1 = Viewport.new(0, 0, Settings::SCREEN_WIDTH, Settings::SCREEN_HEIGHT) # Map, events, player, fog
@@ -40,47 +41,38 @@ class Spriteset_Map
@@viewport3 = Viewport.new(0, 0, Settings::SCREEN_WIDTH, Settings::SCREEN_HEIGHT) # Flashing
@@viewport3.z = 500
def Spriteset_Map.viewport # For access by Spriteset_Global
def self.viewport # For access by Spriteset_Global
return @@viewport1
end
def initialize(map = nil)
@map = (map) ? map : $game_map
@tilemap = TilemapLoader.new(@@viewport1)
@tilemap.tileset = pbGetTileset(@map.tileset_name)
for i in 0...7
autotile_name = @map.autotile_names[i]
@tilemap.autotiles[i] = pbGetAutotile(autotile_name)
end
@tilemap.map_data = @map.data
@tilemap.priorities = @map.priorities
@tilemap.terrain_tags = @map.terrain_tags
$scene.map_renderer.add_tileset(@map.tileset_name)
@map.autotile_names.each { |filename| $scene.map_renderer.add_autotile(filename) }
$scene.map_renderer.add_extra_autotiles(@map.tileset_id)
@panorama = AnimatedPlane.new(@@viewport0)
@fog = AnimatedPlane.new(@@viewport1)
@fog.z = 3000
@character_sprites = []
for i in @map.events.keys.sort
@map.events.keys.sort.each do |i|
sprite = Sprite_Character.new(@@viewport1, @map.events[i])
@character_sprites.push(sprite)
end
@weather = RPG::Weather.new(@@viewport1)
pbOnSpritesetCreate(self,@@viewport1)
EventHandlers.trigger(:on_new_spriteset_map, self, @@viewport1)
update
end
def dispose
@tilemap.tileset.dispose
for i in 0...7
@tilemap.autotiles[i].dispose
if $scene.is_a?(Scene_Map)
$scene.map_renderer.remove_tileset(@map.tileset_name)
@map.autotile_names.each { |filename| $scene.map_renderer.remove_autotile(filename) }
$scene.map_renderer.remove_extra_autotiles(@map.tileset_id)
end
@tilemap.dispose
@panorama.dispose
@fog.dispose
for sprite in @character_sprites
sprite.dispose
end
@character_sprites.each { |sprite| sprite.dispose }
@weather.dispose
@tilemap = nil
@panorama = nil
@fog = nil
@character_sprites.clear
@@ -99,26 +91,23 @@ class Spriteset_Map
if @panorama_name != @map.panorama_name || @panorama_hue != @map.panorama_hue
@panorama_name = @map.panorama_name
@panorama_hue = @map.panorama_hue
@panorama.setPanorama(nil) if @panorama.bitmap!=nil
@panorama.setPanorama(@panorama_name,@panorama_hue) if @panorama_name!=""
@panorama.set_panorama(nil) if !@panorama.bitmap.nil?
@panorama.set_panorama(@panorama_name, @panorama_hue) if !nil_or_empty?(@panorama_name)
Graphics.frame_reset
end
if @fog_name != @map.fog_name || @fog_hue != @map.fog_hue
@fog_name = @map.fog_name
@fog_hue = @map.fog_hue
@fog.setFog(nil) if @fog.bitmap!=nil
@fog.setFog(@fog_name,@fog_hue) if @fog_name!=""
@fog.set_fog(nil) if !@fog.bitmap.nil?
@fog.set_fog(@fog_name, @fog_hue) if !nil_or_empty?(@fog_name)
Graphics.frame_reset
end
tmox = (@map.display_x / Game_Map::X_SUBPIXELS).round
tmoy = (@map.display_y / Game_Map::Y_SUBPIXELS).round
@tilemap.ox = tmox
@tilemap.oy = tmoy
@@viewport1.rect.set(0, 0, Graphics.width, Graphics.height)
@@viewport1.ox = 0
@@viewport1.oy = 0
@@viewport1.ox += $game_screen.shake
@tilemap.update
@panorama.ox = tmox / 2
@panorama.oy = tmoy / 2
@fog.ox = tmox + @map.fog_ox
@@ -130,13 +119,13 @@ class Spriteset_Map
@fog.tone = @map.fog_tone
@panorama.update
@fog.update
for sprite in @character_sprites
@character_sprites.each do |sprite|
sprite.update
end
if self.map!=$game_map
@weather.fade_in(:None, 0, 20)
else
if self.map == $game_map
@weather.fade_in($game_screen.weather_type, $game_screen.weather_max, $game_screen.weather_duration)
else
@weather.fade_in(:None, 0, 20)
end
@weather.ox = tmox
@weather.oy = tmoy

View File

@@ -18,9 +18,9 @@ class AnimationSprite < RPG::Sprite
end
def setCoords
self.x = ((@tileX * Game_Map::REAL_RES_X - @map.display_x) / Game_Map::X_SUBPIXELS).ceil
self.x = (((@tileX * Game_Map::REAL_RES_X) - @map.display_x) / Game_Map::X_SUBPIXELS).ceil
self.x += Game_Map::TILE_WIDTH / 2
self.y = ((@tileY * Game_Map::REAL_RES_Y - @map.display_y) / Game_Map::Y_SUBPIXELS).ceil
self.y = (((@tileY * Game_Map::REAL_RES_Y) - @map.display_y) / Game_Map::Y_SUBPIXELS).ceil
self.y += Game_Map::TILE_HEIGHT
end
@@ -41,9 +41,9 @@ end
class Spriteset_Map
alias _animationSprite_initialize initialize
alias _animationSprite_update update
alias _animationSprite_dispose dispose
alias _animationSprite_initialize initialize unless private_method_defined?(:_animationSprite_initialize)
alias _animationSprite_update update unless method_defined?(:_animationSprite_update)
alias _animationSprite_dispose dispose unless method_defined?(:_animationSprite_dispose)
def initialize(map = nil)
@usersprites = []
@@ -51,36 +51,29 @@ class Spriteset_Map
end
def addUserAnimation(animID, x, y, tinting = false, height = 3)
sprite=AnimationSprite.new(animID,$game_map,x,y,@@viewport1,tinting,height)
sprite = AnimationSprite.new(animID, self.map, x, y, @@viewport1, tinting, height)
addUserSprite(sprite)
return sprite
end
def addUserSprite(sprite)
for i in 0...@usersprites.length
if @usersprites[i]==nil || @usersprites[i].disposed?
@usersprites[i]=sprite
def addUserSprite(new_sprite)
@usersprites.each_with_index do |sprite, i|
next if sprite && !sprite.disposed?
@usersprites[i] = new_sprite
return
end
end
@usersprites.push(sprite)
@usersprites.push(new_sprite)
end
def dispose
_animationSprite_dispose
for i in 0...@usersprites.length
@usersprites[i].dispose
end
@usersprites.each { |sprite| sprite.dispose }
@usersprites.clear
end
def update
return if @tilemap.disposed?
pbDayNightTint(@tilemap)
@@viewport3.tone.set(0, 0, 0, 0)
_animationSprite_update
for i in 0...@usersprites.length
@usersprites[i].update if !@usersprites[i].disposed?
end
@usersprites.each { |sprite| sprite.update if !sprite.disposed? }
end
end

View File

@@ -19,7 +19,7 @@ class Sprite_Shadow < RPG::Sprite
end
def dispose
@chbitmap.dispose if @chbitmap
@chbitmap&.dispose
super
end
@@ -35,8 +35,8 @@ class Sprite_Shadow < RPG::Sprite
@tile_id = @character.tile_id
@character_name = @character.character_name
@character_hue = @character.character_hue
@chbitmap&.dispose
if @tile_id >= 384
@chbitmap.dispose if @chbitmap
@chbitmap = pbGetTileBitmap(@character.map.tileset_name,
@tile_id, @character.character_hue)
self.src_rect.set(0, 0, 32, 32)
@@ -45,9 +45,8 @@ class Sprite_Shadow < RPG::Sprite
self.ox = 16
self.oy = 32
else
@chbitmap.dispose if @chbitmap
@chbitmap = AnimatedBitmap.new(
'Graphics/Characters/'+@character.character_name,@character.character_hue)
@chbitmap = AnimatedBitmap.new("Graphics/Characters/" + @character.character_name,
@character.character_hue)
@cw = @chbitmap.width / 4
@ch = @chbitmap.height / 4
self.ox = @cw / 2
@@ -90,7 +89,7 @@ class Sprite_Shadow < RPG::Sprite
@deltay = ScreenPosHelper.pbScreenY(@source) - self.y
self.color = Color.new(0, 0, 0)
@distance = ((@deltax**2) + (@deltay**2))
self.opacity = @self_opacity * 13000 / ((@distance * 370 / @distancemax) + 6000)
self.opacity = @self_opacity * 13_000 / ((@distance * 370 / @distancemax) + 6000)
self.angle = 57.3 * Math.atan2(@deltax, @deltay)
@angle_trigo = self.angle + 90
@angle_trigo += 360 if @angle_trigo < 0
@@ -124,7 +123,7 @@ end
# ? CLASS Sprite_Character edit
#===================================================
class Sprite_Character < RPG::Sprite
alias :shadow_initialize :initialize
alias shadow_initialize initialize unless private_method_defined?(:shadow_initialize)
def initialize(viewport, character = nil)
@ombrelist = []
@@ -135,34 +134,30 @@ class Sprite_Character < RPG::Sprite
def setShadows(map, shadows)
if character.is_a?(Game_Event) && shadows.length > 0
params = XPML_read(map, "Shadow", @character, 4)
if params != nil
for i in 0...shadows.size
@ombrelist.push(Sprite_Shadow.new(viewport, @character, shadows[i]))
if params
shadows.each do |shadow|
@ombrelist.push(Sprite_Shadow.new(viewport, @character, shadows))
end
end
end
if character.is_a?(Game_Player) && shadows.length > 0
for i in 0...shadows.size
@ombrelist.push(Sprite_Shadow.new(viewport, $game_player, shadows[i]))
shadows.each do |shadow|
@ombrelist.push(Sprite_Shadow.new(viewport, $game_player, shadow))
end
end
update
end
def clearShadows
@ombrelist.each { |s| s.dispose if s }
@ombrelist.each { |s| s&.dispose }
@ombrelist.clear
end
alias shadow_update update
alias shadow_update update unless method_defined?(:shadow_update)
def update
shadow_update
if @ombrelist.length>0
for i in 0...@ombrelist.size
@ombrelist[i].update
end
end
@ombrelist.each { |ombre| ombre.update }
end
end
@@ -183,24 +178,24 @@ end
class Spriteset_Map
attr_accessor :shadows
alias shadow_initialize initialize
alias shadow_initialize initialize unless private_method_defined?(:shadow_initialize)
def initialize(map = nil)
@shadows = []
warn = false
map = $game_map if !map
for k in map.events.keys.sort
map.events.keys.sort.each do |k|
ev = map.events[k]
warn = true if (ev.list != nil && ev.list.length > 0 &&
ev.list[0].code == 108 &&
(ev.list[0].parameters == ["s"] || ev.list[0].parameters == ["o"]))
warn = true if ev.list && ev.list.length > 0 && ev.list[0].code == 108 &&
(ev.list[0].parameters == ["s"] || ev.list[0].parameters == ["o"])
params = XPML_read(map, "Shadow Source", ev, 4)
@shadows.push([ev] + params) if params != nil
@shadows.push([ev] + params) if params
end
if warn == true
p "Warning : At least one event on this map uses the obsolete way to add shadows"
end
shadow_initialize(map)
for sprite in @character_sprites
@character_sprites.each do |sprite|
sprite.setShadows(map, @shadows)
end
$scene.spritesetGlobal.playersprite.setShadows(map, @shadows)
@@ -230,29 +225,22 @@ end
#===================================================
def XPML_read(map, markup, event, max_param_number = 0)
parameter_list = nil
return nil if !event || event.list == nil
for i in 0...event.list.size
if event.list[i].code == 108 &&
return nil if !event || event.list.nil?
event.list.size.times do |i|
next unless event.list[i].code == 108 &&
event.list[i].parameters[0].downcase == "begin " + markup.downcase
parameter_list = [] if parameter_list == nil
for j in i+1...event.list.size
if event.list[j].code == 108
parameter_list = [] if parameter_list.nil?
((i + 1)...event.list.size).each do |j|
return parameter_list if event.list[j].code != 108
parts = event.list[j].parameters[0].split
if parts.size != 1 && parts[0].downcase != "begin"
return parameter_list if parts.size == 1 || parts[0].downcase == "begin"
if parts[1].to_i != 0 || parts[1] == "0"
parameter_list.push(parts[1].to_i)
else
parameter_list.push(parts[1])
end
else
return parameter_list
end
else
return parameter_list
end
return parameter_list if max_param_number != 0 && j == i + max_param_number
end
end
end
return parameter_list
end

View File

@@ -31,7 +31,7 @@ class Particle_Engine
def dispose
return if disposed?
for particle in @effect
@effect.each do |particle|
next if particle.nil?
particle.dispose
end
@@ -57,17 +57,17 @@ class Particle_Engine
def realloc_effect(event, particle)
type = pbEventCommentInput(event, 1, "Particle Engine Type")
if type.nil?
particle.dispose if particle
particle&.dispose
return nil
end
type = type[0].downcase
cls = @effects[type]
if cls.nil?
particle.dispose if particle
particle&.dispose
return nil
end
if !particle || !particle.is_a?(cls)
particle.dispose if particle
particle&.dispose
particle = cls.new(event, @viewport)
end
return particle
@@ -80,13 +80,12 @@ class Particle_Engine
def update
if @firsttime
@firsttime = false
for event in @map.events.values
@map.events.each_value do |event|
remove_effect(event)
add_effect(event)
end
end
for i in 0...@effect.length
particle = @effect[i]
@effect.each_with_index do |particle, i|
next if particle.nil?
if particle.event.pe_refresh
event = particle.event
@@ -94,7 +93,7 @@ class Particle_Engine
particle = realloc_effect(event, particle)
@effect[i] = particle
end
particle.update if particle
particle&.update
end
end
end
@@ -136,7 +135,7 @@ class ParticleSprite
end
def dispose
@sprite.dispose if @sprite
@sprite&.dispose
end
def bitmap=(value)
@@ -217,7 +216,7 @@ class ParticleEffect_Event < ParticleEffect
@zoffset = zOffset
@bmwidth = 32
@bmheight = 32
for i in 0...@maxparticless
@maxparticless.times do |i|
@particlex[i] = -@xoffset
@particley[i] = -@yoffset
@particles[i] = ParticleSprite.new(@viewport)
@@ -261,9 +260,9 @@ class ParticleEffect_Event < ParticleEffect
@real_y = newRealY
if @opacityvar > 0 && @viewport
opac = 255.0 / @opacityvar
minX = opac*(-@xgravity*1.0 / @slowdown).floor + @startingx
maxX = opac*(@xgravity*1.0 / @slowdown).floor + @startingx
minY = opac*(-@ygravity*1.0 / @slowdown).floor + @startingy
minX = (opac * (-@xgravity.to_f / @slowdown).floor) + @startingx
maxX = (opac * (@xgravity.to_f / @slowdown).floor) + @startingx
minY = (opac * (-@ygravity.to_f / @slowdown).floor) + @startingy
maxY = @startingy
minX -= @bmwidth
minY -= @bmheight
@@ -275,7 +274,7 @@ class ParticleEffect_Event < ParticleEffect
end
end
particleZ = selfZ + @zoffset
for i in 0...@maxparticless
@maxparticless.times do |i|
@particles[i].z = particleZ
if @particles[i].y <= @ytop
@particles[i].y = @startingy + @yoffset
@@ -309,15 +308,13 @@ class ParticleEffect_Event < ParticleEffect
@particlex[i] = 0.0
@particley[i] = 0.0
end
else
if @opacity[i] <= 0
elsif @opacity[i] <= 0
@opacity[i] = 250
@particles[i].y = @startingy + @yoffset
@particles[i].x = @startingx + @xoffset
@particlex[i] = 0.0
@particley[i] = 0.0
end
end
calcParticlePos(i)
if @randomhue == 1
@hue += 0.5
@@ -333,11 +330,11 @@ class ParticleEffect_Event < ParticleEffect
def calcParticlePos(i)
@leftright = rand(2)
if @leftright == 1
xo = -@xgravity*1.0 / @slowdown
xo = -@xgravity.to_f / @slowdown
else
xo = @xgravity*1.0 / @slowdown
xo = @xgravity.to_f / @slowdown
end
yo = -@ygravity*1.0 / @slowdown
yo = -@ygravity.to_f / @slowdown
@particlex[i] += xo
@particley[i] += yo
@particlex[i] -= @__offsetx
@@ -349,10 +346,10 @@ class ParticleEffect_Event < ParticleEffect
end
def dispose
for particle in @particles
@particles.each do |particle|
particle.dispose
end
for bitmap in @bitmaps.values
@bitmaps.each_value do |bitmap|
bitmap.dispose
end
@particles.clear
@@ -390,7 +387,7 @@ class Particle_Engine::Teleport < ParticleEffect_Event
setParameters([1, 1, 1, 10, rand(360), 1, -64,
Graphics.height, -64, Graphics.width, 0, 3, -8, -15, 20, 0])
initParticles("wideportal", 250)
for i in 0...@maxparticless
@maxparticless.times do |i|
@particles[i].ox = 16
@particles[i].oy = 16
end
@@ -449,7 +446,7 @@ class Particle_Engine::SootSmoke < ParticleEffect_Event
setParameters([0, 0, 0, 30, 0, 0.5, -64,
Graphics.height, -64, Graphics.width, 0.5, 0.10, -5, -15, 5, 80])
initParticles("smoke", 100, 0)
for i in 0...@maxparticless
@maxparticless.times do |i|
@particles[i].blend_type = rand(6) < 3 ? 1 : 2
end
end
@@ -474,7 +471,7 @@ class Particle_Engine::FixedTeleport < ParticleEffect_Event
setParameters([1, 0, 1, 10, rand(360), 1,
-Graphics.height, Graphics.height, 0, Graphics.width, 0, 3, -8, -15, 20, 0])
initParticles("wideportal", 250)
for i in 0...@maxparticless
@maxparticless.times do |i|
@particles[i].ox = 16
@particles[i].oy = 16
end
@@ -490,7 +487,7 @@ class Particle_Engine::StarTeleport < ParticleEffect_Event
setParameters([0, 0, 1, 10, 0, 1,
-Graphics.height, Graphics.height, 0, Graphics.width, 0, 3, -8, -15, 10, 0])
initParticles("star", 250)
for i in 0...@maxparticless
@maxparticless.times do |i|
@particles[i].ox = 48
@particles[i].oy = 48
end
@@ -505,7 +502,7 @@ class Particle_Engine::Smokescreen < ParticleEffect_Event
setParameters([0, 0, 0, 250, 0, 0.2, -64,
Graphics.height, -64, Graphics.width, 0.8, 0.8, -5, -15, 5, 80])
initParticles(nil, 100)
for i in 0...@maxparticless
@maxparticless.times do |i|
rnd = rand(3)
@opacity[i] = (rnd == 0) ? 1 : 100
filename = (rnd == 0) ? "explosionsmoke" : "smoke"
@@ -520,9 +517,9 @@ class Particle_Engine::Smokescreen < ParticleEffect_Event
end
multiple = 1.7
xgrav = @xgravity * multiple / @slowdown
xgrav = -xgrav if (rand(2)==1)
xgrav = -xgrav if rand(2) == 1
ygrav = @ygravity * multiple / @slowdown
ygrav = -ygrav if (rand(2)==1)
ygrav = -ygrav if rand(2) == 1
@particlex[i] += xgrav
@particley[i] += ygrav
@particlex[i] -= @__offsetx
@@ -557,7 +554,7 @@ class Particle_Engine::Splash < ParticleEffect_Event
def update
super
for i in 0...@maxparticless
@maxparticless.times do |i|
@particles[i].opacity = 50
@particles[i].update
end
@@ -569,7 +566,8 @@ end
class Game_Event < Game_Character
attr_accessor :pe_refresh
alias nf_particles_game_map_initialize initialize
alias nf_particles_game_map_initialize initialize unless private_method_defined?(:nf_particles_game_map_initialize)
def initialize(map_id, event, map = nil)
@pe_refresh = false
begin
@@ -579,7 +577,8 @@ class Game_Event < Game_Character
end
end
alias nf_particles_game_map_refresh refresh
alias nf_particles_game_map_refresh refresh unless method_defined?(:nf_particles_game_map_refresh)
def refresh
nf_particles_game_map_refresh
@pe_refresh = true

View File

@@ -1,65 +1,69 @@
class PictureOrigin
TopLeft = 0
Center = 1
TopRight = 2
BottomLeft = 3
LowerLeft = 3
BottomRight = 4
LowerRight = 4
Top = 5
Bottom = 6
Left = 7
Right = 8
TOP_LEFT = 0
CENTER = 1
TOP_RIGHT = 2
BOTTOM_LEFT = 3
LOWER_LEFT = 3
BOTTOM_RIGHT = 4
LOWER_RIGHT = 4
TOP = 5
BOTTOM = 6
LEFT = 7
RIGHT = 8
end
class Processes
XY = 0
DeltaXY = 1
DELTA_XY = 1
Z = 2
Curve = 3
Zoom = 4
Angle = 5
Tone = 6
Color = 7
Hue = 8
Opacity = 9
Visible = 10
BlendType = 11
CURVE = 3
ZOOM = 4
ANGLE = 5
TONE = 6
COLOR = 7
HUE = 8
OPACITY = 9
VISIBLE = 10
BLEND_TYPE = 11
SE = 12
Name = 13
Origin = 14
Src = 15
SrcSize = 16
CropBottom = 17
NAME = 13
ORIGIN = 14
SRC = 15
SRC_SIZE = 16
CROP_BOTTOM = 17
end
def getCubicPoint2(src, t)
x0 = src[0]; y0 = src[1]
cx0 = src[2]; cy0 = src[3]
cx1 = src[4]; cy1 = src[5]
x1 = src[6]; y1 = src[7]
x0 = src[0]
y0 = src[1]
cx0 = src[2]
cy0 = src[3]
cx1 = src[4]
cy1 = src[5]
x1 = src[6]
y1 = src[7]
x1 = cx1+(x1-cx1)*t
x0 = x0+(cx0-x0)*t
cx0 = cx0+(cx1-cx0)*t
cx1 = cx0+(x1-cx0)*t
cx0 = x0+(cx0-x0)*t
cx = cx0+(cx1-cx0)*t
x1 = cx1 + ((x1 - cx1) * t)
x0 = x0 + ((cx0 - x0) * t)
cx0 = cx0 + ((cx1 - cx0) * t)
cx1 = cx0 + ((x1 - cx0) * t)
cx0 = x0 + ((cx0 - x0) * t)
cx = cx0 + ((cx1 - cx0) * t)
# a = x1 - 3 * cx1 + 3 * cx0 - x0
# b = 3 * (cx1 - 2 * cx0 + x0)
# c = 3 * (cx0 - x0)
# d = x0
# cx = a*t*t*t + b*t*t + c*t + d
y1 = cy1+(y1-cy1)*t
y0 = y0+(cy0-y0)*t
cy0 = cy0+(cy1-cy0)*t
cy1 = cy0+(y1-cy0)*t
cy0 = y0+(cy0-y0)*t
cy = cy0+(cy1-cy0)*t
y1 = cy1 + ((y1 - cy1) * t)
y0 = y0 + ((cy0 - y0) * t)
cy0 = cy0 + ((cy1 - cy0) * t)
cy1 = cy0 + ((y1 - cy0) * t)
cy0 = y0 + ((cy0 - y0) * t)
cy = cy0 + ((cy1 - cy0) * t)
# a = y1 - 3 * cy1 + 3 * cy0 - y0
# b = 3 * (cy1 - 2 * cy0 + y0)
# c = 3 * (cy0 - y0)
@@ -110,16 +114,20 @@ class PictureEx
@visible = true
@blend_type = 0
@name = ""
@origin = PictureOrigin::TopLeft
@origin = PictureOrigin::TOP_LEFT
@src_rect = Rect.new(0, 0, -1, -1)
@cropBottom = -1
@frameUpdates = []
end
def callback(cb)
if cb.is_a?(Proc); cb.call(self)
elsif cb.is_a?(Array); cb[0].method(cb[1]).call(self)
elsif cb.is_a?(Method); cb.call(self)
case cb
when Proc
cb.call(self)
when Array
cb[0].method(cb[1]).call(self, *cb[2])
when Method
cb.call(self)
end
end
@@ -134,7 +142,7 @@ class PictureEx
def totalDuration
ret = 0
for process in @processes
@processes.each do |process|
dur = process[1] + process[2]
ret = dur if dur > ret
end
@@ -163,7 +171,9 @@ class PictureEx
# the angle another way too.
def rotate(speed)
@rotate_speed = speed * 20.0 / Graphics.frame_rate
while @rotate_speed<0; @rotate_speed += 360; end
while @rotate_speed < 0
@rotate_speed += 360
end
@rotate_speed %= 360
end
@@ -176,7 +186,7 @@ class PictureEx
end
def adjustPosition(xOffset, yOffset)
for process in @processes
@processes.each do |process|
next if process[0] != Processes::XY
process[5] += xOffset
process[6] += yOffset
@@ -203,12 +213,12 @@ class PictureEx
def moveCurve(delay, duration, x1, y1, x2, y2, x3, y3, cb = nil)
delay, duration = ensureDelayAndDuration(delay, duration)
@processes.push([Processes::Curve,delay,duration,0,cb,[@x,@y,x1,y1,x2,y2,x3,y3]])
@processes.push([Processes::CURVE, delay, duration, 0, cb, [@x, @y, x1, y1, x2, y2, x3, y3]])
end
def moveDelta(delay, duration, x, y, cb = nil)
delay, duration = ensureDelayAndDuration(delay, duration)
@processes.push([Processes::DeltaXY,delay,duration,0,cb,@x,@y,x,y])
@processes.push([Processes::DELTA_XY, delay, duration, 0, cb, @x, @y, x, y])
end
def setDelta(delay, x, y, cb = nil)
@@ -226,7 +236,7 @@ class PictureEx
def moveZoomXY(delay, duration, zoom_x, zoom_y, cb = nil)
delay, duration = ensureDelayAndDuration(delay, duration)
@processes.push([Processes::Zoom,delay,duration,0,cb,@zoom_x,@zoom_y,zoom_x,zoom_y])
@processes.push([Processes::ZOOM, delay, duration, 0, cb, @zoom_x, @zoom_y, zoom_x, zoom_y])
end
def setZoomXY(delay, zoom_x, zoom_y, cb = nil)
@@ -243,7 +253,7 @@ class PictureEx
def moveAngle(delay, duration, angle, cb = nil)
delay, duration = ensureDelayAndDuration(delay, duration)
@processes.push([Processes::Angle,delay,duration,0,cb,@angle,angle])
@processes.push([Processes::ANGLE, delay, duration, 0, cb, @angle, angle])
end
def setAngle(delay, angle, cb = nil)
@@ -253,7 +263,7 @@ class PictureEx
def moveTone(delay, duration, tone, cb = nil)
delay, duration = ensureDelayAndDuration(delay, duration)
target = (tone) ? tone.clone : Tone.new(0, 0, 0, 0)
@processes.push([Processes::Tone,delay,duration,0,cb,@tone.clone,target])
@processes.push([Processes::TONE, delay, duration, 0, cb, @tone.clone, target])
end
def setTone(delay, tone, cb = nil)
@@ -263,7 +273,7 @@ class PictureEx
def moveColor(delay, duration, color, cb = nil)
delay, duration = ensureDelayAndDuration(delay, duration)
target = (color) ? color.clone : Color.new(0, 0, 0, 0)
@processes.push([Processes::Color,delay,duration,0,cb,@color.clone,target])
@processes.push([Processes::COLOR, delay, duration, 0, cb, @color.clone, target])
end
def setColor(delay, color, cb = nil)
@@ -273,7 +283,7 @@ class PictureEx
# Hue changes don't actually work.
def moveHue(delay, duration, hue, cb = nil)
delay, duration = ensureDelayAndDuration(delay, duration)
@processes.push([Processes::Hue,delay,duration,0,cb,@hue,hue])
@processes.push([Processes::HUE, delay, duration, 0, cb, @hue, hue])
end
# Hue changes don't actually work.
@@ -283,7 +293,7 @@ class PictureEx
def moveOpacity(delay, duration, opacity, cb = nil)
delay, duration = ensureDelayAndDuration(delay, duration)
@processes.push([Processes::Opacity,delay,duration,0,cb,@opacity,opacity])
@processes.push([Processes::OPACITY, delay, duration, 0, cb, @opacity, opacity])
end
def setOpacity(delay, opacity, cb = nil)
@@ -292,13 +302,13 @@ class PictureEx
def setVisible(delay, visible, cb = nil)
delay = ensureDelay(delay)
@processes.push([Processes::Visible,delay,0,0,cb,visible])
@processes.push([Processes::VISIBLE, delay, 0, 0, cb, visible])
end
# Only values of 0 (normal), 1 (additive) and 2 (subtractive) are allowed.
def setBlendType(delay, blend, cb = nil)
delay = ensureDelayAndDuration(delay)
@processes.push([Processes::BlendType,delay,0,0,cb,blend])
@processes.push([Processes::BLEND_TYPE, delay, 0, 0, cb, blend])
end
def setSE(delay, seFile, volume = nil, pitch = nil, cb = nil)
@@ -308,35 +318,34 @@ class PictureEx
def setName(delay, name, cb = nil)
delay = ensureDelay(delay)
@processes.push([Processes::Name,delay,0,0,cb,name])
@processes.push([Processes::NAME, delay, 0, 0, cb, name])
end
def setOrigin(delay, origin, cb = nil)
delay = ensureDelay(delay)
@processes.push([Processes::Origin,delay,0,0,cb,origin])
@processes.push([Processes::ORIGIN, delay, 0, 0, cb, origin])
end
def setSrc(delay, srcX, srcY, cb = nil)
delay = ensureDelay(delay)
@processes.push([Processes::Src,delay,0,0,cb,srcX,srcY])
@processes.push([Processes::SRC, delay, 0, 0, cb, srcX, srcY])
end
def setSrcSize(delay, srcWidth, srcHeight, cb = nil)
delay = ensureDelay(delay)
@processes.push([Processes::SrcSize,delay,0,0,cb,srcWidth,srcHeight])
@processes.push([Processes::SRC_SIZE, delay, 0, 0, cb, srcWidth, srcHeight])
end
# Used to cut Pokémon sprites off when they faint and sink into the ground.
def setCropBottom(delay, y, cb = nil)
delay = ensureDelay(delay)
@processes.push([Processes::CropBottom,delay,0,0,cb,y])
@processes.push([Processes::CROP_BOTTOM, delay, 0, 0, cb, y])
end
def update
procEnded = false
@frameUpdates.clear
for i in 0...@processes.length
process = @processes[i]
@processes.each_with_index do |process, i|
# Decrease delay of processes that are scheduled to start later
if process[1] >= 0
# Set initial values if the process will start this frame
@@ -345,28 +354,28 @@ class PictureEx
when Processes::XY
process[5] = @x
process[6] = @y
when Processes::DeltaXY
when Processes::DELTA_XY
process[5] = @x
process[6] = @y
process[7] += @x
process[8] += @y
when Processes::Curve
when Processes::CURVE
process[5][0] = @x
process[5][1] = @y
when Processes::Z
process[5] = @z
when Processes::Zoom
when Processes::ZOOM
process[5] = @zoom_x
process[6] = @zoom_y
when Processes::Angle
when Processes::ANGLE
process[5] = @angle
when Processes::Tone
when Processes::TONE
process[5] = @tone.clone
when Processes::Color
when Processes::COLOR
process[5] = @color.clone
when Processes::Hue
when Processes::HUE
process[5] = @hue
when Processes::Opacity
when Processes::OPACITY
process[5] = @opacity
end
end
@@ -380,67 +389,68 @@ class PictureEx
fra = (process[2] == 0) ? 1 : process[3] # Frame counter
dur = (process[2] == 0) ? 1 : process[2] # Total duration of process
case process[0]
when Processes::XY, Processes::DeltaXY
@x = process[5] + fra * (process[7] - process[5]) / dur
@y = process[6] + fra * (process[8] - process[6]) / dur
when Processes::Curve
when Processes::XY, Processes::DELTA_XY
@x = process[5] + (fra * (process[7] - process[5]) / dur)
@y = process[6] + (fra * (process[8] - process[6]) / dur)
when Processes::CURVE
@x, @y = getCubicPoint2(process[5], fra.to_f / dur)
when Processes::Z
@z = process[5] + fra * (process[6] - process[5]) / dur
when Processes::Zoom
@zoom_x = process[5] + fra * (process[7] - process[5]) / dur
@zoom_y = process[6] + fra * (process[8] - process[6]) / dur
when Processes::Angle
@angle = process[5] + fra * (process[6] - process[5]) / dur
when Processes::Tone
@tone.red = process[5].red + fra * (process[6].red - process[5].red) / dur
@tone.green = process[5].green + fra * (process[6].green - process[5].green) / dur
@tone.blue = process[5].blue + fra * (process[6].blue - process[5].blue) / dur
@tone.gray = process[5].gray + fra * (process[6].gray - process[5].gray) / dur
when Processes::Color
@color.red = process[5].red + fra * (process[6].red - process[5].red) / dur
@color.green = process[5].green + fra * (process[6].green - process[5].green) / dur
@color.blue = process[5].blue + fra * (process[6].blue - process[5].blue) / dur
@color.alpha = process[5].alpha + fra * (process[6].alpha - process[5].alpha) / dur
when Processes::Hue
@z = process[5] + (fra * (process[6] - process[5]) / dur)
when Processes::ZOOM
@zoom_x = process[5] + (fra * (process[7] - process[5]) / dur)
@zoom_y = process[6] + (fra * (process[8] - process[6]) / dur)
when Processes::ANGLE
@angle = process[5] + (fra * (process[6] - process[5]) / dur)
when Processes::TONE
@tone.red = process[5].red + (fra * (process[6].red - process[5].red) / dur)
@tone.green = process[5].green + (fra * (process[6].green - process[5].green) / dur)
@tone.blue = process[5].blue + (fra * (process[6].blue - process[5].blue) / dur)
@tone.gray = process[5].gray + (fra * (process[6].gray - process[5].gray) / dur)
when Processes::COLOR
@color.red = process[5].red + (fra * (process[6].red - process[5].red) / dur)
@color.green = process[5].green + (fra * (process[6].green - process[5].green) / dur)
@color.blue = process[5].blue + (fra * (process[6].blue - process[5].blue) / dur)
@color.alpha = process[5].alpha + (fra * (process[6].alpha - process[5].alpha) / dur)
when Processes::HUE
@hue = (process[6] - process[5]).to_f / dur
when Processes::Opacity
@opacity = process[5] + fra * (process[6] - process[5]) / dur
when Processes::Visible
when Processes::OPACITY
@opacity = process[5] + (fra * (process[6] - process[5]) / dur)
when Processes::VISIBLE
@visible = process[5]
when Processes::BlendType
when Processes::BLEND_TYPE
@blend_type = process[5]
when Processes::SE
pbSEPlay(process[5], process[6], process[7])
when Processes::Name
when Processes::NAME
@name = process[5]
when Processes::Origin
when Processes::ORIGIN
@origin = process[5]
when Processes::Src
when Processes::SRC
@src_rect.x = process[5]
@src_rect.y = process[6]
when Processes::SrcSize
when Processes::SRC_SIZE
@src_rect.width = process[5]
@src_rect.height = process[6]
when Processes::CropBottom
when Processes::CROP_BOTTOM
@cropBottom = process[5]
end
# Increase frame counter
process[3] += 1
if process[3]>process[2]
next if process[3] <= process[2]
# Process has ended, erase it
callback(process[4]) if process[4]
@processes[i] = nil
procEnded = true
end
end
# Clear out empty spaces in @processes array caused by finished processes
@processes.compact! if procEnded
# Add the constant rotation speed
if @rotate_speed != 0
@frameUpdates.push(Processes::Angle) if !@frameUpdates.include?(Processes::Angle)
@frameUpdates.push(Processes::ANGLE) if !@frameUpdates.include?(Processes::ANGLE)
@angle += @rotate_speed
while @angle<0; @angle += 360; end
while @angle < 0
@angle += 360
end
@angle %= 360
end
end
@@ -453,54 +463,54 @@ end
#===============================================================================
def setPictureSprite(sprite, picture, iconSprite = false)
return if picture.frameUpdates.length == 0
for i in 0...picture.frameUpdates.length
case picture.frameUpdates[i]
when Processes::XY, Processes::DeltaXY
picture.frameUpdates.each do |type|
case type
when Processes::XY, Processes::DELTA_XY
sprite.x = picture.x.round
sprite.y = picture.y.round
when Processes::Z
sprite.z = picture.z
when Processes::Zoom
when Processes::ZOOM
sprite.zoom_x = picture.zoom_x / 100.0
sprite.zoom_y = picture.zoom_y / 100.0
when Processes::Angle
when Processes::ANGLE
sprite.angle = picture.angle
when Processes::Tone
when Processes::TONE
sprite.tone = picture.tone
when Processes::Color
when Processes::COLOR
sprite.color = picture.color
when Processes::Hue
when Processes::HUE
# This doesn't do anything.
when Processes::BlendType
when Processes::BLEND_TYPE
sprite.blend_type = picture.blend_type
when Processes::Opacity
when Processes::OPACITY
sprite.opacity = picture.opacity
when Processes::Visible
when Processes::VISIBLE
sprite.visible = picture.visible
when Processes::Name
when Processes::NAME
sprite.name = picture.name if iconSprite && sprite.name != picture.name
when Processes::Origin
when Processes::ORIGIN
case picture.origin
when PictureOrigin::TopLeft, PictureOrigin::Left, PictureOrigin::BottomLeft
when PictureOrigin::TOP_LEFT, PictureOrigin::LEFT, PictureOrigin::BOTTOM_LEFT
sprite.ox = 0
when PictureOrigin::Top, PictureOrigin::Center, PictureOrigin::Bottom
when PictureOrigin::TOP, PictureOrigin::CENTER, PictureOrigin::BOTTOM
sprite.ox = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.width / 2 : 0
when PictureOrigin::TopRight, PictureOrigin::Right, PictureOrigin::BottomRight
when PictureOrigin::TOP_RIGHT, PictureOrigin::RIGHT, PictureOrigin::BOTTOM_RIGHT
sprite.ox = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.width : 0
end
case picture.origin
when PictureOrigin::TopLeft, PictureOrigin::Top, PictureOrigin::TopRight
when PictureOrigin::TOP_LEFT, PictureOrigin::TOP, PictureOrigin::TOP_RIGHT
sprite.oy = 0
when PictureOrigin::Left, PictureOrigin::Center, PictureOrigin::Right
when PictureOrigin::LEFT, PictureOrigin::CENTER, PictureOrigin::RIGHT
sprite.oy = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.height / 2 : 0
when PictureOrigin::BottomLeft, PictureOrigin::Bottom, PictureOrigin::BottomRight
when PictureOrigin::BOTTOM_LEFT, PictureOrigin::BOTTOM, PictureOrigin::BOTTOM_RIGHT
sprite.oy = (sprite.bitmap && !sprite.bitmap.disposed?) ? sprite.src_rect.height : 0
end
when Processes::Src
when Processes::SRC
next unless iconSprite && sprite.src_rect
sprite.src_rect.x = picture.src_rect.x
sprite.src_rect.y = picture.src_rect.y
when Processes::SrcSize
when Processes::SRC_SIZE
next unless iconSprite && sprite.src_rect
sprite.src_rect.width = picture.src_rect.width
sprite.src_rect.height = picture.src_rect.height

View File

@@ -25,7 +25,7 @@ class Interpolator
@frames = frames
@step = 0
@sprite = sprite
for item in items
items.each do |item|
case item[0]
when ZOOM_X
@tweensteps[item[0]] = [sprite.zoom_x, item[1] - sprite.zoom_x]
@@ -38,12 +38,11 @@ class Interpolator
when OPACITY
@tweensteps[item[0]] = [sprite.opacity, item[1] - sprite.opacity]
when COLOR
@tweensteps[item[0]] = [sprite.color.clone,Color.new(
item[1].red-sprite.color.red,
@tweensteps[item[0]] = [sprite.color.clone,
Color.new(item[1].red - sprite.color.red,
item[1].green - sprite.color.green,
item[1].blue - sprite.color.blue,
item[1].alpha-sprite.color.alpha
)]
item[1].alpha - sprite.color.alpha)]
end
end
@tweening = true
@@ -52,28 +51,26 @@ class Interpolator
def update
if @tweening
t = (@step*1.0)/@frames
for i in 0...@tweensteps.length
t = @step.to_f / @frames
@tweensteps.length.times do |i|
item = @tweensteps[i]
next if !item
case i
when ZOOM_X
@sprite.zoom_x = item[0]+item[1]*t
@sprite.zoom_x = item[0] + (item[1] * t)
when ZOOM_Y
@sprite.zoom_y = item[0]+item[1]*t
@sprite.zoom_y = item[0] + (item[1] * t)
when X
@sprite.x = item[0]+item[1]*t
@sprite.x = item[0] + (item[1] * t)
when Y
@sprite.y = item[0]+item[1]*t
@sprite.y = item[0] + (item[1] * t)
when OPACITY
@sprite.opacity = item[0]+item[1]*t
@sprite.opacity = item[0] + (item[1] * t)
when COLOR
@sprite.color = Color.new(
item[0].red+item[1].red*t,
item[0].green+item[1].green*t,
item[0].blue+item[1].blue*t,
item[0].alpha+item[1].alpha*t
)
@sprite.color = Color.new(item[0].red + (item[1].red * t),
item[0].green + (item[1].green * t),
item[0].blue + (item[1].blue * t),
item[0].alpha + (item[1].alpha * t))
end
end
@step += 1
@@ -111,19 +108,19 @@ class RectInterpolator
def update
return if done?
t = (@curframe*1.0/@frames)
t = @curframe.to_f / @frames
x1 = @oldrect.x
x2 = @newrect.x
x = x1+t*(x2-x1)
x = x1 + (t * (x2 - x1))
y1 = @oldrect.y
y2 = @newrect.y
y = y1+t*(y2-y1)
y = y1 + (t * (y2 - y1))
rx1 = @oldrect.x + @oldrect.width
rx2 = @newrect.x + @newrect.width
rx = rx1+t*(rx2-rx1)
rx = rx1 + (t * (rx2 - rx1))
ry1 = @oldrect.y + @oldrect.height
ry2 = @newrect.y + @newrect.height
ry = ry1+t*(ry2-ry1)
ry = ry1 + (t * (ry2 - ry1))
minx = x < rx ? x : rx
maxx = x > rx ? x : rx
miny = y < ry ? y : ry
@@ -160,13 +157,13 @@ class PointInterpolator
def update
return if done?
t = (@curframe*1.0/@frames)
t = @curframe.to_f / @frames
rx1 = @oldx
rx2 = @newx
@x = rx1+t*(rx2-rx1)
@x = rx1 + (t * (rx2 - rx1))
ry1 = @oldy
ry2 = @newy
@y = ry1+t*(ry2-ry1)
@y = ry1 + (t * (ry2 - ry1))
@curframe += 1
end
end

View File

@@ -29,7 +29,7 @@ module ScreenPosHelper
end
def self.pbScreenZ(ch, height = nil)
if height==nil
if height.nil?
height = 0
if ch.tile_id > 0
height = 32

View File

@@ -1,59 +0,0 @@
class TilemapLoader
def initialize(viewport)
@viewport = viewport
@tilemap = nil
@color = Color.new(0,0,0,0)
@tone = Tone.new(0,0,0,0)
updateClass
end
def updateClass
setClass(CustomTilemap)
end
def setClass(cls)
newtilemap = cls.new(@viewport)
if @tilemap
newtilemap.tileset = @tilemap.tileset
newtilemap.map_data = @tilemap.map_data
newtilemap.flash_data = @tilemap.flash_data
newtilemap.priorities = @tilemap.priorities
newtilemap.terrain_tags = @tilemap.terrain_tags
newtilemap.visible = @tilemap.visible
newtilemap.ox = @tilemap.ox
newtilemap.oy = @tilemap.oy
for i in 0...7
newtilemap.autotiles[i] = @tilemap.autotiles[i]
end
@tilemap.dispose
@tilemap = newtilemap
newtilemap.update
else
@tilemap = newtilemap
end
end
def dispose; @tilemap.dispose; end
def disposed?; @tilemap && @tilemap.disposed?; end
def update; @tilemap.update; end
def viewport; @tilemap.viewport; end
def autotiles; @tilemap.autotiles; end
def tileset; @tilemap.tileset; end
def tileset=(v); @tilemap.tileset = v; end
def map_data; @tilemap.map_data; end
def map_data=(v); @tilemap.map_data = v; end
def flash_data; @tilemap.flash_data; end
def flash_data=(v); @tilemap.flash_data = v; end
def priorities; @tilemap.priorities; end
def priorities=(v); @tilemap.priorities = v; end
def terrain_tags; (@tilemap.terrain_tags rescue nil); end
def terrain_tags=(v); (@tilemap.terrain_tags = v rescue nil); end
def visible; @tilemap.visible; end
def visible=(v); @tilemap.visible = v; end
def tone; (@tilemap.tone rescue @tone); end
def tone=(value); (@tilemap.tone = value rescue nil); end
def ox; @tilemap.ox; end
def ox=(v); @tilemap.ox = v; end
def oy; @tilemap.oy; end
def oy=(v); @tilemap.oy = v; end
end

View File

@@ -0,0 +1,609 @@
#===============================================================================
#
#===============================================================================
class TilemapRenderer
attr_reader :tilesets
attr_reader :autotiles
attr_accessor :tone
attr_accessor :color
attr_reader :viewport
attr_accessor :ox # Does nothing
attr_accessor :oy # Does nothing
attr_accessor :visible # Does nothing
DISPLAY_TILE_WIDTH = Game_Map::TILE_WIDTH rescue 32
DISPLAY_TILE_HEIGHT = Game_Map::TILE_HEIGHT rescue 32
SOURCE_TILE_WIDTH = 32
SOURCE_TILE_HEIGHT = 32
TILESET_TILES_PER_ROW = 8
AUTOTILES_COUNT = 8 # Counting the blank tile as an autotile
TILES_PER_AUTOTILE = 48
TILESET_START_ID = AUTOTILES_COUNT * TILES_PER_AUTOTILE
# If an autotile's filename ends with "[x]", its frame duration will be x/20
# seconds instead.
AUTOTILE_FRAME_DURATION = 5 # In 1/20ths of a second
# Filenames of extra autotiles for each tileset. Each tileset's entry is an
# array containing two other arrays (you can leave either of those empty, but
# they must be defined):
# - The first sub-array is for large autotiles, i.e. ones with 48 different
# tile layouts. For example, "Brick path" and "Sea".
# - The second is for single tile autotiles. For example, "Flowers1" and
# "Waterfall"
# Ihe top tiles of the tileset will instead use these autotiles. Large
# autotiles come first, in the same 8x6 layout as you see when you double-
# click on a real autotile in RMXP. After that are the single tile autotiles.
# Extra autotiles are only useful if the tiles are animated, because otherwise
# you just have some tiles which belong in the tileset instead.
EXTRA_AUTOTILES = {
# Examples:
# 1 => [["Sand shore"], ["Flowers2"]],
# 2 => [[], ["Flowers2", "Waterfall", "Waterfall crest", "Waterfall bottom"]],
# 6 => [["Water rock", "Sea deep"], []]
}
#=============================================================================
#
#=============================================================================
class TilesetBitmaps
attr_accessor :changed
attr_accessor :bitmaps
def initialize
@bitmaps = {}
@bitmap_wraps = {} # Whether each tileset is a mega texture and has multiple columns
@load_counts = {}
@bridge = 0
@changed = true
end
def [](filename)
return @bitmaps[filename]
end
def []=(filename, bitmap)
return if nil_or_empty?(filename)
@bitmaps[filename] = bitmap
@bitmap_wraps[filename] = false
@changed = true
end
def add(filename)
return if nil_or_empty?(filename)
if @bitmaps[filename]
@load_counts[filename] += 1
return
end
bitmap = pbGetTileset(filename)
@bitmap_wraps[filename] = false
if bitmap.mega?
self[filename] = TilemapRenderer::TilesetWrapper.wrapTileset(bitmap)
@bitmap_wraps[filename] = true
bitmap.dispose
else
self[filename] = bitmap
end
@load_counts[filename] = 1
end
def remove(filename)
return if nil_or_empty?(filename) || !@bitmaps[filename]
if @load_counts[filename] > 1
@load_counts[filename] -= 1
return
end
@bitmaps[filename].dispose
@bitmaps.delete(filename)
@bitmap_wraps.delete(filename)
@load_counts.delete(filename)
end
def set_src_rect(tile, tile_id)
return if nil_or_empty?(tile.filename)
return if !@bitmaps[tile.filename]
tile.src_rect.x = ((tile_id - TILESET_START_ID) % TILESET_TILES_PER_ROW) * SOURCE_TILE_WIDTH
tile.src_rect.y = ((tile_id - TILESET_START_ID) / TILESET_TILES_PER_ROW) * SOURCE_TILE_HEIGHT
if @bitmap_wraps[tile.filename]
height = @bitmaps[tile.filename].height
col = (tile_id - TILESET_START_ID) * SOURCE_TILE_HEIGHT / (TILESET_TILES_PER_ROW * height)
tile.src_rect.x += col * TILESET_TILES_PER_ROW * SOURCE_TILE_WIDTH
tile.src_rect.y -= col * height
end
end
def update; end
end
#=============================================================================
#
#=============================================================================
class AutotileBitmaps < TilesetBitmaps
attr_reader :current_frames
def initialize
super
@frame_counts = {} # Number of frames in each autotile
@frame_durations = {} # How long each frame lasts per autotile
@current_frames = {} # Which frame each autotile is currently showing
@timer = 0.0
end
def []=(filename, value)
super
return if nil_or_empty?(filename)
frame_count(filename, true)
set_current_frame(filename)
end
def add(filename)
return if nil_or_empty?(filename)
if @bitmaps[filename]
@load_counts[filename] += 1
return
end
orig_bitmap = pbGetAutotile(filename)
@bitmap_wraps[filename] = false
duration = AUTOTILE_FRAME_DURATION
if filename[/\[\s*(\d+?)\s*\]\s*$/]
duration = $~[1].to_i
end
@frame_durations[filename] = duration.to_f / 20
bitmap = AutotileExpander.expand(orig_bitmap)
self[filename] = bitmap
if bitmap.height > SOURCE_TILE_HEIGHT && bitmap.height < TILES_PER_AUTOTILE * SOURCE_TILE_HEIGHT
@bitmap_wraps[filename] = true
end
orig_bitmap.dispose if orig_bitmap != bitmap
@load_counts[filename] = 1
end
def remove(filename)
super
return if @load_counts[filename] && @load_counts[filename] > 0
@frame_counts.delete(filename)
@current_frames.delete(filename)
@frame_durations.delete(filename)
end
def frame_count(filename, force_recalc = false)
if !@frame_counts[filename] || force_recalc
return 0 if !@bitmaps[filename]
bitmap = @bitmaps[filename]
@frame_counts[filename] = [bitmap.width / SOURCE_TILE_WIDTH, 1].max
if bitmap.height > SOURCE_TILE_HEIGHT && @bitmap_wraps[filename]
@frame_counts[filename] /= 2
end
end
return @frame_counts[filename]
end
def animated?(filename)
return frame_count(filename) > 1
end
def current_frame(filename)
if !@current_frames[filename]
set_current_frame(filename)
end
return @current_frames[filename]
end
def set_current_frame(filename)
frames = frame_count(filename)
if frames < 2
@current_frames[filename] = 0
else
@current_frames[filename] = (@timer / @frame_durations[filename]).floor % frames
end
end
def set_src_rect(tile, tile_id)
return if nil_or_empty?(tile.filename)
return if !@bitmaps[tile.filename]
frame = current_frame(tile.filename)
if @bitmaps[tile.filename].height == SOURCE_TILE_HEIGHT
tile.src_rect.x = frame * SOURCE_TILE_WIDTH
tile.src_rect.y = 0
return
end
wraps = @bitmap_wraps[tile.filename]
high_id = ((tile_id % TILES_PER_AUTOTILE) >= TILES_PER_AUTOTILE / 2)
tile.src_rect.x = 0
tile.src_rect.y = (tile_id % TILES_PER_AUTOTILE) * SOURCE_TILE_HEIGHT
if wraps && high_id
tile.src_rect.x = SOURCE_TILE_WIDTH
tile.src_rect.y -= SOURCE_TILE_HEIGHT * TILES_PER_AUTOTILE / 2
end
tile.src_rect.x += frame * SOURCE_TILE_WIDTH * (wraps ? 2 : 1)
end
def update
super
@timer += Graphics.delta_s
# Update the current frame for each autotile
@bitmaps.each_key do |filename|
next if !@bitmaps[filename] || @bitmaps[filename].disposed?
old_frame = @current_frames[filename]
set_current_frame(filename)
@changed = true if @current_frames[filename] != old_frame
end
end
end
#=============================================================================
#
#=============================================================================
class TileSprite < Sprite
attr_accessor :filename
attr_accessor :tile_id
attr_accessor :is_autotile
attr_accessor :animated
attr_accessor :priority
attr_accessor :shows_reflection
attr_accessor :bridge
attr_accessor :need_refresh
def set_bitmap(filename, tile_id, autotile, animated, priority, bitmap)
self.bitmap = bitmap
self.src_rect = Rect.new(0, 0, DISPLAY_TILE_WIDTH, DISPLAY_TILE_HEIGHT)
@filename = filename
@tile_id = tile_id
@is_autotile = autotile
@animated = animated
@priority = priority
@shows_reflection = false
@bridge = false
self.visible = !bitmap.nil?
@need_refresh = true
end
end
#=============================================================================
#
#=============================================================================
def initialize(viewport)
@tilesets = TilesetBitmaps.new
@autotiles = AutotileBitmaps.new
@tiles_horizontal_count = (Graphics.width.to_f / DISPLAY_TILE_WIDTH).ceil + 1
@tiles_vertical_count = (Graphics.height.to_f / DISPLAY_TILE_HEIGHT).ceil + 1
@tone = Tone.new(0, 0, 0, 0)
@old_tone = Tone.new(0, 0, 0, 0)
@color = Color.new(0, 0, 0, 0)
@old_color = Color.new(0, 0, 0, 0)
@self_viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
@viewport = (viewport) ? viewport : @self_viewport
@old_viewport_ox = 0
@old_viewport_oy = 0
# NOTE: The extra tiles horizontally/vertically hang off the left and top
# edges of the screen, because the pixel_offset values are positive
# and are added to the tile sprite coordinates.
@tiles = []
@tiles_horizontal_count.times do |i|
@tiles[i] = []
@tiles_vertical_count.times do |j|
@tiles[i][j] = Array.new(3) { TileSprite.new(@viewport) }
end
end
@current_map_id = 0
@tile_offset_x = 0
@tile_offset_y = 0
@pixel_offset_x = 0
@pixel_offset_y = 0
@ox = 0
@oy = 0
@visible = true
@disposed = false
end
def dispose
return if disposed?
@tiles.each do |col|
col.each do |coord|
coord.each { |tile| tile.dispose }
end
end
@tilesets.bitmaps.each_value { |bitmap| bitmap.dispose }
@autotiles.bitmaps.each_value { |bitmap| bitmap.dispose }
@self_viewport.dispose
@self_viewport = nil
@disposed = true
end
def disposed?
return @disposed
end
#=============================================================================
def add_tileset(filename)
@tilesets.add(filename)
end
def remove_tileset(filename)
@tilesets.remove(filename)
end
def add_autotile(filename)
@autotiles.add(filename)
end
def remove_autotile(filename)
@autotiles.remove(filename)
end
def add_extra_autotiles(tileset_id)
return if !EXTRA_AUTOTILES[tileset_id]
EXTRA_AUTOTILES[tileset_id].each do |arr|
arr.each { |filename| add_autotile(filename) }
end
end
def remove_extra_autotiles(tileset_id)
return if !EXTRA_AUTOTILES[tileset_id]
EXTRA_AUTOTILES[tileset_id].each do |arr|
arr.each { |filename| remove_autotile(filename) }
end
end
#=============================================================================
def refresh; end
def refresh_tile_bitmap(tile, map, tile_id)
tile.tile_id = tile_id
if tile_id < TILES_PER_AUTOTILE
tile.set_bitmap("", tile_id, false, false, 0, nil)
tile.shows_reflection = false
tile.bridge = false
else
terrain_tag = map.terrain_tags[tile_id] || 0
terrain_tag_data = GameData::TerrainTag.try_get(terrain_tag)
priority = map.priorities[tile_id] || 0
single_autotile_start_id = TILESET_START_ID
true_tileset_start_id = TILESET_START_ID
extra_autotile_arrays = EXTRA_AUTOTILES[map.tileset_id]
if extra_autotile_arrays
large_autotile_count = extra_autotile_arrays[0].length
single_autotile_count = extra_autotile_arrays[1].length
single_autotile_start_id += large_autotile_count * TILES_PER_AUTOTILE
true_tileset_start_id += large_autotile_count * TILES_PER_AUTOTILE
true_tileset_start_id += single_autotile_count
end
if tile_id < true_tileset_start_id
filename = ""
if tile_id < TILESET_START_ID # Real autotiles
filename = map.autotile_names[(tile_id / TILES_PER_AUTOTILE) - 1]
elsif tile_id < single_autotile_start_id # Large extra autotiles
filename = extra_autotile_arrays[0][(tile_id - TILESET_START_ID) / TILES_PER_AUTOTILE]
else # Single extra autotiles
filename = extra_autotile_arrays[1][tile_id - single_autotile_start_id]
end
tile.set_bitmap(filename, tile_id, true, @autotiles.animated?(filename),
priority, @autotiles[filename])
else
filename = map.tileset_name
tile.set_bitmap(filename, tile_id, false, false, priority, @tilesets[filename])
end
tile.shows_reflection = terrain_tag_data&.shows_reflections
tile.bridge = terrain_tag_data&.bridge
end
refresh_tile_src_rect(tile, tile_id)
end
def refresh_tile_src_rect(tile, tile_id)
if tile.is_autotile
@autotiles.set_src_rect(tile, tile_id)
else
@tilesets.set_src_rect(tile, tile_id)
end
end
# For animated autotiles only
def refresh_tile_frame(tile, tile_id)
return if !tile.animated
@autotiles.set_src_rect(tile, tile_id)
end
# x and y are the positions of tile within @tiles, not a map x/y
def refresh_tile_coordinates(tile, x, y)
tile.x = (x * DISPLAY_TILE_WIDTH) - @pixel_offset_x
tile.y = (y * DISPLAY_TILE_HEIGHT) - @pixel_offset_y
end
def refresh_tile_z(tile, map, y, layer, tile_id)
if tile.shows_reflection
tile.z = -100
elsif tile.bridge && $PokemonGlobal.bridge > 0
tile.z = 0
else
priority = tile.priority
tile.z = (priority == 0) ? 0 : (y * DISPLAY_TILE_HEIGHT) + (priority * 32) + 32
end
end
def refresh_tile(tile, x, y, map, layer, tile_id)
refresh_tile_bitmap(tile, map, tile_id)
refresh_tile_coordinates(tile, x, y)
refresh_tile_z(tile, map, y, layer, tile_id)
tile.need_refresh = false
end
#=============================================================================
def check_if_screen_moved
ret = false
# Check for map change
if @current_map_id != $game_map.map_id
if MapFactoryHelper.hasConnections?(@current_map_id)
offsets = $map_factory.getRelativePos(@current_map_id, 0, 0, $game_map.map_id, 0, 0)
if offsets
@tile_offset_x -= offsets[0]
@tile_offset_y -= offsets[1]
else
ret = true # Need a full refresh
end
else
ret = true
end
@current_map_id = $game_map.map_id
end
# Check for tile movement
current_map_display_x = ($game_map.display_x.to_f / Game_Map::X_SUBPIXELS).round
current_map_display_y = ($game_map.display_y.to_f / Game_Map::Y_SUBPIXELS).round
new_tile_offset_x = current_map_display_x / DISPLAY_TILE_WIDTH
new_tile_offset_y = current_map_display_y / DISPLAY_TILE_HEIGHT
if new_tile_offset_x != @tile_offset_x
if new_tile_offset_x > @tile_offset_x
# Take tile stacks off the right and insert them at the beginning (left)
(new_tile_offset_x - @tile_offset_x).times do
c = @tiles.shift
@tiles.push(c)
c.each do |coord|
coord.each { |tile| tile.need_refresh = true }
end
end
else
# Take tile stacks off the beginning (left) and push them onto the end (right)
(@tile_offset_x - new_tile_offset_x).times do
c = @tiles.pop
@tiles.prepend(c)
c.each do |coord|
coord.each { |tile| tile.need_refresh = true }
end
end
end
@screen_moved = true
@tile_offset_x = new_tile_offset_x
end
if new_tile_offset_y != @tile_offset_y
if new_tile_offset_y > @tile_offset_y
# Take tile stacks off the bottom and insert them at the beginning (top)
@tiles.each do |col|
(new_tile_offset_y - @tile_offset_y).times do
c = col.shift
col.push(c)
c.each { |tile| tile.need_refresh = true }
end
end
else
# Take tile stacks off the beginning (top) and push them onto the end (bottom)
@tiles.each do |col|
(@tile_offset_y - new_tile_offset_y).times do
c = col.pop
col.prepend(c)
c.each { |tile| tile.need_refresh = true }
end
end
end
@screen_moved = true
@screen_moved_vertically = true
@tile_offset_y = new_tile_offset_y
end
# Check for pixel movement
new_pixel_offset_x = current_map_display_x % SOURCE_TILE_WIDTH
new_pixel_offset_y = current_map_display_y % SOURCE_TILE_HEIGHT
if new_pixel_offset_x != @pixel_offset_x
@screen_moved = true
@pixel_offset_x = new_pixel_offset_x
end
if new_pixel_offset_y != @pixel_offset_y
@screen_moved = true
@screen_moved_vertically = true
@pixel_offset_y = new_pixel_offset_y
end
return ret
end
#=============================================================================
def update
# Update tone
if @old_tone != @tone
@tiles.each do |col|
col.each do |coord|
coord.each { |tile| tile.tone = @tone }
end
end
@old_tone = @tone.clone
end
# Update color
if @old_color != @color
@tiles.each do |col|
col.each do |coord|
coord.each { |tile| tile.color = @tone }
end
end
@old_color = @color.clone
end
# Recalculate autotile frames
@tilesets.update
@autotiles.update
do_full_refresh = false
if @viewport.ox != @old_viewport_ox || @viewport.oy != @old_viewport_oy
@old_viewport_ox = @viewport.ox
@old_viewport_oy = @viewport.oy
do_full_refresh = true
end
# Check whether the screen has moved since the last update
@screen_moved = false
@screen_moved_vertically = false
if $PokemonGlobal.bridge != @bridge
@bridge = $PokemonGlobal.bridge
@screen_moved_vertically = true # To update bridge tiles' z values
end
do_full_refresh = true if check_if_screen_moved
# Update all tile sprites
visited = []
@tiles_horizontal_count.times do |i|
visited[i] = []
@tiles_vertical_count.times { |j| visited[i][j] = false }
end
$map_factory.maps.each do |map|
# Calculate x/y ranges of tile sprites that represent them
map_display_x = (map.display_x.to_f / Game_Map::X_SUBPIXELS).round
map_display_y = (map.display_y.to_f / Game_Map::Y_SUBPIXELS).round
map_display_x_tile = map_display_x / DISPLAY_TILE_WIDTH
map_display_y_tile = map_display_y / DISPLAY_TILE_HEIGHT
start_x = [-map_display_x_tile, 0].max
start_y = [-map_display_y_tile, 0].max
end_x = @tiles_horizontal_count - 1
end_x = [end_x, map.width - map_display_x_tile - 1].min
end_y = @tiles_vertical_count - 1
end_y = [end_y, map.height - map_display_y_tile - 1].min
next if start_x > end_x || start_y > end_y || end_x < 0 || end_y < 0
# Update all tile sprites representing this map
(start_x..end_x).each do |i|
tile_x = i + map_display_x_tile
(start_y..end_y).each do |j|
tile_y = j + map_display_y_tile
@tiles[i][j].each_with_index do |tile, layer|
tile_id = map.data[tile_x, tile_y, layer]
if do_full_refresh || tile.need_refresh || tile.tile_id != tile_id
refresh_tile(tile, i, j, map, layer, tile_id)
else
refresh_tile_frame(tile, tile_id) if tile.animated && @autotiles.changed
# Update tile's x/y coordinates
refresh_tile_coordinates(tile, i, j) if @screen_moved
# Update tile's z value
refresh_tile_z(tile, map, j, layer, tile_id) if @screen_moved_vertically
end
end
# Record x/y as visited
visited[i][j] = true
end
end
end
# Clear all unvisited tile sprites
@tiles.each_with_index do |col, i|
col.each_with_index do |coord, j|
next if visited[i][j]
coord.each do |tile|
tile.set_bitmap("", 0, false, false, 0, nil)
tile.shows_reflection = false
tile.bridge = false
end
end
end
@autotiles.changed = false
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
#=======================================================================
# This module is a little fix that works around PC hardware limitations.
# Since Essentials isn't working with software rendering anymore, it now
# has to deal with the limits of the GPU. For the most part this is no
# big deal, but people do have some really big tilesets.
#
# The fix is simple enough: If your tileset is too big, a new
# bitmap will be constructed with all the excess pixels sent to the
# image's right side. This basically means that you now have a limit
# far higher than you should ever actually need.
#
# Hardware limit -> max tileset length:
# 1024px -> 4096px
# 2048px -> 16384px (enough to get the normal limit)
# 4096px -> 65536px (enough to load pretty much any tileset)
# 8192px -> 262144px
# 16384px -> 1048576px (what most people have at this point)
# ~Roza/Zoroark
#=======================================================================
class TilemapRenderer
module TilesetWrapper
TILESET_WIDTH = SOURCE_TILE_WIDTH * TILESET_TILES_PER_ROW
# Looks useless, but covers weird numbers given to mkxp.json or a funky driver
MAX_TEX_SIZE = (Bitmap.max_size / 1024) * 1024
MAX_TEX_SIZE_BOOSTED = (MAX_TEX_SIZE**2) / TILESET_WIDTH
module_function
def wrapTileset(originalbmp)
width = originalbmp.width
height = originalbmp.height
if width == TILESET_WIDTH && originalbmp.mega?
columns = (height / MAX_TEX_SIZE.to_f).ceil
if columns * TILESET_WIDTH > MAX_TEX_SIZE
raise "Tileset is too long!\n\nSIZE: #{originalbmp.height}px\nHARDWARE LIMIT: #{MAX_TEX_SIZE}px\nBOOSTED LIMIT: #{MAX_TEX_SIZE_BOOSTED}px"
end
bmp = Bitmap.new(TILESET_WIDTH * columns, MAX_TEX_SIZE)
remainder = height % MAX_TEX_SIZE
columns.times do |col|
srcrect = Rect.new(0, col * MAX_TEX_SIZE, width, (col + 1 == columns) ? remainder : MAX_TEX_SIZE)
bmp.blt(col * TILESET_WIDTH, 0, originalbmp, srcrect)
end
return bmp
end
return originalbmp
end
def getWrappedRect(src_rect)
ret = Rect.new(0, 0, 0, 0)
col = (src_rect.y / MAX_TEX_SIZE.to_f).floor
ret.x = (col * TILESET_WIDTH) + src_rect.x.clamp(0, TILESET_WIDTH)
ret.y = src_rect.y % MAX_TEX_SIZE
ret.width = src_rect.width.clamp(0, TILESET_WIDTH - src_rect.x)
ret.height = src_rect.height.clamp(0, MAX_TEX_SIZE)
return ret
end
private
def blitWrappedPixels(destX, destY, dest, src, srcrect)
if srcrect.y + srcrect.width < MAX_TEX_SIZE
# Save the processing power
dest.blt(destX, destY, src, srcrect)
return
end
merge = (srcrect.y % MAX_TEX_SIZE) > ((srcrect.y + srcrect.height) % MAX_TEX_SIZE)
srcrect_mod = getWrappedRect(srcrect)
if merge
# FIXME: won't work on heights longer than two columns, but nobody should need
# more than 32k pixels high at once anyway
side = {
:a => MAX_TEX_SIZE - srcrect_mod.y,
:b => srcrect_mod.height - MAX_TEX_SIZE + srcrect_mod.y
}
dest.blt(destX, destY, src, Rect.new(srcrect_mod.x, srcrect_mod.y, srcrect_mod.width, side[:a]))
dest.blt(destX, destY + side[:a], src, Rect.new(srcrect_mod.x + TILESET_WIDTH, 0, srcrect_mod.width, side[:b]))
else
dest.blt(destX, destY, src, srcrect_mod)
end
end
def stretchBlitWrappedPixels(destrect, dest, src, srcrect)
if srcrect.y + srcrect.width < MAX_TEX_SIZE
# Save the processing power
dest.stretch_blt(destrect, src, srcrect)
return
end
# Does a regular blit to a non-megasurface, then stretch_blts that to
# the destination. Yes it is slow
tmp = Bitmap.new(srcrect.width, srcrect.height)
blitWrappedPixels(0, 0, tmp, src, srcrect)
dest.stretch_blt(destrect, tmp, Rect.new(0, 0, srcrect.width, srcrect.height))
end
end
end

View File

@@ -0,0 +1,72 @@
class TilemapRenderer
module AutotileExpander
MAX_TEXTURE_SIZE = (Bitmap.max_size / 1024) * 1024
module_function
# This doesn't allow for cache sizes smaller than 768, but if that applies
# to you, you've got bigger problems.
def expand(bitmap)
return bitmap if bitmap.height == SOURCE_TILE_HEIGHT
expanded_format = (bitmap.height == SOURCE_TILE_HEIGHT * 6)
wrap = false
if MAX_TEXTURE_SIZE < TILES_PER_AUTOTILE * SOURCE_TILE_HEIGHT
wrap = true # Each autotile will occupy two columns instead of one
end
frames_count = [bitmap.width / (3 * SOURCE_TILE_WIDTH), 1].max
new_bitmap = Bitmap.new(frames_count * (wrap ? 2 : 1) * SOURCE_TILE_WIDTH,
TILES_PER_AUTOTILE * SOURCE_TILE_HEIGHT / (wrap ? 2 : 1))
rect = Rect.new(0, 0, SOURCE_TILE_WIDTH / 2, SOURCE_TILE_HEIGHT / 2)
TILES_PER_AUTOTILE.times do |id|
pattern = TileDrawingHelper::AUTOTILE_PATTERNS[id >> 3][id % TILESET_TILES_PER_ROW]
wrap_offset_x = (wrap && id >= TILES_PER_AUTOTILE / 2) ? SOURCE_TILE_WIDTH : 0
wrap_offset_y = (wrap && id >= TILES_PER_AUTOTILE / 2) ? (TILES_PER_AUTOTILE / 2) * SOURCE_TILE_HEIGHT : 0
frames_count.times do |frame|
if expanded_format && [1, 2, 4, 8].include?(id)
dest_x = frame * SOURCE_TILE_WIDTH * (wrap ? 2 : 1)
dest_x += wrap_offset_x
next if dest_x > MAX_TEXTURE_SIZE
dest_y = id * SOURCE_TILE_HEIGHT
dest_y -= wrap_offset_y
next if dest_y > MAX_TEXTURE_SIZE
case id
when 1 # Top left corner
new_bitmap.blt(dest_x, dest_y, bitmap,
Rect.new(frame * SOURCE_TILE_WIDTH * 3, SOURCE_TILE_HEIGHT * 4,
SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT))
when 2 # Top right corner
new_bitmap.blt(dest_x, dest_y, bitmap,
Rect.new(SOURCE_TILE_WIDTH + (frame * SOURCE_TILE_WIDTH * 3), SOURCE_TILE_HEIGHT * 4,
SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT))
when 4 # Bottom right corner
new_bitmap.blt(dest_x, dest_y, bitmap,
Rect.new(SOURCE_TILE_WIDTH + (frame * SOURCE_TILE_WIDTH * 3), SOURCE_TILE_HEIGHT * 5,
SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT))
when 8 # Bottom left corner
new_bitmap.blt(dest_x, dest_y, bitmap,
Rect.new(frame * SOURCE_TILE_WIDTH * 3, SOURCE_TILE_HEIGHT * 5,
SOURCE_TILE_WIDTH, SOURCE_TILE_HEIGHT))
end
next
end
pattern.each_with_index do |src_chunk, i|
real_src_chunk = src_chunk - 1
dest_x = (i % 2) * SOURCE_TILE_WIDTH / 2
dest_x += frame * SOURCE_TILE_WIDTH * (wrap ? 2 : 1)
dest_x += wrap_offset_x
next if dest_x > MAX_TEXTURE_SIZE
dest_y = (i / 2) * SOURCE_TILE_HEIGHT / 2
dest_y += id * SOURCE_TILE_HEIGHT
dest_y -= wrap_offset_y
next if dest_y > MAX_TEXTURE_SIZE
rect.x = (real_src_chunk % 6) * SOURCE_TILE_WIDTH / 2
rect.x += SOURCE_TILE_WIDTH * 3 * frame
rect.y = (real_src_chunk / 6) * SOURCE_TILE_HEIGHT / 2
new_bitmap.blt(dest_x, dest_y, bitmap, rect)
end
end
end
return new_bitmap
end
end
end

View File

@@ -1,228 +0,0 @@
class TileDrawingHelper
attr_accessor :tileset
attr_accessor :autotiles
Autotiles = [
[ [27, 28, 33, 34], [ 5, 28, 33, 34], [27, 6, 33, 34], [ 5, 6, 33, 34],
[27, 28, 33, 12], [ 5, 28, 33, 12], [27, 6, 33, 12], [ 5, 6, 33, 12] ],
[ [27, 28, 11, 34], [ 5, 28, 11, 34], [27, 6, 11, 34], [ 5, 6, 11, 34],
[27, 28, 11, 12], [ 5, 28, 11, 12], [27, 6, 11, 12], [ 5, 6, 11, 12] ],
[ [25, 26, 31, 32], [25, 6, 31, 32], [25, 26, 31, 12], [25, 6, 31, 12],
[15, 16, 21, 22], [15, 16, 21, 12], [15, 16, 11, 22], [15, 16, 11, 12] ],
[ [29, 30, 35, 36], [29, 30, 11, 36], [ 5, 30, 35, 36], [ 5, 30, 11, 36],
[39, 40, 45, 46], [ 5, 40, 45, 46], [39, 6, 45, 46], [ 5, 6, 45, 46] ],
[ [25, 30, 31, 36], [15, 16, 45, 46], [13, 14, 19, 20], [13, 14, 19, 12],
[17, 18, 23, 24], [17, 18, 11, 24], [41, 42, 47, 48], [ 5, 42, 47, 48] ],
[ [37, 38, 43, 44], [37, 6, 43, 44], [13, 18, 19, 24], [13, 14, 43, 44],
[37, 42, 43, 48], [17, 18, 47, 48], [13, 18, 43, 48], [ 1, 2, 7, 8] ]
]
# converts neighbors returned from tableNeighbors to tile indexes
NeighborsToTiles = [
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
45, 39, 45, 39, 33, 31, 33, 29, 45, 39, 45, 39, 33, 31, 33, 29,
37, 27, 37, 27, 23, 15, 23, 13, 37, 27, 37, 27, 22, 11, 22, 9,
45, 39, 45, 39, 33, 31, 33, 29, 45, 39, 45, 39, 33, 31, 33, 29,
36, 26, 36, 26, 21, 7, 21, 5, 36, 26, 36, 26, 20, 3, 20, 1,
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
45, 38, 45, 38, 33, 30, 33, 28, 45, 38, 45, 38, 33, 30, 33, 28,
37, 25, 37, 25, 23, 14, 23, 12, 37, 25, 37, 25, 22, 10, 22, 8,
45, 38, 45, 38, 33, 30, 33, 28, 45, 38, 45, 38, 33, 30, 33, 28,
36, 24, 36, 24, 21, 6, 21, 4, 36, 24, 36, 24, 20, 2, 20, 0
]
def self.tableNeighbors(data,x,y)
return 0 if x < 0 || x >= data.xsize
return 0 if y < 0 || y >= data.ysize
t = data[x,y]
xp1 = [x + 1, data.xsize - 1].min
yp1 = [y + 1, data.ysize - 1].min
xm1 = [x - 1, 0].max
ym1 = [y - 1, 0].max
i = 0
i |= 0x01 if data[ x, ym1] == t # N
i |= 0x02 if data[xp1, ym1] == t # NE
i |= 0x04 if data[xp1, y] == t # E
i |= 0x08 if data[xp1, yp1] == t # SE
i |= 0x10 if data[ x, yp1] == t # S
i |= 0x20 if data[xm1, yp1] == t # SW
i |= 0x40 if data[xm1, y] == t # W
i |= 0x80 if data[xm1, ym1] == t # NW
return i
end
def self.fromTileset(tileset)
bmtileset=pbGetTileset(tileset.tileset_name)
bmautotiles=[]
for i in 0...7
bmautotiles.push(pbGetAutotile(tileset.autotile_names[i]))
end
return self.new(bmtileset,bmautotiles)
end
def initialize(tileset, autotiles)
if tileset.mega?
@tileset = TileWrap::wrapTileset(tileset)
tileset.dispose
@shouldWrap = true
else
@tileset = tileset
@shouldWrap = false
end
@autotiles = autotiles
end
def dispose
@tileset.dispose if @tileset
@tileset = nil
for i in 0...@autotiles.length
@autotiles[i].dispose
@autotiles[i] = nil
end
end
def bltSmallAutotile(bitmap,x,y,cxTile,cyTile,id,frame)
return if id >= 384 || frame < 0 || !@autotiles
autotile = @autotiles[id / 48 - 1]
return if !autotile || autotile.disposed?
cxTile = [cxTile / 2, 1].max
cyTile = [cyTile / 2, 1].max
if autotile.height == 32
anim = frame * 32
src_rect = Rect.new(anim, 0, 32, 32)
bitmap.stretch_blt(Rect.new(x, y, cxTile * 2, cyTile * 2), autotile, src_rect)
else
anim = frame * 96
id %= 48
tiles = TileDrawingHelper::Autotiles[id >> 3][id & 7]
src = Rect.new(0, 0, 0, 0)
for i in 0...4
tile_position = tiles[i] - 1
src.set(tile_position % 6 * 16 + anim, tile_position / 6 * 16, 16, 16)
bitmap.stretch_blt(Rect.new(i % 2 * cxTile + x, i / 2 * cyTile + y, cxTile, cyTile),
autotile, src)
end
end
end
def bltSmallRegularTile(bitmap,x,y,cxTile,cyTile,id)
return if id < 384 || !@tileset || @tileset.disposed?
rect = Rect.new((id - 384) % 8 * 32, (id - 384) / 8 * 32, 32, 32)
rect = TileWrap::getWrappedRect(rect) if @shouldWrap
bitmap.stretch_blt(Rect.new(x, y, cxTile, cyTile), @tileset, rect)
end
def bltSmallTile(bitmap,x,y,cxTile,cyTile,id,frame=0)
if id >= 384
bltSmallRegularTile(bitmap, x, y, cxTile, cyTile, id)
elsif id > 0
bltSmallAutotile(bitmap, x, y, cxTile, cyTile, id, frame)
end
end
def bltAutotile(bitmap,x,y,id,frame)
bltSmallAutotile(bitmap, x, y, 32, 32, id, frame)
end
def bltRegularTile(bitmap,x,y,id)
bltSmallRegularTile(bitmap, x, y, 32, 32, id)
end
def bltTile(bitmap,x,y,id,frame=0)
if id >= 384
bltRegularTile(bitmap, x, y, id)
elsif id > 0
bltAutotile(bitmap, x, y, id, frame)
end
end
end
#===============================================================================
#
#===============================================================================
def createMinimap(mapid)
map=load_data(sprintf("Data/Map%03d.rxdata",mapid)) rescue nil
return BitmapWrapper.new(32,32) if !map
bitmap=BitmapWrapper.new(map.width*4,map.height*4)
black=Color.new(0,0,0)
tilesets=$data_tilesets
tileset=tilesets[map.tileset_id]
return bitmap if !tileset
helper=TileDrawingHelper.fromTileset(tileset)
for y in 0...map.height
for x in 0...map.width
for z in 0..2
id=map.data[x,y,z]
id=0 if !id
helper.bltSmallTile(bitmap,x*4,y*4,4,4,id)
end
end
end
bitmap.fill_rect(0,0,bitmap.width,1,black)
bitmap.fill_rect(0,bitmap.height-1,bitmap.width,1,black)
bitmap.fill_rect(0,0,1,bitmap.height,black)
bitmap.fill_rect(bitmap.width-1,0,1,bitmap.height,black)
return bitmap
end
def bltMinimapAutotile(dstBitmap,x,y,srcBitmap,id)
return if id>=48 || !srcBitmap || srcBitmap.disposed?
anim=0
cxTile=3
cyTile=3
tiles = TileDrawingHelper::Autotiles[id>>3][id&7]
src=Rect.new(0,0,0,0)
for i in 0...4
tile_position = tiles[i] - 1
src.set(
tile_position % 6 * cxTile + anim,
tile_position / 6 * cyTile, cxTile, cyTile)
dstBitmap.blt(i%2*cxTile+x,i/2*cyTile+y, srcBitmap, src)
end
end
def passable?(passages,tile_id)
return false if tile_id == nil
passage = passages[tile_id]
return (passage && passage<15)
end
# Unused
def getPassabilityMinimap(mapid)
map = load_data(sprintf("Data/Map%03d.rxdata",mapid))
tileset = $data_tilesets[map.tileset_id]
minimap = AnimatedBitmap.new("Graphics/Pictures/minimap_tiles")
ret = Bitmap.new(map.width*6,map.height*6)
passtable = Table.new(map.width,map.height)
passages = tileset.passages
for i in 0...map.width
for j in 0...map.height
pass=true
for z in [2,1,0]
if !passable?(passages,map.data[i,j,z])
pass=false
break
end
end
passtable[i,j]=pass ? 1 : 0
end
end
neighbors=TileDrawingHelper::NeighborsToTiles
for i in 0...map.width
for j in 0...map.height
if passtable[i,j]==0
nb=TileDrawingHelper.tableNeighbors(passtable,i,j)
tile=neighbors[nb]
bltMinimapAutotile(ret,i*6,j*6,minimap.bitmap,tile)
end
end
end
minimap.disposes
return ret
end

View File

@@ -0,0 +1,226 @@
class TileDrawingHelper
attr_accessor :tileset
attr_accessor :autotiles
AUTOTILE_PATTERNS = [
[[27, 28, 33, 34], [5, 28, 33, 34], [27, 6, 33, 34], [5, 6, 33, 34],
[27, 28, 33, 12], [5, 28, 33, 12], [27, 6, 33, 12], [5, 6, 33, 12]],
[[27, 28, 11, 34], [5, 28, 11, 34], [27, 6, 11, 34], [5, 6, 11, 34],
[27, 28, 11, 12], [5, 28, 11, 12], [27, 6, 11, 12], [5, 6, 11, 12]],
[[25, 26, 31, 32], [25, 6, 31, 32], [25, 26, 31, 12], [25, 6, 31, 12],
[15, 16, 21, 22], [15, 16, 21, 12], [15, 16, 11, 22], [15, 16, 11, 12]],
[[29, 30, 35, 36], [29, 30, 11, 36], [5, 30, 35, 36], [5, 30, 11, 36],
[39, 40, 45, 46], [5, 40, 45, 46], [39, 6, 45, 46], [5, 6, 45, 46]],
[[25, 30, 31, 36], [15, 16, 45, 46], [13, 14, 19, 20], [13, 14, 19, 12],
[17, 18, 23, 24], [17, 18, 11, 24], [41, 42, 47, 48], [5, 42, 47, 48]],
[[37, 38, 43, 44], [37, 6, 43, 44], [13, 18, 19, 24], [13, 14, 43, 44],
[37, 42, 43, 48], [17, 18, 47, 48], [13, 18, 43, 48], [1, 2, 7, 8]]
]
# converts neighbors returned from tableNeighbors to tile indexes
NEIGHBORS_TO_AUTOTILE_INDEX = [
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
45, 39, 45, 39, 33, 31, 33, 29, 45, 39, 45, 39, 33, 31, 33, 29,
37, 27, 37, 27, 23, 15, 23, 13, 37, 27, 37, 27, 22, 11, 22, 9,
45, 39, 45, 39, 33, 31, 33, 29, 45, 39, 45, 39, 33, 31, 33, 29,
36, 26, 36, 26, 21, 7, 21, 5, 36, 26, 36, 26, 20, 3, 20, 1,
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40,
42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16,
45, 38, 45, 38, 33, 30, 33, 28, 45, 38, 45, 38, 33, 30, 33, 28,
37, 25, 37, 25, 23, 14, 23, 12, 37, 25, 37, 25, 22, 10, 22, 8,
45, 38, 45, 38, 33, 30, 33, 28, 45, 38, 45, 38, 33, 30, 33, 28,
36, 24, 36, 24, 21, 6, 21, 4, 36, 24, 36, 24, 20, 2, 20, 0
]
def self.tableNeighbors(data, x, y)
return 0 if x < 0 || x >= data.xsize
return 0 if y < 0 || y >= data.ysize
t = data[x, y]
xp1 = [x + 1, data.xsize - 1].min
yp1 = [y + 1, data.ysize - 1].min
xm1 = [x - 1, 0].max
ym1 = [y - 1, 0].max
i = 0
i |= 0x01 if data[x, ym1] == t # N
i |= 0x02 if data[xp1, ym1] == t # NE
i |= 0x04 if data[xp1, y] == t # E
i |= 0x08 if data[xp1, yp1] == t # SE
i |= 0x10 if data[x, yp1] == t # S
i |= 0x20 if data[xm1, yp1] == t # SW
i |= 0x40 if data[xm1, y] == t # W
i |= 0x80 if data[xm1, ym1] == t # NW
return i
end
def self.fromTileset(tileset)
bmtileset = pbGetTileset(tileset.tileset_name)
bmautotiles = []
7.times do |i|
bmautotiles.push(pbGetAutotile(tileset.autotile_names[i]))
end
return self.new(bmtileset, bmautotiles)
end
def initialize(tileset, autotiles)
if tileset.mega?
@tileset = TilemapRenderer::TilesetWrapper.wrapTileset(tileset)
tileset.dispose
@shouldWrap = true
else
@tileset = tileset
@shouldWrap = false
end
@autotiles = autotiles
end
def dispose
@tileset&.dispose
@tileset = nil
@autotiles.each_with_index do |autotile, i|
autotile.dispose
@autotiles[i] = nil
end
end
def bltSmallAutotile(bitmap, x, y, cxTile, cyTile, id, frame)
return if id >= 384 || frame < 0 || !@autotiles
autotile = @autotiles[(id / 48) - 1]
return if !autotile || autotile.disposed?
cxTile = [cxTile / 2, 1].max
cyTile = [cyTile / 2, 1].max
if autotile.height == 32
anim = frame * 32
src_rect = Rect.new(anim, 0, 32, 32)
bitmap.stretch_blt(Rect.new(x, y, cxTile * 2, cyTile * 2), autotile, src_rect)
else
anim = frame * 96
id %= 48
tiles = AUTOTILE_PATTERNS[id >> 3][id & 7]
src = Rect.new(0, 0, 0, 0)
4.times do |i|
tile_position = tiles[i] - 1
src.set((tile_position % 6 * 16) + anim, tile_position / 6 * 16, 16, 16)
bitmap.stretch_blt(Rect.new((i % 2 * cxTile) + x, (i / 2 * cyTile) + y, cxTile, cyTile),
autotile, src)
end
end
end
def bltSmallRegularTile(bitmap, x, y, cxTile, cyTile, id)
return if id < 384 || !@tileset || @tileset.disposed?
rect = Rect.new((id - 384) % 8 * 32, (id - 384) / 8 * 32, 32, 32)
rect = TilemapRenderer::TilesetWrapper.getWrappedRect(rect) if @shouldWrap
bitmap.stretch_blt(Rect.new(x, y, cxTile, cyTile), @tileset, rect)
end
def bltSmallTile(bitmap, x, y, cxTile, cyTile, id, frame = 0)
if id >= 384
bltSmallRegularTile(bitmap, x, y, cxTile, cyTile, id)
elsif id > 0
bltSmallAutotile(bitmap, x, y, cxTile, cyTile, id, frame)
end
end
def bltAutotile(bitmap, x, y, id, frame)
bltSmallAutotile(bitmap, x, y, 32, 32, id, frame)
end
def bltRegularTile(bitmap, x, y, id)
bltSmallRegularTile(bitmap, x, y, 32, 32, id)
end
def bltTile(bitmap, x, y, id, frame = 0)
if id >= 384
bltRegularTile(bitmap, x, y, id)
elsif id > 0
bltAutotile(bitmap, x, y, id, frame)
end
end
end
#===============================================================================
#
#===============================================================================
def createMinimap(mapid)
map = load_data(sprintf("Data/Map%03d.rxdata", mapid)) rescue nil
return BitmapWrapper.new(32, 32) if !map
bitmap = BitmapWrapper.new(map.width * 4, map.height * 4)
black = Color.new(0, 0, 0)
tilesets = $data_tilesets
tileset = tilesets[map.tileset_id]
return bitmap if !tileset
helper = TileDrawingHelper.fromTileset(tileset)
map.height.times do |y|
map.width.times do |x|
3.times do |z|
id = map.data[x, y, z]
id = 0 if !id
helper.bltSmallTile(bitmap, x * 4, y * 4, 4, 4, id)
end
end
end
bitmap.fill_rect(0, 0, bitmap.width, 1, black)
bitmap.fill_rect(0, bitmap.height - 1, bitmap.width, 1, black)
bitmap.fill_rect(0, 0, 1, bitmap.height, black)
bitmap.fill_rect(bitmap.width - 1, 0, 1, bitmap.height, black)
return bitmap
end
def bltMinimapAutotile(dstBitmap, x, y, srcBitmap, id)
return if id >= 48 || !srcBitmap || srcBitmap.disposed?
anim = 0
cxTile = 3
cyTile = 3
tiles = TileDrawingHelper::AUTOTILE_PATTERNS[id >> 3][id & 7]
src = Rect.new(0, 0, 0, 0)
4.times do |i|
tile_position = tiles[i] - 1
src.set((tile_position % 6 * cxTile) + anim,
tile_position / 6 * cyTile, cxTile, cyTile)
dstBitmap.blt((i % 2 * cxTile) + x, (i / 2 * cyTile) + y, srcBitmap, src)
end
end
def passable?(passages, tile_id)
return false if tile_id.nil?
passage = passages[tile_id]
return (passage && passage < 15)
end
# Unused
def getPassabilityMinimap(mapid)
map = load_data(sprintf("Data/Map%03d.rxdata", mapid))
tileset = $data_tilesets[map.tileset_id]
minimap = AnimatedBitmap.new("Graphics/Pictures/minimap_tiles")
ret = Bitmap.new(map.width * 6, map.height * 6)
passtable = Table.new(map.width, map.height)
passages = tileset.passages
map.width.times do |i|
map.height.times do |j|
pass = true
[2, 1, 0].each do |z|
if !passable?(passages, map.data[i, j, z])
pass = false
break
end
end
passtable[i, j] = pass ? 1 : 0
end
end
neighbors = TileDrawingHelper::NEIGHBORS_TO_AUTOTILE_INDEX
map.width.times do |i|
map.height.times do |j|
next if passtable[i, j] != 0
nb = TileDrawingHelper.tableNeighbors(passtable, i, j)
tile = neighbors[nb]
bltMinimapAutotile(ret, i * 6, j * 6, minimap.bitmap, tile)
end
end
minimap.disposes
return ret
end

View File

@@ -27,7 +27,7 @@ module RPG
def self.fromCache(i)
return nil if !@cache.include?(i)
obj = @cache[i]
return nil if obj && obj.disposed?
return nil if obj&.disposed?
return obj
end

View File

@@ -4,11 +4,14 @@ module MessageConfig
DARK_TEXT_MAIN_COLOR = Color.new(80, 80, 88)
DARK_TEXT_SHADOW_COLOR = Color.new(160, 160, 168)
FONT_NAME = "Power Green"
FONT_SIZE = 29
FONT_SIZE = 27
FONT_Y_OFFSET = 8
SMALL_FONT_NAME = "Power Green Small"
SMALL_FONT_SIZE = 25
SMALL_FONT_SIZE = 21
SMALL_FONT_Y_OFFSET = 8
NARROW_FONT_NAME = "Power Green Narrow"
NARROW_FONT_SIZE = 29
NARROW_FONT_SIZE = 27
NARROW_FONT_Y_OFFSET = 8
# 0 = Pause cursor is displayed at end of text
# 1 = Pause cursor is displayed at bottom right
# 2 = Pause cursor is displayed at lower middle side
@@ -144,12 +147,13 @@ module MessageConfig
end
def self.pbTryFonts(*args)
for a in args
args.each do |a|
next if !a
if a.is_a?(String)
case a
when String
return a if Font.exist?(a)
elsif a.is_a?(Array)
for aa in a
when Array
a.each do |aa|
ret = MessageConfig.pbTryFonts(aa)
return ret if ret != ""
end
@@ -176,8 +180,8 @@ end
def pbBottomLeftLines(window, lines, width = nil)
window.x = 0
window.width=width ? width : Graphics.width
window.height=(window.borderY rescue 32)+lines*32
window.width = width || Graphics.width
window.height = (window.borderY rescue 32) + (lines * 32)
window.y = Graphics.height - window.height
end
@@ -230,9 +234,9 @@ end
# internal function
def pbRepositionMessageWindow(msgwindow, linecount = 2)
msgwindow.height=32*linecount+msgwindow.borderY
msgwindow.height = (32 * linecount) + msgwindow.borderY
msgwindow.y = (Graphics.height) - (msgwindow.height)
if $game_system && $game_system.respond_to?("message_position")
if $game_system
case $game_system.message_position
when 0 # up
msgwindow.y = 0
@@ -241,11 +245,7 @@ def pbRepositionMessageWindow(msgwindow, linecount=2)
when 2
msgwindow.y = (Graphics.height) - (msgwindow.height)
end
end
if $game_system && $game_system.respond_to?("message_frame")
if $game_system.message_frame != 0
msgwindow.opacity = 0
end
msgwindow.opacity = 0 if $game_system.message_frame != 0
end
end
@@ -282,13 +282,13 @@ def isDarkBackground(background,rect=nil)
return true if rect.width <= 0 || rect.height <= 0
xSeg = (rect.width / 16)
xLoop = (xSeg == 0) ? 1 : 16
xStart = (xSeg==0) ? rect.x+(rect.width/2) : rect.x+xSeg/2
xStart = (xSeg == 0) ? rect.x + (rect.width / 2) : rect.x + (xSeg / 2)
ySeg = (rect.height / 16)
yLoop = (ySeg == 0) ? 1 : 16
yStart = (ySeg==0) ? rect.y+(rect.height/2) : rect.y+ySeg/2
yStart = (ySeg == 0) ? rect.y + (rect.height / 2) : rect.y + (ySeg / 2)
count = 0
y = yStart
r = 0; g = 0; b = 0
r = g = b = 0
yLoop.times do
x = xStart
xLoop.times do
@@ -307,7 +307,7 @@ def isDarkBackground(background,rect=nil)
r /= count
g /= count
b /= count
return (r*0.299+g*0.587+b*0.114)<160
return ((r * 0.299) + (g * 0.587) + (b * 0.114)) < 160
end
def isDarkWindowskin(windowskin)
@@ -320,7 +320,7 @@ def isDarkWindowskin(windowskin)
return isDarkBackground(windowskin, Rect.new(32, 16, 16, 16))
else
clr = windowskin.get_pixel(windowskin.width / 2, windowskin.height / 2)
return (clr.red*0.299+clr.green*0.587+clr.blue*0.114)<160
return ((clr.red * 0.299) + (clr.green * 0.587) + (clr.blue * 0.114)) < 160
end
end
@@ -356,14 +356,14 @@ def getSkinColor(windowskin,color,isDarkSkin)
end
# Special colour as listed above
if isDarkSkin && color != 12 # Dark background, light text
return sprintf("<c3=%s,%s>",textcolors[2*(color-1)+1],textcolors[2*(color-1)])
return sprintf("<c3=%s,%s>", textcolors[(2 * (color - 1)) + 1], textcolors[2 * (color - 1)])
end
# Light background, dark text
return sprintf("<c3=%s,%s>",textcolors[2*(color-1)],textcolors[2*(color-1)+1])
return sprintf("<c3=%s,%s>", textcolors[2 * (color - 1)], textcolors[(2 * (color - 1)) + 1])
else # VX windowskin
color = 0 if color >= 32
x = 64 + (color % 8) * 8
y = 96 + (color / 8) * 8
x = 64 + ((color % 8) * 8)
y = 96 + ((color / 8) * 8)
pixel = windowskin.get_pixel(x, y)
return shadowctagFromColor(pixel)
end
@@ -396,10 +396,10 @@ end
def pbDoEnsureBitmap(bitmap, dwidth, dheight)
if !bitmap || bitmap.disposed? || bitmap.width < dwidth || bitmap.height < dheight
oldfont = (bitmap && !bitmap.disposed?) ? bitmap.font : nil
bitmap.dispose if bitmap
bitmap&.dispose
bitmap = Bitmap.new([1, dwidth].max, [1, dheight].max)
(oldfont) ? bitmap.font = oldfont : pbSetSystemFont(bitmap)
bitmap.font.shadow = false if bitmap.font && bitmap.font.respond_to?("shadow")
bitmap.font.shadow = false if bitmap.font.respond_to?("shadow")
end
return bitmap
end
@@ -411,18 +411,21 @@ end
def pbSetSystemFont(bitmap)
bitmap.font.name = MessageConfig.pbGetSystemFontName
bitmap.font.size = MessageConfig::FONT_SIZE
bitmap.text_offset_y = MessageConfig::FONT_Y_OFFSET
end
# Sets a bitmap's font to the system small font.
def pbSetSmallFont(bitmap)
bitmap.font.name = MessageConfig.pbGetSmallFontName
bitmap.font.size = MessageConfig::SMALL_FONT_SIZE
bitmap.text_offset_y = MessageConfig::SMALL_FONT_Y_OFFSET
end
# Sets a bitmap's font to the system narrow font.
def pbSetNarrowFont(bitmap)
bitmap.font.name = MessageConfig.pbGetNarrowFontName
bitmap.font.size = MessageConfig::NARROW_FONT_SIZE
bitmap.text_offset_y = MessageConfig::NARROW_FONT_Y_OFFSET
end
#===============================================================================
@@ -445,10 +448,10 @@ def pbSrcOver(dstColor,srcColor)
cg = dstColor.green * dstColor.alpha / 255
cb = dstColor.blue * dstColor.alpha / 255
ica = 255 - dstColor.alpha
a=255-(iea*ica)/255
r=(iea*cr)/255+er
g=(iea*cg)/255+eg
b=(iea*cb)/255+eb
a = 255 - ((iea * ica) / 255)
r = ((iea * cr) / 255) + er
g = ((iea * cg) / 255) + eg
b = ((iea * cb) / 255) + eb
r = (a == 0) ? 0 : r * 255 / a
g = (a == 0) ? 0 : g * 255 / a
b = (a == 0) ? 0 : b * 255 / a
@@ -458,14 +461,14 @@ end
def pbSetSpritesToColor(sprites, color)
return if !sprites || !color
colors = {}
for i in sprites
sprites.each do |i|
next if !i[1] || pbDisposed?(i[1])
colors[i[0]] = i[1].color.clone
i[1].color = pbSrcOver(i[1].color, color)
end
Graphics.update
Input.update
for i in colors
colors.each do |i|
next if !sprites[i[0]]
sprites[i[0]].color = i[1]
end
@@ -483,7 +486,7 @@ def using(window)
end
def pbUpdateSpriteHash(windows)
for i in windows
windows.each do |i|
window = i[1]
if window
if window.is_a?(Sprite) || window.is_a?(Window)
@@ -506,7 +509,7 @@ end
# Disposes all objects in the specified hash.
def pbDisposeSpriteHash(sprites)
return if !sprites
for i in sprites.keys
sprites.each_key do |i|
pbDisposeSprite(sprites, i)
end
sprites.clear
@@ -555,7 +558,7 @@ def pbFadeOutIn(z=99999,nofadeout=false)
viewport.z = z
numFrames = (Graphics.frame_rate * 0.4).floor
alphaDiff = (255.0 / numFrames).ceil
for j in 0..numFrames
(0..numFrames).each do |j|
col.set(0, 0, 0, j * alphaDiff)
viewport.color = col
Graphics.update
@@ -563,11 +566,13 @@ def pbFadeOutIn(z=99999,nofadeout=false)
end
pbPushFade
begin
yield if block_given?
val = 0
val = yield if block_given?
nofadeout = true if val == 99999 # Ugly hack used by Town Map in the Bag/Pokégear
ensure
pbPopFade
if !nofadeout
for j in 0..numFrames
(0..numFrames).each do |j|
col.set(0, 0, 0, (numFrames - j) * alphaDiff)
viewport.color = col
Graphics.update
@@ -584,7 +589,7 @@ def pbFadeOutInWithUpdate(z,sprites,nofadeout=false)
viewport.z = z
numFrames = (Graphics.frame_rate * 0.4).floor
alphaDiff = (255.0 / numFrames).ceil
for j in 0..numFrames
(0..numFrames).each do |j|
col.set(0, 0, 0, j * alphaDiff)
viewport.color = col
pbUpdateSpriteHash(sprites)
@@ -597,7 +602,7 @@ def pbFadeOutInWithUpdate(z,sprites,nofadeout=false)
ensure
pbPopFade
if !nofadeout
for j in 0..numFrames
(0..numFrames).each do |j|
col.set(0, 0, 0, (numFrames - j) * alphaDiff)
viewport.color = col
pbUpdateSpriteHash(sprites)
@@ -630,12 +635,12 @@ def pbFadeOutAndHide(sprites)
numFrames = (Graphics.frame_rate * 0.4).floor
alphaDiff = (255.0 / numFrames).ceil
pbDeactivateWindows(sprites) {
for j in 0..numFrames
(0..numFrames).each do |j|
pbSetSpritesToColor(sprites, Color.new(0, 0, 0, j * alphaDiff))
(block_given?) ? yield : pbUpdateSpriteHash(sprites)
end
}
for i in sprites
sprites.each do |i|
next if !i[1]
next if pbDisposed?(i[1])
visiblesprites[i[0]] = true if i[1].visible
@@ -646,7 +651,7 @@ end
def pbFadeInAndShow(sprites, visiblesprites = nil)
if visiblesprites
for i in visiblesprites
visiblesprites.each do |i|
if i[1] && sprites[i[0]] && !pbDisposed?(sprites[i[0]])
sprites[i[0]].visible = true
end
@@ -655,7 +660,7 @@ def pbFadeInAndShow(sprites,visiblesprites=nil)
numFrames = (Graphics.frame_rate * 0.4).floor
alphaDiff = (255.0 / numFrames).ceil
pbDeactivateWindows(sprites) {
for j in 0..numFrames
(0..numFrames).each do |j|
pbSetSpritesToColor(sprites, Color.new(0, 0, 0, ((numFrames - j) * alphaDiff)))
(block_given?) ? yield : pbUpdateSpriteHash(sprites)
end
@@ -666,8 +671,8 @@ end
# _activeStatuses_ is the result of a previous call to pbActivateWindows
def pbRestoreActivations(sprites, activeStatuses)
return if !sprites || !activeStatuses
for k in activeStatuses.keys
if sprites[k] && sprites[k].is_a?(Window) && !pbDisposed?(sprites[k])
activeStatuses.each_key do |k|
if sprites[k].is_a?(Window) && !pbDisposed?(sprites[k])
sprites[k].active = activeStatuses[k] ? true : false
end
end
@@ -689,8 +694,8 @@ end
def pbActivateWindow(sprites, key)
return if !sprites
activeStatuses = {}
for i in sprites
if i[1] && i[1].is_a?(Window) && !pbDisposed?(i[1])
sprites.each do |i|
if i[1].is_a?(Window) && !pbDisposed?(i[1])
activeStatuses[i[0]] = i[1].active
i[1].active = (i[0] == key)
end
@@ -718,13 +723,13 @@ end
def addBackgroundPlane(sprites, planename, background, viewport = nil)
sprites[planename] = AnimatedPlane.new(viewport)
bitmapName = pbResolveBitmap("Graphics/Pictures/#{background}")
if bitmapName==nil
if bitmapName.nil?
# Plane should exist in any case
sprites[planename].bitmap = nil
sprites[planename].visible = false
else
sprites[planename].setBitmap(bitmapName)
for spr in sprites.values
sprites.each_value do |spr|
if spr.is_a?(Window)
spr.windowskin = nil
end
@@ -740,13 +745,13 @@ end
# _viewport_ is a viewport to place the background in.
def addBackgroundOrColoredPlane(sprites, planename, background, color, viewport = nil)
bitmapName = pbResolveBitmap("Graphics/Pictures/#{background}")
if bitmapName==nil
if bitmapName.nil?
# Plane should exist in any case
sprites[planename] = ColoredPlane.new(color, viewport)
else
sprites[planename] = AnimatedPlane.new(viewport)
sprites[planename].setBitmap(bitmapName)
for spr in sprites.values
sprites.each_value do |spr|
if spr.is_a?(Window)
spr.windowskin = nil
end
@@ -773,8 +778,8 @@ end
if !defined?(_INTL)
def _INTL(*args)
string = args[0].clone
for i in 1...args.length
string.gsub!(/\{#{i}\}/,"#{args[i]}")
(1...args.length).each do |i|
string.gsub!(/\{#{i}\}/, args[i].to_s)
end
return string
end
@@ -783,7 +788,7 @@ end
if !defined?(_ISPRINTF)
def _ISPRINTF(*args)
string = args[0].clone
for i in 1...args.length
(1...args.length).each do |i|
string.gsub!(/\{#{i}\:([^\}]+?)\}/) { |m|
next sprintf("%" + $1, args[i])
}
@@ -795,8 +800,8 @@ end
if !defined?(_MAPINTL)
def _MAPINTL(*args)
string = args[1].clone
for i in 2...args.length
string.gsub!(/\{#{i}\}/,"#{args[i+1]}")
(2...args.length).each do |i|
string.gsub!(/\{#{i}\}/, args[i + 1].to_s)
end
return string
end

View File

@@ -6,7 +6,6 @@ class WindowCursorRect < Rect
def empty
return unless needs_update?(0, 0, 0, 0)
set(0, 0, 0, 0)
end
@@ -16,9 +15,7 @@ class WindowCursorRect < Rect
def set(x, y, width, height)
return unless needs_update?(x, y, width, height)
super(x, y, width, height)
@window.width = @window.width
end
@@ -92,7 +89,7 @@ class Window
@cursorbitmap = nil
@bgbitmap = nil
@viewport = viewport
for i in @spritekeys
@spritekeys.each do |i|
@sprites[i] = Sprite.new(@viewport)
end
@disposed = false
@@ -129,17 +126,17 @@ class Window
def dispose
if !self.disposed?
for i in @sprites
i[1].dispose if i[1]
@sprites.each do |i|
i[1]&.dispose
@sprites[i[0]] = nil
end
for i in 0...@sidebitmaps.length
@sidebitmaps[i].dispose if @sidebitmaps[i]
@sidebitmaps.each_with_index do |bitmap, i|
bitmap&.dispose
@sidebitmaps[i] = nil
end
@blankcontents.dispose
@cursorbitmap.dispose if @cursorbitmap
@backbitmap.dispose if @backbitmap
@cursorbitmap&.dispose
@backbitmap&.dispose
@sprites.clear
@sidebitmaps.clear
@_windowskin = nil
@@ -167,7 +164,7 @@ class Window
def viewport=(value)
@viewport = value
for i in @spritekeys
@spritekeys.each do |i|
@sprites[i].dispose
if @sprites[i].is_a?(Sprite)
@sprites[i] = Sprite.new(@viewport)
@@ -194,7 +191,7 @@ class Window
def windowskin=(value)
@_windowskin = value
if value && value.is_a?(Bitmap) && !value.disposed? && value.width==128
if value.is_a?(Bitmap) && !value.disposed? && value.width == 128
@rpgvx = true
else
@rpgvx = false
@@ -213,10 +210,10 @@ class Window
end
def cursor_rect=(value)
if !value
@cursor_rect.empty
else
if value
@cursor_rect.set(value.x, value.y, value.width, value.height)
else
@cursor_rect.empty
end
end
@@ -289,7 +286,7 @@ class Window
def flash(color, duration)
return if disposed?
for i in @sprites
@sprites.each do |i|
i[1].flash(color, duration)
end
end
@@ -316,7 +313,7 @@ class Window
mustchange = true
end
privRefresh if mustchange
for i in @sprites
@sprites.each do |i|
i[1].update
end
end
@@ -325,7 +322,7 @@ class Window
def ensureBitmap(bitmap, dwidth, dheight)
if !bitmap || bitmap.disposed? || bitmap.width < dwidth || bitmap.height < dheight
bitmap.dispose if bitmap
bitmap&.dispose
bitmap = Bitmap.new([1, dwidth].max, [1, dheight].max)
end
return bitmap
@@ -335,8 +332,12 @@ class Window
return if !srcbitmap || srcbitmap.disposed?
left = dstrect.x
top = dstrect.y
y=0;loop do break unless y<dstrect.height
x=0;loop do break unless x<dstrect.width
y = 0
loop do
break unless y < dstrect.height
x = 0
loop do
break unless x < dstrect.width
dstbitmap.blt(x + left, y + top, srcbitmap, srcrect)
x += srcrect.width
end
@@ -349,14 +350,14 @@ class Window
backopac = self.back_opacity * self.opacity / 255
contopac = self.contents_opacity
cursoropac = @cursoropacity * contopac / 255
for i in 0...4
4.times do |i|
@sprites["corner#{i}"].bitmap = @_windowskin
@sprites["scroll#{i}"].bitmap = @_windowskin
end
@sprites["pause"].bitmap = @_windowskin
@sprites["contents"].bitmap = @contents
if @_windowskin && !@_windowskin.disposed?
for i in 0...4
4.times do |i|
@sprites["corner#{i}"].opacity = @opacity
@sprites["corner#{i}"].tone = @tone
@sprites["corner#{i}"].color = @color
@@ -373,7 +374,7 @@ class Window
@sprites["scroll#{i}"].color = @color
@sprites["scroll#{i}"].visible = @visible
end
for i in ["back","cursor","pause","contents"]
["back", "cursor", "pause", "contents"].each do |i|
@sprites[i].color = @color
@sprites[i].tone = @tone
@sprites[i].blend_type = @blend_type
@@ -395,7 +396,7 @@ class Window
@sprites["scroll3"].visible = @visible && hascontents &&
(@contents.height - @oy) > @height - 32
else
for i in 0...4
4.times do |i|
@sprites["corner#{i}"].visible = false
@sprites["side#{i}"].visible = false
@sprites["scroll#{i}"].visible = false
@@ -409,7 +410,7 @@ class Window
@sprites["pause"].visible = false
@sprites["cursor"].visible = false
end
for i in @sprites
@sprites.each do |i|
i[1].z = @z
end
if @rpgvx
@@ -432,10 +433,10 @@ class Window
backRect = Rect.new(0, 0, 128, 128)
blindsRect = nil
end
@sprites["corner0"].src_rect.set(trimX,trimY+0,16,16);
@sprites["corner1"].src_rect.set(trimX+48,trimY+0,16,16);
@sprites["corner2"].src_rect.set(trimX,trimY+48,16,16);
@sprites["corner3"].src_rect.set(trimX+48,trimY+48,16,16);
@sprites["corner0"].src_rect.set(trimX, trimY + 0, 16, 16)
@sprites["corner1"].src_rect.set(trimX + 48, trimY + 0, 16, 16)
@sprites["corner2"].src_rect.set(trimX, trimY + 48, 16, 16)
@sprites["corner3"].src_rect.set(trimX + 48, trimY + 48, 16, 16)
@sprites["scroll0"].src_rect.set(trimX + 24, trimY + 16, 16, 8) # up
@sprites["scroll3"].src_rect.set(trimX + 24, trimY + 40, 16, 8) # down
@sprites["scroll1"].src_rect.set(trimX + 16, trimY + 24, 8, 16) # left
@@ -457,15 +458,14 @@ class Window
trimX + 32, trimY + 64,
trimX + 48, trimY + 64,
trimX + 32, trimY + 80,
trimX+48,trimY+80,
trimX + 48, trimY + 80
]
pauseWidth = 16
pauseHeight = 16
@sprites["pause"].src_rect.set(
pauseRects[@pauseframe*2],
pauseRects[@pauseframe*2+1],
pauseWidth,pauseHeight
)
@sprites["pause"].src_rect.set(pauseRects[@pauseframe * 2],
pauseRects[(@pauseframe * 2) + 1],
pauseWidth,
pauseHeight)
@sprites["pause"].x = @x + (@width / 2) - (pauseWidth / 2)
@sprites["pause"].y = @y + @height - 16 # 16 refers to skin margin
@sprites["contents"].x = @x + 16
@@ -486,13 +486,13 @@ class Window
@sprites["side2"].y = @y + 16
@sprites["side3"].x = @x + 16
@sprites["side3"].y = @y + @height - 16
@sprites["scroll0"].x = @x+@width / 2 - 8
@sprites["scroll0"].x = @x + (@width / 2) - 8
@sprites["scroll0"].y = @y + 8
@sprites["scroll1"].x = @x + 8
@sprites["scroll1"].y = @y+@height / 2 - 8
@sprites["scroll1"].y = @y + (@height / 2) - 8
@sprites["scroll2"].x = @x + @width - 16
@sprites["scroll2"].y = @y+@height / 2 - 8
@sprites["scroll3"].x = @x+@width / 2 - 8
@sprites["scroll2"].y = @y + (@height / 2) - 8
@sprites["scroll3"].x = @x + (@width / 2) - 8
@sprites["scroll3"].y = @y + @height - 16
@sprites["back"].x = @x + 2
@sprites["back"].y = @y + 2
@@ -522,39 +522,33 @@ class Window
@cursorbitmap.clear
@sprites["cursor"].bitmap = @cursorbitmap
@sprites["cursor"].src_rect.set(0, 0, width, height)
rect = Rect.new(margin,margin,
width - fullmargin, height - fullmargin)
rect = Rect.new(margin, margin, width - fullmargin, height - fullmargin)
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[8])
@cursorbitmap.blt(0, 0, @_windowskin, cursorrects[4]) # top left
@cursorbitmap.blt(width - margin, 0, @_windowskin, cursorrects[5]) # top right
@cursorbitmap.blt(0, height - margin, @_windowskin, cursorrects[6]) # bottom right
@cursorbitmap.blt(width - margin, height - margin, @_windowskin, cursorrects[7]) # bottom left
rect = Rect.new(margin, 0,
width - fullmargin, margin)
rect = Rect.new(margin, 0, width - fullmargin, margin)
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[0])
rect = Rect.new(0, margin,
margin, height - fullmargin)
rect = Rect.new(0, margin, margin, height - fullmargin)
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[1])
rect = Rect.new(width - margin, margin,
margin, height - fullmargin)
rect = Rect.new(width - margin, margin, margin, height - fullmargin)
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[2])
rect = Rect.new(margin, height-margin,
width - fullmargin, margin)
rect = Rect.new(margin, height - margin, width - fullmargin, margin)
@cursorbitmap.stretch_blt(rect, @_windowskin, cursorrects[3])
else
@sprites["cursor"].visible = false
@sprites["cursor"].src_rect.set(0, 0, 0, 0)
end
for i in 0...4
dwidth = (i==0 || i==3) ? @width-32 : 16
dheight = (i==0 || i==3) ? 16 : @height-32
4.times do |i|
dwidth = [0, 3].include?(i) ? @width - 32 : 16
dheight = [0, 3].include?(i) ? 16 : @height - 32
@sidebitmaps[i] = ensureBitmap(@sidebitmaps[i], dwidth, dheight)
@sprites["side#{i}"].bitmap = @sidebitmaps[i]
@sprites["side#{i}"].src_rect.set(0, 0, dwidth, dheight)
@sidebitmaps[i].clear
if sideRects[i].width > 0 && sideRects[i].height > 0
@sidebitmaps[i].stretch_blt(@sprites["side#{i}"].src_rect,
@_windowskin,sideRects[i])
@sidebitmaps[i].stretch_blt(@sprites["side#{i}"].src_rect, @_windowskin, sideRects[i])
end
end
backwidth = @width - 4
@@ -577,24 +571,24 @@ class Window
@sprites["back"].src_rect.set(0, 0, 0, 0)
end
end
if @openness!=255
opn=@openness/255.0
for k in @spritekeys
if @openness == 255
@spritekeys.each do |k|
sprite = @sprites[k]
ratio=(@height<=0) ? 0 : (sprite.y-@y)*1.0/@height
sprite.zoom_y = 1.0
end
else
opn = @openness / 255.0
@spritekeys.each do |k|
sprite = @sprites[k]
ratio = (@height <= 0) ? 0 : (sprite.y - @y) / @height.to_f
sprite.zoom_y = opn
sprite.oy = 0
sprite.y = (@y + (@height / 2.0) + (@height * ratio * opn) - (@height / 2 * opn)).floor
end
else
for k in @spritekeys
sprite=@sprites[k]
sprite.zoom_y=1.0
end
end
i = 0
# Ensure Z order
for k in @spritekeys
@spritekeys.each do |k|
sprite = @sprites[k]
y = sprite.y
sprite.y = i

View File

@@ -66,7 +66,7 @@ class SpriteWindow < Window
@sidebitmaps = [nil, nil, nil, nil]
@cursorbitmap = nil
@bgbitmap = nil
for i in @spritekeys
@spritekeys.each do |i|
@sprites[i] = Sprite.new(@viewport)
end
@disposed = false
@@ -112,17 +112,17 @@ class SpriteWindow < Window
def dispose
if !self.disposed?
for i in @sprites
i[1].dispose if i[1]
@sprites.each do |i|
i[1]&.dispose
@sprites[i[0]] = nil
end
for i in 0...@sidebitmaps.length
@sidebitmaps[i].dispose if @sidebitmaps[i]
@sidebitmaps.each_with_index do |bitmap, i|
bitmap&.dispose
@sidebitmaps[i] = nil
end
@blankcontents.dispose
@cursorbitmap.dispose if @cursorbitmap
@backbitmap.dispose if @backbitmap
@cursorbitmap&.dispose
@backbitmap&.dispose
@sprites.clear
@sidebitmaps.clear
@_windowskin = nil
@@ -142,10 +142,8 @@ class SpriteWindow < Window
def viewport=(value)
@viewport = value
for i in @spritekeys
@sprites[i].dispose if @sprites[i]
end
for i in @spritekeys
@spritekeys.each do |i|
@sprites[i]&.dispose
if @sprites[i].is_a?(Sprite)
@sprites[i] = Sprite.new(@viewport)
else
@@ -191,10 +189,10 @@ class SpriteWindow < Window
end
def cursor_rect=(value)
if !value
@cursor_rect.empty
else
if value
@cursor_rect.set(value.x, value.y, value.width, value.height)
else
@cursor_rect.empty
end
end
@@ -290,7 +288,7 @@ class SpriteWindow < Window
def flash(color, duration)
return if disposed?
@flash = duration + 1
for i in @sprites
@sprites.each do |i|
i[1].flash(color, duration)
end
end
@@ -306,11 +304,10 @@ class SpriteWindow < Window
@cursoropacity += 8
@cursorblink = 0 if @cursoropacity >= 255
end
privRefreshCursor
else
@cursoropacity = 128
privRefreshCursor
end
privRefreshCursor
if @pause
oldpauseframe = @pauseframe
oldpauseopacity = @pauseopacity
@@ -320,7 +317,7 @@ class SpriteWindow < Window
end
privRefresh if mustchange
if @flash > 0
for i in @sprites.values
@sprites.each_value do |i|
i.update
end
@flash -= 1
@@ -361,7 +358,7 @@ class SpriteWindow < Window
@trim = [16, 16, 16, 16]
end
else
if value && value.is_a?(Bitmap) && !value.disposed? && value.width==128
if value.is_a?(Bitmap) && !value.disposed? && value.width == 128
@rpgvx = true
else
@rpgvx = false
@@ -445,7 +442,7 @@ class SpriteWindow < Window
def ensureBitmap(bitmap, dwidth, dheight)
if !bitmap || bitmap.disposed? || bitmap.width < dwidth || bitmap.height < dheight
bitmap.dispose if bitmap
bitmap&.dispose
bitmap = Bitmap.new([1, dwidth].max, [1, dheight].max)
end
return bitmap
@@ -455,8 +452,12 @@ class SpriteWindow < Window
return if !srcbitmap || srcbitmap.disposed?
left = dstrect.x
top = dstrect.y
y=0;loop do break unless y<dstrect.height
x=0;loop do break unless x<dstrect.width
y = 0
loop do
break unless y < dstrect.height
x = 0
loop do
break unless x < dstrect.width
dstbitmap.blt(x + left, y + top, srcbitmap, srcrect)
x += srcrect.width
end
@@ -476,20 +477,20 @@ class SpriteWindow < Window
contopac = self.contents_opacity
cursoropac = @cursoropacity * contopac / 255
haveskin = @_windowskin && !@_windowskin.disposed?
for i in 0...4
4.times do |i|
@sprites["corner#{i}"].bitmap = @_windowskin
@sprites["scroll#{i}"].bitmap = @_windowskin
end
@sprites["pause"].bitmap = @_windowskin
@sprites["contents"].bitmap = @contents
if haveskin
for i in 0...4
@sprites["corner#{i}"].opacity=@opacity
4.times do |i|
@sprites["corner#{i}"].opacity = backopac
@sprites["corner#{i}"].tone = @tone
@sprites["corner#{i}"].color = @color
@sprites["corner#{i}"].visible = @visible
@sprites["corner#{i}"].blend_type = @blend_type
@sprites["side#{i}"].opacity=@opacity
@sprites["side#{i}"].opacity = backopac
@sprites["side#{i}"].tone = @tone
@sprites["side#{i}"].color = @color
@sprites["side#{i}"].blend_type = @blend_type
@@ -500,7 +501,7 @@ class SpriteWindow < Window
@sprites["scroll#{i}"].visible = @visible
@sprites["scroll#{i}"].blend_type = @blend_type
end
for i in ["back","cursor","pause","contents"]
["back", "cursor", "pause", "contents"].each do |i|
@sprites[i].color = @color
@sprites[i].tone = @tone
@sprites[i].blend_type = @blend_type
@@ -523,7 +524,7 @@ class SpriteWindow < Window
@sprites["scroll2"].visible = false
@sprites["scroll3"].visible = false
else
for i in 0...4
4.times do |i|
@sprites["corner#{i}"].visible = false
@sprites["side#{i}"].visible = false
@sprites["scroll#{i}"].visible = false
@@ -537,7 +538,7 @@ class SpriteWindow < Window
@sprites["pause"].visible = false
@sprites["cursor"].visible = false
end
for i in @spritekeys
@spritekeys.each do |i|
@sprites[i].z = @z
end
if (@compat & CompatBits::CorrectZ) > 0 && @skinformat == 0 && !@rpgvx
@@ -567,33 +568,29 @@ class SpriteWindow < Window
blindsRect = nil
end
if @_windowskin && !@_windowskin.disposed?
@sprites["corner0"].src_rect.set(trimX,trimY+0,16,16);
@sprites["corner1"].src_rect.set(trimX+48,trimY+0,16,16);
@sprites["corner2"].src_rect.set(trimX,trimY+48,16,16);
@sprites["corner3"].src_rect.set(trimX+48,trimY+48,16,16);
@sprites["corner0"].src_rect.set(trimX, trimY + 0, 16, 16)
@sprites["corner1"].src_rect.set(trimX + 48, trimY + 0, 16, 16)
@sprites["corner2"].src_rect.set(trimX, trimY + 48, 16, 16)
@sprites["corner3"].src_rect.set(trimX + 48, trimY + 48, 16, 16)
@sprites["scroll0"].src_rect.set(trimX + 24, trimY + 16, 16, 8) # up
@sprites["scroll3"].src_rect.set(trimX + 24, trimY + 40, 16, 8) # down
@sprites["scroll1"].src_rect.set(trimX + 16, trimY + 24, 8, 16) # left
@sprites["scroll2"].src_rect.set(trimX + 40, trimY + 24, 8, 16) # right
cursorX = trimX
cursorY = trimY + 64
sideRects=[
Rect.new(trimX+16,trimY+0,32,16),
sideRects = [Rect.new(trimX + 16, trimY + 0, 32, 16),
Rect.new(trimX, trimY + 16, 16, 32),
Rect.new(trimX + 48, trimY + 16, 16, 32),
Rect.new(trimX+16,trimY+48,32,16)
]
pauseRects=[
trimX+32,trimY+64,
Rect.new(trimX + 16, trimY + 48, 32, 16)]
pauseRects = [trimX + 32, trimY + 64,
trimX + 48, trimY + 64,
trimX + 32, trimY + 80,
trimX+48,trimY+80,
]
trimX + 48, trimY + 80]
pauseWidth = 16
pauseHeight = 16
@sprites["pause"].src_rect.set(
pauseRects[@pauseframe * 2],
pauseRects[@pauseframe*2+1],
pauseRects[(@pauseframe * 2) + 1],
pauseWidth, pauseHeight
)
end
@@ -613,12 +610,11 @@ class SpriteWindow < Window
endX = (!@_windowskin || @_windowskin.disposed?) ? @skinrect.x : @_windowskin.width - cx
# height of bottom end of window
endY = (!@_windowskin || @_windowskin.disposed?) ? @skinrect.y : @_windowskin.height - cy
@sprites["corner0"].src_rect.set(0,0,startX,startY);
@sprites["corner1"].src_rect.set(cx,0,endX,startY);
@sprites["corner2"].src_rect.set(0,cy,startX,endY);
@sprites["corner3"].src_rect.set(cx,cy,endX,endY);
backRect=Rect.new(@skinrect.x,@skinrect.y,
@skinrect.width,@skinrect.height);
@sprites["corner0"].src_rect.set(0, 0, startX, startY)
@sprites["corner1"].src_rect.set(cx, 0, endX, startY)
@sprites["corner2"].src_rect.set(0, cy, startX, endY)
@sprites["corner3"].src_rect.set(cx, cy, endX, endY)
backRect = Rect.new(@skinrect.x, @skinrect.y, @skinrect.width, @skinrect.height)
blindsRect = nil
sideRects = [
Rect.new(startX, 0, @skinrect.width, startY), # side0 (top)
@@ -635,16 +631,14 @@ class SpriteWindow < Window
end
@sprites["contents"].x = @x + trimStartX
@sprites["contents"].y = @y + trimStartY
if (@compat & CompatBits::ShowScrollArrows)>0 && @skinformat==0
# Compatibility mode: Make scroll arrows visible
if @skinformat==0 && @_windowskin && !@_windowskin.disposed? &&
if (@compat & CompatBits::ShowScrollArrows) > 0 && @skinformat == 0 &&
@_windowskin && !@_windowskin.disposed? &&
@contents && !@contents.disposed?
@sprites["scroll0"].visible = @visible && hascontents && @oy > 0
@sprites["scroll1"].visible = @visible && hascontents && @ox > 0
@sprites["scroll2"].visible = @visible && (@contents.width - @ox) > @width - trimWidth
@sprites["scroll3"].visible = @visible && (@contents.height - @oy) > @height - trimHeight
end
end
if @_windowskin && !@_windowskin.disposed?
borderX = startX + endX
borderY = startY + endY
@@ -664,13 +658,13 @@ class SpriteWindow < Window
@sprites["side2"].y = @y + startY
@sprites["side3"].x = @x + startX
@sprites["side3"].y = @y + @height - endY
@sprites["scroll0"].x = @x+@width / 2 - 8
@sprites["scroll0"].x = @x + (@width / 2) - 8
@sprites["scroll0"].y = @y + 8
@sprites["scroll1"].x = @x + 8
@sprites["scroll1"].y = @y+@height / 2 - 8
@sprites["scroll1"].y = @y + (@height / 2) - 8
@sprites["scroll2"].x = @x + @width - 16
@sprites["scroll2"].y = @y+@height / 2 - 8
@sprites["scroll3"].x = @x+@width / 2 - 8
@sprites["scroll2"].y = @y + (@height / 2) - 8
@sprites["scroll3"].x = @x + (@width / 2) - 8
@sprites["scroll3"].y = @y + @height - 16
@sprites["cursor"].x = @x + startX + @cursor_rect.x
@sprites["cursor"].y = @y + startY + @cursor_rect.y
@@ -729,7 +723,7 @@ class SpriteWindow < Window
@sprites["cursor"].src_rect.set(0, 0, 0, 0)
end
end
for i in 0..3
4.times do |i|
case i
when 0
dwidth = @width - startX - endX
@@ -785,26 +779,26 @@ class SpriteWindow < Window
@sprites["back"].src_rect.set(0, 0, 0, 0)
end
end
if @openness!=255
opn=@openness/255.0
for k in @spritekeys
if @openness == 255
@spritekeys.each do |k|
sprite = @sprites[k]
ratio=(@height<=0) ? 0 : (sprite.y-@y)*1.0/@height
sprite.zoom_x = 1.0
sprite.zoom_y = 1.0
end
else
opn = @openness / 255.0
@spritekeys.each do |k|
sprite = @sprites[k]
ratio = (@height <= 0) ? 0 : (sprite.y - @y) / @height.to_f
sprite.zoom_y = opn
sprite.zoom_x = 1.0
sprite.oy = 0
sprite.y = (@y + (@height / 2.0) + (@height * ratio * opn) - (@height / 2 * opn)).floor
end
else
for k in @spritekeys
sprite=@sprites[k]
sprite.zoom_x=1.0
sprite.zoom_y=1.0
end
end
i = 0
# Ensure Z order
for k in @spritekeys
@spritekeys.each do |k|
sprite = @sprites[k]
y = sprite.y
sprite.y = i
@@ -834,19 +828,19 @@ class SpriteWindow_Base < SpriteWindow
self.width = width
self.height = height
self.z = 100
@curframe=MessageConfig.pbGetSystemFrame()
@curfont=MessageConfig.pbGetSystemFontName()
@curframe = MessageConfig.pbGetSystemFrame
@curfont = MessageConfig.pbGetSystemFontName
@sysframe = AnimatedBitmap.new(@curframe)
RPG::Cache.retain(@curframe) if @curframe && !@curframe.empty?
@customskin = nil
__setWindowskin(@sysframe.bitmap)
__resolveSystemFrame()
__resolveSystemFrame
pbSetSystemFont(self.contents) if self.contents
end
def __setWindowskin(skin)
if skin && (skin.width==192 && skin.height==128) || # RPGXP Windowskin
(skin.width==128 && skin.height==128) # RPGVX Windowskin
if skin && ((skin.width == 192 && skin.height == 128) || # RPGXP Windowskin
(skin.width == 128 && skin.height == 128)) # RPGVX Windowskin
self.skinformat = 0
else
self.skinformat = 1
@@ -857,7 +851,7 @@ class SpriteWindow_Base < SpriteWindow
def __resolveSystemFrame
if self.skinformat == 1
if !@resolvedFrame
@resolvedFrame=MessageConfig.pbGetSystemFrame()
@resolvedFrame = MessageConfig.pbGetSystemFrame
@resolvedFrame.sub!(/\.[^\.\/\\]+$/, "")
end
self.loadSkinFile("#{@resolvedFrame}.txt") if @resolvedFrame != ""
@@ -865,7 +859,7 @@ class SpriteWindow_Base < SpriteWindow
end
def setSkin(skin) # Filename of windowskin to apply. Supports XP, VX, and animated skins.
@customskin.dispose if @customskin
@customskin&.dispose
@customskin = nil
resolvedName = pbResolveBitmap(skin)
return if nil_or_empty?(resolvedName)
@@ -879,10 +873,10 @@ class SpriteWindow_Base < SpriteWindow
end
def setSystemFrame
@customskin.dispose if @customskin
@customskin&.dispose
@customskin = nil
__setWindowskin(@sysframe.bitmap)
__resolveSystemFrame()
__resolveSystemFrame
end
def update
@@ -900,23 +894,23 @@ class SpriteWindow_Base < SpriteWindow
end
end
end
if @curframe!=MessageConfig.pbGetSystemFrame()
@curframe=MessageConfig.pbGetSystemFrame()
if @curframe != MessageConfig.pbGetSystemFrame
@curframe = MessageConfig.pbGetSystemFrame
if @sysframe && !@customskin
@sysframe.dispose if @sysframe
@sysframe&.dispose
@sysframe = AnimatedBitmap.new(@curframe)
RPG::Cache.retain(@curframe) if @curframe && !@curframe.empty?
@resolvedFrame = nil
__setWindowskin(@sysframe.bitmap)
__resolveSystemFrame()
__resolveSystemFrame
end
begin
refresh
rescue NoMethodError
end
end
if @curfont!=MessageConfig.pbGetSystemFontName()
@curfont=MessageConfig.pbGetSystemFontName()
if @curfont != MessageConfig.pbGetSystemFontName
@curfont = MessageConfig.pbGetSystemFontName
if self.contents && !self.contents.disposed?
pbSetSystemFont(self.contents)
end
@@ -928,9 +922,9 @@ class SpriteWindow_Base < SpriteWindow
end
def dispose
self.contents.dispose if self.contents
self.contents&.dispose
@sysframe.dispose
@customskin.dispose if @customskin
@customskin&.dispose
super
end
end

View File

@@ -101,7 +101,7 @@ class Window_UnformattedTextPokemon < SpriteWindow_Base
self.contents = pbDoEnsureBitmap(self.contents, self.width - self.borderX,
self.height - self.borderY)
self.contents.clear
drawTextEx(self.contents,0,4,self.contents.width,0,
drawTextEx(self.contents, 0, -2, self.contents.width, 0, # TEXT OFFSET
@text.gsub(/\r/, ""), @baseColor, @shadowColor)
end
end
@@ -134,7 +134,7 @@ class Window_AdvancedTextPokemon < SpriteWindow_Base
@lastDrawnChar = -1
@fmtchars = []
@frameskipChanged = false
@frameskip = MessageConfig.pbGetTextSpeed()
@frameskip = MessageConfig.pbGetTextSpeed
super(0, 0, 33, 33)
@pausesprite = nil
@text = ""
@@ -160,7 +160,7 @@ class Window_AdvancedTextPokemon < SpriteWindow_Base
def dispose
return if disposed?
@pausesprite.dispose if @pausesprite
@pausesprite&.dispose
@pausesprite = nil
super
end
@@ -235,7 +235,7 @@ class Window_AdvancedTextPokemon < SpriteWindow_Base
cwidth = (maxwidth < 0) ? Graphics.width : maxwidth
chars = getFormattedTextForDims(self.contents, 0, 0,
cwidth - self.borderX - 2 - 6, -1, text, @lineHeight, true)
for ch in chars
chars.each do |ch|
dims[0] = [dims[0], ch[1] + ch[3]].max
dims[1] = [dims[1], ch[2] + ch[4]].max
end
@@ -312,12 +312,11 @@ class Window_AdvancedTextPokemon < SpriteWindow_Base
self.width - self.borderX - SpriteWindow_Base::TEXTPADDING, -1,
shadowctag(@baseColor, @shadowColor) + value, 32, true)
@oldfont = self.contents.font.clone
for ch in fmt
fmt.each do |ch|
chx = ch[1] + ch[3]
chy = ch[2] + ch[4]
width = chx if width < chx
height = chy if height < chy
ch[2] += 4
if !ch[5] && ch[0] == "\n"
numlines += 1
if numlines >= visiblelines
@@ -340,12 +339,11 @@ class Window_AdvancedTextPokemon < SpriteWindow_Base
self.width - self.borderX - SpriteWindow_Base::TEXTPADDING, -1,
shadowctag(@baseColor, @shadowColor) + value, 32, true)
@oldfont = self.contents.font.clone
for ch in @fmtchars
@fmtchars.each do |ch|
chx = ch[1] + ch[3]
chy = ch[2] + ch[4]
width = chx if width < chx
height = chy if height < chy
ch[2] += 4
@textchars.push(ch[5] ? "" : ch[0])
end
end
@@ -390,7 +388,7 @@ class Window_AdvancedTextPokemon < SpriteWindow_Base
def maxPosition
pos = 0
for ch in @fmtchars
@fmtchars.each do |ch|
# index after the last character's index
pos = ch[14] + 1 if pos < ch[14] + 1
end
@@ -481,7 +479,7 @@ class Window_AdvancedTextPokemon < SpriteWindow_Base
end
maxX = self.width - self.borderX
maxY = self.height - self.borderY
for i in @drawncurchar+1..numchars
(@drawncurchar + 1..numchars).each do |i|
next if i >= @fmtchars.length
if !self.letterbyletter
next if @fmtchars[i][1] >= maxX
@@ -490,10 +488,8 @@ class Window_AdvancedTextPokemon < SpriteWindow_Base
drawSingleFormattedChar(self.contents, @fmtchars[i])
@lastDrawnChar = i
end
if !self.letterbyletter
# all characters were drawn, reset old font
self.contents.font = @oldfont if @oldfont
end
self.contents.font = @oldfont if !self.letterbyletter && @oldfont
if numchars > 0 && numchars != @numtextchars
fch = @fmtchars[numchars - 1]
if fch
@@ -579,7 +575,7 @@ class Window_AdvancedTextPokemon < SpriteWindow_Base
def update
super
@pausesprite.update if @pausesprite && @pausesprite.visible
@pausesprite.update if @pausesprite&.visible
if @waitcount > 0
@waitcount -= 1
return
@@ -601,7 +597,7 @@ class Window_AdvancedTextPokemon < SpriteWindow_Base
break if @textchars[@curchar] == "\n" || # newline
@textchars[@curchar] == "\1" || # pause
@textchars[@curchar] == "\2" || # letter-by-letter break
@textchars[@curchar]==nil
@textchars[@curchar].nil?
end
end
end
@@ -621,7 +617,7 @@ class Window_InputNumberPokemon < SpriteWindow_Base
@sign = false
@negative = false
super(0, 0, 32, 32)
self.width=digits_max*24+8+self.borderX
self.width = (digits_max * 24) + 8 + self.borderX
self.height = 32 + self.borderY
colors = getDefaultTextColors(self.windowskin)
@baseColor = colors[0]
@@ -644,16 +640,16 @@ class Window_InputNumberPokemon < SpriteWindow_Base
value = 0 if !value.is_a?(Numeric)
if @sign
@negative = (value < 0)
@number = [value.abs, 10 ** @digits_max - 1].min
@number = [value.abs, (10**@digits_max) - 1].min
else
@number = [[value, 0].max, 10 ** @digits_max - 1].min
@number = [[value, 0].max, (10**@digits_max) - 1].min
end
refresh
end
def sign=(value)
@sign = value
self.width=@digits_max*24+8+self.borderX+(@sign ? 24 : 0)
self.width = (@digits_max * 24) + 8 + self.borderX + (@sign ? 24 : 0)
@index = (@digits_max - 1) + (@sign ? 1 : 0)
refresh
end
@@ -667,7 +663,7 @@ class Window_InputNumberPokemon < SpriteWindow_Base
if @sign
textHelper(0, 0, @negative ? "-" : "+", 0)
end
for i in 0...@digits_max
@digits_max.times do |i|
index = i + (@sign ? 1 : 0)
textHelper(index * 24, 0, s[i, 1], index)
end
@@ -679,7 +675,7 @@ class Window_InputNumberPokemon < SpriteWindow_Base
refresh if @frame % 15 == 0
if self.active
if Input.repeat?(Input::UP) || Input.repeat?(Input::DOWN)
pbPlayCursorSE()
pbPlayCursorSE
if @index == 0 && @sign
@negative = !@negative
else
@@ -696,14 +692,14 @@ class Window_InputNumberPokemon < SpriteWindow_Base
refresh
elsif Input.repeat?(Input::RIGHT)
if digits >= 2
pbPlayCursorSE()
pbPlayCursorSE
@index = (@index + 1) % digits
@frame = 0
refresh
end
elsif Input.repeat?(Input::LEFT)
if digits >= 2
pbPlayCursorSE()
pbPlayCursorSE
@index = (@index + digits - 1) % digits
@frame = 0
refresh
@@ -717,9 +713,12 @@ class Window_InputNumberPokemon < SpriteWindow_Base
def textHelper(x, y, text, i)
textwidth = self.contents.text_size(text).width
pbDrawShadowText(self.contents, x+(12-textwidth/2), y, textwidth+4, 32, text, @baseColor, @shadowColor)
pbDrawShadowText(self.contents,
x + (12 - (textwidth / 2)),
y - 2 + (self.contents.text_offset_y || 0), # TEXT OFFSET (the - 2)
textwidth + 4, 32, text, @baseColor, @shadowColor)
if @index == i && @active && @frame / 15 == 0
self.contents.fill_rect(x+(12-textwidth/2), y+30, textwidth, 2, @baseColor)
self.contents.fill_rect(x + (12 - (textwidth / 2)), y + 30, textwidth, 2, @baseColor)
end
end
end
@@ -731,12 +730,13 @@ end
#===============================================================================
class SpriteWindow_Selectable < SpriteWindow_Base
attr_reader :index
attr_writer :ignore_input
def initialize(x, y, width, height)
super(x, y, width, height)
@item_max = 1
@column_max = 1
@virtualOy=0
@virtualOy = 2 # TEXT OFFSET
@index = -1
@row_height = 32
@column_spacing = 32
@@ -789,10 +789,6 @@ class SpriteWindow_Selectable < SpriteWindow_Base
end
end
def ignore_input=(value)
@ignore_input=value
end
def count
return @item_max
end
@@ -808,7 +804,7 @@ class SpriteWindow_Selectable < SpriteWindow_Base
def top_row=(row)
row = row_max - 1 if row > row_max - 1
row = 0 if row < 0
@virtualOy = row*@row_height
@virtualOy = (row * @row_height) + 2 # TEXT OFFSET (the + 2)
end
def top_item
@@ -828,9 +824,9 @@ class SpriteWindow_Selectable < SpriteWindow_Base
item > self.top_item + self.page_item_max
return Rect.new(0, 0, 0, 0)
else
cursor_width = (self.width-self.borderX-(@column_max-1)*@column_spacing) / @column_max
cursor_width = (self.width - self.borderX - ((@column_max - 1) * @column_spacing)) / @column_max
x = item % @column_max * (cursor_width + @column_spacing)
y = item / @column_max * @row_height - @virtualOy
y = (item / @column_max * @row_height) - @virtualOy
return Rect.new(x, y, cursor_width, @row_height)
end
end
@@ -850,7 +846,7 @@ class SpriteWindow_Selectable < SpriteWindow_Base
oldindex = @index
@index = (@index - @column_max + @item_max) % @item_max
if @index != oldindex
pbPlayCursorSE()
pbPlayCursorSE
update_cursor_rect
end
end
@@ -860,7 +856,7 @@ class SpriteWindow_Selectable < SpriteWindow_Base
oldindex = @index
@index = (@index + @column_max) % @item_max
if @index != oldindex
pbPlayCursorSE()
pbPlayCursorSE
update_cursor_rect
end
end
@@ -869,7 +865,7 @@ class SpriteWindow_Selectable < SpriteWindow_Base
oldindex = @index
@index -= 1
if @index != oldindex
pbPlayCursorSE()
pbPlayCursorSE
update_cursor_rect
end
end
@@ -878,7 +874,7 @@ class SpriteWindow_Selectable < SpriteWindow_Base
oldindex = @index
@index += 1
if @index != oldindex
pbPlayCursorSE()
pbPlayCursorSE
update_cursor_rect
end
end
@@ -887,7 +883,7 @@ class SpriteWindow_Selectable < SpriteWindow_Base
oldindex = @index
@index = [self.index - self.page_item_max, 0].max
if @index != oldindex
pbPlayCursorSE()
pbPlayCursorSE
self.top_row -= self.page_row_max
update_cursor_rect
end
@@ -897,7 +893,7 @@ class SpriteWindow_Selectable < SpriteWindow_Base
oldindex = @index
@index = [self.index + self.page_item_max, @item_max - 1].min
if @index != oldindex
pbPlayCursorSE()
pbPlayCursorSE
self.top_row += self.page_row_max
update_cursor_rect
end
@@ -949,7 +945,7 @@ class SpriteWindow_Selectable < SpriteWindow_Base
# End of code
cursor_width = (self.width - self.borderX) / @column_max
x = self.index % @column_max * (cursor_width + @column_spacing)
y = self.index / @column_max * @row_height - @virtualOy
y = (self.index / @column_max * @row_height) - @virtualOy
self.cursor_rect.set(x, y, cursor_width, @row_height)
self.refresh if dorefresh || force
end
@@ -995,8 +991,8 @@ module UpDownArrowMixin
def adjustForZoom(sprite)
sprite.zoom_x = self.zoom_x
sprite.zoom_y = self.zoom_y
sprite.x = sprite.x*self.zoom_x + self.offset_x/self.zoom_x
sprite.y = sprite.y*self.zoom_y + self.offset_y/self.zoom_y
sprite.x = (sprite.x * self.zoom_x) + (self.offset_x / self.zoom_x)
sprite.y = (sprite.y * self.zoom_y) + (self.offset_y / self.zoom_y)
end
def update
@@ -1087,7 +1083,7 @@ class Window_DrawableCommand < SpriteWindow_SelectableEx
width = 0
tmpbitmap = BitmapWrapper.new(1, 1)
pbSetSystemFont(tmpbitmap)
for i in commands
commands.each do |i|
width = [width, tmpbitmap.text_size(i).width].max
end
# one 16 to allow cursor
@@ -1095,8 +1091,8 @@ class Window_DrawableCommand < SpriteWindow_SelectableEx
tmpbitmap.dispose
end
# Store suggested width and height of window
dims[0] = [self.borderX+1,(width*self.columns)+self.borderX+
(self.columns-1)*self.columnSpacing].max
dims[0] = [self.borderX + 1,
(width * self.columns) + self.borderX + ((self.columns - 1) * self.columnSpacing)].max
dims[1] = [self.borderY + 1, windowheight].max
dims[1] = [dims[1], Graphics.height].min
end
@@ -1111,7 +1107,7 @@ class Window_DrawableCommand < SpriteWindow_SelectableEx
def drawCursor(index, rect)
if self.index == index
pbCopyBitmap(self.contents,@selarrow.bitmap,rect.x,rect.y)
pbCopyBitmap(self.contents, @selarrow.bitmap, rect.x, rect.y + 2) # TEXT OFFSET (counters the offset above)
end
return Rect.new(rect.x + 16, rect.y, rect.width - 16, rect.height)
end
@@ -1120,16 +1116,15 @@ class Window_DrawableCommand < SpriteWindow_SelectableEx
return 0
end
def drawItem(index,count,rect) # to be implemented by derived classes
end
def drawItem(index, count, rect); end # to be implemented by derived classes
def refresh
@item_max = itemCount()
@item_max = itemCount
dwidth = self.width - self.borderX
dheight = self.height - self.borderY
self.contents = pbDoEnsureBitmap(self.contents, dwidth, dheight)
self.contents.clear
for i in 0...@item_max
@item_max.times do |i|
next if i < self.top_item || i > self.top_item + self.page_item_max
drawItem(i, @item_max, itemRect(i))
end
@@ -1229,8 +1224,8 @@ class Window_CommandPokemon < Window_DrawableCommand
def drawItem(index, _count, rect)
pbSetSystemFont(self.contents) if @starting
rect = drawCursor(index, rect)
pbDrawShadowText(self.contents,rect.x,rect.y,rect.width,rect.height,
@commands[index],self.baseColor,self.shadowColor)
pbDrawShadowText(self.contents, rect.x, rect.y + (self.contents.text_offset_y || 0),
rect.width, rect.height, @commands[index], self.baseColor, self.shadowColor)
end
end
@@ -1254,7 +1249,7 @@ class Window_AdvancedCommandPokemon < Window_DrawableCommand
chars = getFormattedText(bitmap, 0, 0,
Graphics.width - self.borderX - SpriteWindow_Base::TEXTPADDING - 16,
-1, text, self.rowHeight, true, true)
for ch in chars
chars.each do |ch|
dims[0] = dims[0] ? [dims[0], ch[1]].min : ch[1]
dims[1] = [dims[1], ch[1] + ch[3]].max
end
@@ -1348,8 +1343,7 @@ class Window_AdvancedCommandPokemon < Window_DrawableCommand
pbDrawShadowText(self.contents, rect.x, rect.y, rect.width, rect.height,
@commands[index], self.baseColor, self.shadowColor)
else
chars=getFormattedText(
self.contents,rect.x,rect.y+4,rect.width,rect.height,
chars = getFormattedText(self.contents, rect.x, rect.y + 4, rect.width, rect.height,
@commands[index], rect.height, true, true)
drawFormattedChars(self.contents, chars)
end

View File

@@ -13,7 +13,7 @@ class IconWindow < SpriteWindow_Base
end
def dispose
clearBitmaps()
clearBitmaps
super
end
@@ -26,7 +26,7 @@ class IconWindow < SpriteWindow_Base
end
def clearBitmaps
@_iconbitmap.dispose if @_iconbitmap
@_iconbitmap&.dispose
@_iconbitmap = nil
self.contents = nil if !self.disposed?
end
@@ -38,15 +38,15 @@ class IconWindow < SpriteWindow_Base
# Sets the icon's filename.
def setBitmap(file, hue = 0)
clearBitmaps()
clearBitmaps
@name = file
return if file==nil
if file!=""
return if file.nil?
if file == ""
@_iconbitmap = nil
else
@_iconbitmap = AnimatedBitmap.new(file, hue)
# for compatibility
self.contents = @_iconbitmap ? @_iconbitmap.bitmap : nil
else
@_iconbitmap=nil
end
end
end
@@ -67,7 +67,7 @@ class PictureWindow < SpriteWindow_Base
end
def dispose
clearBitmaps()
clearBitmaps
super
end
@@ -84,7 +84,7 @@ class PictureWindow < SpriteWindow_Base
end
def clearBitmaps
@_iconbitmap.dispose if @_iconbitmap
@_iconbitmap&.dispose
@_iconbitmap = nil
self.contents = nil if !self.disposed?
end
@@ -92,25 +92,24 @@ class PictureWindow < SpriteWindow_Base
# Sets the icon's bitmap or filename. (hue parameter
# is ignored unless pathOrBitmap is a filename)
def setBitmap(pathOrBitmap, hue = 0)
clearBitmaps()
if pathOrBitmap!=nil && pathOrBitmap!=""
if pathOrBitmap.is_a?(Bitmap)
clearBitmaps
if pathOrBitmap && pathOrBitmap != ""
case pathOrBitmap
when Bitmap
@_iconbitmap = pathOrBitmap
self.contents = @_iconbitmap
self.width = @_iconbitmap.width + self.borderX
self.height = @_iconbitmap.height + self.borderY
elsif pathOrBitmap.is_a?(AnimatedBitmap)
when AnimatedBitmap
@_iconbitmap = pathOrBitmap
self.contents = @_iconbitmap.bitmap
self.width = @_iconbitmap.bitmap.width + self.borderX
self.height = @_iconbitmap.bitmap.height + self.borderY
else
@_iconbitmap = AnimatedBitmap.new(pathOrBitmap, hue)
self.contents=@_iconbitmap ? @_iconbitmap.bitmap : nil
self.width=@_iconbitmap ? @_iconbitmap.bitmap.width+self.borderX :
32+self.borderX
self.height=@_iconbitmap ? @_iconbitmap.bitmap.height+self.borderY :
32+self.borderY
self.contents = @_iconbitmap&.bitmap
self.width = self.borderX + (@_iconbitmap&.bitmap&.width || 32)
self.height = self.borderY + (@_iconbitmap&.bitmap&.height || 32)
end
else
@_iconbitmap = nil

View File

@@ -245,13 +245,14 @@ class IconSprite < SpriteWrapper
attr_reader :name
def initialize(*args)
if args.length==0
case args.length
when 0
super(nil)
self.bitmap = nil
elsif args.length==1
when 1
super(args[0])
self.bitmap = nil
elsif args.length==2
when 2
super(nil)
self.x = args[0]
self.y = args[1]
@@ -265,7 +266,7 @@ class IconSprite < SpriteWrapper
end
def dispose
clearBitmaps()
clearBitmaps
super
end
@@ -277,21 +278,21 @@ class IconSprite < SpriteWrapper
# Sets the icon's filename.
def setBitmap(file, hue = 0)
oldrc = self.src_rect
clearBitmaps()
clearBitmaps
@name = file
return if file==nil
if file!=""
return if file.nil?
if file == ""
@_iconbitmap = nil
else
@_iconbitmap = AnimatedBitmap.new(file, hue)
# for compatibility
self.bitmap = @_iconbitmap ? @_iconbitmap.bitmap : nil
self.src_rect = oldrc
else
@_iconbitmap=nil
end
end
def clearBitmaps
@_iconbitmap.dispose if @_iconbitmap
@_iconbitmap&.dispose
@_iconbitmap = nil
self.bitmap = nil if !self.disposed?
end
@@ -335,7 +336,7 @@ class ChangelingSprite < SpriteWrapper
end
def addBitmap(key, path)
@bitmaps[key].dispose if @bitmaps[key]
@bitmaps[key]&.dispose
@bitmaps[key] = AnimatedBitmap.new(path)
end
@@ -346,14 +347,14 @@ class ChangelingSprite < SpriteWrapper
def dispose
return if disposed?
for bm in @bitmaps.values; bm.dispose; end
@bitmaps.each_value { |bm| bm.dispose }
@bitmaps.clear
super
end
def update
return if disposed?
for bm in @bitmaps.values; bm.update; end
@bitmaps.each_value { |bm| bm.update }
self.bitmap = (@currentBitmap) ? @currentBitmap.bitmap : nil
end
end

View File

@@ -6,10 +6,10 @@ class AnimatedBitmap
raise "Filename is nil (missing graphic)." if file.nil?
path = file
filename = ""
if file.last != '/' # Isn't just a directory
if file.last != "/" # Isn't just a directory
split_file = file.split(/[\\\/]/)
filename = split_file.pop
path = split_file.join('/') + '/'
path = split_file.join("/") + "/"
end
if filename[/^\[\d+(?:,\d+)?\]/] # Starts with 1 or 2 numbers in square brackets
@bitmap = PngAnimatedBitmap.new(path, filename, hue)
@@ -57,7 +57,7 @@ class PngAnimatedBitmap
end
@frameDelay = delay
subWidth = panorama.width / numFrames
for i in 0...numFrames
numFrames.times do |i|
subBitmap = BitmapWrapper.new(subWidth, panorama.height)
subBitmap.blt(0, 0, panorama, Rect.new(subWidth * i, 0, subWidth, panorama.height))
@frames.push(subBitmap)
@@ -76,7 +76,7 @@ class PngAnimatedBitmap
def height; self.bitmap.height; end
def deanimate
for i in 1...@frames.length
(1...@frames.length).each do |i|
@frames[i].dispose
end
@frames = [@frames[0]]
@@ -134,9 +134,7 @@ class PngAnimatedBitmap
def copy
x = self.clone
x.frames = x.frames.clone
for i in 0...x.frames.length
x.frames[i] = x.frames[i].copy
end
x.frames.each_with_index { |frame, i| x.frames[i] = frame.copy }
return x
end
end

View File

@@ -6,225 +6,69 @@ class Plane
def refresh; end
end
#===============================================================================
# This class works around a limitation that planes are always
# 640 by 480 pixels in size regardless of the window's size.
#===============================================================================
class LargePlane < Plane
attr_accessor :borderX
attr_accessor :borderY
def initialize(viewport=nil)
@__sprite=Sprite.new(viewport)
@__disposed=false
@__ox=0
@__oy=0
@__bitmap=nil
@__visible=true
@__sprite.visible=false
@borderX=0
@borderY=0
end
def disposed?
return @__disposed
end
def dispose
if !@__disposed
@__sprite.bitmap.dispose if @__sprite.bitmap
@__sprite.dispose
@__sprite=nil
@__bitmap=nil
@__disposed=true
end
#super
end
def ox; @__ox; end
def oy; @__oy; end
def ox=(value);
return if @__ox==value
@__ox = value
refresh
end
def oy=(value);
return if @__oy==value
@__oy = value
refresh
end
def bitmap
return @__bitmap
end
def bitmap=(value)
if value==nil
if @__bitmap!=nil
@__bitmap=nil
@__sprite.visible=(@__visible && !@__bitmap.nil?)
end
elsif @__bitmap!=value && !value.disposed?
@__bitmap=value
refresh
elsif value.disposed?
if @__bitmap!=nil
@__bitmap=nil
@__sprite.visible=(@__visible && !@__bitmap.nil?)
end
end
end
def viewport; @__sprite.viewport; end
def zoom_x; @__sprite.zoom_x; end
def zoom_y; @__sprite.zoom_y; end
def opacity; @__sprite.opacity; end
def blend_type; @__sprite.blend_type; end
def visible; @__visible; end
def z; @__sprite.z; end
def color; @__sprite.color; end
def tone; @__sprite.tone; end
def zoom_x=(v);
return if @__sprite.zoom_x==v
@__sprite.zoom_x = v
refresh
end
def zoom_y=(v);
return if @__sprite.zoom_y==v
@__sprite.zoom_y = v
refresh
end
def opacity=(v); @__sprite.opacity=(v); end
def blend_type=(v); @__sprite.blend_type=(v); end
def visible=(v); @__visible=v; @__sprite.visible=(@__visible && !@__bitmap.nil?); end
def z=(v); @__sprite.z=(v); end
def color=(v); @__sprite.color=(v); end
def tone=(v); @__sprite.tone=(v); end
def update; ;end
def refresh
@__sprite.visible = (@__visible && !@__bitmap.nil?)
if @__bitmap
if !@__bitmap.disposed?
@__ox += @__bitmap.width*@__sprite.zoom_x if @__ox<0
@__oy += @__bitmap.height*@__sprite.zoom_y if @__oy<0
@__ox -= @__bitmap.width*@__sprite.zoom_x if @__ox>@__bitmap.width
@__oy -= @__bitmap.height*@__sprite.zoom_y if @__oy>@__bitmap.height
dwidth = (Graphics.width/@__sprite.zoom_x+@borderX).to_i # +2
dheight = (Graphics.height/@__sprite.zoom_y+@borderY).to_i # +2
@__sprite.bitmap = ensureBitmap(@__sprite.bitmap,dwidth,dheight)
@__sprite.bitmap.clear
tileBitmap(@__sprite.bitmap,@__bitmap,@__bitmap.rect)
else
@__sprite.visible = false
end
end
end
private
def ensureBitmap(bitmap,dwidth,dheight)
if !bitmap || bitmap.disposed? || bitmap.width<dwidth || bitmap.height<dheight
bitmap.dispose if bitmap
bitmap = Bitmap.new([1,dwidth].max,[1,dheight].max)
end
return bitmap
end
def tileBitmap(dstbitmap,srcbitmap,srcrect)
return if !srcbitmap || srcbitmap.disposed?
dstrect = dstbitmap.rect
left = (dstrect.x-@__ox/@__sprite.zoom_x).to_i
top = (dstrect.y-@__oy/@__sprite.zoom_y).to_i
while left>0; left -= srcbitmap.width; end
while top>0; top -= srcbitmap.height; end
y = top
while y<dstrect.height
x = left
while x<dstrect.width
dstbitmap.blt(x+@borderX,y+@borderY,srcbitmap,srcrect)
x += srcrect.width
end
y += srcrect.height
end
end
end
#===============================================================================
# A plane class that displays a single color.
#===============================================================================
class ColoredPlane < LargePlane
class ColoredPlane < Plane
def initialize(color, viewport = nil)
super(viewport)
self.bitmap = Bitmap.new(32, 32)
setPlaneColor(color)
set_plane_color(color)
end
def dispose
self.bitmap.dispose if self.bitmap
self.bitmap&.dispose
super
end
def setPlaneColor(value)
def set_plane_color(value)
self.bitmap.fill_rect(0, 0, self.bitmap.width, self.bitmap.height, value)
self.refresh
refresh
end
end
#===============================================================================
# A plane class that supports animated images.
#===============================================================================
class AnimatedPlane < LargePlane
class AnimatedPlane < Plane
def initialize(viewport)
super(viewport)
@bitmap = nil
end
def dispose
clearBitmaps()
clear_bitmap
super
end
def update
super
if @bitmap
@bitmap.update
self.bitmap=@bitmap.bitmap
end
end
def clearBitmaps
@bitmap.dispose if @bitmap
@bitmap=nil
self.bitmap=nil if !self.disposed?
end
def setPanorama(file, hue=0)
clearBitmaps()
return if file==nil
@bitmap=AnimatedBitmap.new("Graphics/Panoramas/"+file,hue)
end
def setFog(file, hue=0)
clearBitmaps()
return if file==nil
@bitmap=AnimatedBitmap.new("Graphics/Fogs/"+file,hue)
end
def setBitmap(file, hue = 0)
clearBitmaps()
return if file==nil
clear_bitmap
return if file.nil?
@bitmap = AnimatedBitmap.new(file, hue)
self.bitmap = @bitmap.bitmap if @bitmap
end
def set_panorama(file, hue = 0)
if file.is_a?(String) && file.length > 0
setBitmap("Graphics/Panoramas/" + file, hue)
else
clear_bitmap
end
end
def set_fog(file, hue = 0)
if file.is_a?(String) && file.length > 0
setBitmap("Graphics/Fogs/" + file, hue)
else
clear_bitmap
end
end
private
def clear_bitmap
@bitmap&.dispose
@bitmap = nil
self.bitmap = nil if !self.disposed?
end
end

View File

@@ -45,26 +45,27 @@ end
def rgbToColor(param)
return Font.default_color if !param
baseint = param.to_i(16)
if param.length==8 # 32-bit hex
case param.length
when 8 # 32-bit hex
return Color.new(
(baseint >> 24) & 0xFF,
(baseint >> 16) & 0xFF,
(baseint >> 8) & 0xFF,
(baseint) & 0xFF
)
elsif param.length==6 # 24-bit hex
when 6 # 24-bit hex
return Color.new(
(baseint >> 16) & 0xFF,
(baseint >> 8) & 0xFF,
(baseint) & 0xFF
)
elsif param.length==4 # 16-bit hex
when 4 # 16-bit hex
return Color.new(
((baseint) & 0x1F) << 3,
((baseint >> 5) & 0x1F) << 3,
((baseint >> 10) & 0x1F) << 3
)
elsif param.length==1 # Color number
when 1 # Color number
i = param.to_i
return Font.default_color if i >= 8
return [
@@ -93,11 +94,13 @@ end
def getContrastColor(color)
raise "No color given" if !color
r=color.red; g=color.green; b=color.blue
r = color.red
g = color.green
b = color.blue
yuv = [
r * 0.299 + g * 0.587 + b * 0.114,
r * -0.1687 + g * -0.3313 + b * 0.500 + 0.5,
r * 0.500 + g * -0.4187 + b * -0.0813 + 0.5
(r * 0.299) + (g * 0.587) + (b * 0.114),
(r * -0.1687) + (g * -0.3313) + (b * 0.500) + 0.5,
(r * 0.500) + (g * -0.4187) + (b * -0.0813) + 0.5
]
if yuv[0] < 127.5
yuv[0] += (255 - yuv[0]) / 2
@@ -105,9 +108,9 @@ def getContrastColor(color)
yuv[0] = yuv[0] / 2
end
return Color.new(
yuv[0] + 1.4075 * (yuv[2] - 0.5),
yuv[0] - 0.3455 * (yuv[1] - 0.5) - 0.7169 * (yuv[2] - 0.5),
yuv[0] + 1.7790 * (yuv[1] - 0.5),
yuv[0] + (1.4075 * (yuv[2] - 0.5)),
yuv[0] - (0.3455 * (yuv[1] - 0.5)) - (0.7169 * (yuv[2] - 0.5)),
yuv[0] + (1.7790 * (yuv[1] - 0.5)),
color.alpha
)
end
@@ -160,8 +163,7 @@ def getFormattedTextForDims(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight,
if newlineBreaks
text2.gsub!(/<(\/?)(br)(\s*\=\s*([^>]*))?>/i, "\n")
end
return getFormattedText(
bitmap,xDst,yDst,widthDst,heightDst,
return getFormattedText(bitmap, xDst, yDst, widthDst, heightDst,
text2, lineheight, newlineBreaks,
explicitBreaksOnly, true)
end
@@ -172,7 +174,7 @@ def getFormattedTextFast(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight,
characters = []
textchunks = []
textchunks.push(text)
text=textchunks.join("")
text = textchunks.join
textchars = text.scan(/./m)
lastword = [0, 0] # position of last word
hadspace = false
@@ -196,7 +198,7 @@ def getFormattedTextFast(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight,
if textchars[position] == "\n"
if newlineBreaks # treat newline as break
havenl = true
characters.push(["\n",x,y*lineheight+yDst,0,lineheight,false,false,
characters.push(["\n", x, (y * lineheight) + yDst, 0, lineheight, false, false,
false, colorclone, nil, false, false, "", 8, position, nil, 0])
y += 1
x = 0
@@ -222,8 +224,7 @@ def getFormattedTextFast(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight,
# Push character
if heightDst < 0 || yStart < yDst + heightDst
havenl = true if isWaitChar(textchars[position])
characters.push([
textchars[position],
characters.push([textchars[position],
x + xStart, texty, width + 2, lineheight,
false, bold, italic, colorclone, nil, false, false,
defaultfontname, bitmap.font.size, position, nil, 0])
@@ -232,12 +233,12 @@ def getFormattedTextFast(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight,
if !explicitBreaksOnly && x + 2 > widthDst && lastword[1] != 0 &&
(!hadnonspace || !hadspace)
havenl = true
characters.insert(lastword[0],["\n",x,y*lineheight+yDst,0,lineheight,
characters.insert(lastword[0], ["\n", x, (y * lineheight) + yDst, 0, lineheight,
false, false, false, colorclone, nil, false, false, "", 8, position])
lastword[0] += 1
y += 1
x = 0
for i in lastword[0]...characters.length
(lastword[0]...characters.length).each do |i|
characters[i][2] += lineheight
charwidth = characters[i][3] - 2
characters[i][1] = x
@@ -247,76 +248,36 @@ def getFormattedTextFast(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight,
end
position += 1
end
# This code looks at whether the text occupies exactly two lines when
# displayed. If it does, it balances the length of each line.
=begin
# Count total number of lines
numlines = (x==0 && y>0) ? y-1 : y
realtext = (newlineBreaks) ? text : text.gsub(/\n/," ")
if numlines==2 && !explicitBreaksOnly && !realtext[/\n/] && realtext.length>=50
# Set half to middle of text (known to contain no formatting)
half = realtext.length/2
leftSearch = 0
rightSearch = 0
# Search left for a space
i = half; while i>=0
break if realtext[i,1][/\s/]||isWaitChar(realtext[i]) # found a space
leftSearch += 1
i -= 1
end
# Search right for a space
i = half; while i<realtext.length
break if realtext[i,1][/\s/]||isWaitChar(realtext[i]) # found a space
rightSearch += 1
i += 1
end
# Move half left or right whichever is closer
trialHalf = half+((leftSearch<rightSearch) ? -leftSearch : rightSearch)
if trialHalf!=0 && trialHalf!=realtext.length
# Insert newline and re-call this function (force explicitBreaksOnly)
newText = realtext.clone
newText.insert(trialHalf,"\n")
return getFormattedTextFast(bitmap,xDst,yDst,
widthDst,heightDst,newText,lineheight,true,explicitBreaksOnly)
end
end
=end
# Eliminate spaces before newlines and pause character
if havenl
firstspace = -1
for i in 0...characters.length
characters.length.times do |i|
if characters[i][5] != false # If not a character
firstspace = -1
elsif (characters[i][0] == "\n" || isWaitChar(characters[i][0])) &&
firstspace >= 0
for j in firstspace...i
(firstspace...i).each do |j|
characters[j] = nil
end
firstspace = -1
elsif characters[i][0][/[ \r\t]/]
if firstspace<0
firstspace=i
end
firstspace = i if firstspace < 0
else
firstspace = -1
end
end
if firstspace > 0
for j in firstspace...characters.length
(firstspace...characters.length).each do |j|
characters[j] = nil
end
end
characters.compact!
end
for i in 0...characters.length
characters[i][1]=xDst+characters[i][1]
end
characters.each { |char| char[1] = xDst + char[1] }
# Remove all characters with Y greater or equal to _yDst_+_heightDst_
if heightDst >= 0
for i in 0...characters.length
if characters[i][2]>=yDst+heightDst
characters[i]=nil
end
characters.each_with_index do |char, i|
characters[i] = nil if char[2] >= yDst + heightDst
end
characters.compact!
end
@@ -324,7 +285,7 @@ def getFormattedTextFast(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight,
end
def isWaitChar(x)
return (x=="\001" || x=="\002")
return (["\001", "\002"].include?(x))
end
def getLastParam(array, default)
@@ -340,10 +301,10 @@ def getLastColors(colorstack,opacitystack,defaultcolors)
colors = getLastParam(colorstack, defaultcolors)
opacity = getLastParam(opacitystack, 255)
if opacity != 255
colors=[Color.new(colors[0].red,colors[0].green,colors[0].blue,
colors[0].alpha*opacity/255),
colors[1] ? Color.new(colors[1].red,colors[1].green,colors[1].blue,
colors[1].alpha*opacity/255) : nil]
colors = [
Color.new(colors[0].red, colors[0].green, colors[0].blue, colors[0].alpha * opacity / 255),
colors[1] ? Color.new(colors[1].red, colors[1].green, colors[1].blue, colors[1].alpha * opacity / 255) : nil
]
end
return colors
end
@@ -432,35 +393,34 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
end
textchunks = []
controls = []
oldtext=text
# oldtext = text
while text[FORMATREGEXP]
textchunks.push($~.pre_match)
if $~[3]
controls.push([$~[2].downcase,$~[4],-1,$~[1]=="/" ? true : false])
controls.push([$~[2].downcase, $~[4], -1, $~[1] == "/"])
else
controls.push([$~[2].downcase,"",-1,$~[1]=="/" ? true : false])
controls.push([$~[2].downcase, "", -1, $~[1] == "/"])
end
text = $~.post_match
end
if controls.length == 0
ret = getFormattedTextFast(bitmap, xDst, yDst, widthDst, heightDst, text, lineheight,
newlineBreaks, explicitBreaksOnly)
dummybitmap.dispose if dummybitmap
dummybitmap&.dispose
return ret
end
x = y = 0
characters = []
charactersInternal = []
realtext=nil
realtextStart=""
if !explicitBreaksOnly && textchunks.join("").length==0
# All commands occurred at the beginning of the text string
realtext=(newlineBreaks) ? text : text.gsub(/\n/," ")
realtextStart=oldtext[0,oldtext.length-realtext.length]
realtextHalf=text.length/2
end
# realtext = nil
# realtextStart = ""
# if !explicitBreaksOnly && textchunks.join.length == 0
# # All commands occurred at the beginning of the text string
# realtext = (newlineBreaks) ? text : text.gsub(/\n/, " ")
# realtextStart = oldtext[0, oldtext.length - realtext.length]
# end
textchunks.push(text)
for chunk in textchunks
textchunks.each do |chunk|
chunk.gsub!(/&lt;/, "<")
chunk.gsub!(/&gt;/, ">")
chunk.gsub!(/&apos;/, "'")
@@ -468,11 +428,11 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
chunk.gsub!(/&amp;/, "&")
end
textlen = 0
for i in 0...controls.length
controls.each_with_index do |control, i|
textlen += textchunks[i].scan(/./m).length
controls[i][2]=textlen
control[2] = textlen
end
text=textchunks.join("")
text = textchunks.join
textchars = text.scan(/./m)
colorstack = []
boldcount = 0
@@ -511,19 +471,20 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
graphicWidth = nil
graphicHeight = nil
graphicRect = nil
for i in 0...controls.length
controls.length.times do |i|
if controls[i] && controls[i][2] == position
control = controls[i][0]
param = controls[i][1]
endtag = controls[i][3]
if control=="c"
case control
when "c"
if endtag
colorstack.pop
else
color = rgbToColor(param)
colorstack.push([color, nil])
end
elsif control=="c2"
when "c2"
if endtag
colorstack.pop
else
@@ -531,7 +492,7 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
shadow = Rgb16ToColor(param[4, 4])
colorstack.push([base, shadow])
end
elsif control=="c3"
when "c3"
if endtag
colorstack.pop
else
@@ -542,25 +503,25 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
shadow = (param[1] && param[1] != "") ? rgbToColor(param[1]) : oldColors[1]
colorstack.push([base, shadow])
end
elsif control=="o"
when "o"
if endtag
opacitystack.pop
else
opacitystack.push(param.sub(/\s+$/, "").to_i)
end
elsif control=="b"
when "b"
boldcount += (endtag ? -1 : 1)
elsif control=="i"
when "i"
italiccount += (endtag ? -1 : 1)
elsif control=="u"
when "u"
underlinecount += (endtag ? -1 : 1)
elsif control=="s"
when "s"
strikecount += (endtag ? -1 : 1)
elsif control=="outln"
when "outln"
outlinecount += (endtag ? -1 : 1)
elsif control=="outln2"
when "outln2"
outline2count += (endtag ? -1 : 1)
elsif control=="fs" # Font size
when "fs" # Font size
if endtag
fontsizestack.pop
else
@@ -568,7 +529,7 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
end
fontsize = getLastParam(fontsizestack, defaultfontsize)
bitmap.font.size = fontsize
elsif control=="fn" # Font name
when "fn" # Font name
if endtag
fontnamestack.pop
else
@@ -577,38 +538,35 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
end
fontname = getLastParam(fontnamestack, defaultfontname)
bitmap.font.name = fontname
elsif control=="ar" # Right align
if !endtag
when "ar" # Right align
if endtag
alignstack.pop
else
alignstack.push(1)
nextline=1 if x>0 && nextline==0
else
alignstack.pop
nextline=1 if x>0 && nextline==0
end
elsif control=="al" # Left align
if !endtag
nextline = 1 if x > 0 && nextline == 0
when "al" # Left align
if endtag
alignstack.pop
else
alignstack.push(0)
nextline=1 if x>0 && nextline==0
else
alignstack.pop
nextline=1 if x>0 && nextline==0
end
elsif control=="ac" # Center align
if !endtag
nextline = 1 if x > 0 && nextline == 0
when "ac" # Center align
if endtag
alignstack.pop
else
alignstack.push(2)
nextline=1 if x>0 && nextline==0
else
alignstack.pop
nextline=1 if x>0 && nextline==0
end
elsif control=="icon" # Icon
nextline = 1 if x > 0 && nextline == 0
when "icon" # Icon
if !endtag
param = param.sub(/\s+$/, "")
graphic = "Graphics/Icons/#{param}"
controls[i] = nil
break
end
elsif control=="img" # Icon
when "img" # Icon
if !endtag
param = param.sub(/\s+$/, "")
param = param.split("|")
@@ -622,14 +580,15 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
controls[i] = nil
break
end
elsif control=="br" # Line break
when "br" # Line break
if !endtag
nextline += 1
end
elsif control=="r" # Right align this line
when "r" # Right align this line
if !endtag
x = 0
rightalign=1; lastword=[characters.length,x]
rightalign = 1
lastword = [characters.length, x]
end
end
controls[i] = nil
@@ -647,6 +606,7 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
width = graphicWidth # +8 # No padding
xStart = 0 # 4
yStart = [(lineheight / 2) - (graphicHeight / 2), 0].max
yStart += 4 # TEXT OFFSET
graphicRect = Rect.new(graphicX, graphicY, graphicWidth, graphicHeight)
else
xStart = 0
@@ -661,7 +621,7 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
end
nextline.times do
havenl = true
characters.push(["\n",x,y*lineheight+yDst,0,lineheight,false,false,false,
characters.push(["\n", x, (y * lineheight) + yDst, 0, lineheight, false, false, false,
defaultcolors[0], defaultcolors[1], false, false, "", 8, position, nil, 0])
charactersInternal.push([alignment, y, 0])
y += 1
@@ -675,7 +635,7 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
if newlineBreaks
if nextline == 0
havenl = true
characters.push(["\n",x,y*lineheight+yDst,0,lineheight,false,false,false,
characters.push(["\n", x, (y * lineheight) + yDst, 0, lineheight, false, false, false,
defaultcolors[0], defaultcolors[1], false, false, "", 8, position, nil, 0])
charactersInternal.push([alignment, y, 0])
y += 1
@@ -704,35 +664,34 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
elsif isspace
hadspace = true
end
texty=(lineheight*y)+yDst+yStart
texty = (lineheight * y) + yDst + yStart - 2 # TEXT OFFSET
colors = getLastColors(colorstack, opacitystack, defaultcolors)
# Push character
if heightDst < 0 || texty < yDst + heightDst
havenl = true if !graphic && isWaitChar(textchars[position])
extraspace = (!graphic && italiccount > 0) ? 2 + (width / 2) : 2
characters.push([
graphic ? graphic : textchars[position],
characters.push([graphic || textchars[position],
x + xStart, texty, width + extraspace, lineheight,
graphic ? true : false,
(boldcount > 0), (italiccount > 0), colors[0], colors[1],
(underlinecount > 0), (strikecount > 0), fontname, fontsize,
position, graphicRect,
((outlinecount>0) ? 1 : 0)+((outline2count>0) ? 2 : 0)
])
((outlinecount > 0) ? 1 : 0) + ((outline2count > 0) ? 2 : 0)])
charactersInternal.push([alignment, y, xStart, textchars[position], extraspace])
end
x += width
if !explicitBreaksOnly && x + 2 > widthDst && lastword[1] != 0 &&
(!hadnonspace || !hadspace)
havenl = true
characters.insert(lastword[0],["\n",x,y*lineheight+yDst,0,lineheight,false,
false,false,defaultcolors[0],defaultcolors[1],false,false,"",8,position,
nil])
characters.insert(lastword[0], ["\n", x, (y * lineheight) + yDst, 0, lineheight,
false, false, false,
defaultcolors[0], defaultcolors[1],
false, false, "", 8, position, nil])
charactersInternal.insert(lastword[0], [alignment, y, 0])
lastword[0] += 1
y += 1
x = 0
for i in lastword[0]...characters.length
(lastword[0]...characters.length).each do |i|
characters[i][2] += lineheight
charactersInternal[i][1] += 1
extraspace = (charactersInternal[i][4]) ? charactersInternal[i][4] : 0
@@ -755,13 +714,15 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
leftSearch = 0
rightSearch = 0
# Search left for a space
i = half; while i>=0
i = half
while i>=0
break if realtext[i,1][/\s/]||isWaitChar(realtext[i,1]) # found a space
leftSearch += 1
i -= 1
end
# Search right for a space
i = half; while i<realtext.length
i = half
while i<realtext.length
break if realtext[i,1][/\s/]||isWaitChar(realtext[i,1]) # found a space
rightSearch += 1
i += 1
@@ -790,12 +751,12 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
if havenl
# Eliminate spaces before newlines and pause character
firstspace = -1
for i in 0...characters.length
characters.length.times do |i|
if characters[i][5] != false # If not a character
firstspace = -1
elsif (characters[i][0] == "\n" || isWaitChar(characters[i][0])) &&
firstspace >= 0
for j in firstspace...i
(firstspace...i).each do |j|
characters[j] = nil
charactersInternal[j] = nil
end
@@ -809,7 +770,7 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
end
end
if firstspace > 0
for j in firstspace...characters.length
(firstspace...characters.length).each do |j|
characters[j] = nil
charactersInternal[j] = nil
end
@@ -824,7 +785,7 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
lastalign = 0
lasty = 0
runstart = 0
for i in 0...characters.length
characters.length.times do |i|
c = characters[i]
if i > 0 && (charactersInternal[i][0] != lastalign ||
charactersInternal[i][1] != lasty)
@@ -842,7 +803,7 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
if collapseAlignments
# Calculate the total width of each line
totalLineWidths = []
for block in widthblocks
widthblocks.each do |block|
y = block[4]
if !totalLineWidths[y]
totalLineWidths[y] = 0
@@ -857,9 +818,9 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
widthDst = [widthDst, (totalLineWidths.compact.max || 0)].min
end
# Now, based on the text runs found, recalculate Xs
for block in widthblocks
widthblocks.each do |block|
next if block[0] >= block[1]
for i in block[0]...block[1]
(block[0]...block[1]).each do |i|
case block[2]
when 1 then characters[i][1] = xDst + (widthDst - block[3] - 4) + characters[i][1]
when 2 then characters[i][1] = xDst + ((widthDst / 2) - (block[3] / 2)) + characters[i][1]
@@ -868,16 +829,9 @@ def getFormattedText(bitmap,xDst,yDst,widthDst,heightDst,text,lineheight=32,
end
end
# Remove all characters with Y greater or equal to _yDst_+_heightDst_
if heightDst>=0
for i in 0...characters.length
if characters[i][2]>=yDst+heightDst
characters[i]=nil
end
end
characters.compact!
end
characters.delete_if { |ch| ch[2] >= yDst + heightDst } if heightDst >= 0
bitmap.font = oldfont
dummybitmap.dispose if dummybitmap
dummybitmap&.dispose
return characters
end
@@ -901,7 +855,7 @@ def getLineBrokenText(bitmap,value,width,dims)
return ret if !bitmap || bitmap.disposed? || width <= 0
textmsg = value.clone
ret.push(["", 0, 0, 0, bitmap.text_size("X").height, 0, 0, 0, 0])
while ((c = textmsg.slice!(/\n|(\S*([ \r\t\f]?))/)) != nil)
while (c = textmsg.slice!(/\n|(\S*([ \r\t\f]?))/)) != nil
break if c == ""
length = c.scan(/./m).length
ccheck = c
@@ -917,7 +871,7 @@ def getLineBrokenText(bitmap,value,width,dims)
next
end
words = [ccheck]
for i in 0...words.length
words.length.times do |i|
word = words[i]
if word && word != ""
textSize = bitmap.text_size(word)
@@ -965,15 +919,14 @@ def getLineBrokenChunks(bitmap,value,width,dims,plain=false)
y += 32
next
end
if ccheck[/</] && !plain
textcols = []
if ccheck[/</] && !plain
ccheck.scan(re) { textcols.push(rgbToColor($1)) }
words = ccheck.split(reNoMatch) # must have no matches because split can include match
else
textcols=[]
words = [ccheck]
end
for i in 0...words.length
words.length.times do |i|
word = words[i]
if word && word != ""
textSize = bitmap.text_size(word)
@@ -999,25 +952,25 @@ def getLineBrokenChunks(bitmap,value,width,dims,plain=false)
end
def renderLineBrokenChunks(bitmap, xDst, yDst, normtext, maxheight = 0)
for i in 0...normtext.length
width=normtext[i][3]
textx=normtext[i][1]+xDst
texty=normtext[i][2]+yDst
if maxheight==0 || normtext[i][2]<maxheight
bitmap.font.color=normtext[i][5]
bitmap.draw_text(textx,texty,width+2,normtext[i][4],normtext[i][0])
normtext.each do |text|
width = text[3]
textx = text[1] + xDst
texty = text[2] + yDst
if maxheight == 0 || text[2] < maxheight
bitmap.font.color = text[5]
bitmap.draw_text(textx, texty, width + 2, text[4], text[0])
end
end
end
def renderLineBrokenChunksWithShadow(bitmap, xDst, yDst, normtext, maxheight, baseColor, shadowColor)
for i in 0...normtext.length
width=normtext[i][3]
textx=normtext[i][1]+xDst
texty=normtext[i][2]+yDst
if maxheight==0 || normtext[i][2]<maxheight
height=normtext[i][4]
text=normtext[i][0]
normtext.each do |text|
width = text[3]
textx = text[1] + xDst
texty = text[2] + yDst
if maxheight == 0 || text[2] < maxheight
height = text[4]
text = text[0]
bitmap.font.color = shadowColor
bitmap.draw_text(textx + 2, texty, width + 2, height, text)
bitmap.draw_text(textx, texty + 2, width + 2, height, text)
@@ -1031,7 +984,7 @@ end
def drawBitmapBuffer(chars)
width = 1
height = 1
for ch in chars
chars.each do |ch|
chx = ch[1] + ch[3]
chy = ch[2] + ch[4]
width = chx if width < chx
@@ -1085,8 +1038,8 @@ def drawSingleFormattedChar(bitmap,ch)
end
bitmap.font.color = ch[8] if bitmap.font.color != ch[8]
bitmap.draw_text(ch[1] + offset, ch[2] + offset, ch[3], ch[4], ch[0])
else
bitmap.font.color=ch[8] if bitmap.font.color!=ch[8]
elsif bitmap.font.color != ch[8]
bitmap.font.color = ch[8]
end
if ch[10] # underline
bitmap.fill_rect(ch[1], ch[2] + ch[4] - 4 - [(ch[4] - bitmap.font.size) / 2, 0].max - 2,
@@ -1101,7 +1054,7 @@ end
def drawFormattedChars(bitmap, chars)
return if chars.length == 0 || !bitmap || bitmap.disposed?
oldfont = bitmap.font.clone
for ch in chars
chars.each do |ch|
drawSingleFormattedChar(bitmap, ch)
end
bitmap.font = oldfont
@@ -1110,10 +1063,10 @@ end
# Unused
def drawTextTable(bitmap, x, y, totalWidth, rowHeight, columnWidthPercents, table)
yPos = y
for i in 0...table.length
table.length.times do |i|
row = table[i]
xPos = x
for j in 0...row.length
row.length.times do |j|
cell = row[j]
cellwidth = columnWidthPercents[j] * totalWidth / 100
chars = getFormattedText(bitmap, xPos, yPos, cellwidth, -1, cell, rowHeight)
@@ -1131,8 +1084,8 @@ def drawTextEx(bitmap,x,y,width,numlines,text,baseColor,shadowColor)
end
def drawFormattedTextEx(bitmap, x, y, width, text, baseColor = nil, shadowColor = nil, lineheight = 32)
base=!baseColor ? Color.new(12*8,12*8,12*8) : baseColor.clone
shadow=!shadowColor ? Color.new(26*8,26*8,25*8) : shadowColor.clone
base = baseColor ? baseColor.clone : Color.new(96, 96, 96)
shadow = shadowColor ? shadowColor.clone : Color.new(208, 208, 200)
text = "<c2=" + colorToRgb16(base) + colorToRgb16(shadow) + ">" + text
chars = getFormattedText(bitmap, x, y, width, -1, text, lineheight)
drawFormattedChars(bitmap, chars)
@@ -1148,7 +1101,6 @@ def pbDrawShadowText(bitmap,x,y,width,height,string,baseColor,shadowColor=nil,al
return if !bitmap || !string
width = (width < 0) ? bitmap.text_size(string).width + 1 : width
height = (height < 0) ? bitmap.text_size(string).height + 1 : height
y += 4
if shadowColor && shadowColor.alpha > 0
bitmap.font.color = shadowColor
bitmap.draw_text(x + 2, y, width, height, string, align)
@@ -1193,13 +1145,14 @@ end
# 5 - Shadow color
# 6 - If true or 1, the text has an outline. Otherwise, the text has a shadow.
def pbDrawTextPositions(bitmap, textpos)
for i in textpos
textpos.each do |i|
textsize = bitmap.text_size(i[0])
x = i[1]
y = i[2] + 6
if i[3]==true || i[3]==1 # right align
y = i[2]
case i[3]
when true, 1 # right align
x -= textsize.width
elsif i[3]==2 # centered
when 2 # centered
x -= (textsize.width / 2)
end
if i[6] == true || i[6] == 1 # outline text
@@ -1221,7 +1174,7 @@ def pbCopyBitmap(dstbm,srcbm,x,y,opacity=255)
end
def pbDrawImagePositions(bitmap, textpos)
for i in textpos
textpos.each do |i|
srcbitmap = AnimatedBitmap.new(pbBitmapName(i[0]))
x = i[1]
y = i[2]

View File

@@ -1,102 +1,22 @@
#===============================================================================
#
#===============================================================================
class Scene_Map
def updatemini
oldmws=$game_temp.message_window_showing
$game_temp.message_window_showing=true
loop do
$game_map.update
$game_player.update
$game_system.update
if $game_screen
$game_screen.update
else
$game_map.screen.update
end
break unless $game_temp.player_transferring
transfer_player
break if $game_temp.transition_processing
end
$game_temp.message_window_showing=oldmws
@spriteset.update if @spriteset
@message_window.update if @message_window
end
end
class Scene_Battle
def updatemini
if self.respond_to?("update_basic")
update_basic(true)
update_info_viewport # Update information viewport
else
oldmws=$game_temp.message_window_showing
$game_temp.message_window_showing=true
# Update system (timer) and screen
$game_system.update
if $game_screen
$game_screen.update
else
$game_map.screen.update
end
# If timer has reached 0
if $game_system.timer_working && $game_system.timer == 0
# Abort battle
$game_temp.battle_abort = true
end
# Update windows
@help_window.update if @help_window
@party_command_window.update if @party_command_window
@actor_command_window.update if @actor_command_window
@status_window.update if @status_window
$game_temp.message_window_showing=oldmws
@message_window.update if @message_window
# Update sprite set
@spriteset.update if @spriteset
end
end
end
def pbMapInterpreter
if $game_map.respond_to?("interpreter")
return $game_map.interpreter
elsif $game_system
return $game_system.map_interpreter
end
return nil
return $game_system&.map_interpreter
end
def pbMapInterpreterRunning?
interp = pbMapInterpreter
return interp && interp.running?
return interp&.running?
end
# Unused
def pbRefreshSceneMap
if $scene && $scene.is_a?(Scene_Map)
if $scene.respond_to?("miniupdate")
$scene.miniupdate
else
$scene.updatemini
end
elsif $scene && $scene.is_a?(Scene_Battle)
$scene.updatemini
end
$scene.miniupdate if $scene.is_a?(Scene_Map)
end
def pbUpdateSceneMap
if $scene && $scene.is_a?(Scene_Map) && !pbIsFaded?
if $scene.respond_to?("miniupdate")
$scene.miniupdate
else
$scene.updatemini
end
elsif $scene && $scene.is_a?(Scene_Battle)
$scene.updatemini
end
$scene.miniupdate if $scene.is_a?(Scene_Map) && !pbIsFaded?
end
#===============================================================================
@@ -107,26 +27,24 @@ def pbEventCommentInput(*args)
list = args[0].list # List of commands for event or event page
elements = args[1] # Number of elements
trigger = args[2] # Trigger
return nil if list == nil
return nil if list.nil?
return nil unless list.is_a?(Array)
for item in list
next unless item.code == 108 || item.code == 408
if item.parameters[0] == trigger
list.each do |item|
next if ![108, 108].include?(item.code)
next if item.parameters[0] != trigger
start = list.index(item) + 1
finish = start + elements
for id in start...finish
next if !list[id]
parameters.push(list[id].parameters[0])
(start...finish).each do |id|
parameters.push(list[id].parameters[0]) if list[id]
end
return parameters
end
end
return nil
end
def pbCurrentEventCommentInput(elements, trigger)
return nil if !pbMapInterpreterRunning?
event = pbMapInterpreter.get_character(0)
event = pbMapInterpreter.get_self
return nil if !event
return pbEventCommentInput(event, elements, trigger)
end
@@ -137,6 +55,9 @@ end
#
#===============================================================================
class ChooseNumberParams
attr_reader :messageSkin # Set the full path for the message's window skin
attr_reader :skin
def initialize
@maxDigits = 0
@minNumber = 0
@@ -152,18 +73,10 @@ class ChooseNumberParams
@messageSkin = value
end
def messageSkin # Set the full path for the message's window skin
@messageSkin
end
def setSkin(value)
@skin = value
end
def skin
@skin
end
def setNegativesAllowed(value)
@negativeAllowed = value
end
@@ -272,20 +185,20 @@ def pbChooseNumber(msgwindow,params)
Input.update
pbUpdateSceneMap
cmdwindow.update
msgwindow.update if msgwindow
msgwindow&.update
yield if block_given?
if Input.trigger?(Input::USE)
ret = cmdwindow.number
if ret > maximum
pbPlayBuzzerSE()
pbPlayBuzzerSE
elsif ret < minimum
pbPlayBuzzerSE()
pbPlayBuzzerSE
else
pbPlayDecisionSE()
pbPlayDecisionSE
break
end
elsif Input.trigger?(Input::BACK)
pbPlayCancelSE()
pbPlayCancelSE
ret = cancelNumber
break
end
@@ -306,14 +219,12 @@ class FaceWindowVX < SpriteWindow_Base
faceinfo = face.split(",")
facefile = pbResolveBitmap("Graphics/Faces/" + faceinfo[0])
facefile = pbResolveBitmap("Graphics/Pictures/" + faceinfo[0]) if !facefile
self.contents.dispose if self.contents
self.contents&.dispose
@faceIndex = faceinfo[1].to_i
@facebitmaptmp = AnimatedBitmap.new(facefile)
@facebitmap = BitmapWrapper.new(96, 96)
@facebitmap.blt(0,0,@facebitmaptmp.bitmap,Rect.new(
(@faceIndex % 4) * 96,
(@faceIndex / 4) * 96, 96, 96
))
@facebitmap.blt(0, 0, @facebitmaptmp.bitmap,
Rect.new((@faceIndex % 4) * 96, (@faceIndex / 4) * 96, 96, 96))
self.contents = @facebitmap
end
@@ -321,16 +232,14 @@ class FaceWindowVX < SpriteWindow_Base
super
if @facebitmaptmp.totalFrames > 1
@facebitmaptmp.update
@facebitmap.blt(0,0,@facebitmaptmp.bitmap,Rect.new(
(@faceIndex % 4) * 96,
(@faceIndex / 4) * 96, 96, 96
))
@facebitmap.blt(0, 0, @facebitmaptmp.bitmap,
Rect.new((@faceIndex % 4) * 96, (@faceIndex / 4) * 96, 96, 96))
end
end
def dispose
@facebitmaptmp.dispose
@facebitmap.dispose if @facebitmap
@facebitmap&.dispose
super
end
end
@@ -351,9 +260,10 @@ def pbGetBasicMapNameFromId(id)
end
def pbGetMapNameFromId(id)
map=pbGetBasicMapNameFromId(id)
map.gsub!(/\\PN/,$Trainer.name) if $Trainer
return map
name = pbGetMessage(MessageTypes::MapNames, id)
name = pbGetBasicMapNameFromId(id) if nil_or_empty?(name)
name.gsub!(/\\PN/, $player.name) if $player
return name
end
def pbCsvField!(str)
@@ -405,21 +315,11 @@ end
# Money and coins windows
#===============================================================================
def pbGetGoldString
moneyString=""
begin
moneyString=_INTL("${1}",$Trainer.money.to_s_formatted)
rescue
if $data_system.respond_to?("words")
moneyString=_INTL("{1} {2}",$game_party.gold,$data_system.words.gold)
else
moneyString=_INTL("{1} {2}",$game_party.gold,Vocab.gold)
end
end
return moneyString
return _INTL("${1}", $player.money.to_s_formatted)
end
def pbDisplayGoldWindow(msgwindow)
moneyString=pbGetGoldString()
moneyString = pbGetGoldString
goldwindow = Window_AdvancedTextPokemon.new(_INTL("Money:\n<ar>{1}</ar>", moneyString))
goldwindow.setSkin("Graphics/Windowskins/goldskin")
goldwindow.resizeToFit(goldwindow.text, Graphics.width)
@@ -435,7 +335,7 @@ def pbDisplayGoldWindow(msgwindow)
end
def pbDisplayCoinsWindow(msgwindow, goldwindow)
coinString=($Trainer) ? $Trainer.coins.to_s_formatted : "0"
coinString = ($player) ? $player.coins.to_s_formatted : "0"
coinwindow = Window_AdvancedTextPokemon.new(_INTL("Coins:\n<ar>{1}</ar>", coinString))
coinwindow.setSkin("Graphics/Windowskins/goldskin")
coinwindow.resizeToFit(coinwindow.text, Graphics.width)
@@ -451,7 +351,7 @@ def pbDisplayCoinsWindow(msgwindow,goldwindow)
end
def pbDisplayBattlePointsWindow(msgwindow)
pointsString = ($Trainer) ? $Trainer.battle_points.to_s_formatted : "0"
pointsString = ($player) ? $player.battle_points.to_s_formatted : "0"
pointswindow = Window_AdvancedTextPokemon.new(_INTL("Battle Points:\n<ar>{1}</ar>", pointsString))
pointswindow.setSkin("Graphics/Windowskins/goldskin")
pointswindow.resizeToFit(pointswindow.text, Graphics.width)
@@ -473,32 +373,32 @@ end
#===============================================================================
def pbCreateStatusWindow(viewport = nil)
msgwindow = Window_AdvancedTextPokemon.new("")
if !viewport
msgwindow.z=99999
else
if viewport
msgwindow.viewport = viewport
else
msgwindow.z = 99999
end
msgwindow.visible = false
msgwindow.letterbyletter = false
pbBottomLeftLines(msgwindow, 2)
skinfile=MessageConfig.pbGetSpeechFrame()
skinfile = MessageConfig.pbGetSpeechFrame
msgwindow.setSkin(skinfile)
return msgwindow
end
def pbCreateMessageWindow(viewport = nil, skin = nil)
msgwindow = Window_AdvancedTextPokemon.new("")
if !viewport
msgwindow.z=99999
else
if viewport
msgwindow.viewport = viewport
else
msgwindow.z = 99999
end
msgwindow.visible = true
msgwindow.letterbyletter = true
msgwindow.back_opacity = MessageConfig::WINDOW_OPACITY
pbBottomLeftLines(msgwindow, 2)
$game_temp.message_window_showing = true if $game_temp
skin=MessageConfig.pbGetSpeechFrame() if !skin
skin = MessageConfig.pbGetSpeechFrame if !skin
msgwindow.setSkin(skin)
return msgwindow
end
@@ -542,14 +442,14 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
next $game_actors[m].name
}
end
text.gsub!(/\\pn/i,$Trainer.name) if $Trainer
text.gsub!(/\\pm/i,_INTL("${1}",$Trainer.money.to_s_formatted)) if $Trainer
text.gsub!(/\\pn/i, $player.name) if $player
text.gsub!(/\\pm/i, _INTL("${1}", $player.money.to_s_formatted)) if $player
text.gsub!(/\\n/i, "\n")
text.gsub!(/\\\[([0-9a-f]{8,8})\]/i) { "<c2=" + $1 + ">" }
text.gsub!(/\\pg/i,"\\b") if $Trainer && $Trainer.male?
text.gsub!(/\\pg/i,"\\r") if $Trainer && $Trainer.female?
text.gsub!(/\\pog/i,"\\r") if $Trainer && $Trainer.male?
text.gsub!(/\\pog/i,"\\b") if $Trainer && $Trainer.female?
text.gsub!(/\\pg/i, "\\b") if $player&.male?
text.gsub!(/\\pg/i, "\\r") if $player&.female?
text.gsub!(/\\pog/i, "\\r") if $player&.male?
text.gsub!(/\\pog/i, "\\b") if $player&.female?
text.gsub!(/\\pg/i, "")
text.gsub!(/\\pog/i, "")
text.gsub!(/\\b/i, "<c3=3050C8,D0D0C8>")
@@ -564,7 +464,7 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
next ""
}
isDarkSkin = isDarkWindowskin(msgwindow.windowskin)
text.gsub!(/\\[Cc]\[([0-9]+)\]/) {
text.gsub!(/\\c\[([0-9]+)\]/i) {
m = $1.to_i
next getSkinColor(msgwindow.windowskin, m, isDarkSkin)
}
@@ -582,8 +482,7 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
break if text == last_text
end
colortag = ""
if $game_system && $game_system.respond_to?("message_frame") &&
$game_system.message_frame != 0
if $game_system && $game_system.message_frame != 0
colortag = getSkinColor(msgwindow.windowskin, 0, true)
else
colortag = getSkinColor(msgwindow.windowskin, 0, isDarkSkin)
@@ -602,11 +501,11 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
text = $~.post_match
end
textchunks.push(text)
for chunk in textchunks
textchunks.each do |chunk|
chunk.gsub!(/\005/, "\\")
end
textlen = 0
for i in 0...controls.length
controls.length.times do |i|
control = controls[i][0]
case control
when "wt", "wtnp", ".", "|"
@@ -617,12 +516,13 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
textlen += toUnformattedText(textchunks[i]).scan(/./m).length
controls[i][2] = textlen
end
text = textchunks.join("")
text = textchunks.join
signWaitCount = 0
signWaitTime = Graphics.frame_rate / 2
haveSpecialClose = false
specialCloseSE = ""
for i in 0...controls.length
startSE = nil
controls.length.times do |i|
control = controls[i][0]
param = controls[i][1]
case control
@@ -633,10 +533,10 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
haveSpecialClose = true
specialCloseSE = param
when "f"
facewindow.dispose if facewindow
facewindow&.dispose
facewindow = PictureWindow.new("Graphics/Pictures/#{param}")
when "ff"
facewindow.dispose if facewindow
facewindow&.dispose
facewindow = FaceWindowVX.new(param)
when "ch"
cmds = param.clone
@@ -655,10 +555,10 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
end
end
end
if startSE!=nil
if startSE
pbSEPlay(pbStringToAudioFile(startSE))
elsif signWaitCount == 0 && letterbyletter
pbPlayDecisionSE()
pbPlayDecisionSE
end
########## Position message window ##############
pbRepositionMessageWindow(msgwindow, linecount)
@@ -677,35 +577,35 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
if atTop
msgwindow.y = -msgwindow.height * signWaitCount / signWaitTime
else
msgwindow.y = Graphics.height-msgwindow.height*(signWaitTime-signWaitCount)/signWaitTime
msgwindow.y = Graphics.height - (msgwindow.height * (signWaitTime - signWaitCount) / signWaitTime)
end
end
for i in 0...controls.length
controls.length.times do |i|
next if !controls[i]
next if controls[i][2] > msgwindow.position || msgwindow.waitcount != 0
control = controls[i][0]
param = controls[i][1]
case control
when "f"
facewindow.dispose if facewindow
facewindow&.dispose
facewindow = PictureWindow.new("Graphics/Pictures/#{param}")
pbPositionNearMsgWindow(facewindow, msgwindow, :left)
facewindow.viewport = msgwindow.viewport
facewindow.z = msgwindow.z
when "ff"
facewindow.dispose if facewindow
facewindow&.dispose
facewindow = FaceWindowVX.new(param)
pbPositionNearMsgWindow(facewindow, msgwindow, :left)
facewindow.viewport = msgwindow.viewport
facewindow.z = msgwindow.z
when "g" # Display gold window
goldwindow.dispose if goldwindow
goldwindow&.dispose
goldwindow = pbDisplayGoldWindow(msgwindow)
when "cn" # Display coins window
coinwindow.dispose if coinwindow
coinwindow&.dispose
coinwindow = pbDisplayCoinsWindow(msgwindow, goldwindow)
when "pt" # Display battle points window
battlepointswindow.dispose if battlepointswindow
battlepointswindow&.dispose
battlepointswindow = pbDisplayBattlePointsWindow(msgwindow)
when "wu"
msgwindow.y = 0
@@ -723,7 +623,7 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
msgwindow.y = Graphics.height - msgwindow.height
msgback.y = msgwindow.y if msgback
pbPositionNearMsgWindow(facewindow, msgwindow, :left)
msgwindow.y = Graphics.height-msgwindow.height*(signWaitTime-signWaitCount)/signWaitTime
msgwindow.y = Graphics.height - (msgwindow.height * (signWaitTime - signWaitCount) / signWaitTime)
when "ts" # Change text speed
msgwindow.textspeed = (param == "") ? -999 : param.to_i
when "." # Wait 0.25 seconds
@@ -749,7 +649,7 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
break if !letterbyletter
Graphics.update
Input.update
facewindow.update if facewindow
facewindow&.update
if autoresume && msgwindow.waitcount == 0
msgwindow.resume if msgwindow.busy?
break if !msgwindow.busy?
@@ -758,8 +658,8 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
if msgwindow.busy?
pbPlayDecisionSE if msgwindow.pausing?
msgwindow.resume
else
break if signWaitCount==0
elsif signWaitCount == 0
break
end
end
pbUpdateSceneMap
@@ -776,19 +676,19 @@ def pbMessageDisplay(msgwindow,message,letterbyletter=true,commandProc=nil)
if commandProc
ret = commandProc.call(msgwindow)
end
msgback.dispose if msgback
goldwindow.dispose if goldwindow
coinwindow.dispose if coinwindow
battlepointswindow.dispose if battlepointswindow
facewindow.dispose if facewindow
msgback&.dispose
goldwindow&.dispose
coinwindow&.dispose
battlepointswindow&.dispose
facewindow&.dispose
if haveSpecialClose
pbSEPlay(pbStringToAudioFile(specialCloseSE))
atTop = (msgwindow.y == 0)
for i in 0..signWaitTime
(0..signWaitTime).each do |i|
if atTop
msgwindow.y = -msgwindow.height * i / signWaitTime
else
msgwindow.y = Graphics.height-msgwindow.height*(signWaitTime-i)/signWaitTime
msgwindow.y = Graphics.height - (msgwindow.height * (signWaitTime - i) / signWaitTime)
end
Graphics.update
Input.update
@@ -851,7 +751,7 @@ def pbShowCommands(msgwindow,commands=nil,cmdIfCancel=0,defaultCmd=0)
Graphics.update
Input.update
cmdwindow.update
msgwindow.update if msgwindow
msgwindow&.update
yield if block_given?
if Input.trigger?(Input::BACK)
if cmdIfCancel > 0
@@ -931,7 +831,7 @@ def pbMessageWaitForInput(msgwindow,frames,showPause=false)
frames.times do
Graphics.update
Input.update
msgwindow.update if msgwindow
msgwindow&.update
pbUpdateSceneMap
if Input.trigger?(Input::USE) || Input.trigger?(Input::BACK)
break
@@ -962,7 +862,7 @@ def pbFreeText(msgwindow,currenttext,passwordbox,maxlength,width=240)
break
end
window.update
msgwindow.update if msgwindow
msgwindow&.update
yield if block_given?
end
Input.text_input = false

View File

@@ -2,7 +2,7 @@
#
#===============================================================================
class CharacterEntryHelper
attr_reader :text
attr_accessor :text
attr_accessor :maxlength
attr_reader :passwordChar
attr_accessor :cursor
@@ -14,10 +14,6 @@ class CharacterEntryHelper
@cursor = text.scan(/./m).length
end
def text=(value)
@text=value
end
def textChars
chars = text.scan(/./m)
if @passwordChar != ""
@@ -27,7 +23,7 @@ class CharacterEntryHelper
end
def passwordChar=(value)
@passwordChar=value ? value : ""
@passwordChar = value || ""
end
def length
@@ -45,7 +41,7 @@ class CharacterEntryHelper
return false if @maxlength >= 0 && chars.length >= @maxlength
chars.insert(@cursor, ch)
@text = ""
for ch in chars
chars.each do |ch|
@text += ch if ch
end
@cursor += 1
@@ -63,7 +59,7 @@ class CharacterEntryHelper
return false if chars.length <= 0 || @cursor <= 0
chars.delete_at(@cursor - 1)
@text = ""
for ch in chars
chars.each do |ch|
@text += ch if ch
end
@cursor -= 1
@@ -79,7 +75,7 @@ class CharacterEntryHelper
chars = chars[0, @maxlength]
end
@text = ""
for ch in chars
chars.each do |ch|
@text += ch if ch
end
end
@@ -196,13 +192,13 @@ class Window_TextEntry < SpriteWindow_Base
@helper.cursor = 0 if @helper.cursor < 0
startpos = @helper.cursor
fromcursor = 0
while (startpos>0)
while startpos > 0
c = (@helper.passwordChar != "") ? @helper.passwordChar : textscan[startpos - 1]
fromcursor += bitmap.text_size(c).width
break if fromcursor > width - 4
startpos -= 1
end
for i in startpos...scanlength
(startpos...scanlength).each do |i|
c = (@helper.passwordChar != "") ? @helper.passwordChar : textscan[i]
textwidth = bitmap.text_size(c).width
next if c == "\n"
@@ -230,7 +226,7 @@ class Window_TextEntry_Keyboard < Window_TextEntry
def update
@frame += 1
@frame %= 20
self.refresh if ((@frame%10)==0)
self.refresh if (@frame % 10) == 0
return if !self.active
# Moving cursor
if Input.triggerex?(:LEFT) || Input.repeatex?(:LEFT)
@@ -352,13 +348,13 @@ class Window_MultilineTextEntry < SpriteWindow_Base
def getLineY(line)
textchars = getTextChars
return 0 if textchars.length == 0
totallines=getTotalLines()
totallines = getTotalLines
line = 0 if line < 0
line = totallines - 1 if line >= totallines
maximumY = 0
for i in 0...textchars.length
thisline=textchars[i][5]
y=textchars[i][2]
textchars.each do |text|
thisline = text[5]
y = text[2]
return y if thisline == line
maximumY = y if maximumY < y
end
@@ -368,13 +364,13 @@ class Window_MultilineTextEntry < SpriteWindow_Base
def getColumnsInLine(line)
textchars = getTextChars
return 0 if textchars.length == 0
totallines=getTotalLines()
totallines = getTotalLines
line = 0 if line < 0
line = totallines - 1 if line >= totallines
endpos = 0
for i in 0...textchars.length
thisline=textchars[i][5]
thislength=textchars[i][8]
textchars.each do |text|
thisline = text[5]
thislength = text[8]
endpos += thislength if thisline == line
end
return endpos
@@ -383,15 +379,15 @@ class Window_MultilineTextEntry < SpriteWindow_Base
def getPosFromLineAndColumn(line, column)
textchars = getTextChars
return 0 if textchars.length == 0
totallines=getTotalLines()
totallines = getTotalLines
line = 0 if line < 0
line = totallines - 1 if line >= totallines
endpos = 0
for i in 0...textchars.length
thisline=textchars[i][5]
thispos=textchars[i][6]
thiscolumn=textchars[i][7]
thislength=textchars[i][8]
textchars.each do |text|
thisline = text[5]
thispos = text[6]
thiscolumn = text[7]
thislength = text[8]
if thisline == line
endpos = thispos + thislength
# echoln [endpos,thispos+(column-thiscolumn),textchars[i]]
@@ -409,7 +405,7 @@ class Window_MultilineTextEntry < SpriteWindow_Base
end
def getLastVisibleLine
getTextChars()
getTextChars
textheight = [1, self.contents.text_size("X").height].max
lastVisible = @firstline + ((self.height - self.borderY) / textheight) - 1
return lastVisible
@@ -423,7 +419,7 @@ class Window_MultilineTextEntry < SpriteWindow_Base
self.refresh
end
@firstline = @cursorLine if @cursorLine < @firstline
lastVisible=getLastVisibleLine()
lastVisible = getLastVisibleLine
@firstline += (@cursorLine - lastVisible) if @cursorLine > lastVisible
end
@@ -432,7 +428,7 @@ class Window_MultilineTextEntry < SpriteWindow_Base
# can affect line offset)
# echoln ["beforemoving",@cursorLine,@cursorColumn]
totalColumns = getColumnsInLine(@cursorLine) # check current line
totalLines=getTotalLines()
totalLines = getTotalLines
oldCursorLine = @cursorLine
oldCursorColumn = @cursorColumn
@cursorColumn += columnOffset
@@ -457,17 +453,14 @@ class Window_MultilineTextEntry < SpriteWindow_Base
totalColumns = getColumnsInLine(@cursorLine)
@cursorColumn = totalColumns if @cursorColumn > totalColumns
@cursorColumn = 0 if @cursorColumn < 0 # totalColumns can be 0
updateCursorPos(
oldCursorLine!=@cursorLine ||
oldCursorColumn!=@cursorColumn
)
updateCursorPos(oldCursorLine != @cursorLine || oldCursorColumn != @cursorColumn)
# echoln ["aftermoving",@cursorLine,@cursorColumn]
end
def update
@frame += 1
@frame %= 20
self.refresh if ((@frame%10)==0)
self.refresh if (@frame % 10) == 0
return if !self.active
# Moving cursor
if Input.triggerex?(:UP) || Input.repeatex?(:UP)
@@ -491,7 +484,7 @@ class Window_MultilineTextEntry < SpriteWindow_Base
return
elsif Input.press?(Input::CTRL) && Input.triggerex?(:END)
# Move cursor to end
@cursorLine=getTotalLines()-1
@cursorLine = getTotalLines - 1
@cursorColumn = getColumnsInLine(@cursorLine)
updateCursorPos(true)
return
@@ -515,42 +508,41 @@ class Window_MultilineTextEntry < SpriteWindow_Base
getTextChars
height = self.height - self.borderY
cursorcolor = Color.new(0, 0, 0)
textchars=getTextChars()
textchars = getTextChars
startY = getLineY(@firstline)
for i in 0...textchars.length
thisline=textchars[i][5]
thiscolumn=textchars[i][7]
thislength=textchars[i][8]
textY=textchars[i][2]-startY
textchars.each do |text|
thisline = text[5]
thislength = text[8]
textY = text[2] - startY
# Don't draw lines before the first or zero-length segments
next if thisline < @firstline || thislength == 0
# Don't draw lines beyond the window's height
break if textY >= height
c=textchars[i][0]
c = text[0]
# Don't draw spaces
next if c == " "
textwidth=textchars[i][3]+4 # add 4 to prevent draw_text from stretching text
textheight=textchars[i][4]
textwidth = text[3] + 4 # add 4 to prevent draw_text from stretching text
textheight = text[4]
# Draw text
pbDrawShadowText(bitmap, textchars[i][1], textY, textwidth, textheight, c, @baseColor, @shadowColor)
pbDrawShadowText(bitmap, text[1], textY, textwidth, textheight, c, @baseColor, @shadowColor)
end
# Draw cursor
if ((@frame / 10) & 1) == 0
textheight = bitmap.text_size("X").height
cursorY = (textheight * @cursorLine) - startY
cursorX = 0
for i in 0...textchars.length
thisline=textchars[i][5]
thiscolumn=textchars[i][7]
thislength=textchars[i][8]
textchars.each do |text|
thisline = text[5]
thiscolumn = text[7]
thislength = text[8]
if thisline == @cursorLine && @cursorColumn >= thiscolumn &&
@cursorColumn <= thiscolumn + thislength
cursorY=textchars[i][2]-startY
cursorX=textchars[i][1]
textheight=textchars[i][4]
cursorY = text[2] - startY
cursorX = text[1]
textheight = text[4]
posToCursor = @cursorColumn - thiscolumn
if posToCursor >= 0
partialString=textchars[i][0].scan(/./m)[0,posToCursor].join("")
partialString = text[0].scan(/./m)[0, posToCursor].join
cursorX += bitmap.text_size(partialString).width
end
break

View File

@@ -4,7 +4,7 @@
$AtExitProcs = [] if !$AtExitProcs
def exit(code = 0)
for p in $AtExitProcs
$AtExitProcs.each do |p|
p.call
end
raise SystemExit.new(code)
@@ -51,7 +51,7 @@ def oggfiletime(file)
i = -1
pcmlengths = []
rates = []
for page in pages
pages.each do |page|
header = page[0]
serial = header[10, 4].unpack("V")
frame = header[2, 8].unpack("C*")
@@ -78,9 +78,7 @@ def oggfiletime(file)
pcmlengths[i] = frameno
end
ret = 0.0
for i in 0...pcmlengths.length
ret += pcmlengths[i].to_f / rates[i].to_f
end
pcmlengths.each_with_index { |length, i| ret += length.to_f / rates[i] }
return ret * 256.0
end
@@ -110,36 +108,37 @@ def getPlayTime2(filename)
File.open(filename, "rb") { |file|
file.pos = 0
fdw = fgetdw.call(file)
if fdw == 0x46464952 # "RIFF"
case fdw
when 0x46464952 # "RIFF"
filesize = fgetdw.call(file)
wave = fgetdw.call(file)
return -1 if wave != 0x45564157 # "WAVE"
fmt = fgetdw.call(file)
return -1 if fmt != 0x20746d66 # "fmt "
fmtsize = fgetdw.call(file)
format = fgetw.call(file)
channels = fgetw.call(file)
rate = fgetdw.call(file)
fgetdw.call(file) # fmtsize
fgetw.call(file) # format
fgetw.call(file) # channels
fgetdw.call(file) # rate
bytessec = fgetdw.call(file)
return -1 if bytessec == 0
bytessample = fgetw.call(file)
bitssample = fgetw.call(file)
fgetw.call(file) # bytessample
fgetw.call(file) # bitssample
data = fgetdw.call(file)
return -1 if data != 0x61746164 # "data"
datasize = fgetdw.call(file)
time = (datasize*1.0)/bytessec
time = datasize.to_f / bytessec
return time
elsif fdw == 0x5367674F # "OggS"
when 0x5367674F # "OggS"
file.pos = 0
time = oggfiletime(file)
return time
end
file.pos = 0
# Find the length of an MP3 file
while true
loop do
rstr = ""
ateof = false
while !file.eof?
until file.eof?
if (file.read(1)[0] rescue 0) == 0xFF
begin
rstr = file.read(3)
@@ -152,15 +151,15 @@ def getPlayTime2(filename)
break if ateof || !rstr || rstr.length != 3
if rstr[0] == 0xFB
t = rstr[1] >> 4
next if t == 0 || t == 15
freqs = [44100, 22050, 11025, 48000]
next if [0, 15].include?(t)
freqs = [44_100, 22_050, 11_025, 48_000]
bitrates = [32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320]
bitrate = bitrates[t]
t = (rstr[1] >> 2) & 3
freq = freqs[t]
t = (rstr[1] >> 1) & 1
filesize = FileTest.size(filename)
frameLength = ((144000 * bitrate) / freq) + t
frameLength = ((144_000 * bitrate) / freq) + t
numFrames = filesize / (frameLength + 4)
time = (numFrames * 1152.0 / freq)
break

View File

@@ -53,12 +53,12 @@ def pbBGMPlay(param,volume=nil,pitch=nil)
return if !param
param = pbResolveAudioFile(param, volume, pitch)
if param.name && param.name != ""
if $game_system && $game_system.respond_to?("bgm_play")
if $game_system
$game_system.bgm_play(param)
return
elsif (RPG.const_defined?(:BGM) rescue false)
b = RPG::BGM.new(param.name, param.volume, param.pitch)
if b && b.respond_to?("play")
if b.respond_to?("play")
b.play
return
end
@@ -72,10 +72,10 @@ def pbBGMFade(x=0.0); pbBGMStop(x);end
# Fades out or stops BGM playback. 'x' is the time in seconds to fade out.
def pbBGMStop(timeInSeconds = 0.0)
if $game_system && timeInSeconds>0.0 && $game_system.respond_to?("bgm_fade")
if $game_system && timeInSeconds > 0.0
$game_system.bgm_fade(timeInSeconds)
return
elsif $game_system && $game_system.respond_to?("bgm_stop")
elsif $game_system
$game_system.bgm_stop
return
elsif (RPG.const_defined?(:BGM) rescue false)
@@ -103,13 +103,14 @@ def pbMEPlay(param,volume=nil,pitch=nil)
return if !param
param = pbResolveAudioFile(param, volume, pitch)
if param.name && param.name != ""
if $game_system && $game_system.respond_to?("me_play")
if $game_system
$game_system.me_play(param)
return
elsif (RPG.const_defined?(:ME) rescue false)
b = RPG::ME.new(param.name, param.volume, param.pitch)
if b && b.respond_to?("play")
b.play; return
if b.respond_to?("play")
b.play
return
end
end
Audio.me_play(canonicalize("Audio/ME/" + param.name), param.volume, param.pitch)
@@ -124,7 +125,7 @@ def pbMEStop(timeInSeconds=0.0)
if $game_system && timeInSeconds > 0.0 && $game_system.respond_to?("me_fade")
$game_system.me_fade(timeInSeconds)
return
elsif $game_system && $game_system.respond_to?("me_stop")
elsif $game_system.respond_to?("me_stop")
$game_system.me_stop(nil)
return
elsif (RPG.const_defined?(:ME) rescue false)
@@ -152,13 +153,14 @@ def pbBGSPlay(param,volume=nil,pitch=nil)
return if !param
param = pbResolveAudioFile(param, volume, pitch)
if param.name && param.name != ""
if $game_system && $game_system.respond_to?("bgs_play")
if $game_system
$game_system.bgs_play(param)
return
elsif (RPG.const_defined?(:BGS) rescue false)
b = RPG::BGS.new(param.name, param.volume, param.pitch)
if b && b.respond_to?("play")
b.play; return
if b.respond_to?("play")
b.play
return
end
end
Audio.bgs_play(canonicalize("Audio/BGS/" + param.name), param.volume, param.pitch)
@@ -170,10 +172,10 @@ def pbBGSFade(x=0.0); pbBGSStop(x);end
# Fades out or stops BGS playback. 'x' is the time in seconds to fade out.
def pbBGSStop(timeInSeconds = 0.0)
if $game_system && timeInSeconds>0.0 && $game_system.respond_to?("bgs_fade")
if $game_system && timeInSeconds > 0.0
$game_system.bgs_fade(timeInSeconds)
return
elsif $game_system && $game_system.respond_to?("bgs_play")
elsif $game_system
$game_system.bgs_play(nil)
return
elsif (RPG.const_defined?(:BGS) rescue false)
@@ -201,13 +203,13 @@ def pbSEPlay(param,volume=nil,pitch=nil)
return if !param
param = pbResolveAudioFile(param, volume, pitch)
if param.name && param.name != ""
if $game_system && $game_system.respond_to?("se_play")
if $game_system
$game_system.se_play(param)
return
end
if (RPG.const_defined?(:SE) rescue false)
b = RPG::SE.new(param.name, param.volume, param.pitch)
if b && b.respond_to?("play")
if b.respond_to?("play")
b.play
return
end
@@ -234,12 +236,8 @@ end
# Plays a sound effect that plays when the player moves the cursor.
def pbPlayCursorSE
if $data_system && $data_system.respond_to?("cursor_se") &&
$data_system.cursor_se && $data_system.cursor_se.name!=""
if !nil_or_empty?($data_system&.cursor_se&.name)
pbSEPlay($data_system.cursor_se)
elsif $data_system && $data_system.respond_to?("sounds") &&
$data_system.sounds && $data_system.sounds[0] && $data_system.sounds[0].name!=""
pbSEPlay($data_system.sounds[0])
elsif FileTest.audio_exist?("Audio/SE/GUI sel cursor")
pbSEPlay("GUI sel cursor", 80)
end
@@ -247,12 +245,8 @@ end
# Plays a sound effect that plays when a decision is confirmed or a choice is made.
def pbPlayDecisionSE
if $data_system && $data_system.respond_to?("decision_se") &&
$data_system.decision_se && $data_system.decision_se.name!=""
if !nil_or_empty?($data_system&.decision_se&.name)
pbSEPlay($data_system.decision_se)
elsif $data_system && $data_system.respond_to?("sounds") &&
$data_system.sounds && $data_system.sounds[1] && $data_system.sounds[1].name!=""
pbSEPlay($data_system.sounds[1])
elsif FileTest.audio_exist?("Audio/SE/GUI sel decision")
pbSEPlay("GUI sel decision", 80)
end
@@ -260,12 +254,8 @@ end
# Plays a sound effect that plays when a choice is canceled.
def pbPlayCancelSE
if $data_system && $data_system.respond_to?("cancel_se") &&
$data_system.cancel_se && $data_system.cancel_se.name!=""
if !nil_or_empty?($data_system&.cancel_se&.name)
pbSEPlay($data_system.cancel_se)
elsif $data_system && $data_system.respond_to?("sounds") &&
$data_system.sounds && $data_system.sounds[2] && $data_system.sounds[2].name!=""
pbSEPlay($data_system.sounds[2])
elsif FileTest.audio_exist?("Audio/SE/GUI sel cancel")
pbSEPlay("GUI sel cancel", 80)
end
@@ -273,12 +263,8 @@ end
# Plays a buzzer sound effect.
def pbPlayBuzzerSE
if $data_system && $data_system.respond_to?("buzzer_se") &&
$data_system.buzzer_se && $data_system.buzzer_se.name!=""
if !nil_or_empty?($data_system&.buzzer_se&.name)
pbSEPlay($data_system.buzzer_se)
elsif $data_system && $data_system.respond_to?("sounds") &&
$data_system.sounds && $data_system.sounds[3] && $data_system.sounds[3].name!=""
pbSEPlay($data_system.sounds[3])
elsif FileTest.audio_exist?("Audio/SE/GUI sel buzzer")
pbSEPlay("GUI sel buzzer", 80)
end

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@ class PictureSprite < SpriteWrapper
end
def dispose
@pictureBitmap.dispose if @pictureBitmap
@pictureBitmap&.dispose
super
end
@@ -22,7 +22,7 @@ class PictureSprite < SpriteWrapper
def update
super
@pictureBitmap.update if @pictureBitmap
@pictureBitmap&.update
# If picture file name is different from current one
if @customBitmap && @picture.name == ""
self.bitmap = (@customBitmapIsBitmap) ? @customBitmap : @customBitmap.bitmap
@@ -32,13 +32,13 @@ class PictureSprite < SpriteWrapper
@hue = @picture.hue.to_i
# If file name is not empty
if @picture_name == ""
@pictureBitmap.dispose if @pictureBitmap
@pictureBitmap&.dispose
@pictureBitmap = nil
self.visible = false
return
end
# Get picture graphic
@pictureBitmap.dispose if @pictureBitmap
@pictureBitmap&.dispose
@pictureBitmap = AnimatedBitmap.new(@picture_name, @hue)
self.bitmap = (@pictureBitmap) ? @pictureBitmap.bitmap : nil
elsif @picture_name == ""
@@ -55,7 +55,7 @@ end
def pbTextBitmap(text, maxwidth = Graphics.width)
tmp = Bitmap.new(maxwidth, Graphics.height)
pbSetSystemFont(tmp)
drawFormattedTextEx(tmp,0,0,maxwidth,text,Color.new(248,248,248),Color.new(168,184,184))
drawFormattedTextEx(tmp, 0, 4, maxwidth, text, Color.new(248, 248, 248), Color.new(168, 184, 184))
return tmp
end
@@ -80,10 +80,10 @@ class EventScene
def dispose
return if disposed?
for sprite in @picturesprites
@picturesprites.each do |sprite|
sprite.dispose
end
for sprite in @usersprites
@usersprites.each do |sprite|
sprite.dispose
end
@onCTrigger.clear
@@ -143,7 +143,7 @@ class EventScene
def pictureWait(extraframes = 0)
loop do
hasRunning = false
for pic in @pictures
@pictures.each do |pic|
hasRunning = true if pic.running?
end
break if !hasRunning
@@ -156,13 +156,13 @@ class EventScene
return if disposed?
Graphics.update
Input.update
for picture in @pictures
@pictures.each do |picture|
picture.update
end
for sprite in @picturesprites
@picturesprites.each do |sprite|
sprite.update
end
for sprite in @usersprites
@usersprites.each do |sprite|
next if !sprite || sprite.disposed? || !sprite.is_a?(Sprite)
sprite.update
end
@@ -175,7 +175,7 @@ class EventScene
end
def main
while !disposed?
until disposed?
update
end
end

View File

@@ -26,9 +26,6 @@ module GameData
validate other => [Symbol, self, String, Integer]
return other if other.is_a?(self)
other = other.to_sym if other.is_a?(String)
# if other.is_a?(Integer)
# p "Please switch to symbols, thanks."
# end
raise "Unknown ID #{other}." unless self::DATA.has_key?(other)
return self::DATA[other]
end
@@ -40,9 +37,6 @@ module GameData
validate other => [Symbol, self, String, Integer]
return other if other.is_a?(self)
other = other.to_sym if other.is_a?(String)
# if other.is_a?(Integer)
# p "Please switch to symbols, thanks."
# end
return (self::DATA.has_key?(other)) ? self::DATA[other] : nil
end
@@ -54,8 +48,12 @@ module GameData
# Yields all data in order of their id_number.
def each
keys = self::DATA.keys.sort { |a, b| self::DATA[a].id_number <=> self::DATA[b].id_number }
keys.each { |key| yield self::DATA[key] if !key.is_a?(Integer) }
sorted_keys = self::DATA.keys.sort { |a, b| self::DATA[a].id_number <=> self::DATA[b].id_number }
sorted_keys.each { |key| yield self::DATA[key] if !key.is_a?(Integer) }
end
def count
return self::DATA.length / 2
end
def load
@@ -114,12 +112,21 @@ module GameData
return self::DATA.keys
end
# Yields all data in alphabetical order.
# Yields all data in the order they were defined.
def each
self::DATA.each_value { |value| yield value }
end
# Yields all data in alphabetical order.
def each_alphabetically
keys = self::DATA.keys.sort { |a, b| self::DATA[a].real_name <=> self::DATA[b].real_name }
keys.each { |key| yield self::DATA[key] }
end
def count
return self::DATA.length
end
def load
const_set(:DATA, load_data("Data/#{self::DATA_FILENAME}"))
end
@@ -177,6 +184,10 @@ module GameData
keys.each { |key| yield self::DATA[key] }
end
def count
return self::DATA.length
end
def load
const_set(:DATA, load_data("Data/#{self::DATA_FILENAME}"))
end
@@ -196,13 +207,14 @@ module GameData
# @return [Boolean] whether other represents the same thing as this thing
def ==(other)
return false if other.nil?
if other.is_a?(Symbol)
case other
when Symbol
return @id == other
elsif other.is_a?(self.class)
when self.class
return @id == other.id
elsif other.is_a?(String)
return @id_number == other.to_sym
elsif other.is_a?(Integer)
when String
return @id == other.to_sym
when Integer
return @id_number == other
end
return false
@@ -219,11 +231,14 @@ module GameData
Item.load
BerryPlant.load
Species.load
SpeciesMetrics.load
ShadowPokemon.load
Ribbon.load
Encounter.load
TrainerType.load
Trainer.load
Metadata.load
PlayerMetadata.load
MapMetadata.load
end
end

View File

@@ -64,7 +64,7 @@ module GameData
return ArgumentError.new("Exp amount #{level} is invalid.") if !exp || exp < 0
max = GrowthRate.max_level
return max if exp >= maximum_exp
for level in 1..max
(1..max).each do |level|
return level - 1 if exp < minimum_exp_for_level(level)
end
return max
@@ -133,7 +133,7 @@ GameData::GrowthRate.register({
765275, 804997, 834809, 877201, 908905, 954084, 987754, 1035837, 1071552, 1122660,
1160499, 1214753, 1254796, 1312322, 1354652, 1415577, 1460276, 1524731, 1571884, 1640000],
:exp_formula => proc { |level|
rate = [82 - (level - 100) / 2.0, 40].max
rate = [82 - ((level - 100) / 2.0), 40].max
next (level**4) * rate / 5000
}
})
@@ -152,7 +152,7 @@ GameData::GrowthRate.register({
360838, 377197, 394045, 411388, 429235, 447591, 466464, 485862, 505791, 526260,
547274, 568841, 590969, 613664, 636935, 660787, 685228, 710266, 735907, 762160,
789030, 816525, 844653, 873420, 902835, 932903, 963632, 995030, 1027103, 1059860],
:exp_formula => proc { |level| next ((level ** 3) * 6 / 5) - 15 * (level ** 2) + 100 * level - 140 }
:exp_formula => proc { |level| next ((level**3) * 6 / 5) - (15 * (level**2)) + (100 * level) - 140 }
})
GameData::GrowthRate.register({

View File

@@ -26,6 +26,12 @@ module GameData
def name
return _INTL(@real_name)
end
# @return [Boolean] whether a Pokémon with this gender ratio can only ever
# be a single gender
def single_gendered?
return @female_chance.nil?
end
end
end

View File

@@ -1,17 +1,16 @@
# NOTE: The id_number is only used to determine the order that body shapes are
# listed in the Pokédex search screen. Number 0 (:None) is ignored; they
# start with shape 1.
# NOTE: The order these shapes are registered are the order they are listed in
# the Pokédex search screen.
# "Graphics/Pictures/Pokedex/icon_shapes.png" contains icons for these
# shapes.
module GameData
class BodyShape
attr_reader :id
attr_reader :id_number
attr_reader :real_name
attr_reader :icon_position # Where this shape's icon is within icon_shapes.png
DATA = {}
extend ClassMethods
extend ClassMethodsSymbols
include InstanceMethods
def self.load; end
@@ -19,8 +18,8 @@ module GameData
def initialize(hash)
@id = hash[:id]
@id_number = hash[:id_number] || -1
@real_name = hash[:name] || "Unnamed"
@icon_position = hash[:icon_position] || 0
end
# @return [String] the translated name of this body shape
@@ -34,84 +33,84 @@ end
GameData::BodyShape.register({
:id => :Head,
:id_number => 1,
:name => _INTL("Head")
:name => _INTL("Head"),
:icon_position => 0
})
GameData::BodyShape.register({
:id => :Serpentine,
:id_number => 2,
:name => _INTL("Serpentine")
:name => _INTL("Serpentine"),
:icon_position => 1
})
GameData::BodyShape.register({
:id => :Finned,
:id_number => 3,
:name => _INTL("Finned")
:name => _INTL("Finned"),
:icon_position => 2
})
GameData::BodyShape.register({
:id => :HeadArms,
:id_number => 4,
:name => _INTL("Head and arms")
:name => _INTL("Head and arms"),
:icon_position => 3
})
GameData::BodyShape.register({
:id => :HeadBase,
:id_number => 5,
:name => _INTL("Head and base")
:name => _INTL("Head and base"),
:icon_position => 4
})
GameData::BodyShape.register({
:id => :BipedalTail,
:id_number => 6,
:name => _INTL("Bipedal with tail")
:name => _INTL("Bipedal with tail"),
:icon_position => 5
})
GameData::BodyShape.register({
:id => :HeadLegs,
:id_number => 7,
:name => _INTL("Head and legs")
:name => _INTL("Head and legs"),
:icon_position => 6
})
GameData::BodyShape.register({
:id => :Quadruped,
:id_number => 8,
:name => _INTL("Quadruped")
:name => _INTL("Quadruped"),
:icon_position => 7
})
GameData::BodyShape.register({
:id => :Winged,
:id_number => 9,
:name => _INTL("Winged")
:name => _INTL("Winged"),
:icon_position => 8
})
GameData::BodyShape.register({
:id => :Multiped,
:id_number => 10,
:name => _INTL("Multiped")
:name => _INTL("Multiped"),
:icon_position => 9
})
GameData::BodyShape.register({
:id => :MultiBody,
:id_number => 11,
:name => _INTL("Multi Body")
:name => _INTL("Multi Body"),
:icon_position => 10
})
GameData::BodyShape.register({
:id => :Bipedal,
:id_number => 12,
:name => _INTL("Bipedal")
:name => _INTL("Bipedal"),
:icon_position => 11
})
GameData::BodyShape.register({
:id => :MultiWinged,
:id_number => 13,
:name => _INTL("Multi Winged")
:name => _INTL("Multi Winged"),
:icon_position => 12
})
GameData::BodyShape.register({
:id => :Insectoid,
:id_number => 14,
:name => _INTL("Insectoid")
:name => _INTL("Insectoid"),
:icon_position => 13
})

View File

@@ -1,14 +1,13 @@
# NOTE: The id_number is only used to determine the order that body colors are
# listed in the Pokédex search screen.
# NOTE: The order these colors are registered are the order they are listed in
# the Pokédex search screen.
module GameData
class BodyColor
attr_reader :id
attr_reader :id_number
attr_reader :real_name
DATA = {}
extend ClassMethods
extend ClassMethodsSymbols
include InstanceMethods
def self.load; end
@@ -16,7 +15,6 @@ module GameData
def initialize(hash)
@id = hash[:id]
@id_number = hash[:id_number] || -1
@real_name = hash[:name] || "Unnamed"
end
@@ -31,60 +29,50 @@ end
GameData::BodyColor.register({
:id => :Red,
:id_number => 0,
:name => _INTL("Red")
})
GameData::BodyColor.register({
:id => :Blue,
:id_number => 1,
:name => _INTL("Blue")
})
GameData::BodyColor.register({
:id => :Yellow,
:id_number => 2,
:name => _INTL("Yellow")
})
GameData::BodyColor.register({
:id => :Green,
:id_number => 3,
:name => _INTL("Green")
})
GameData::BodyColor.register({
:id => :Black,
:id_number => 4,
:name => _INTL("Black")
})
GameData::BodyColor.register({
:id => :Brown,
:id_number => 5,
:name => _INTL("Brown")
})
GameData::BodyColor.register({
:id => :Purple,
:id_number => 6,
:name => _INTL("Purple")
})
GameData::BodyColor.register({
:id => :Gray,
:id_number => 7,
:name => _INTL("Gray")
})
GameData::BodyColor.register({
:id => :White,
:id_number => 8,
:name => _INTL("White")
})
GameData::BodyColor.register({
:id => :Pink,
:id_number => 9,
:name => _INTL("Pink")
})

View File

@@ -7,6 +7,8 @@ module GameData
attr_reader :level_up_proc
attr_reader :use_item_proc
attr_reader :on_trade_proc
attr_reader :after_battle_proc
attr_reader :event_proc
attr_reader :after_evolution_proc
DATA = {}
@@ -25,6 +27,8 @@ module GameData
@level_up_proc = hash[:level_up_proc]
@use_item_proc = hash[:use_item_proc]
@on_trade_proc = hash[:on_trade_proc]
@after_battle_proc = hash[:after_battle_proc]
@event_proc = hash[:event_proc]
@after_evolution_proc = hash[:after_evolution_proc]
end
@@ -40,8 +44,16 @@ module GameData
return (@on_trade_proc) ? @on_trade_proc.call(*args) : nil
end
def call_after_battle(*args)
return (@after_battle_proc) ? @after_battle_proc.call(*args) : nil
end
def call_event(*args)
return (@event_proc) ? @event_proc.call(*args) : nil
end
def call_after_evolution(*args)
@after_evolution_proc.call(*args) if @after_evolution_proc
@after_evolution_proc&.call(*args)
end
end
end
@@ -188,8 +200,7 @@ GameData::Evolution.register({
:id => :LevelDarkness,
:parameter => Integer,
:level_up_proc => proc { |pkmn, parameter|
map_metadata = GameData::MapMetadata.try_get($game_map.map_id)
next pkmn.level >= parameter && map_metadata && map_metadata.dark_map
next pkmn.level >= parameter && $game_map.metadata&.dark_map
}
})
@@ -197,7 +208,7 @@ GameData::Evolution.register({
:id => :LevelDarkInParty,
:parameter => Integer,
:level_up_proc => proc { |pkmn, parameter|
next pkmn.level >= parameter && $Trainer.has_pokemon_of_type?(:DARK)
next pkmn.level >= parameter && $player.has_pokemon_of_type?(:DARK)
}
})
@@ -252,14 +263,11 @@ GameData::Evolution.register({
GameData::Evolution.register({
:id => :Shedinja,
:parameter => Integer,
:level_up_proc => proc { |pkmn, parameter|
next false # This is a dummy proc and shouldn't next true
},
:after_evolution_proc => proc { |pkmn, new_species, parameter, evo_species|
next false if $Trainer.party_full?
next false if !$PokemonBag.pbHasItem?(:POKEBALL)
next false if $player.party_full?
next false if !$bag.has?(:POKEBALL)
PokemonEvolutionScene.pbDuplicatePokemon(pkmn, new_species)
$PokemonBag.pbDeleteItem(:POKEBALL)
$bag.remove(:POKEBALL)
next true
}
})
@@ -268,7 +276,7 @@ GameData::Evolution.register({
:id => :Happiness,
:minimum_level => 1, # Needs any level up
:level_up_proc => proc { |pkmn, parameter|
next pkmn.happiness >= 220
next pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220)
}
})
@@ -276,7 +284,7 @@ GameData::Evolution.register({
:id => :HappinessMale,
:minimum_level => 1, # Needs any level up
:level_up_proc => proc { |pkmn, parameter|
next pkmn.happiness >= 220 && pkmn.male?
next pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220) && pkmn.male?
}
})
@@ -284,7 +292,7 @@ GameData::Evolution.register({
:id => :HappinessFemale,
:minimum_level => 1, # Needs any level up
:level_up_proc => proc { |pkmn, parameter|
next pkmn.happiness >= 220 && pkmn.female?
next pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220) && pkmn.female?
}
})
@@ -292,7 +300,7 @@ GameData::Evolution.register({
:id => :HappinessDay,
:minimum_level => 1, # Needs any level up
:level_up_proc => proc { |pkmn, parameter|
next pkmn.happiness >= 220 && PBDayNight.isDay?
next pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220) && PBDayNight.isDay?
}
})
@@ -300,7 +308,7 @@ GameData::Evolution.register({
:id => :HappinessNight,
:minimum_level => 1, # Needs any level up
:level_up_proc => proc { |pkmn, parameter|
next pkmn.happiness >= 220 && PBDayNight.isNight?
next pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220) && PBDayNight.isNight?
}
})
@@ -309,7 +317,7 @@ GameData::Evolution.register({
:parameter => :Move,
:minimum_level => 1, # Needs any level up
:level_up_proc => proc { |pkmn, parameter|
if pkmn.happiness >= 220
if pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220)
next pkmn.moves.any? { |m| m && m.id == parameter }
end
}
@@ -320,7 +328,7 @@ GameData::Evolution.register({
:parameter => :Type,
:minimum_level => 1, # Needs any level up
:level_up_proc => proc { |pkmn, parameter|
if pkmn.happiness >= 220
if pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220)
next pkmn.moves.any? { |m| m && m.type == parameter }
end
}
@@ -331,7 +339,7 @@ GameData::Evolution.register({
:parameter => :Item,
:minimum_level => 1, # Needs any level up
:level_up_proc => proc { |pkmn, parameter|
next pkmn.item == parameter && pkmn.happiness >= 220
next pkmn.item == parameter && pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220)
},
:after_evolution_proc => proc { |pkmn, new_species, parameter, evo_species|
next false if evo_species != new_species || !pkmn.hasItem?(parameter)
@@ -432,7 +440,7 @@ GameData::Evolution.register({
:parameter => :Item,
:minimum_level => 1, # Needs any level up
:level_up_proc => proc { |pkmn, parameter|
next pkmn.item == parameter && pkmn.happiness >= 220
next pkmn.item == parameter && pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220)
},
:after_evolution_proc => proc { |pkmn, new_species, parameter, evo_species|
next false if evo_species != new_species || !pkmn.hasItem?(parameter)
@@ -464,7 +472,7 @@ GameData::Evolution.register({
:parameter => :Species,
:minimum_level => 1, # Needs any level up
:level_up_proc => proc { |pkmn, parameter|
next $Trainer.has_species?(parameter)
next $player.has_species?(parameter)
}
})
@@ -477,14 +485,22 @@ GameData::Evolution.register({
}
})
GameData::Evolution.register({
:id => :LocationFlag,
:parameter => String,
:minimum_level => 1, # Needs any level up
:level_up_proc => proc { |pkmn, parameter|
next $game_map.metadata&.has_flag?(parameter)
}
})
GameData::Evolution.register({
:id => :Region,
:parameter => Integer,
:minimum_level => 1, # Needs any level up
:level_up_proc => proc { |pkmn, parameter|
map_metadata = GameData::MapMetadata.try_get($game_map.map_id)
next map_metadata && map_metadata.town_map_position &&
map_metadata.town_map_position[0] == parameter
map_metadata = $game_map.metadata
next map_metadata&.town_map_position && map_metadata.town_map_position[0] == parameter
}
})
@@ -535,7 +551,7 @@ GameData::Evolution.register({
:id => :ItemHappiness,
:parameter => :Item,
:use_item_proc => proc { |pkmn, parameter, item|
next item == parameter && pkmn.happiness >= 220
next item == parameter && pkmn.happiness >= (Settings::APPLY_HAPPINESS_SOFT_CAP ? 160 : 220)
}
})
@@ -597,3 +613,62 @@ GameData::Evolution.register({
next pkmn.species == parameter && !other_pkmn.hasItem?(:EVERSTONE)
}
})
#===============================================================================
# Evolution methods that are triggered after any battle
#===============================================================================
GameData::Evolution.register({
:id => :BattleDealCriticalHit,
:parameter => Integer,
:after_battle_proc => proc { |pkmn, party_index, parameter|
next $game_temp.party_critical_hits_dealt &&
$game_temp.party_critical_hits_dealt[party_index] &&
$game_temp.party_critical_hits_dealt[party_index] >= parameter
}
})
#===============================================================================
# Evolution methods that are triggered by an event
# Each event has its own number, which is the value of the parameter as defined
# in pokemon.txt/pokemon_forms.txt. It is also 'number' in def pbEvolutionEvent,
# which triggers evolution checks for a particular event number. 'value' in an
# event_proc is the number of the evolution event currently being triggered.
# Evolutions caused by different events should have different numbers. Used
# event numbers are:
# 1: Kubfu -> Urshifu
# 2: Galarian Yamask -> Runerigus
# These used event numbers are only used in pokemon.txt/pokemon_forms.txt and in
# map events that call pbEvolutionEvent, so they are relatively easy to change
# if you need to (no script changes are required). However, you could just
# ignore them instead if you don't want to use them.
#===============================================================================
def pbEvolutionEvent(number)
return if !$player
$player.able_party.each do |pkmn|
pkmn.trigger_event_evolution(number)
end
end
GameData::Evolution.register({
:id => :Event,
:parameter => Integer,
:event_proc => proc { |pkmn, parameter, value|
next value == parameter
}
})
GameData::Evolution.register({
:id => :EventAfterDamageTaken,
:parameter => Integer,
:after_battle_proc => proc { |pkmn, party_index, parameter|
if $game_temp.party_direct_damage_taken &&
$game_temp.party_direct_damage_taken[party_index] &&
$game_temp.party_direct_damage_taken[party_index] >= 49
pkmn.ready_to_evolve = true
end
next false
},
:event_proc => proc { |pkmn, parameter, value|
next value == parameter && pkmn.ready_to_evolve
}
})

View File

@@ -1,5 +1,3 @@
# The id_number value determines which order the stats are iterated through by
# the "each" methods.
# The pbs_order value determines the order in which the stats are written in
# several PBS files, where base stats/IVs/EVs/EV yields are defined. Only stats
# which are yielded by the "each_main" method can have stat numbers defined in
@@ -8,7 +6,6 @@
module GameData
class Stat
attr_reader :id
attr_reader :id_number
attr_reader :real_name
attr_reader :real_name_brief
attr_reader :type
@@ -16,7 +13,7 @@ module GameData
DATA = {}
extend ClassMethods
extend ClassMethodsSymbols
include InstanceMethods
def self.load; end
@@ -39,7 +36,6 @@ module GameData
def initialize(hash)
@id = hash[:id]
@id_number = hash[:id_number] || -1
@real_name = hash[:name] || "Unnamed"
@real_name_brief = hash[:name_brief] || "None"
@type = hash[:type] || :none
@@ -62,7 +58,6 @@ end
GameData::Stat.register({
:id => :HP,
:id_number => 0,
:name => _INTL("HP"),
:name_brief => _INTL("HP"),
:type => :main,
@@ -71,7 +66,6 @@ GameData::Stat.register({
GameData::Stat.register({
:id => :ATTACK,
:id_number => 1,
:name => _INTL("Attack"),
:name_brief => _INTL("Atk"),
:type => :main_battle,
@@ -80,7 +74,6 @@ GameData::Stat.register({
GameData::Stat.register({
:id => :DEFENSE,
:id_number => 2,
:name => _INTL("Defense"),
:name_brief => _INTL("Def"),
:type => :main_battle,
@@ -89,7 +82,6 @@ GameData::Stat.register({
GameData::Stat.register({
:id => :SPECIAL_ATTACK,
:id_number => 3,
:name => _INTL("Special Attack"),
:name_brief => _INTL("SpAtk"),
:type => :main_battle,
@@ -98,7 +90,6 @@ GameData::Stat.register({
GameData::Stat.register({
:id => :SPECIAL_DEFENSE,
:id_number => 4,
:name => _INTL("Special Defense"),
:name_brief => _INTL("SpDef"),
:type => :main_battle,
@@ -107,7 +98,6 @@ GameData::Stat.register({
GameData::Stat.register({
:id => :SPEED,
:id_number => 5,
:name => _INTL("Speed"),
:name_brief => _INTL("Spd"),
:type => :main_battle,
@@ -116,7 +106,6 @@ GameData::Stat.register({
GameData::Stat.register({
:id => :ACCURACY,
:id_number => 6,
:name => _INTL("accuracy"),
:name_brief => _INTL("Acc"),
:type => :battle
@@ -124,7 +113,6 @@ GameData::Stat.register({
GameData::Stat.register({
:id => :EVASION,
:id_number => 7,
:name => _INTL("evasiveness"),
:name_brief => _INTL("Eva"),
:type => :battle

View File

@@ -1,13 +1,12 @@
module GameData
class Nature
attr_reader :id
attr_reader :id_number
attr_reader :real_name
attr_reader :stat_changes
DATA = {}
extend ClassMethods
extend ClassMethodsSymbols
include InstanceMethods
def self.load; end
@@ -15,7 +14,6 @@ module GameData
def initialize(hash)
@id = hash[:id]
@id_number = hash[:id_number] || -1
@real_name = hash[:name] || "Unnamed"
@stat_changes = hash[:stat_changes] || []
end
@@ -31,170 +29,145 @@ end
GameData::Nature.register({
:id => :HARDY,
:id_number => 0,
:name => _INTL("Hardy")
})
GameData::Nature.register({
:id => :LONELY,
:id_number => 1,
:name => _INTL("Lonely"),
:stat_changes => [[:ATTACK, 10], [:DEFENSE, -10]]
})
GameData::Nature.register({
:id => :BRAVE,
:id_number => 2,
:name => _INTL("Brave"),
:stat_changes => [[:ATTACK, 10], [:SPEED, -10]]
})
GameData::Nature.register({
:id => :ADAMANT,
:id_number => 3,
:name => _INTL("Adamant"),
:stat_changes => [[:ATTACK, 10], [:SPECIAL_ATTACK, -10]]
})
GameData::Nature.register({
:id => :NAUGHTY,
:id_number => 4,
:name => _INTL("Naughty"),
:stat_changes => [[:ATTACK, 10], [:SPECIAL_DEFENSE, -10]]
})
GameData::Nature.register({
:id => :BOLD,
:id_number => 5,
:name => _INTL("Bold"),
:stat_changes => [[:DEFENSE, 10], [:ATTACK, -10]]
})
GameData::Nature.register({
:id => :DOCILE,
:id_number => 6,
:name => _INTL("Docile")
})
GameData::Nature.register({
:id => :RELAXED,
:id_number => 7,
:name => _INTL("Relaxed"),
:stat_changes => [[:DEFENSE, 10], [:SPEED, -10]]
})
GameData::Nature.register({
:id => :IMPISH,
:id_number => 8,
:name => _INTL("Impish"),
:stat_changes => [[:DEFENSE, 10], [:SPECIAL_ATTACK, -10]]
})
GameData::Nature.register({
:id => :LAX,
:id_number => 9,
:name => _INTL("Lax"),
:stat_changes => [[:DEFENSE, 10], [:SPECIAL_DEFENSE, -10]]
})
GameData::Nature.register({
:id => :TIMID,
:id_number => 10,
:name => _INTL("Timid"),
:stat_changes => [[:SPEED, 10], [:ATTACK, -10]]
})
GameData::Nature.register({
:id => :HASTY,
:id_number => 11,
:name => _INTL("Hasty"),
:stat_changes => [[:SPEED, 10], [:DEFENSE, -10]]
})
GameData::Nature.register({
:id => :SERIOUS,
:id_number => 12,
:name => _INTL("Serious")
})
GameData::Nature.register({
:id => :JOLLY,
:id_number => 13,
:name => _INTL("Jolly"),
:stat_changes => [[:SPEED, 10], [:SPECIAL_ATTACK, -10]]
})
GameData::Nature.register({
:id => :NAIVE,
:id_number => 14,
:name => _INTL("Naive"),
:stat_changes => [[:SPEED, 10], [:SPECIAL_DEFENSE, -10]]
})
GameData::Nature.register({
:id => :MODEST,
:id_number => 15,
:name => _INTL("Modest"),
:stat_changes => [[:SPECIAL_ATTACK, 10], [:ATTACK, -10]]
})
GameData::Nature.register({
:id => :MILD,
:id_number => 16,
:name => _INTL("Mild"),
:stat_changes => [[:SPECIAL_ATTACK, 10], [:DEFENSE, -10]]
})
GameData::Nature.register({
:id => :QUIET,
:id_number => 17,
:name => _INTL("Quiet"),
:stat_changes => [[:SPECIAL_ATTACK, 10], [:SPEED, -10]]
})
GameData::Nature.register({
:id => :BASHFUL,
:id_number => 18,
:name => _INTL("Bashful")
})
GameData::Nature.register({
:id => :RASH,
:id_number => 19,
:name => _INTL("Rash"),
:stat_changes => [[:SPECIAL_ATTACK, 10], [:SPECIAL_DEFENSE, -10]]
})
GameData::Nature.register({
:id => :CALM,
:id_number => 20,
:name => _INTL("Calm"),
:stat_changes => [[:SPECIAL_DEFENSE, 10], [:ATTACK, -10]]
})
GameData::Nature.register({
:id => :GENTLE,
:id_number => 21,
:name => _INTL("Gentle"),
:stat_changes => [[:SPECIAL_DEFENSE, 10], [:DEFENSE, -10]]
})
GameData::Nature.register({
:id => :SASSY,
:id_number => 22,
:name => _INTL("Sassy"),
:stat_changes => [[:SPECIAL_DEFENSE, 10], [:SPEED, -10]]
})
GameData::Nature.register({
:id => :CAREFUL,
:id_number => 23,
:name => _INTL("Careful"),
:stat_changes => [[:SPECIAL_DEFENSE, 10], [:SPECIAL_ATTACK, -10]]
})
GameData::Nature.register({
:id => :QUIRKY,
:id_number => 24,
:name => _INTL("Quirky")
})

View File

@@ -1,21 +1,19 @@
# NOTE: The id_number is only used to determine the order of the status icons in
# the graphics containing them. Number 0 (:NONE) is ignored; they start
# with status 1.
# "Graphics/Pictures/statuses.png" also contains icons for being fainted
# NOTE: "Graphics/Pictures/statuses.png" also contains icons for being fainted
# and for having Pokérus, in that order, at the bottom of the graphic.
# "Graphics/Pictures/Battle/icon_statuses.png" also contains an icon for
# bad poisoning (toxic), at the bottom of the graphic.
# Both graphics automatically handle varying numbers of defined statuses.
# Both graphics automatically handle varying numbers of defined statuses,
# as long as their extra icons remain at the bottom of them.
module GameData
class Status
attr_reader :id
attr_reader :id_number
attr_reader :real_name
attr_reader :animation
attr_reader :icon_position # Where this status's icon is within statuses.png
DATA = {}
extend ClassMethods
extend ClassMethodsSymbols
include InstanceMethods
def self.load; end
@@ -23,9 +21,9 @@ module GameData
def initialize(hash)
@id = hash[:id]
@id_number = hash[:id_number]
@real_name = hash[:name] || "Unnamed"
@animation = hash[:animation]
@icon_position = hash[:icon_position] || 0
end
# @return [String] the translated name of this status condition
@@ -39,41 +37,40 @@ end
GameData::Status.register({
:id => :NONE,
:id_number => 0,
:name => _INTL("None")
})
GameData::Status.register({
:id => :SLEEP,
:id_number => 1,
:name => _INTL("Sleep"),
:animation => "Sleep"
:animation => "Sleep",
:icon_position => 0
})
GameData::Status.register({
:id => :POISON,
:id_number => 2,
:name => _INTL("Poison"),
:animation => "Poison"
:animation => "Poison",
:icon_position => 1
})
GameData::Status.register({
:id => :BURN,
:id_number => 3,
:name => _INTL("Burn"),
:animation => "Burn"
:animation => "Burn",
:icon_position => 2
})
GameData::Status.register({
:id => :PARALYSIS,
:id_number => 4,
:name => _INTL("Paralysis"),
:animation => "Paralysis"
:animation => "Paralysis",
:icon_position => 3
})
GameData::Status.register({
:id => :FROZEN,
:id_number => 5,
:name => _INTL("Frozen"),
:animation => "Frozen"
:animation => "Frozen",
:icon_position => 4
})

View File

@@ -170,8 +170,9 @@ GameData::TerrainTag.register({
:ignore_passability => true
})
# NOTE: This is referenced by ID in an Events.onStepTakenFieldMovement proc that
# adds soot to the Soot Sack if the player walks over one of these tiles.
# NOTE: This is referenced by ID in the :pick_up_soot proc added to
# EventHandlers. It adds soot to the Soot Sack if the player walks over
# one of these tiles.
GameData::TerrainTag.register({
:id => :SootGrass,
:id_number => 14,
@@ -192,3 +193,8 @@ GameData::TerrainTag.register({
:battle_environment => :Puddle,
:shows_reflections => true
})
GameData::TerrainTag.register({
:id => :NoEffect,
:id_number => 17
})

View File

@@ -4,7 +4,6 @@ module GameData
attr_reader :real_name
attr_reader :type # :land, :cave, :water, :fishing, :contest, :none
attr_reader :trigger_chance
attr_reader :old_slots
DATA = {}
@@ -19,7 +18,6 @@ module GameData
@real_name = hash[:id].to_s || "Unnamed"
@type = hash[:type] || :none
@trigger_chance = hash[:trigger_chance] || 0
@old_slots = hash[:old_slots]
end
end
end
@@ -29,169 +27,144 @@ end
GameData::EncounterType.register({
:id => :Land,
:type => :land,
:trigger_chance => 21,
:old_slots => [20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1]
:trigger_chance => 21
})
GameData::EncounterType.register({
:id => :LandDay,
:type => :land,
:trigger_chance => 21,
:old_slots => [20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1]
:trigger_chance => 21
})
GameData::EncounterType.register({
:id => :LandNight,
:type => :land,
:trigger_chance => 21,
:old_slots => [20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1]
:trigger_chance => 21
})
GameData::EncounterType.register({
:id => :LandMorning,
:type => :land,
:trigger_chance => 21,
:old_slots => [20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1]
:trigger_chance => 21
})
GameData::EncounterType.register({
:id => :LandAfternoon,
:type => :land,
:trigger_chance => 21,
:old_slots => [20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1]
:trigger_chance => 21
})
GameData::EncounterType.register({
:id => :LandEvening,
:type => :land,
:trigger_chance => 21,
:old_slots => [20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1]
:trigger_chance => 21
})
GameData::EncounterType.register({
:id => :Cave,
:type => :cave,
:trigger_chance => 5,
:old_slots => [20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1]
:trigger_chance => 5
})
GameData::EncounterType.register({
:id => :CaveDay,
:type => :cave,
:trigger_chance => 5,
:old_slots => [20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1]
:trigger_chance => 5
})
GameData::EncounterType.register({
:id => :CaveNight,
:type => :cave,
:trigger_chance => 5,
:old_slots => [20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1]
:trigger_chance => 5
})
GameData::EncounterType.register({
:id => :CaveMorning,
:type => :cave,
:trigger_chance => 5,
:old_slots => [20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1]
:trigger_chance => 5
})
GameData::EncounterType.register({
:id => :CaveAfternoon,
:type => :cave,
:trigger_chance => 5,
:old_slots => [20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1]
:trigger_chance => 5
})
GameData::EncounterType.register({
:id => :CaveEvening,
:type => :cave,
:trigger_chance => 5,
:old_slots => [20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1]
:trigger_chance => 5
})
GameData::EncounterType.register({
:id => :Water,
:type => :water,
:trigger_chance => 2,
:old_slots => [60, 30, 5, 4, 1]
:trigger_chance => 2
})
GameData::EncounterType.register({
:id => :WaterDay,
:type => :water,
:trigger_chance => 2,
:old_slots => [60, 30, 5, 4, 1]
:trigger_chance => 2
})
GameData::EncounterType.register({
:id => :WaterNight,
:type => :water,
:trigger_chance => 2,
:old_slots => [60, 30, 5, 4, 1]
:trigger_chance => 2
})
GameData::EncounterType.register({
:id => :WaterMorning,
:type => :water,
:trigger_chance => 2,
:old_slots => [60, 30, 5, 4, 1]
:trigger_chance => 2
})
GameData::EncounterType.register({
:id => :WaterAfternoon,
:type => :water,
:trigger_chance => 2,
:old_slots => [60, 30, 5, 4, 1]
:trigger_chance => 2
})
GameData::EncounterType.register({
:id => :WaterEvening,
:type => :water,
:trigger_chance => 2,
:old_slots => [60, 30, 5, 4, 1]
:trigger_chance => 2
})
GameData::EncounterType.register({
:id => :OldRod,
:type => :fishing,
:old_slots => [70, 30]
:type => :fishing
})
GameData::EncounterType.register({
:id => :GoodRod,
:type => :fishing,
:old_slots => [60, 20, 20]
:type => :fishing
})
GameData::EncounterType.register({
:id => :SuperRod,
:type => :fishing,
:old_slots => [40, 40, 15, 4, 1]
:type => :fishing
})
GameData::EncounterType.register({
:id => :RockSmash,
:type => :none,
:trigger_chance => 50,
:old_slots => [60, 30, 5, 4, 1]
:trigger_chance => 50
})
GameData::EncounterType.register({
:id => :HeadbuttLow,
:type => :none,
:old_slots => [30, 25, 20, 10, 5, 5, 4, 1]
:type => :none
})
GameData::EncounterType.register({
:id => :HeadbuttHigh,
:type => :none,
:old_slots => [30, 25, 20, 10, 5, 5, 4, 1]
:type => :none
})
GameData::EncounterType.register({
:id => :BugContest,
:type => :contest,
:trigger_chance => 21,
:old_slots => [20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1]
:trigger_chance => 21
})

View File

@@ -8,7 +8,6 @@
module GameData
class Target
attr_reader :id
attr_reader :id_number
attr_reader :real_name
attr_reader :num_targets # 0, 1 or 2 (meaning 2+)
attr_reader :targets_foe # Is able to target one or more foes
@@ -18,7 +17,7 @@ module GameData
DATA = {}
extend ClassMethods
extend ClassMethodsSymbols
include InstanceMethods
def self.load; end
@@ -54,20 +53,17 @@ end
# Bide, Counter, Metal Burst, Mirror Coat (calculate a target)
GameData::Target.register({
:id => :None,
:id_number => 1,
:name => _INTL("None")
})
GameData::Target.register({
:id => :User,
:id_number => 10,
:name => _INTL("User")
})
# Aromatic Mist, Helping Hand, Hold Hands
GameData::Target.register({
:id => :NearAlly,
:id_number => 100,
:name => _INTL("Near Ally"),
:num_targets => 1
})
@@ -75,15 +71,22 @@ GameData::Target.register({
# Acupressure
GameData::Target.register({
:id => :UserOrNearAlly,
:id_number => 200,
:name => _INTL("User or Near Ally"),
:num_targets => 1
})
# Coaching
GameData::Target.register({
:id => :AllAllies,
:name => _INTL("All Allies"),
:num_targets => 2,
:targets_all => true,
:long_range => true
})
# Aromatherapy, Gear Up, Heal Bell, Life Dew, Magnetic Flux, Howl (in Gen 8+)
GameData::Target.register({
:id => :UserAndAllies,
:id_number => 5,
:name => _INTL("User and Allies"),
:num_targets => 2,
:long_range => true
@@ -92,7 +95,6 @@ GameData::Target.register({
# Me First
GameData::Target.register({
:id => :NearFoe,
:id_number => 400,
:name => _INTL("Near Foe"),
:num_targets => 1,
:targets_foe => true
@@ -101,7 +103,6 @@ GameData::Target.register({
# Petal Dance, Outrage, Struggle, Thrash, Uproar
GameData::Target.register({
:id => :RandomNearFoe,
:id_number => 2,
:name => _INTL("Random Near Foe"),
:num_targets => 1,
:targets_foe => true
@@ -109,7 +110,6 @@ GameData::Target.register({
GameData::Target.register({
:id => :AllNearFoes,
:id_number => 4,
:name => _INTL("All Near Foes"),
:num_targets => 2,
:targets_foe => true
@@ -118,7 +118,6 @@ GameData::Target.register({
# For throwing a Poké Ball
GameData::Target.register({
:id => :Foe,
:id_number => 9,
:name => _INTL("Foe"),
:num_targets => 1,
:targets_foe => true,
@@ -128,7 +127,6 @@ GameData::Target.register({
# Unused
GameData::Target.register({
:id => :AllFoes,
:id_number => 6,
:name => _INTL("All Foes"),
:num_targets => 2,
:targets_foe => true,
@@ -137,7 +135,6 @@ GameData::Target.register({
GameData::Target.register({
:id => :NearOther,
:id_number => 0,
:name => _INTL("Near Other"),
:num_targets => 1,
:targets_foe => true
@@ -145,7 +142,6 @@ GameData::Target.register({
GameData::Target.register({
:id => :AllNearOthers,
:id_number => 8,
:name => _INTL("All Near Others"),
:num_targets => 2,
:targets_foe => true
@@ -154,7 +150,6 @@ GameData::Target.register({
# Most Flying-type moves, pulse moves (hits non-near targets)
GameData::Target.register({
:id => :Other,
:id_number => 3,
:name => _INTL("Other"),
:num_targets => 1,
:targets_foe => true,
@@ -164,7 +159,6 @@ GameData::Target.register({
# Flower Shield, Perish Song, Rototiller, Teatime
GameData::Target.register({
:id => :AllBattlers,
:id_number => 7,
:name => _INTL("All Battlers"),
:num_targets => 2,
:targets_foe => true,
@@ -174,21 +168,18 @@ GameData::Target.register({
GameData::Target.register({
:id => :UserSide,
:id_number => 40,
:name => _INTL("User Side")
})
# Entry hazards
GameData::Target.register({
:id => :FoeSide,
:id_number => 80,
:name => _INTL("Foe Side"),
:affects_foe_side => true
})
GameData::Target.register({
:id => :BothSides,
:id_number => 20,
:name => _INTL("Both Sides"),
:affects_foe_side => true
})

View File

@@ -1,25 +1,23 @@
#===============================================================================
# Data caches.
#===============================================================================
class PokemonTemp
attr_accessor :townMapData
attr_accessor :phoneData
attr_accessor :speciesShadowMovesets
attr_accessor :regionalDexes
attr_accessor :battleAnims
attr_accessor :moveToAnim
attr_accessor :mapInfos
class Game_Temp
attr_accessor :town_map_data
attr_accessor :phone_messages_data
attr_accessor :regional_dexes_data
attr_accessor :battle_animations_data
attr_accessor :move_to_battle_animation_data
attr_accessor :map_infos
end
def pbClearData
if $PokemonTemp
$PokemonTemp.townMapData = nil
$PokemonTemp.phoneData = nil
$PokemonTemp.speciesShadowMovesets = nil
$PokemonTemp.regionalDexes = nil
$PokemonTemp.battleAnims = nil
$PokemonTemp.moveToAnim = nil
$PokemonTemp.mapInfos = nil
if $game_temp
$game_temp.town_map_data = nil
$game_temp.phone_messages_data = nil
$game_temp.regional_dexes_data = nil
$game_temp.battle_animations_data = nil
$game_temp.move_to_battle_animation_data = nil
$game_temp.map_infos = nil
end
MapFactoryHelper.clear
$PokemonEncounters.setup($game_map.map_id) if $game_map && $PokemonEncounters
@@ -32,76 +30,61 @@ end
# Method to get Town Map data.
#===============================================================================
def pbLoadTownMapData
$PokemonTemp = PokemonTemp.new if !$PokemonTemp
if !$PokemonTemp.townMapData
$PokemonTemp.townMapData = load_data("Data/town_map.dat")
$game_temp = Game_Temp.new if !$game_temp
if !$game_temp.town_map_data
$game_temp.town_map_data = load_data("Data/town_map.dat")
end
return $PokemonTemp.townMapData
return $game_temp.town_map_data
end
#===============================================================================
# Method to get phone call data.
#===============================================================================
def pbLoadPhoneData
$PokemonTemp = PokemonTemp.new if !$PokemonTemp
if !$PokemonTemp.phoneData
if pbRgssExists?("Data/phone.dat")
$PokemonTemp.phoneData = load_data("Data/phone.dat")
$game_temp = Game_Temp.new if !$game_temp
if !$game_temp.phone_messages_data && pbRgssExists?("Data/phone.dat")
$game_temp.phone_messages_data = load_data("Data/phone.dat")
end
end
return $PokemonTemp.phoneData
end
#===============================================================================
# Method to get Shadow Pokémon moveset data.
#===============================================================================
def pbLoadShadowMovesets
$PokemonTemp = PokemonTemp.new if !$PokemonTemp
if !$PokemonTemp.speciesShadowMovesets
$PokemonTemp.speciesShadowMovesets = load_data("Data/shadow_movesets.dat") || []
end
return $PokemonTemp.speciesShadowMovesets
return $game_temp.phone_messages_data
end
#===============================================================================
# Method to get Regional Dexes data.
#===============================================================================
def pbLoadRegionalDexes
$PokemonTemp = PokemonTemp.new if !$PokemonTemp
if !$PokemonTemp.regionalDexes
$PokemonTemp.regionalDexes = load_data("Data/regional_dexes.dat")
$game_temp = Game_Temp.new if !$game_temp
if !$game_temp.regional_dexes_data
$game_temp.regional_dexes_data = load_data("Data/regional_dexes.dat")
end
return $PokemonTemp.regionalDexes
return $game_temp.regional_dexes_data
end
#===============================================================================
# Methods relating to battle animations data.
#===============================================================================
def pbLoadBattleAnimations
$PokemonTemp = PokemonTemp.new if !$PokemonTemp
if !$PokemonTemp.battleAnims
if pbRgssExists?("Data/PkmnAnimations.rxdata")
$PokemonTemp.battleAnims = load_data("Data/PkmnAnimations.rxdata")
$game_temp = Game_Temp.new if !$game_temp
if !$game_temp.battle_animations_data && pbRgssExists?("Data/PkmnAnimations.rxdata")
$game_temp.battle_animations_data = load_data("Data/PkmnAnimations.rxdata")
end
end
return $PokemonTemp.battleAnims
return $game_temp.battle_animations_data
end
def pbLoadMoveToAnim
$PokemonTemp = PokemonTemp.new if !$PokemonTemp
if !$PokemonTemp.moveToAnim
$PokemonTemp.moveToAnim = load_data("Data/move2anim.dat") || []
$game_temp = Game_Temp.new if !$game_temp
if !$game_temp.move_to_battle_animation_data
$game_temp.move_to_battle_animation_data = load_data("Data/move2anim.dat") || []
end
return $PokemonTemp.moveToAnim
return $game_temp.move_to_battle_animation_data
end
#===============================================================================
# Method relating to map infos data.
#===============================================================================
def pbLoadMapInfos
$PokemonTemp = PokemonTemp.new if !$PokemonTemp
if !$PokemonTemp.mapInfos
$PokemonTemp.mapInfos = load_data("Data/MapInfos.rxdata")
$game_temp = Game_Temp.new if !$game_temp
if !$game_temp.map_infos
$game_temp.map_infos = load_data("Data/MapInfos.rxdata")
end
return $PokemonTemp.mapInfos
return $game_temp.map_infos
end

View File

@@ -22,10 +22,3 @@ class PhoneDatabase
@trainers = []
end
end
module PhoneMsgType
Generic = 0
Greeting = 1
Body = 2
BattleRequest = 3
end

View File

@@ -1,52 +1,60 @@
module GameData
class Type
attr_reader :id
attr_reader :id_number
attr_reader :real_name
attr_reader :special_type
attr_reader :pseudo_type
attr_reader :flags
attr_reader :weaknesses
attr_reader :resistances
attr_reader :immunities
attr_reader :icon_position # Where this type's icon is within types.png
DATA = {}
DATA_FILENAME = "types.dat"
SCHEMA = {
"Name" => [1, "s"],
"InternalName" => [2, "s"],
"IsPseudoType" => [3, "b"],
"IsSpecialType" => [4, "b"],
"Weaknesses" => [5, "*s"],
"Resistances" => [6, "*s"],
"Immunities" => [7, "*s"]
"Name" => [0, "s"],
"InternalName" => [0, "s"],
"IsSpecialType" => [0, "b"],
"IsPseudoType" => [0, "b"],
"Flags" => [0, "*s"],
"Weaknesses" => [0, "*s"],
"Resistances" => [0, "*s"],
"Immunities" => [0, "*s"],
"IconPosition" => [0, "u"]
}
extend ClassMethods
extend ClassMethodsSymbols
include InstanceMethods
def initialize(hash)
@id = hash[:id]
@id_number = hash[:id_number] || -1
@real_name = hash[:name] || "Unnamed"
@pseudo_type = hash[:pseudo_type] || false
@special_type = hash[:special_type] || false
@pseudo_type = hash[:pseudo_type] || false
@flags = hash[:flags] || []
@weaknesses = hash[:weaknesses] || []
@weaknesses = [@weaknesses] if !@weaknesses.is_a?(Array)
@resistances = hash[:resistances] || []
@resistances = [@resistances] if !@resistances.is_a?(Array)
@immunities = hash[:immunities] || []
@immunities = [@immunities] if !@immunities.is_a?(Array)
@icon_position = hash[:icon_position] || 0
end
# @return [String] the translated name of this item
def name
return pbGetMessage(MessageTypes::Types, @id_number)
return pbGetMessageFromHash(MessageTypes::Types, @real_name)
end
def physical?; return !@special_type; end
def special?; return @special_type; end
def has_flag?(flag)
return @flags.any? { |f| f.downcase == flag.downcase }
end
def effectiveness(other_type)
return Effectiveness::NORMAL_EFFECTIVE_ONE if !other_type
return Effectiveness::SUPER_EFFECTIVE_ONE if @weaknesses.include?(other_type)

View File

@@ -1,31 +1,41 @@
module GameData
class Ability
attr_reader :id
attr_reader :id_number
attr_reader :real_name
attr_reader :real_description
attr_reader :flags
DATA = {}
DATA_FILENAME = "abilities.dat"
extend ClassMethods
extend ClassMethodsSymbols
include InstanceMethods
SCHEMA = {
"Name" => [:name, "s"],
"Description" => [:description, "q"],
"Flags" => [:flags, "*s"]
}
def initialize(hash)
@id = hash[:id]
@id_number = hash[:id_number] || -1
@real_name = hash[:name] || "Unnamed"
@real_description = hash[:description] || "???"
@flags = hash[:flags] || []
end
# @return [String] the translated name of this ability
def name
return pbGetMessage(MessageTypes::Abilities, @id_number)
return pbGetMessageFromHash(MessageTypes::Abilities, @real_name)
end
# @return [String] the translated description of this ability
def description
return pbGetMessage(MessageTypes::AbilityDescs, @id_number)
return pbGetMessageFromHash(MessageTypes::AbilityDescs, @real_description)
end
def has_flag?(flag)
return @flags.any? { |f| f.downcase == flag.downcase }
end
end
end

View File

@@ -1,51 +1,70 @@
module GameData
class Move
attr_reader :id
attr_reader :id_number
attr_reader :real_name
attr_reader :function_code
attr_reader :base_damage
attr_reader :type
attr_reader :category
attr_reader :base_damage
attr_reader :accuracy
attr_reader :total_pp
attr_reader :effect_chance
attr_reader :target
attr_reader :priority
attr_reader :function_code
attr_reader :flags
attr_reader :effect_chance
attr_reader :real_description
DATA = {}
DATA_FILENAME = "moves.dat"
extend ClassMethods
SCHEMA = {
"Name" => [:name, "s"],
"Type" => [:type, "e", :Type],
"Category" => [:category, "e", ["Physical", "Special", "Status"]],
"BaseDamage" => [:base_damage, "u"],
"Accuracy" => [:accuracy, "u"],
"TotalPP" => [:total_pp, "u"],
"Target" => [:target, "e", :Target],
"Priority" => [:priority, "i"],
"FunctionCode" => [:function_code, "s"],
"Flags" => [:flags, "*s"],
"EffectChance" => [:effect_chance, "u"],
"Description" => [:description, "q"]
}
extend ClassMethodsSymbols
include InstanceMethods
def initialize(hash)
convert_move_data(hash)
@id = hash[:id]
@id_number = hash[:id_number] || -1
@real_name = hash[:name] || "Unnamed"
@function_code = hash[:function_code]
@base_damage = hash[:base_damage]
@type = hash[:type]
@category = hash[:category]
@accuracy = hash[:accuracy]
@total_pp = hash[:total_pp]
@effect_chance = hash[:effect_chance]
@target = hash[:target]
@priority = hash[:priority]
@flags = hash[:flags]
@type = hash[:type] || :NONE
@category = hash[:category] || 2
@base_damage = hash[:base_damage] || 0
@accuracy = hash[:accuracy] || 100
@total_pp = hash[:total_pp] || 5
@target = hash[:target] || :None
@priority = hash[:priority] || 0
@function_code = hash[:function_code] || "None"
@flags = hash[:flags] || []
@flags = [@flags] if !@flags.is_a?(Array)
@effect_chance = hash[:effect_chance] || 0
@real_description = hash[:description] || "???"
end
# @return [String] the translated name of this move
def name
return pbGetMessage(MessageTypes::Moves, @id_number)
return pbGetMessageFromHash(MessageTypes::Moves, @real_name)
end
# @return [String] the translated description of this move
def description
return pbGetMessage(MessageTypes::MoveDescriptions, @id_number)
return pbGetMessageFromHash(MessageTypes::MoveDescriptions, @real_description)
end
def has_flag?(flag)
return @flags.any? { |f| f.downcase == flag.downcase }
end
def physical?
@@ -66,20 +85,729 @@ module GameData
end
return false
end
def display_type(pkmn, move = nil)
=begin
case @function_code
when "TypeDependsOnUserIVs"
return pbHiddenPower(pkmn)[0]
when "TypeAndPowerDependOnUserBerry"
type_array = {
:NORMAL => [:CHILANBERRY],
:FIRE => [:CHERIBERRY, :BLUKBERRY, :WATMELBERRY, :OCCABERRY],
:WATER => [:CHESTOBERRY, :NANABBERRY, :DURINBERRY, :PASSHOBERRY],
:ELECTRIC => [:PECHABERRY, :WEPEARBERRY, :BELUEBERRY, :WACANBERRY],
:GRASS => [:RAWSTBERRY, :PINAPBERRY, :RINDOBERRY, :LIECHIBERRY],
:ICE => [:ASPEARBERRY, :POMEGBERRY, :YACHEBERRY, :GANLONBERRY],
:FIGHTING => [:LEPPABERRY, :KELPSYBERRY, :CHOPLEBERRY, :SALACBERRY],
:POISON => [:ORANBERRY, :QUALOTBERRY, :KEBIABERRY, :PETAYABERRY],
:GROUND => [:PERSIMBERRY, :HONDEWBERRY, :SHUCABERRY, :APICOTBERRY],
:FLYING => [:LUMBERRY, :GREPABERRY, :COBABERRY, :LANSATBERRY],
:PSYCHIC => [:SITRUSBERRY, :TAMATOBERRY, :PAYAPABERRY, :STARFBERRY],
:BUG => [:FIGYBERRY, :CORNNBERRY, :TANGABERRY, :ENIGMABERRY],
:ROCK => [:WIKIBERRY, :MAGOSTBERRY, :CHARTIBERRY, :MICLEBERRY],
:GHOST => [:MAGOBERRY, :RABUTABERRY, :KASIBBERRY, :CUSTAPBERRY],
:DRAGON => [:AGUAVBERRY, :NOMELBERRY, :HABANBERRY, :JABOCABERRY],
:DARK => [:IAPAPABERRY, :SPELONBERRY, :COLBURBERRY, :ROWAPBERRY, :MARANGABERRY],
:STEEL => [:RAZZBERRY, :PAMTREBERRY, :BABIRIBERRY],
:FAIRY => [:ROSELIBERRY, :KEEBERRY]
}
if pkmn.hasItem?
type_array.each do |type, items|
return type if items.include?(pkmn.item_id) && GameData::Type.exists?(type)
end
end
when "TypeDependsOnUserPlate"
item_types = {
:FISTPLATE => :FIGHTING,
:SKYPLATE => :FLYING,
:TOXICPLATE => :POISON,
:EARTHPLATE => :GROUND,
:STONEPLATE => :ROCK,
:INSECTPLATE => :BUG,
:SPOOKYPLATE => :GHOST,
:IRONPLATE => :STEEL,
:FLAMEPLATE => :FIRE,
:SPLASHPLATE => :WATER,
:MEADOWPLATE => :GRASS,
:ZAPPLATE => :ELECTRIC,
:MINDPLATE => :PSYCHIC,
:ICICLEPLATE => :ICE,
:DRACOPLATE => :DRAGON,
:DREADPLATE => :DARK,
:PIXIEPLATE => :FAIRY
}
if pkmn.hasItem?
item_types.each do |item, item_type|
return item_type if pkmn.item_id == item && GameData::Type.exists?(item_type)
end
end
when "TypeDependsOnUserMemory"
item_types = {
:FIGHTINGMEMORY => :FIGHTING,
:FLYINGMEMORY => :FLYING,
:POISONMEMORY => :POISON,
:GROUNDMEMORY => :GROUND,
:ROCKMEMORY => :ROCK,
:BUGMEMORY => :BUG,
:GHOSTMEMORY => :GHOST,
:STEELMEMORY => :STEEL,
:FIREMEMORY => :FIRE,
:WATERMEMORY => :WATER,
:GRASSMEMORY => :GRASS,
:ELECTRICMEMORY => :ELECTRIC,
:PSYCHICMEMORY => :PSYCHIC,
:ICEMEMORY => :ICE,
:DRAGONMEMORY => :DRAGON,
:DARKMEMORY => :DARK,
:FAIRYMEMORY => :FAIRY
}
if pkmn.hasItem?
item_types.each do |item, item_type|
return item_type if pkmn.item_id == item && GameData::Type.exists?(item_type)
end
end
when "TypeDependsOnUserDrive"
item_types = {
:SHOCKDRIVE => :ELECTRIC,
:BURNDRIVE => :FIRE,
:CHILLDRIVE => :ICE,
:DOUSEDRIVE => :WATER
}
if pkmn.hasItem?
item_types.each do |item, item_type|
return item_type if pkmn.item_id == item && GameData::Type.exists?(item_type)
end
end
when "TypeIsUserFirstType"
return pkmn.types[0]
end
=end
return @type
end
#===============================================================================
# Deprecated methods
#===============================================================================
# @deprecated This alias is slated to be removed in v20.
def pbGetMoveData(move_id, move_data_type = -1)
Deprecation.warn_method('pbGetMoveData', 'v20', 'GameData::Move.get(move_id)')
return GameData::Move.get(move_id)
def display_damage(pkmn, move = nil)
=begin
case @function_code
when "TypeDependsOnUserIVs"
return pbHiddenPower(pkmn)[1]
when "TypeAndPowerDependOnUserBerry"
damage_array = {
60 => [:CHERIBERRY, :CHESTOBERRY, :PECHABERRY, :RAWSTBERRY, :ASPEARBERRY,
:LEPPABERRY, :ORANBERRY, :PERSIMBERRY, :LUMBERRY, :SITRUSBERRY,
:FIGYBERRY, :WIKIBERRY, :MAGOBERRY, :AGUAVBERRY, :IAPAPABERRY,
:RAZZBERRY, :OCCABERRY, :PASSHOBERRY, :WACANBERRY, :RINDOBERRY,
:YACHEBERRY, :CHOPLEBERRY, :KEBIABERRY, :SHUCABERRY, :COBABERRY,
:PAYAPABERRY, :TANGABERRY, :CHARTIBERRY, :KASIBBERRY, :HABANBERRY,
:COLBURBERRY, :BABIRIBERRY, :CHILANBERRY, :ROSELIBERRY],
70 => [:BLUKBERRY, :NANABBERRY, :WEPEARBERRY, :PINAPBERRY, :POMEGBERRY,
:KELPSYBERRY, :QUALOTBERRY, :HONDEWBERRY, :GREPABERRY, :TAMATOBERRY,
:CORNNBERRY, :MAGOSTBERRY, :RABUTABERRY, :NOMELBERRY, :SPELONBERRY,
:PAMTREBERRY],
80 => [:WATMELBERRY, :DURINBERRY, :BELUEBERRY, :LIECHIBERRY, :GANLONBERRY,
:SALACBERRY, :PETAYABERRY, :APICOTBERRY, :LANSATBERRY, :STARFBERRY,
:ENIGMABERRY, :MICLEBERRY, :CUSTAPBERRY, :JABOCABERRY, :ROWAPBERRY,
:KEEBERRY, :MARANGABERRY]
}
if pkmn.hasItem?
damage_array.each do |dmg, items|
next if !items.include?(pkmn.item_id)
ret = dmg
ret += 20 if Settings::MECHANICS_GENERATION >= 6
return ret
end
end
when "ThrowUserItemAtTarget"
fling_powers = {
130 => [:IRONBALL
],
100 => [:HARDSTONE,:RAREBONE,
# Fossils
:ARMORFOSSIL,:CLAWFOSSIL,:COVERFOSSIL,:DOMEFOSSIL,:HELIXFOSSIL,
:JAWFOSSIL,:OLDAMBER,:PLUMEFOSSIL,:ROOTFOSSIL,:SAILFOSSIL,
:SKULLFOSSIL
],
90 => [:DEEPSEATOOTH,:GRIPCLAW,:THICKCLUB,
# Plates
:DRACOPLATE,:DREADPLATE,:EARTHPLATE,:FISTPLATE,:FLAMEPLATE,
:ICICLEPLATE,:INSECTPLATE,:IRONPLATE,:MEADOWPLATE,:MINDPLATE,
:PIXIEPLATE,:SKYPLATE,:SPLASHPLATE,:SPOOKYPLATE,:STONEPLATE,
:TOXICPLATE,:ZAPPLATE
],
80 => [:ASSAULTVEST,:CHIPPEDPOT,:CRACKEDPOT,:DAWNSTONE,:DUSKSTONE,
:ELECTIRIZER,:HEAVYDUTYBOOTS,:MAGMARIZER,:ODDKEYSTONE,:OVALSTONE,
:PROTECTOR,:QUICKCLAW,:RAZORCLAW,:SACHET,:SAFETYGOGGLES,
:SHINYSTONE,:STICKYBARB,:WEAKNESSPOLICY,:WHIPPEDDREAM
],
70 => [:DRAGONFANG,:POISONBARB,
# EV-training items (Macho Brace is 60)
:POWERANKLET,:POWERBAND,:POWERBELT,:POWERBRACER,:POWERLENS,
:POWERWEIGHT,
# Drives
:BURNDRIVE,:CHILLDRIVE,:DOUSEDRIVE,:SHOCKDRIVE
],
60 => [:ADAMANTORB,:DAMPROCK,:GRISEOUSORB,:HEATROCK,:LEEK,:LUSTROUSORB,
:MACHOBRACE,:ROCKYHELMET,:STICK,:TERRAINEXTENDER
],
50 => [:DUBIOUSDISC,:SHARPBEAK,
# Memories
:BUGMEMORY,:DARKMEMORY,:DRAGONMEMORY,:ELECTRICMEMORY,:FAIRYMEMORY,
:FIGHTINGMEMORY,:FIREMEMORY,:FLYINGMEMORY,:GHOSTMEMORY,
:GRASSMEMORY,:GROUNDMEMORY,:ICEMEMORY,:POISONMEMORY,
:PSYCHICMEMORY,:ROCKMEMORY,:STEELMEMORY,:WATERMEMORY
],
40 => [:EVIOLITE,:ICYROCK,:LUCKYPUNCH
],
30 => [:ABSORBBULB,:ADRENALINEORB,:AMULETCOIN,:BINDINGBAND,:BLACKBELT,
:BLACKGLASSES,:BLACKSLUDGE,:BOTTLECAP,:CELLBATTERY,:CHARCOAL,
:CLEANSETAG,:DEEPSEASCALE,:DRAGONSCALE,:EJECTBUTTON,:ESCAPEROPE,
:EXPSHARE,:FLAMEORB,:FLOATSTONE,:FLUFFYTAIL,:GOLDBOTTLECAP,
:HEARTSCALE,:HONEY,:KINGSROCK,:LIFEORB,:LIGHTBALL,:LIGHTCLAY,
:LUCKYEGG,:LUMINOUSMOSS,:MAGNET,:METALCOAT,:METRONOME,
:MIRACLESEED,:MYSTICWATER,:NEVERMELTICE,:PASSORB,:POKEDOLL,
:POKETOY,:PRISMSCALE,:PROTECTIVEPADS,:RAZORFANG,:SACREDASH,
:SCOPELENS,:SHELLBELL,:SHOALSALT,:SHOALSHELL,:SMOKEBALL,:SNOWBALL,
:SOULDEW,:SPELLTAG,:TOXICORB,:TWISTEDSPOON,:UPGRADE,
# Healing items
:ANTIDOTE,:AWAKENING,:BERRYJUICE,:BIGMALASADA,:BLUEFLUTE,
:BURNHEAL,:CASTELIACONE,:ELIXIR,:ENERGYPOWDER,:ENERGYROOT,:ETHER,
:FRESHWATER,:FULLHEAL,:FULLRESTORE,:HEALPOWDER,:HYPERPOTION,
:ICEHEAL,:LAVACOOKIE,:LEMONADE,:LUMIOSEGALETTE,:MAXELIXIR,
:MAXETHER,:MAXHONEY,:MAXPOTION,:MAXREVIVE,:MOOMOOMILK,:OLDGATEAU,
:PARALYZEHEAL,:PARLYZHEAL,:PEWTERCRUNCHIES,:POTION,:RAGECANDYBAR,
:REDFLUTE,:REVIVALHERB,:REVIVE,:SHALOURSABLE,:SODAPOP,
:SUPERPOTION,:SWEETHEART,:YELLOWFLUTE,
# Battle items
:XACCURACY,:XACCURACY2,:XACCURACY3,:XACCURACY6,
:XATTACK,:XATTACK2,:XATTACK3,:XATTACK6,
:XDEFEND,:XDEFEND2,:XDEFEND3,:XDEFEND6,
:XDEFENSE,:XDEFENSE2,:XDEFENSE3,:XDEFENSE6,
:XSPATK,:XSPATK2,:XSPATK3,:XSPATK6,
:XSPECIAL,:XSPECIAL2,:XSPECIAL3,:XSPECIAL6,
:XSPDEF,:XSPDEF2,:XSPDEF3,:XSPDEF6,
:XSPEED,:XSPEED2,:XSPEED3,:XSPEED6,
:DIREHIT,:DIREHIT2,:DIREHIT3,
:ABILITYURGE,:GUARDSPEC,:ITEMDROP,:ITEMURGE,:RESETURGE,
:MAXMUSHROOMS,
# Vitamins
:CALCIUM,:CARBOS,:HPUP,:IRON,:PPUP,:PPMAX,:PROTEIN,:ZINC,
:RARECANDY,
# Most evolution stones (see also 80)
:EVERSTONE,:FIRESTONE,:ICESTONE,:LEAFSTONE,:MOONSTONE,:SUNSTONE,
:THUNDERSTONE,:WATERSTONE,:SWEETAPPLE,:TARTAPPLE, :GALARICACUFF,
:GALARICAWREATH,
# Repels
:MAXREPEL,:REPEL,:SUPERREPEL,
# Mulches
:AMAZEMULCH,:BOOSTMULCH,:DAMPMULCH,:GOOEYMULCH,:GROWTHMULCH,
:RICHMULCH,:STABLEMULCH,:SURPRISEMULCH,
# Shards
:BLUESHARD,:GREENSHARD,:REDSHARD,:YELLOWSHARD,
# Valuables
:BALMMUSHROOM,:BIGMUSHROOM,:BIGNUGGET,:BIGPEARL,:COMETSHARD,
:NUGGET,:PEARL,:PEARLSTRING,:RELICBAND,:RELICCOPPER,:RELICCROWN,
:RELICGOLD,:RELICSILVER,:RELICSTATUE,:RELICVASE,:STARDUST,
:STARPIECE,:STRANGESOUVENIR,:TINYMUSHROOM,
# Exp Candies
:EXPCANDYXS, :EXPCANDYS, :EXPCANDYM, :EXPCANDYL, :EXPCANDYXL
],
20 => [# Feathers
:CLEVERFEATHER,:GENIUSFEATHER,:HEALTHFEATHER,:MUSCLEFEATHER,
:PRETTYFEATHER,:RESISTFEATHER,:SWIFTFEATHER,
:CLEVERWING,:GENIUSWING,:HEALTHWING,:MUSCLEWING,:PRETTYWING,
:RESISTWING,:SWIFTWING
],
10 => [:AIRBALLOON,:BIGROOT,:BRIGHTPOWDER,:CHOICEBAND,:CHOICESCARF,
:CHOICESPECS,:DESTINYKNOT,:DISCOUNTCOUPON,:EXPERTBELT,:FOCUSBAND,
:FOCUSSASH,:LAGGINGTAIL,:LEFTOVERS,:MENTALHERB,:METALPOWDER,
:MUSCLEBAND,:POWERHERB,:QUICKPOWDER,:REAPERCLOTH,:REDCARD,
:RINGTARGET,:SHEDSHELL,:SILKSCARF,:SILVERPOWDER,:SMOOTHROCK,
:SOFTSAND,:SOOTHEBELL,:WHITEHERB,:WIDELENS,:WISEGLASSES,:ZOOMLENS,
# Terrain seeds
:ELECTRICSEED,:GRASSYSEED,:MISTYSEED,:PSYCHICSEED,
# Nectar
:PINKNECTAR,:PURPLENECTAR,:REDNECTAR,:YELLOWNECTAR,
# Incenses
:FULLINCENSE,:LAXINCENSE,:LUCKINCENSE,:ODDINCENSE,:PUREINCENSE,
:ROCKINCENSE,:ROSEINCENSE,:SEAINCENSE,:WAVEINCENSE,
# Scarves
:BLUESCARF,:GREENSCARF,:PINKSCARF,:REDSCARF,:YELLOWSCARF,
# Mints
:LONELYMINT, :ADAMANTMINT, :NAUGHTYMINT, :BRAVEMINT, :BOLDMINT,
:IMPISHMINT, :LAXMINT, :RELAXEDMINT, :MODESTMINT, :MILDMINT,
:RASHMINT, :QUIETMINT, :CALMMINT, :GENTLEMINT, :CAREFULMINT,
:SASSYMINT, :TIMIDMINT, :HASTYMINT, :JOLLYMINT, :NAIVEMINT,
:SERIOUSMINT,
# Sweets
:STRAWBERRYSWEET, :LOVESWEET, :BERRYSWEET, :CLOVERSWEET,
:FLOWERSWEET, :STARSWEET, :RIBBONSWEET
]
}
return 0 if !pkmn.item
return 10 if pkmn.item.is_berry?
return 80 if pkmn.item.is_mega_stone?
if pkmn.item.is_TR?
ret = GameData::Move.get(pkmn.item.move).base_damage
ret = 10 if ret < 10
return ret
end
fling_powers.each do |power,items|
return power if items.include?(pkmn.item_id)
end
return 10
when "PowerHigherWithUserHP"
return [150 * pkmn.hp / pkmn.totalhp, 1].max
when "PowerLowerWithUserHP"
n = 48 * pkmn.hp / pkmn.totalhp
return 200 if n < 2
return 150 if n < 5
return 100 if n < 10
return 80 if n < 17
return 40 if n < 33
return 20
when "PowerHigherWithUserHappiness"
return [(pkmn.happiness * 2 / 5).floor, 1].max
when "PowerLowerWithUserHappiness"
return [((255 - pkmn.happiness) * 2 / 5).floor, 1].max
when "PowerHigherWithLessPP"
dmgs = [200, 80, 60, 50, 40]
ppLeft = [[(move&.pp || @total_pp) - 1, 0].max, dmgs.length - 1].min
return dmgs[ppLeft]
end
=end
return @base_damage
end
# @deprecated This alias is slated to be removed in v20.
def pbIsHiddenMove?(move)
Deprecation.warn_method('pbIsHiddenMove?', 'v20', 'GameData::Move.get(move).hidden_move?')
return GameData::Move.get(move).hidden_move?
def display_category(pkmn, move = nil); return @category; end
def display_accuracy(pkmn, move = nil); return @accuracy; end
def convert_move_data(data)
new_code = data[:function_code]
case data[:function_code]
when "000" then new_code = "None"
when "001" then new_code = "DoesNothingUnusableInGravity"
when "002" then new_code = "Struggle"
when "003"
if data[:id] == :RELICSONG
new_code = "SleepTargetChangeUserMeloettaForm"
elsif data[:id] == :DARKVOID && Settings::MECHANICS_GENERATION >= 7
new_code = "SleepTargetIfUserDarkrai"
else
new_code = "SleepTarget"
end
when "004" then new_code = "SleepTargetNextTurn"
when "005" then new_code = "PoisonTarget"
when "006" then new_code = "BadPoisonTarget"
when "007"
if data[:id] == :THUNDERWAVE
new_code = "ParalyzeTargetIfNotTypeImmune"
else
new_code = "ParalyzeTarget"
end
when "008" then new_code = "ParalyzeTargetAlwaysHitsInRainHitsTargetInSky"
when "009" then new_code = "ParalyzeFlinchTarget"
when "00A" then new_code = "BurnTarget"
when "00B" then new_code = "BurnFlinchTarget"
when "00C" then new_code = "FreezeTarget"
when "00D" then new_code = "FreezeTargetAlwaysHitsInHail"
when "00E" then new_code = "FreezeFlinchTarget"
when "00F", "010" then new_code = "FlinchTarget"
when "011" then new_code = "FlinchTargetFailsIfUserNotAsleep"
when "012" then new_code = "FlinchTargetFailsIfNotUserFirstTurn"
when "013", "014" then new_code = "ConfuseTarget"
when "015" then new_code = "ConfuseTargetAlwaysHitsInRainHitsTargetInSky"
when "016" then new_code = "AttractTarget"
when "017" then new_code = "ParalyzeBurnOrFreezeTarget"
when "018" then new_code = "CureUserBurnPoisonParalysis"
when "019" then new_code = "CureUserPartyStatus"
when "01A" then new_code = "StartUserSideImmunityToInflictedStatus"
when "01B" then new_code = "GiveUserStatusToTarget"
when "01C" then new_code = "RaiseUserAttack1"
when "01D" then new_code = "RaiseUserDefense1"
when "01E" then new_code = "RaiseUserDefense1CurlUpUser"
when "01F" then new_code = "RaiseUserSpeed1"
when "020" then new_code = "RaiseUserSpAtk1"
when "021" then new_code = "RaiseUserSpDef1PowerUpElectricMove"
when "022" then new_code = "RaiseUserEvasion1"
when "023" then new_code = "RaiseUserCriticalHitRate2"
when "024" then new_code = "RaiseUserAtkDef1"
when "025" then new_code = "RaiseUserAtkDefAcc1"
when "026" then new_code = "RaiseUserAtkSpd1"
when "027" then new_code = "RaiseUserAtkSpAtk1"
when "028" then new_code = "RaiseUserAtkSpAtk1Or2InSun"
when "029" then new_code = "RaiseUserAtkAcc1"
when "02A" then new_code = "RaiseUserDefSpDef1"
when "02B" then new_code = "RaiseUserSpAtkSpDefSpd1"
when "02C" then new_code = "RaiseUserSpAtkSpDef1"
when "02D" then new_code = "RaiseUserMainStats1"
when "02E" then new_code = "RaiseUserAttack2"
when "02F" then new_code = "RaiseUserDefense2"
when "030" then new_code = "RaiseUserSpeed2"
when "031" then new_code = "RaiseUserSpeed2LowerUserWeight"
when "032" then new_code = "RaiseUserSpAtk2"
when "033" then new_code = "RaiseUserSpDef2"
when "034" then new_code = "RaiseUserEvasion2MinimizeUser"
when "035" then new_code = "LowerUserDefSpDef1RaiseUserAtkSpAtkSpd2"
when "036" then new_code = "RaiseUserAtk1Spd2"
when "037" then new_code = "RaiseTargetRandomStat2"
when "038" then new_code = "RaiseUserDefense3"
when "039" then new_code = "RaiseUserSpAtk3"
when "03A" then new_code = "MaxUserAttackLoseHalfOfTotalHP"
when "03B" then new_code = "LowerUserAtkDef1"
when "03C" then new_code = "LowerUserDefSpDef1"
when "03D" then new_code = "LowerUserDefSpDefSpd1"
when "03E" then new_code = "LowerUserSpeed1"
when "03F" then new_code = "LowerUserSpAtk2"
when "040" then new_code = "RaiseTargetSpAtk1ConfuseTarget"
when "041" then new_code = "RaiseTargetAttack2ConfuseTarget"
when "042" then new_code = "LowerTargetAttack1"
when "043" then new_code = "LowerTargetDefense1"
when "044"
if data[:id] == :BULLDOZE
new_code = "LowerTargetSpeed1WeakerInGrassyTerrain"
else
new_code = "LowerTargetSpeed1"
end
when "045" then new_code = "LowerTargetSpAtk1"
when "046" then new_code = "LowerTargetSpDef1"
when "047" then new_code = "LowerTargetAccuracy1"
when "048"
if data[:id] == :SWEETSCENT && Settings::MECHANICS_GENERATION >= 6
new_code = "LowerTargetEvasion2"
else
new_code = "LowerTargetEvasion1"
end
when "049" then new_code = "LowerTargetEvasion1RemoveSideEffects"
when "04A" then new_code = "LowerTargetAtkDef1"
when "04B" then new_code = "LowerTargetAttack2"
when "04C" then new_code = "LowerTargetDefense2"
when "04D" then new_code = "LowerTargetSpeed2"
when "04E" then new_code = "LowerTargetSpAtk2IfCanAttract"
when "04F" then new_code = "LowerTargetSpDef2"
when "050" then new_code = "ResetTargetStatStages"
when "051" then new_code = "ResetAllBattlersStatStages"
when "052" then new_code = "UserTargetSwapAtkSpAtkStages"
when "053" then new_code = "UserTargetSwapDefSpDefStages"
when "054" then new_code = "UserTargetSwapStatStages"
when "055" then new_code = "UserCopyTargetStatStages"
when "056" then new_code = "StartUserSideImmunityToStatStageLowering"
when "057" then new_code = "UserSwapBaseAtkDef"
when "058" then new_code = "UserTargetAverageBaseAtkSpAtk"
when "059" then new_code = "UserTargetAverageBaseDefSpDef"
when "05A" then new_code = "UserTargetAverageHP"
when "05B" then new_code = "StartUserSideDoubleSpeed"
when "05C" then new_code = "ReplaceMoveThisBattleWithTargetLastMoveUsed"
when "05D" then new_code = "ReplaceMoveWithTargetLastMoveUsed"
when "05E" then new_code = "SetUserTypesToUserMoveType"
when "05F" then new_code = "SetUserTypesToResistLastAttack"
when "060" then new_code = "SetUserTypesBasedOnEnvironment"
when "061" then new_code = "SetTargetTypesToWater"
when "062" then new_code = "SetUserTypesToTargetTypes"
when "063" then new_code = "SetTargetAbilityToSimple"
when "064" then new_code = "SetTargetAbilityToInsomnia"
when "065" then new_code = "SetUserAbilityToTargetAbility"
when "066" then new_code = "SetTargetAbilityToUserAbility"
when "067" then new_code = "UserTargetSwapAbilities"
when "068" then new_code = "NegateTargetAbility"
when "069" then new_code = "TransformUserIntoTarget"
when "06A" then new_code = "FixedDamage20"
when "06B" then new_code = "FixedDamage40"
when "06C" then new_code = "FixedDamageHalfTargetHP"
when "06D" then new_code = "FixedDamageUserLevel"
when "06E" then new_code = "LowerTargetHPToUserHP"
when "06F" then new_code = "FixedDamageUserLevelRandom"
when "070"
if data[:id] == :FISSURE
new_code = "OHKOHitsUndergroundTarget"
elsif data[:id] == :SHEERCOLD && Settings::MECHANICS_GENERATION >= 7
new_code = "OHKOIce"
else
new_code = "OHKO"
end
when "071" then new_code = "CounterPhysicalDamage"
when "072" then new_code = "CounterSpecialDamage"
when "073" then new_code = "CounterDamagePlusHalf"
when "074" then new_code = "DamageTargetAlly"
when "075" then new_code = "DoublePowerIfTargetUnderwater"
when "076" then new_code = "DoublePowerIfTargetUnderground"
when "077" then new_code = "DoublePowerIfTargetInSky"
when "078" then new_code = "FlinchTargetDoublePowerIfTargetInSky"
when "079" then new_code = "DoublePowerAfterFusionFlare"
when "07A" then new_code = "DoublePowerAfterFusionBolt"
when "07B" then new_code = "DoublePowerIfTargetPoisoned"
when "07C" then new_code = "DoublePowerIfTargetParalyzedCureTarget"
when "07D" then new_code = "DoublePowerIfTargetAsleepCureTarget"
when "07E" then new_code = "DoublePowerIfUserPoisonedBurnedParalyzed"
when "07F" then new_code = "DoublePowerIfTargetStatusProblem"
when "080" then new_code = "DoublePowerIfTargetHPLessThanHalf"
when "081" then new_code = "DoublePowerIfUserLostHPThisTurn"
when "082" then new_code = "DoublePowerIfTargetLostHPThisTurn"
when "083" then new_code = "UsedAfterAllyRoundWithDoublePower"
when "084" then new_code = "DoublePowerIfTargetActed"
when "085" then new_code = "DoublePowerIfAllyFaintedLastTurn"
when "086" then new_code = "DoublePowerIfUserHasNoItem"
when "087" then new_code = "TypeAndPowerDependOnWeather"
when "088" then new_code = "PursueSwitchingFoe"
when "089" then new_code = "PowerHigherWithUserHappiness"
when "08A" then new_code = "PowerLowerWithUserHappiness"
when "08B" then new_code = "PowerHigherWithUserHP"
when "08C" then new_code = "PowerHigherWithTargetHP"
when "08D" then new_code = "PowerHigherWithTargetFasterThanUser"
when "08E" then new_code = "PowerHigherWithUserPositiveStatStages"
when "08F" then new_code = "PowerHigherWithTargetPositiveStatStages"
when "090" then new_code = "TypeDependsOnUserIVs"
when "091" then new_code = "PowerHigherWithConsecutiveUse"
when "092" then new_code = "PowerHigherWithConsecutiveUseOnUserSide"
when "093" then new_code = "StartRaiseUserAtk1WhenDamaged"
when "094" then new_code = "RandomlyDamageOrHealTarget"
when "095" then new_code = "RandomPowerDoublePowerIfTargetUnderground"
when "096" then new_code = "TypeAndPowerDependOnUserBerry"
when "097" then new_code = "PowerHigherWithLessPP"
when "098" then new_code = "PowerLowerWithUserHP"
when "099" then new_code = "PowerHigherWithUserFasterThanTarget"
when "09A" then new_code = "PowerHigherWithTargetWeight"
when "09B" then new_code = "PowerHigherWithUserHeavierThanTarget"
when "09C" then new_code = "PowerUpAllyMove"
when "09D" then new_code = "StartWeakenElectricMoves"
when "09E" then new_code = "StartWeakenFireMoves"
when "09F"
case data[:id]
when :MULTIATTACK
new_code = "TypeDependsOnUserMemory"
when :TECHNOBLAST
new_code = "TypeDependsOnUserDrive"
else
new_code = "TypeDependsOnUserPlate"
end
when "0A0" then new_code = "AlwaysCriticalHit"
when "0A1" then new_code = "StartPreventCriticalHitsAgainstUserSide"
when "0A2" then new_code = "StartWeakenPhysicalDamageAgainstUserSide"
when "0A3" then new_code = "StartWeakenSpecialDamageAgainstUserSide"
when "0A4" then new_code = "EffectDependsOnEnvironment"
when "0A5"
new_code = "None"
data[:accuracy] = 0
when "0A6" then new_code = "EnsureNextMoveAlwaysHits"
when "0A7" then new_code = "StartNegateTargetEvasionStatStageAndGhostImmunity"
when "0A8" then new_code = "StartNegateTargetEvasionStatStageAndDarkImmunity"
when "0A9" then new_code = "IgnoreTargetDefSpDefEvaStatStages"
when "0AA" then new_code = "ProtectUser"
when "0AB" then new_code = "ProtectUserSideFromPriorityMoves"
when "0AC" then new_code = "ProtectUserSideFromMultiTargetDamagingMoves"
when "0AD" then new_code = "RemoveProtections"
when "0AE" then new_code = "UseLastMoveUsedByTarget"
when "0AF" then new_code = "UseLastMoveUsed"
when "0B0" then new_code = "UseMoveTargetIsAboutToUse"
when "0B1" then new_code = "BounceBackProblemCausingStatusMoves"
when "0B2" then new_code = "StealAndUseBeneficialStatusMove"
when "0B3" then new_code = "UseMoveDependingOnEnvironment"
when "0B4" then new_code = "UseRandomUserMoveIfAsleep"
when "0B5" then new_code = "UseRandomMoveFromUserParty"
when "0B6" then new_code = "UseRandomMove"
when "0B7" then new_code = "DisableTargetUsingSameMoveConsecutively"
when "0B8" then new_code = "DisableTargetMovesKnownByUser"
when "0B9" then new_code = "DisableTargetLastMoveUsed"
when "0BA" then new_code = "DisableTargetStatusMoves"
when "0BB" then new_code = "DisableTargetHealingMoves"
when "0BC" then new_code = "DisableTargetUsingDifferentMove"
when "0BD" then new_code = "HitTwoTimes"
when "0BE" then new_code = "HitTwoTimesPoisonTarget"
when "0BF" then new_code = "HitThreeTimesPowersUpWithEachHit"
when "0C0"
if data[:id] == :WATERSHURIKEN
new_code = "HitTwoToFiveTimesOrThreeForAshGreninja"
else
new_code = "HitTwoToFiveTimes"
end
when "0C1" then new_code = "HitOncePerUserTeamMember"
when "0C2" then new_code = "AttackAndSkipNextTurn"
when "0C3" then new_code = "TwoTurnAttack"
when "0C4" then new_code = "TwoTurnAttackOneTurnInSun"
when "0C5" then new_code = "TwoTurnAttackParalyzeTarget"
when "0C6" then new_code = "TwoTurnAttackBurnTarget"
when "0C7" then new_code = "TwoTurnAttackFlinchTarget"
when "0C8" then new_code = "TwoTurnAttackChargeRaiseUserDefense1"
when "0C9" then new_code = "TwoTurnAttackInvulnerableInSky"
when "0CA" then new_code = "TwoTurnAttackInvulnerableUnderground"
when "0CB" then new_code = "TwoTurnAttackInvulnerableUnderwater"
when "0CC" then new_code = "TwoTurnAttackInvulnerableInSkyParalyzeTarget"
when "0CD" then new_code = "TwoTurnAttackInvulnerableRemoveProtections"
when "0CE" then new_code = "TwoTurnAttackInvulnerableInSkyTargetCannotAct"
when "0CF" then new_code = "BindTarget"
when "0D0" then new_code = "BindTargetDoublePowerIfTargetUnderwater"
when "0D1" then new_code = "MultiTurnAttackPreventSleeping"
when "0D2" then new_code = "MultiTurnAttackConfuseUserAtEnd"
when "0D3" then new_code = "MultiTurnAttackPowersUpEachTurn"
when "0D4" then new_code = "MultiTurnAttackBideThenReturnDoubleDamage"
when "0D5" then new_code = "HealUserHalfOfTotalHP"
when "0D6" then new_code = "HealUserHalfOfTotalHPLoseFlyingTypeThisTurn"
when "0D7" then new_code = "HealUserPositionNextTurn"
when "0D8" then new_code = "HealUserDependingOnWeather"
when "0D9" then new_code = "HealUserFullyAndFallAsleep"
when "0DA" then new_code = "StartHealUserEachTurn"
when "0DB" then new_code = "StartHealUserEachTurnTrapUserInBattle"
when "0DC" then new_code = "StartLeechSeedTarget"
when "0DD" then new_code = "HealUserByHalfOfDamageDone"
when "0DE" then new_code = "HealUserByHalfOfDamageDoneIfTargetAsleep"
when "0DF" then new_code = "HealTargetHalfOfTotalHP"
when "0E0" then new_code = "UserFaintsExplosive"
when "0E1" then new_code = "UserFaintsFixedDamageUserHP"
when "0E2" then new_code = "UserFaintsLowerTargetAtkSpAtk2"
when "0E3" then new_code = "UserFaintsHealAndCureReplacement"
when "0E4" then new_code = "UserFaintsHealAndCureReplacementRestorePP"
when "0E5" then new_code = "StartPerishCountsForAllBattlers"
when "0E6" then new_code = "SetAttackerMovePPTo0IfUserFaints"
when "0E7" then new_code = "AttackerFaintsIfUserFaints"
when "0E8" then new_code = "UserEnduresFaintingThisTurn"
when "0E9" then new_code = "CannotMakeTargetFaint"
when "0EA"
if Settings::MECHANICS_GENERATION >= 8
new_code = "SwitchOutUserStatusMove"
else
new_code = "FleeFromBattle"
end
when "0EB" then new_code = "SwitchOutTargetStatusMove"
when "0EC" then new_code = "SwitchOutTargetDamagingMove"
when "0ED" then new_code = "SwitchOutUserPassOnEffects"
when "0EE" then new_code = "SwitchOutUserDamagingMove"
when "0EF" then new_code = "TrapTargetInBattle"
when "0F0" then new_code = "RemoveTargetItem"
when "0F1" then new_code = "UserTakesTargetItem"
when "0F2" then new_code = "UserTargetSwapItems"
when "0F3" then new_code = "TargetTakesUserItem"
when "0F4" then new_code = "UserConsumeTargetBerry"
when "0F5" then new_code = "DestroyTargetBerryOrGem"
when "0F6" then new_code = "RestoreUserConsumedItem"
when "0F7" then new_code = "ThrowUserItemAtTarget"
when "0F8" then new_code = "StartTargetCannotUseItem"
when "0F9" then new_code = "StartNegateHeldItems"
when "0FA" then new_code = "RecoilQuarterOfDamageDealt"
when "0FB" then new_code = "RecoilThirdOfDamageDealt"
when "0FC" then new_code = "RecoilHalfOfDamageDealt"
when "0FD" then new_code = "RecoilThirdOfDamageDealtParalyzeTarget"
when "0FE" then new_code = "RecoilThirdOfDamageDealtBurnTarget"
when "0FF" then new_code = "StartSunWeather"
when "100" then new_code = "StartRainWeather"
when "101" then new_code = "StartSandstormWeather"
when "102" then new_code = "StartHailWeather"
when "103" then new_code = "AddSpikesToFoeSide"
when "104" then new_code = "AddToxicSpikesToFoeSide"
when "105" then new_code = "AddStealthRocksToFoeSide"
when "106" then new_code = "GrassPledge"
when "107" then new_code = "FirePledge"
when "108" then new_code = "WaterPledge"
when "109" then new_code = "AddMoneyGainedFromBattle"
when "10A" then new_code = "RemoveScreens"
when "10B" then new_code = "CrashDamageIfFailsUnusableInGravity"
when "10C" then new_code = "UserMakeSubstitute"
when "10D" then new_code = "CurseTargetOrLowerUserSpd1RaiseUserAtkDef1"
when "10E" then new_code = "LowerPPOfTargetLastMoveBy4"
when "10F" then new_code = "StartDamageTargetEachTurnIfTargetAsleep"
when "110" then new_code = "RemoveUserBindingAndEntryHazards"
when "111" then new_code = "AttackTwoTurnsLater"
when "112" then new_code = "UserAddStockpileRaiseDefSpDef1"
when "113" then new_code = "PowerDependsOnUserStockpile"
when "114" then new_code = "HealUserDependingOnUserStockpile"
when "115" then new_code = "FailsIfUserDamagedThisTurn"
when "116" then new_code = "FailsIfTargetActed"
when "117" then new_code = "RedirectAllMovesToUser"
when "118" then new_code = "StartGravity"
when "119" then new_code = "StartUserAirborne"
when "11A" then new_code = "StartTargetAirborneAndAlwaysHitByMoves"
when "11B" then new_code = "HitsTargetInSky"
when "11C" then new_code = "HitsTargetInSkyGroundsTarget"
when "11D" then new_code = "TargetActsNext"
when "11E" then new_code = "TargetActsLast"
when "11F" then new_code = "StartSlowerBattlersActFirst"
when "120" then new_code = "UserSwapsPositionsWithAlly"
when "121" then new_code = "UseTargetAttackInsteadOfUserAttack"
when "122" then new_code = "UseTargetDefenseInsteadOfTargetSpDef"
when "123" then new_code = "FailsUnlessTargetSharesTypeWithUser"
when "124" then new_code = "StartSwapAllBattlersBaseDefensiveStats"
when "125" then new_code = "FailsIfUserHasUnusedMove"
when "126" then new_code = "None"
when "127" then new_code = "ParalyzeTarget"
when "128" then new_code = "BurnTarget"
when "129" then new_code = "FreezeTarget"
when "12A" then new_code = "ConfuseTarget"
when "12B" then new_code = "LowerTargetDefense2"
when "12C" then new_code = "LowerTargetEvasion2"
when "12D" then new_code = "DoublePowerIfTargetUnderwater"
when "12E" then new_code = "AllBattlersLoseHalfHPUserSkipsNextTurn"
when "12F" then new_code = "TrapTargetInBattle"
when "130" then new_code = "UserLosesHalfHP"
when "131" then new_code = "StartShadowSkyWeather"
when "132" then new_code = "RemoveAllScreens"
when "133" then new_code = "DoesNothingFailsIfNoAlly"
when "134" then new_code = "DoesNothingCongratulations"
when "135" then new_code = "FreezeTargetSuperEffectiveAgainstWater"
when "136" then new_code = "RaiseUserDefense2"
when "137" then new_code = "RaisePlusMinusUserAndAlliesDefSpDef1"
when "138" then new_code = "RaiseTargetSpDef1"
when "139" then new_code = "LowerTargetAttack1BypassSubstitute"
when "13A" then new_code = "LowerTargetAtkSpAtk1"
when "13B" then new_code = "HoopaRemoveProtectionsBypassSubstituteLowerUserDef1"
when "13C" then new_code = "LowerTargetSpAtk1"
when "13D" then new_code = "LowerTargetSpAtk2"
when "13E" then new_code = "RaiseGroundedGrassBattlersAtkSpAtk1"
when "13F" then new_code = "RaiseGrassBattlersDef1"
when "140" then new_code = "LowerPoisonedTargetAtkSpAtkSpd1"
when "141" then new_code = "InvertTargetStatStages"
when "142" then new_code = "AddGhostTypeToTarget"
when "143" then new_code = "AddGrassTypeToTarget"
when "144" then new_code = "EffectivenessIncludesFlyingType"
when "145" then new_code = "TargetMovesBecomeElectric"
when "146" then new_code = "NormalMovesBecomeElectric"
when "147" then new_code = "RemoveProtectionsBypassSubstitute"
when "148" then new_code = "TargetNextFireMoveDamagesTarget"
when "149" then new_code = "ProtectUserSideFromDamagingMovesIfUserFirstTurn"
when "14A" then new_code = "ProtectUserSideFromStatusMoves"
when "14B" then new_code = "ProtectUserFromDamagingMovesKingsShield"
when "14C" then new_code = "ProtectUserFromTargetingMovesSpikyShield"
when "14D" then new_code = "TwoTurnAttackInvulnerableRemoveProtections"
when "14E" then new_code = "TwoTurnAttackRaiseUserSpAtkSpDefSpd2"
when "14F" then new_code = "HealUserByThreeQuartersOfDamageDone"
when "150" then new_code = "RaiseUserAttack3IfTargetFaints"
when "151" then new_code = "LowerTargetAtkSpAtk1SwitchOutUser"
when "152" then new_code = "TrapAllBattlersInBattleForOneTurn"
when "153" then new_code = "AddStickyWebToFoeSide"
when "154" then new_code = "StartElectricTerrain"
when "155" then new_code = "StartGrassyTerrain"
when "156" then new_code = "StartMistyTerrain"
when "157" then new_code = "DoubleMoneyGainedFromBattle"
when "158" then new_code = "FailsIfUserNotConsumedBerry"
when "159" then new_code = "PoisonTargetLowerTargetSpeed1"
when "15A" then new_code = "CureTargetBurn"
when "15B" then new_code = "CureTargetStatusHealUserHalfOfTotalHP"
when "15C" then new_code = "RaisePlusMinusUserAndAlliesAtkSpAtk1"
when "15D" then new_code = "UserStealTargetPositiveStatStages"
when "15E" then new_code = "EnsureNextCriticalHit"
when "15F" then new_code = "LowerUserDefense1"
when "160" then new_code = "HealUserByTargetAttackLowerTargetAttack1"
when "161" then new_code = "UserTargetSwapBaseSpeed"
when "162" then new_code = "UserLosesFireType"
when "163" then new_code = "IgnoreTargetAbility"
when "164" then new_code = "CategoryDependsOnHigherDamageIgnoreTargetAbility"
when "165" then new_code = "NegateTargetAbilityIfTargetActed"
when "166" then new_code = "DoublePowerIfUserLastMoveFailed"
when "167" then new_code = "StartWeakenDamageAgainstUserSideIfHail"
when "168" then new_code = "ProtectUserBanefulBunker"
when "169" then new_code = "TypeIsUserFirstType"
when "16A" then new_code = "RedirectAllMovesToTarget"
when "16B" then new_code = "TargetUsesItsLastUsedMoveAgain"
when "16C" then new_code = "DisableTargetSoundMoves"
when "16D" then new_code = "HealUserDependingOnSandstorm"
when "16E" then new_code = "HealTargetDependingOnGrassyTerrain"
when "16F" then new_code = "HealAllyOrDamageFoe"
when "170" then new_code = "UserLosesHalfOfTotalHPExplosive"
when "171" then new_code = "UsedAfterUserTakesPhysicalDamage"
when "172" then new_code = "BurnAttackerBeforeUserActs"
when "173" then new_code = "StartPsychicTerrain"
when "174" then new_code = "FailsIfNotUserFirstTurn"
when "175" then new_code = "HitTwoTimesFlinchTarget"
end
data[:function_code] = new_code
return data
end
end
end

View File

@@ -1,21 +1,38 @@
module GameData
class Item
attr_reader :id
attr_reader :id_number
attr_reader :real_name
attr_reader :real_name_plural
attr_reader :pocket
attr_reader :price
attr_reader :sell_price
attr_reader :real_description
attr_reader :field_use
attr_reader :battle_use
attr_reader :type
attr_reader :consumable
attr_reader :flags
attr_reader :move
DATA = {}
DATA_FILENAME = "items.dat"
extend ClassMethods
SCHEMA = {
"Name" => [:name, "s"],
"NamePlural" => [:name_plural, "s"],
"Pocket" => [:pocket, "v"],
"Price" => [:price, "u"],
"SellPrice" => [:sell_price, "u"],
"Description" => [:description, "q"],
"FieldUse" => [:field_use, "e", { "OnPokemon" => 1, "Direct" => 2, "TM" => 3,
"HM" => 4, "TR" => 5 }],
"BattleUse" => [:battle_use, "e", { "OnPokemon" => 1, "OnMove" => 2, "OnBattler" => 3,
"OnFoe" => 4, "Direct" => 5 }],
"Consumable" => [:consumable, "b"],
"Flags" => [:flags, "*s"],
"Move" => [:move, "e", :Move]
}
extend ClassMethodsSymbols
include InstanceMethods
def self.icon_filename(item)
@@ -65,49 +82,55 @@ module GameData
def initialize(hash)
@id = hash[:id]
@id_number = hash[:id_number] || -1
@real_name = hash[:name] || "Unnamed"
@real_name_plural = hash[:name_plural] || "Unnamed"
@pocket = hash[:pocket] || 1
@price = hash[:price] || 0
@sell_price = hash[:sell_price] || (@price / 2)
@real_description = hash[:description] || "???"
@field_use = hash[:field_use] || 0
@battle_use = hash[:battle_use] || 0
@type = hash[:type] || 0
@flags = hash[:flags] || []
@consumable = hash[:consumable]
@consumable = !is_important? if @consumable.nil?
@move = hash[:move]
end
# @return [String] the translated name of this item
def name
return pbGetMessage(MessageTypes::Items, @id_number)
return pbGetMessageFromHash(MessageTypes::Items, @real_name)
end
# @return [String] the translated plural version of the name of this item
def name_plural
return pbGetMessage(MessageTypes::ItemPlurals, @id_number)
return pbGetMessageFromHash(MessageTypes::ItemPlurals, @real_name_plural)
end
# @return [String] the translated description of this item
def description
return pbGetMessage(MessageTypes::ItemDescriptions, @id_number)
return pbGetMessageFromHash(MessageTypes::ItemDescriptions, @real_description)
end
def has_flag?(flag)
return @flags.any? { |f| f.downcase == flag.downcase }
end
def is_TM?; return @field_use == 3; end
def is_HM?; return @field_use == 4; end
def is_TR?; return @field_use == 6; end
def is_TR?; return @field_use == 5; end
def is_machine?; return is_TM? || is_HM? || is_TR?; end
def is_mail?; return @type == 1 || @type == 2; end
def is_icon_mail?; return @type == 2; end
def is_poke_ball?; return @type == 3 || @type == 4; end
def is_snag_ball?; return @type == 3 || (@type == 4 && $Trainer.has_snag_machine); end
def is_berry?; return @type == 5; end
def is_key_item?; return @type == 6; end
def is_evolution_stone?; return @type == 7; end
def is_fossil?; return @type == 8; end
def is_apricorn?; return @type == 9; end
def is_gem?; return @type == 10; end
def is_mulch?; return @type == 11; end
def is_mega_stone?; return @type == 12; end # Does NOT include Red Orb/Blue Orb
def is_mail?; return has_flag?("Mail") || has_flag?("IconMail"); end
def is_icon_mail?; return has_flag?("IconMail"); end
def is_poke_ball?; return has_flag?("PokeBall") || has_flag?("SnagBall"); end
def is_snag_ball?; return has_flag?("SnagBall") || (is_poke_ball? && $player.has_snag_machine); end
def is_berry?; return has_flag?("Berry"); end
def is_key_item?; return has_flag?("KeyItem"); end
def is_evolution_stone?; return has_flag?("EvolutionStone"); end
def is_fossil?; return has_flag?("Fossil"); end
def is_apricorn?; return has_flag?("Apricorn"); end
def is_gem?; return has_flag?("TypeGem"); end
def is_mulch?; return has_flag?("Mulch"); end
def is_mega_stone?; return has_flag?("MegaStone"); end # Does NOT include Red Orb/Blue Orb
def is_important?
return true if is_key_item? || is_HM? || is_TM?
@@ -116,6 +139,10 @@ module GameData
def can_hold?; return !is_important?; end
def consumed_after_use?
return !is_important? && @consumable
end
def unlosable?(species, ability)
return false if species == :ARCEUS && ability != :MULTITYPE
return false if species == :SILVALLY && ability != :RKSSYSTEM
@@ -157,156 +184,11 @@ module GameData
:GIRATINA => [:GRISEOUSORB],
:GENESECT => [:BURNDRIVE, :CHILLDRIVE, :DOUSEDRIVE, :SHOCKDRIVE],
:KYOGRE => [:BLUEORB],
:GROUDON => [:REDORB]
:GROUDON => [:REDORB],
:ZACIAN => [:RUSTEDSWORD],
:ZAMAZENTA => [:RUSTEDSHIELD]
}
return combos[species] && combos[species].include?(@id)
return combos[species]&.include?(@id)
end
end
end
#===============================================================================
# Deprecated methods
#===============================================================================
# @deprecated This alias is slated to be removed in v20.
def pbGetPocket(item)
Deprecation.warn_method('pbGetPocket', 'v20', 'GameData::Item.get(item).pocket')
return GameData::Item.get(item).pocket
end
# @deprecated This alias is slated to be removed in v20.
def pbGetPrice(item)
Deprecation.warn_method('pbGetPrice', 'v20', 'GameData::Item.get(item).price')
return GameData::Item.get(item).price
end
# @deprecated This alias is slated to be removed in v20.
def pbGetMachine(item)
Deprecation.warn_method('pbGetMachine', 'v20', 'GameData::Item.get(item).move')
return GameData::Item.get(item).move
end
# @deprecated This alias is slated to be removed in v20.
def pbIsTechnicalMachine?(item)
Deprecation.warn_method('pbIsTechnicalMachine?', 'v20', 'GameData::Item.get(item).is_TM?')
return GameData::Item.get(item).is_TM?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsHiddenMachine?(item)
Deprecation.warn_method('pbIsHiddenMachine?', 'v20', 'GameData::Item.get(item).is_HM?')
return GameData::Item.get(item).is_HM?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsMachine?(item)
Deprecation.warn_method('pbIsMachine?', 'v20', 'GameData::Item.get(item).is_machine?')
return GameData::Item.get(item).is_machine?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsMail?(item)
Deprecation.warn_method('pbIsMail?', 'v20', 'GameData::Item.get(item).is_mail?')
return GameData::Item.get(item).is_mail?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsMailWithPokemonIcons?(item)
Deprecation.warn_method('pbIsMailWithPokemonIcons?', 'v20', 'GameData::Item.get(item).is_icon_mail?')
return GameData::Item.get(item).is_icon_mail?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsPokeBall?(item)
Deprecation.warn_method('pbIsPokeBall?', 'v20', 'GameData::Item.get(item).is_poke_ball?')
return GameData::Item.get(item).is_poke_ball?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsSnagBall?(item)
Deprecation.warn_method('pbIsSnagBall?', 'v20', 'GameData::Item.get(item).is_snag_ball?')
return GameData::Item.get(item).is_snag_ball?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsBerry?(item)
Deprecation.warn_method('pbIsBerry?', 'v20', 'GameData::Item.get(item).is_berry?')
return GameData::Item.get(item).is_berry?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsKeyItem?(item)
Deprecation.warn_method('pbIsKeyItem?', 'v20', 'GameData::Item.get(item).is_key_item?')
return GameData::Item.get(item).is_key_item?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsEvolutionStone?(item)
Deprecation.warn_method('pbIsEvolutionStone?', 'v20', 'GameData::Item.get(item).is_evolution_stone?')
return GameData::Item.get(item).is_evolution_stone?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsFossil?(item)
Deprecation.warn_method('pbIsFossil?', 'v20', 'GameData::Item.get(item).is_fossil?')
return GameData::Item.get(item).is_fossil?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsApricorn?(item)
Deprecation.warn_method('pbIsApricorn?', 'v20', 'GameData::Item.get(item).is_apricorn?')
return GameData::Item.get(item).is_apricorn?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsGem?(item)
Deprecation.warn_method('pbIsGem?', 'v20', 'GameData::Item.get(item).is_gem?')
return GameData::Item.get(item).is_gem?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsMulch?(item)
Deprecation.warn_method('pbIsMulch?', 'v20', 'GameData::Item.get(item).is_mulch?')
return GameData::Item.get(item).is_mulch?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsMegaStone?(item)
Deprecation.warn_method('pbIsMegaStone?', 'v20', 'GameData::Item.get(item).is_mega_stone?')
return GameData::Item.get(item).is_mega_stone?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsImportantItem?(item)
Deprecation.warn_method('pbIsImportantItem?', 'v20', 'GameData::Item.get(item).is_important?')
return GameData::Item.get(item).is_important?
end
# @deprecated This alias is slated to be removed in v20.
def pbCanHoldItem?(item)
Deprecation.warn_method('pbCanHoldItem?', 'v20', 'GameData::Item.get(item).can_hold?')
return GameData::Item.get(item).can_hold?
end
# @deprecated This alias is slated to be removed in v20.
def pbIsUnlosableItem?(check_item, species, ability)
Deprecation.warn_method('pbIsUnlosableItem?', 'v20', 'GameData::Item.get(item).unlosable?')
return GameData::Item.get(check_item).unlosable?(species, ability)
end
# @deprecated This alias is slated to be removed in v20.
def pbItemIconFile(item)
Deprecation.warn_method('pbItemIconFile', 'v20', 'GameData::Item.icon_filename(item)')
return GameData::Item.icon_filename(item)
end
# @deprecated This alias is slated to be removed in v20.
def pbHeldItemIconFile(item)
Deprecation.warn_method('pbHeldItemIconFile', 'v20', 'GameData::Item.held_icon_filename(item)')
return GameData::Item.held_icon_filename(item)
end
# @deprecated This alias is slated to be removed in v20.
def pbMailBackFile(item)
Deprecation.warn_method('pbMailBackFile', 'v20', 'GameData::Item.mail_filename(item)')
return GameData::Item.mail_filename(item)
end

Some files were not shown because too many files have changed in this diff Show More