Compare commits

..

26 Commits

Author SHA1 Message Date
chardub 7a4c34b872 [6.8.2] Safari Zone crash patch 2026-07-11 10:49:34 -04:00
chardub d3f378b833 i^dates version number 2026-07-10 17:09:32 -04:00
chardub 3014d486a1 hats 2026-07-10 17:08:16 -04:00
chardub 86bc491913 game.exe 2026-07-10 15:46:21 -04:00
chardub 6a6f126a18 Update 6.8 2026-07-10 15:42:06 -04:00
chardub 5b85e72cb2 6.7.2 patch 2025-10-02 10:35:46 -04:00
chardub e5406179bf 6.7.1 patch fixes 2025-10-01 11:28:13 -04:00
chardub 1271d7e8f0 fixes naked sprite when fishing 2025-09-28 18:22:11 -04:00
chardub e11e62272c possible missing files 2025-09-28 16:18:37 -04:00
chardub 51f98b9cc7 sprites credits 2025-09-28 16:14:12 -04:00
chardub 318ff90d8d update 6.7 2025-09-28 15:53:01 -04:00
chardub ef5e023ae0 6.6.2 2025-06-28 15:18:40 -04:00
chardub d383af130b koga necrozma fix 2025-06-11 15:46:36 -04:00
chardub 0c50a74a13 fixes typo causing crash 2025-06-10 16:10:31 -04:00
chardub 3e6e955070 6.6.1 patch 2025-06-10 12:45:27 -04:00
chardub 4ba51c7473 Fixes necrozma quest crash 2025-06-08 01:08:32 -04:00
chardub aa795459b4 game.exe (needed for launcher) 2025-06-08 01:00:33 -04:00
chardub fd3429c3b5 6.6 release fixes 2025-06-07 14:42:44 -04:00
chardub a50151c4af fixes oran berry hat 2025-06-07 13:07:41 -04:00
chardub 3622cb9bed fixes oran berry hat 2025-06-07 12:47:25 -04:00
chardub 23de3cb6e4 updates gitignore 2025-06-07 12:00:11 -04:00
chardub 451490edc7 spritesheets cache 2025-06-07 11:25:44 -04:00
chardub 30db0a406c gitkeep 2025-06-07 11:18:41 -04:00
chardub 937527828f removes temp folder 2025-06-07 10:40:53 -04:00
chardub b2f6901c6b fixes alt sprites option being on by default 2025-06-07 10:22:50 -04:00
chardub a393ba1137 6.6 update 2025-06-07 08:16:50 -04:00
2784 changed files with 497189 additions and 557406 deletions
+2 -7
View File
@@ -1,17 +1,12 @@
Graphics/CustomBattlers/local_sprites/*
Graphics/Battlers/Shiny/*
Graphics/Pokemon/FusionIcons/*
Graphics/CustomBattlers/spritesheets/*
Graphics/CustomBattlers/*
Data/sprites/*
Data/VERSION
infinitefusion.sh
Data/sprites/CUSTOM_SPRITES
Data/sprites
Data/sprites/updated_spritesheets_cache
Data/sprites/sprites_rate_limit.log
.gitignore
Game.rxproj
.DS_Store
Game.exe
PBS/*
rpgmaker.sh
-3
View File
@@ -1,3 +0,0 @@
[submodule "Data/Scripts"]
path = Data/Scripts
url = https://github.com/infinitefusion/scripts.git
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -1
View File
@@ -206,7 +206,8 @@ audreyeyeyeye https://www.deviantart.com/audreyeyeyeye/art/Pokemon-Type-Icons-FR
Chardub, chimcharsfireworkd, Rossay, Shiney570,
Phyromatical, Gallanty (deviantart)
### Music ###
### Music ###
Saffron City (Team Rocket): mystora
Pokeli https://www.youtube.com/channel/UC2ccJMFWSbjklOQESSBP_dw
https://www.youtube.com/watch?v=0ohkADYWCYE
https://www.youtube.com/watch?v=6EWYYzRSpMM
BIN
View File
Binary file not shown.
-8
View File
@@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/../../../../../../../../../../../:\Users\charl\Documents\Jeux\rpgmaker\infinitefusion\dev\infinitefusion-e18\Data\.idea/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Submodule Data/Scripts deleted from 4a4cde6707
+710
View File
@@ -0,0 +1,710 @@
#==============================================================================#
# Pokémon Essentials #
# Version 19.1.dev #
# 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_NUMBER = "6.8.2"
LATEST_GAME_RELEASE = "6.8"
HOENN_VERSION_NUMBER = "1.1.0"
HOENN_LATEST_GAME_RELEASE = "1.1.0"
SNOW_DAY = false
KANTO = GAME_ID == :IF_KANTO
HOENN = GAME_ID == :IF_HOENN
OVERWORLD_POKEMON_LIMIT = 8
POKERADAR_LIGHT_ANIMATION_RED_ID = 17
POKERADAR_LIGHT_ANIMATION_GREEN_ID = 18
POKERADAR_HIDDEN_ABILITY_POKE_CHANCE = 32
POKERADAR_BATTERY_STEPS = HOENN ? 1000 : 0
LEADER_VICTORY_MUSIC = "victory_gymLeader"
TRAINER_VICTORY_MUSIC = "victory_trainer"
WILD_VICTORY_MUSIC = "victory_wild"
GRUNT_VICTORY_MUSIC = "victory_grunt"
CHAMPION_VICTORY_MUSIC = "victory_champion"
FRONTIER_VICTORY_MUSIC = "victory_frontierBrain"
# getRandomCustomFusionForIntro
FUSION_ICON_SPRITE_OFFSET = 10
ANIMATE_REFLECTIONS = false # GAME_ID == :IF_HOENN #true
USE_REFLECTIONS = false
# Infinite fusion settings
NB_POKEMON = 576
TRANSFER_BOX_DISCLAIMER_MESSAGE = ""
CUSTOM_BASE_SPRITES_FOLDER = "Graphics/CustomBattlers/local_sprites/BaseSprites/"
CUSTOM_BATTLERS_FOLDER = "Graphics/CustomBattlers/"
CUSTOM_SPRITES_TO_IMPORT_FOLDER = "Graphics/CustomBattlers/Sprites to import/"
CUSTOM_BATTLERS_FOLDER_INDEXED = "Graphics/CustomBattlers/local_sprites/indexed/"
CUSTOM_BASE_SPRITE_FOLDER = "Graphics/CustomBattlers/local_sprites/BaseSprites/"
BATTLERS_FOLDER = "Graphics/Battlers/Autogens/"
DOWNLOADED_SPRITES_FOLDER = "Graphics/temp/"
DEFAULT_SPRITE_PATH = "Graphics/Battlers/Special/000.png"
CREDITS_FILE_PATH = "Data/sprites/Sprite_Credits.csv"
VERSION_FILE_PATH = "Data/VERSION"
CUSTOM_SPRITES_FILE_PATH = "Data/sprites/CUSTOM_SPRITES"
BASE_SPRITES_FILE_PATH = "Data/sprites/BASE_SPRITES"
CUSTOM_DEX_ENTRIES_PATH = "Data/pokedex/dex.json"
AI_DEX_ENTRIES_PATH = "Data/pokedex/generated_entries.json"
POKEDEX_ENTRIES_PATH = "Data/pokedex/all_entries.json"
UPDATED_SPRITESHEETS_CACHE = "Data/sprites/updated_spritesheets_cache"
BACK_ITEM_ICON_PATH = "Graphics/Items/back.png"
PLAYER_GRAPHICS_FOLDER = "Graphics/Characters/player/"
PLAYER_HAT_FOLDER = 'hat'
PLAYER_HAIR_FOLDER = 'hair'
PLAYER_CLOTHES_FOLDER = 'clothes'
PLAYER_BALL_FOLDER = 'balls'
PLAYER_TEMP_OUTFIT_FALLBACK = 'temp'
HATS_DATA_PATH = "Data/outfits/hats_data.json"
HAIRSTYLE_DATA_PATH = "Data/outfits/hairstyles_data.json"
CLOTHES_DATA_PATH = "Data/outfits/clothes_data.json"
PLAYER_SURFBASE_FOLDER = 'surf_base/'
OW_SHINE_ANIMATION_ID = 25
FEEDBACK_FORM_URL = ""
HTTP_CONFIGS_FILE_URL = "https://raw.githubusercontent.com/infinitefusion/pif-downloadables/refs/heads/master/Settings.rb"
HTTP_CONFIGS_FILE_PATH = "Data/Scripts/DownloadedSettings.rb"
SPRITES_FILE_URL = "https://raw.githubusercontent.com/infinitefusion/infinitefusion-e18/main/Data/sprites/CUSTOM_SPRITES"
BASE_SPRITES_FILE_URL = "https://raw.githubusercontent.com/infinitefusion/infinitefusion-e18/main/Data/sprites/BASE_SPRITES"
CREDITS_FILE_URL = "https://infinitefusion.net/customsprites/Sprite_Credits.csv"
CUSTOM_DEX_FILE_URL = "https://raw.githubusercontent.com/infinitefusion/pif-downloadables/refs/heads/master/dex.json"
SECRETBASE_UPLOAD_URL = "http://secretbases-upload.pkmninfinitefusion.workers.dev"
SECRETBASE_DOWNLOAD_URL = "https://secretbase-download.pkmninfinitefusion.workers.dev"
STARTUP_MESSAGES = ""
STARTUP_MESSAGES_KANTO = ""
STARTUP_MESSAGES_HOENN = ""
LEVEL_CAPS_KANTO = [12, 22, 26, 35, 38, 45, 51, 54, 62, 62, 63, 64, 64, 65, 67, 68]
LEVEL_CAPS_HOENN = [15, 19, 26, 99, 99, 99, 99, 99]
CUSTOM_ENTRIES_NAME_PLACEHOLDER = "POKENAME"
DEFAULT_SPEED_UP_SPEED = 2
FRONTSPRITE_POSITION_OFFSET = 20
FRONTSPRITE_SCALE = 0.6666666666666666
BACKRPSPRITE_SCALE = 1
EGGSPRITE_SCALE = 1
BACKSPRITE_POSITION_OFFSET = 20
FRONTSPRITE_POSITION = 200
SHINY_HUE_OFFSET = 75 # no longer used
NO_LEVEL_MODE_LEVEL_INCR = 5.8
NO_LEVEL_MODE_LEVEL_BASE = 6
MEW_OW_ENCOUNTER_CHANCE = 0
SAVEFILE_NB_BACKUPS = 10
MAIN_MENU_LINKS = {
}
DISCORD_URL = "https://discord.com/invite/infinitefusion"
WIKI_URL = "https://infinitefusion.fandom.com/"
FAQ_URL = "https://hackmd.io/@PIF-Staff/PIF-Hoenn-FAQ"
AI_ENTRIES_URL = "https://ai-entries.pkmninfinitefusion.workers.dev/"
AI_ENTRIES_RATE_MAX_NB_REQUESTS = 10 # Nb. requests allowed in each time window
AI_ENTRIES_RATE_TIME_WINDOW = 120 # In seconds
AI_ENTRIES_RATE_LOG_FILE = 'Data/pokedex/dex_rate_limit.log' # Path to the log file
CUSTOMSPRITES_RATE_MAX_NB_REQUESTS = 15 # Nb. requests allowed in each time window
CUSTOMSPRITES_ENTRIES_RATE_TIME_WINDOW = 120 # In seconds
CUSTOMSPRITES_RATE_LOG_FILE = 'Data/sprites/sprites_rate_limit.log' # Path to the log file
MAX_NB_SPRITES_TO_DOWNLOAD_AT_ONCE = 5
CUSTOM_SPRITES_REPO_URL = "https://bitbucket.org/infinitefusionsprites/customsprites/raw/main/CustomBattlers/"
CUSTOM_SPRITES_NEW_URL = "https://infinitefusion.net/CustomBattlers/"
BASE_POKEMON_ALT_SPRITES_REPO_URL = "https://bitbucket.org/infinitefusionsprites/customsprites/raw/main/Other/BaseSprites/"
BASE_POKEMON_ALT_SPRITES_NEW_URL = "https://infinitefusion.net/Other/BaseSprites/"
BASE_POKEMON_SPRITESHEET_URL = "https://infinitefusion.net/spritesheets/spritesheets_base/"
CUSTOM_FUSIONS_SPRITESHEET_URL = "https://infinitefusion.net/spritesheets/spritesheets_custom/"
BASE_POKEMON_SPRITESHEET_TRUE_SIZE_URL = ""
CUSTOM_FUSIONS_SPRITESHEET_TRUE_SIZE_URL = ""
RIVAL_STARTER_PLACEHOLDER_SPECIES = :MEW #(MEW)
VAR_1_PLACEHOLDER_SPECIES = :DIALGA
VAR_2_PLACEHOLDER_SPECIES = :PALKIA
VAR_3_PLACEHOLDER_SPECIES = :GIRATINA
RIVAL_STARTER_PLACEHOLDER_VARIABLE = 250
OVERRIDE_BATTLE_LEVEL_SWITCH = 785
OVERRIDE_BATTLE_LEVEL_VALUE_VAR = 240
HARD_MODE_LEVEL_MODIFIER = 1.1
EASY_MODE_LEVEL_MODIFIER = 0.9
ZAPMOLCUNO_NB = 999999 # 176821
MAPS_WITHOUT_SURF_MUSIC = [762]
WONDERTRADE_BASE_URL = "http://localhost:8080"
WONDERTRADE_PUBLIC_KEY = "http://localhost:8080"
MAX_NB_OUTFITS = 99
OUTFIT_PREVIEW_PICTURE_ID = 20
DEFAULT_TRAINER_CARD_BG = "BLUE"
# 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
# (you can of course change those settings to suit your game).
# 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 = 5
#=============================================================================
# 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
FADEOUT_SPEED = 0.2
#=============================================================================
# The maximum level Pokémon can reach.
MAXIMUM_LEVEL = 100
# The level of newly hatched Pokémon.
EGG_LEVEL = 1
# Number of badges in the game
NB_BADGES = 16
# The odds of a newly generated Pokémon being shiny (out of 65536).
SHINY_POKEMON_CHANCE = 16 #(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)
KANTO_STARTERS = [:BULBASAUR, :CHARMANDER, :SQUIRTLE]
JOHTO_STARTERS = [:CHIKORITA, :CYNDAQUIL, :TOTODILE]
HOENN_STARTERS = [:TREECKO, :TORCHIC, :MUDKIP]
SINNOH_STARTERS = [:TURTWIG, :CHIMCHAR, :PIPLUP]
KALOS_STARTERS = [:CHESPIN, :FENNEKIN, :FROAKIE]
DEFAULT_STARTERS = Settings::GAME_ID == :IF_KANTO ? KANTO_STARTERS : HOENN_STARTERS
GRASS_STARTERS = [:BULBASAUR, :CHIKORITA, :TREECKO, :TURTWIG, :CHESPIN]
FIRE_STARTERS = [:CHARMANDER, :CYNDAQUIL, :TORCHIC, :CHIMCHAR, :FENNEKIN]
WATER_STARTERS = [:SQUIRTLE, :TOTODILE, :MUDKIP, :PIPLUP, :FROAKIE]
ALTERING_CAVE_ENCOUNTERS =
{
:MONDAY => [:ZUBAT, :ZUBAT, :ZUBAT, :WOOBAT, :HOUNDOUR],
:TUESDAY => [:ZUBAT, :ZUBAT, :ZUBAT, :WOOBAT, :SCRAGGY],
:WEDNESDAY => [:ZUBAT, :ZUBAT, :ZUBAT, :WOOBAT, :PINECO],
:THURSDAY => [:ZUBAT, :ZUBAT, :ZUBAT, :WOOBAT, :MAREEP],
:FRIDAY => [:ZUBAT, :ZUBAT, :ZUBAT, :WOOBAT, :TEDDIURSA],
:SATURDAY => [:ZUBAT, :ZUBAT, :ZUBAT, :WOOBAT, :AIPOM],
:SUNDAY => [:ZUBAT, :ZUBAT, :ZUBAT, :WOOBAT, :SMEARGLE],
}
#=============================================================================
# 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.
MAX_COINS = 99_999
# The maximum number of Battle Points the player can have.
MAX_BATTLE_POINTS = 9_999
# The maximum amount of soot the player can have.
MAX_SOOT = 9_999
# The maximum length, in characters, that the player's name can be.
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]
]
#=============================================================================
# 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 = true #(MECHANICS_GENERATION <= 4)
# Whether poisoned Pokémon will faint while walking around in the field
# (true), or survive the poisoning with 1 HP (false).
POISON_FAINT_IN_FIELD = false
# Whether planted berries grow according to Gen 4 mechanics (true) or Gen 3
# mechanics (false).
NEW_BERRY_PLANTS = true
# Whether fishing automatically hooks the Pokémon (true), or whether there is
# a reaction test first (false).
FISHING_AUTO_HOOK = false
# The ID of the common event that runs when the player starts fishing (runs
# instead of showing the casting animation).
FISHING_BEGIN_COMMON_EVENT = -1
# 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
#=============================================================================
# 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).
BUG_CONTEST_TIME = 20 * 60 # 20 minutes
#=============================================================================
# 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 = []
#=============================================================================
# Whether you need at least a certain number of badges to use some hidden
# moves in the field (true), or whether you need one specific badge to use
# them (false). The amounts/specific badges are defined below.
FIELD_MOVES_COUNT_BADGES = true
# Depending on FIELD_MOVES_COUNT_BADGES, either the number of badges required
# to use each hidden move in the field, or the specific badge number required
# to use each move. Remember that badge 0 is the first badge, badge 1 is the
# second badge, etc.
# e.g. To require the second badge, put false and 1.
# To require at least 2 badges, put true and 2.
BADGE_FOR_CUT = 1
BADGE_FOR_FLASH = Settings::KANTO ? 1 : 2
BADGE_FOR_ROCKSMASH = Settings::KANTO ? 0 : 4
BADGE_FOR_SURF = 6
BADGE_FOR_FLY = 3
BADGE_FOR_STRENGTH = 5
BADGE_FOR_DIVE = 9
BADGE_FOR_WATERFALL = 9
BADGE_FOR_TELEPORT = 1
BADGE_FOR_BOUNCE = 8
BADGE_FOR_ROCKCLIMB = 16
#=============================================================================
# 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 = 40
#=============================================================================
# The names of each pocket of the Bag. Ignore the first entry ("").
def self.bag_pocket_names
return ["",
_INTL("Items"),
_INTL("Medicine"),
_INTL("Poké Balls"),
_INTL("TMs & HMs"),
_INTL("Berries"),
_INTL("Mail"),
_INTL("Battle Items"),
_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 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]
#=============================================================================
# Whether the Pokédex list shown is the one for the player's current region
# (true), or whether a menu pops up for the player to manually choose which
# 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.
def self.pokedex_names
return [
# ["Kanto Pokédex", 0]
]
end
# Whether all forms of a given species will be immediately available to view
# in the Pokédex so long as that species has been seen at all (true), or
# whether each form needs to be seen specifically before that form appears in
# the Pokédex (false).
DEX_SHOWS_ALL_FORMS = false
# An array of numbers, where each number is that of a Dex list (in the same
# order as above, except the National Dex is -1). All Dex lists included here
# will begin their numbering at 0 rather than 1 (e.g. Victini in Unova's Dex).
DEXES_WITH_OFFSETS = []
#=============================================================================
# A set of arrays, each containing details of a graphic to be shown on the
# region map if appropriate. The values for each array are as follows:
# * Region number.
# * Game Switch; the graphic is shown if this is ON (non-wall maps only).
# * X coordinate of the graphic on the map, in squares.
# * Y coordinate of the graphic on the map, in squares.
# * Name of the graphic, found in the Graphics/Pictures folder.
# * The graphic will always (true) or never (false) be shown on a wall map.
REGION_MAP_EXTRAS = [
#[0, 51, 16, 15, "mapHiddenBerth", false],
#[0, 52, 20, 14, "mapHiddenFaraday", false]
]
TRIPLE_TYPES = [:QMARKS, :ICEFIREELECTRIC, :FIREWATERELECTRIC, :WATERGROUNDFLYING, :GHOSTSTEELWATER,
:FIREWATERGRASS, :GRASSSTEEL, :BUGSTEELPSYCHIC, :ICEROCKSTEEL]
#=============================================================================
# A list of maps used by roaming Pokémon. Each map has an array of other maps
# it can lead to.
ROAMING_AREAS = {
262 => [261, 311],
311 => [262, 312],
312 => [311],
261 => [262, 288, 267],
288 => [261, 267, 285],
267 => [261, 288, 300, 254],
284 => [288, 266, 285],
300 => [267, 254],
254 => [300, 265],
266 => [284, 265],
265 => [266, 254],
285 => [284, 288] }
SEVII_ROAMING = {
528 => [526], # Treasure beach
526 => [528, 559], # Knot Island
559 => [526, 561, 564], # Kindle Road
561 => [559], # Mt. Ember
564 => [559, 562, 563, 594], # brine road
562 => [564], # boon island
563 => [564, 600], # kin island
594 => [564, 566, 603], # water labyrinth
600 => [563, 619], # bond bridge
619 => [600], # Berry forest
566 => [594, 603], # Resort gorgeous
603 => [566, 594], # Chrono Island
}
# A set of arrays, each containing the details of a roaming Pokémon. The
# information within each array is as follows:
# * Species.
# * Level.
# * Game Switch; the Pokémon roams while this is ON.
# * Encounter type (0=any, 1=grass/walking in cave, 2=surfing, 3=fishing,
# 4=surfing/fishing). See the bottom of PField_RoamingPokemon for lists.
# * Name of BGM to play for that encounter (optional).
# * Roaming areas specifically for this Pokémon (optional).
ROAMING_SPECIES = [
[:ENTEI, 50, 350, 1, "Legendary Birds", ROAMING_AREAS, :Sunny],
[:B245H243, 50, 341, 1, "Legendary Birds", ROAMING_AREAS, :Storm],
[:B379H378, 50, 602, 0, "Legendary Birds", SEVII_ROAMING, :StrongWinds],
[:B378H379, 50, 602, 0, "Legendary Birds", SEVII_ROAMING, :StrongWinds],
[:FEEBAS, 15, 4, 3, "Pokemon HeartGold and SoulSilver - Wild Pokemon Battle (Kanto)", SEVII_ROAMING, :Rain]
]
PINKAN_ISLAND_MAPS = Settings::KANTO ? [51, 46, 428, 531] : []
#=============================================================================
# A set of arrays, each containing the details of a wild encounter that can
# only occur via using the Poké Radar. The information within each array is as
# follows:
# * Map ID on which this encounter can occur.
# * Probability that this encounter will occur (as a percentage).
# * Species.
# * Minimum possible level.
# * Maximum possible level (optional).
POKE_RADAR_ENCOUNTERS = [
[78, 50, :FLETCHLING, 2, 5], # Rt. 1
[86, 50, :FLETCHLING, 2, 5], # Rt. 2
[90, 50, :FLETCHLING, 2, 5], # Rt. 2
[491, 50, :SHROOMISH, 2, 5], # Viridian Forest
[490, 50, :BUDEW, 4, 9], # Rt. 3
[106, 50, :NINCADA, 8, 10], # Rt. 4
[12, 50, :TOGEPI, 10, 10], # Rt. 5
[16, 50, :SLAKOTH, 12, 15], # Rt. 6
[413, 50, :DRIFLOON, 17, 20], # Rt. 7
[409, 50, :SHINX, 17, 18], # Rt. 8
[495, 50, :ARON, 12, 15], # Rt. 9
[351, 50, :ARON, 12, 15], # Rt. 9
[154, 50, :KLINK, 14, 17], # Rt. 10
[155, 50, :NINCADA, 12, 15], # Rt. 11
[159, 50, :COTTONEE, 22, 25], # Rt. 12
[437, 50, :COTTONEE, 22, 25], # Rt. 13
[437, 50, :JOLTIK, 22, 25], # Rt. 13
[440, 50, :JOLTIK, 22, 25], # Rt. 14
[444, 50, :SOLOSIS, 22, 25], # Rt. 15
[438, 50, :NATU, 22, 25], # Rt. 16
[146, 50, :KLEFKI, 22, 25], # Rt. 17
[517, 50, :FERROSEED, 22, 25], # Rt. 18
[445, 50, :BAGON, 20, 20], # Safari zone 1
[484, 50, :AXEW, 20, 20], # Safari zone 2
[485, 50, :DEINO, 20, 20], # Safari zone 3
[486, 50, :LARVITAR, 20, 20], # Safari zone 4
[487, 50, :JANGMOO, 20, 20], # Safari zone 5
[59, 50, :DUNSPARCE, 25, 30], # Rt. 21
[171, 50, :BIDOOF, 2, 5], # Rt. 22
[143, 50, :RIOLU, 25, 25], # Rt. 23
[8, 50, :BUNEARY, 12, 13], # Rt. 24
[145, 50, :ABSOL, 30, 35], # Rt. 26
[147, 50, :ABSOL, 30, 35], # Rt. 27
[311, 50, :BIDOOF, 5, 5], # Rt. 29
[284, 50, :LUXIO, 40, 45], # Rt. 33
[288, 50, :VIGOROTH, 40, 45], # Rt. 32
[342, 50, :GOLETT, 40, 45], # Ruins of Alph
[261, 50, :BELLOSSOM, 45, 50], # Rt. 31
[262, 50, :BIBAREL, 45, 50], # Rt. 30
[265, 50, :KIRLIA, 25, 30], # Rt. 34
[254, 50, :SMEARGLE, 25, 30], # Rt. 35
[267, 50, :SUDOWOODO, 25, 30], # Rt. 36
[500, 50, :FOMANTIS, 30, 30], # National Park
[266, 50, :BRELOOM, 30, 30], # Ilex Forest
[670, 50, :WEAVILE, 50, 50], # Ice mountains
[528, 50, :PYUKUMUKU, 20, 20], # Treasure Beach
[690, 50, :OCTILLERY, 32, 45], # Deep Ocean
[561, 50, :FLETCHINDER, 32, 45], # Mt. Ember
[562, 50, :NINJASK, 45, 50], # Boon Island
[603, 50, :KECLEON, 45, 50], # Chrono Island
[654, 50, :WHIMSICOTT, 32, 45], # Brine Road
[559, 50, :SCRAGGY, 32, 45] # Kindle Road
]
#=============================================================================
# The Game Switch that is set to ON when the player blacks out.
STARTING_OVER_SWITCH = 1
# The Game Switch that is set to ON when the player has seen Pokérus in the
# Poké Center (and doesn't need to be told about it again).
SEEN_POKERUS_SWITCH = 2
# The Game Switch which, while ON, makes all wild Pokémon created be shiny.
SHINY_WILD_POKEMON_SWITCH = 31
# The Game Switch which, while ON, makes all Pokémon created considered to be
# met via a fateful encounter.
FATEFUL_ENCOUNTER_SWITCH = 32
#=============================================================================
# ID of the animation played when the player steps on grass (grass rustling).
GRASS_ANIMATION_ID = 1
# ID of the animation played when the player lands on the ground after hopping
# over a ledge (shows a dust impact).
DUST_ANIMATION_ID = 2
# ID of the animation played when a trainer notices the player (an exclamation
# bubble).
EXCLAMATION_ANIMATION_ID = 3
QUESTION_MARK_ANIMATION_ID = 4
ANGRY_ANIMATION_ID = 24
ANGRY_SHORT_ANIMATION_ID = 34
FUSE_ANIMATION_ID = 33
# ID of the animation played when a patch of grass rustles due to using the
# Poké Radar.
RUSTLE_NORMAL_ANIMATION_ID = 1
# ID of the animation played when a patch of grass rustles vigorously due to
# using the Poké Radar. (Rarer species)
RUSTLE_VIGOROUS_ANIMATION_ID = 5
# ID of the animation played when a patch of grass rustles and shines due to
# using the Poké Radar. (Shiny encounter)
RUSTLE_SHINY_ANIMATION_ID = 6
# ID of the animation played when a berry tree grows a stage while the player
# is on the map (for new plant growth mechanics only).
PLANT_SPARKLE_ANIMATION_ID = 7
SPARKLE_SHORT_ANIMATION_ID = 25
SPARKLE_SUBTLE_ANIMATION_ID = 29
SLEEP_ANIMATION_ID = 26
CUT_TREE_ANIMATION_ID = 19
ROCK_SMASH_ANIMATION_ID = 20
#=============================================================================
# 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.
LANGUAGES = {
:IF_KANTO => [
["English", "english.dat"],
["Français", "french.dat"],
],
:IF_HOENN => [
["English", "english.dat"],
["Français", "french.dat"],
#["Español", "spanish.dat"],
#["中文", "chinese.dat"]
]
}
# Experimental
REMOTE_BATTLES_CONTROL = false
REMOTE_NPC_DIALOG = false
REMOTE_BATTLE_CONTROL_SERVER_URL = "http://127.0.0.1:5000/choose_move"
REMOTE_NPC_DIALOG_SERVER_URL = "http://127.0.0.1:5050"
# Technical
SPRITE_CACHE_MAX_NB = 100
NEWEST_SPRITEPACK_MONTH = 12
NEWEST_SPRITEPACK_YEAR = 2020
#=============================================================================
# Available speech frames. These are graphic files in "Graphics/Windowskins/".
SPEECH_WINDOWSKINS = [
"speech hgss 1",
"speech hgss 2",
"speech hgss 3",
"speech hgss 4",
"speech hgss 5",
"speech hgss 6",
"speech hgss 7",
"speech hgss 8",
"speech hgss 9",
"speech hgss 10",
"speech hgss 11",
"speech hgss 12",
"speech hgss 13",
"speech hgss 14",
"speech hgss 15",
"speech hgss 16",
"speech hgss 17",
"speech hgss 18",
"speech hgss 19",
"speech hgss 20",
"speech pl 18",
]
# Available menu frames. These are graphic files in "Graphics/Windowskins/".
MENU_WINDOWSKINS = [
"default_transparent",
"default_opaque",
"choice 2",
"choice 3",
"choice 4",
"choice 5",
"choice 6",
"choice 7",
"choice 8",
"choice 9",
"choice 10",
"choice 11",
"choice 12",
"choice 13",
"choice 14",
"choice 15",
"choice 16",
"choice 17",
"choice 18",
"choice 19",
"choice 20",
"choice 21",
"choice 22",
"choice 23",
"choice 24",
"choice 25",
"choice 26",
"choice 27",
"choice 28"
]
RANDOMIZED_GYM_TYPE_TM =
{
:NORMAL => [:TM32, :TM49, :TM42, :TM98], # DOUBLETEAM ECHOEDVOICE FACADE BATONPASS
:FIGHTING => [:TM83, :TM115, :TM52, :TM112], # WORKUP POWERUPPUNCH FOCUSBLAST FOCUSPUNCH
:FLYING => [:TM62, :TM58, :TM108, :TM100], # ACROBATICS SKYDROP SKYATTACK DEFOG
:POISON => [:TM84, :TM06, :TM36, :TM34], # POISONJAB TOXIC SLUDGEBOMB SLUDGEWAVE
:GROUND => [:TM28, :TM78, :TM26, :TM119], # DIG BULLDOZE EARTHQUAKE STOMPINGTANTRUM
:ROCK => [:TM39, :TM80, :TM71, :TM69], # ROCKTOMB ROCKTHROW STONEDGE ROCKPOLISH
:BUG => [:TM76, :TM89, :TM113, :TM99], # STRUGGLEBUG UTURN INFESTATION QUIVERDANCE
:GHOST => [:TM85, :TM65, :TM30, :TM97], # DREAMEATER SHADOWCLAW SHADOWBALL NASTYPLOT
:STEEL => [:TM74, :TM118, :TM117, :TM75], # GYROBALL STEELWING SMARTSTRIKE SWORDDANCE
:FIRE => [:TM11, :TM43, :TM38, :TM61], # SUNNYDAY FLAMECHARGE FIREBLAST WILLOWISP
:WATER => [:TM55, :TM105, :TM121, :TM18], # WATERPULSE AQUAJET SCALD RAINDANCE
:GRASS => [:TM22, :TM53, :TM86, :TM102], # SOLARBEAM ENERGYBALL GRASSKNOT SPORE
:ELECTRIC => [:TM73, :TM116, :TM93, :TM72], # THUNDERWAVE SHOCKWAVE WILDCHARGE VOLTSWITCH
:PSYCHIC => [:TM77, :TM03, :TM29, :TM04], # PSYCHUP PSYSHOCK PSYCHIC CALMMIND
:ICE => [:TM110, :TM13, :TM14, :TM07], # AURORAVEIL ICEBEAM BLIZZARD HAIL
:DRAGON => [:TM95, :TM02, :TM82, :TM101], # SNARL DRAGONCLAW DRAGONTAIL DRAGONDANCE
:DARK => [:TM95, :TM46, :TM120, :TM97], # SNARL THIEF THROATCHOP NASTYPLOT
:FAIRY => [:TM45, :TM111, :TM96, :TM104] # ATTRACT DAZZLINGGLEAM MOONBLAST RECOVER
}
EXCLUDE_FROM_RANDOM_SHOPS = [:RARECANDY]
end
module MysteryGift
URL = "https://download.infinitefusion.net/mystery_gift/MysteryGiftPublic.json"
PRIVATE_URL = "https://download.infinitefusion.net/mystery_gift/MysteryGiftsPrivate/"
end
# DO NOT EDIT THESE!
module Essentials
VERSION = "19.1.dev"
ERROR_TEXT = ""
end
@@ -0,0 +1,8 @@
module Encryption
ENCRYPTION_KEY = [0x4A, 0x8F, 0x2C, 0xE1, 0x73, 0xB5, 0x96, 0x0D,
0x5E, 0xA2, 0x3F, 0xC7, 0x81, 0x14, 0x6B, 0xD9]
def self.xor(data)
data.bytes.each_with_index.map { |b, i| b ^ ENCRYPTION_KEY[i % ENCRYPTION_KEY.length] }.pack("C*")
end
end
@@ -0,0 +1,40 @@
module PBDebug
@@log = []
def self.logonerr
begin
yield
rescue
PBDebug.log("")
PBDebug.log("**Exception: #{$!.message}")
PBDebug.log("#{$!.backtrace.inspect}")
PBDebug.log("")
# if $INTERNAL
pbPrintException($!)
# end
PBDebug.flush
end
end
def self.flush
if $DEBUG && $INTERNAL && @@log.length>0
File.open("Data/debuglog.txt", "a+b") { |f| f.write("#{@@log}") }
end
@@log.clear
end
def self.log(msg)
if $DEBUG && $INTERNAL
@@log.push("#{msg}\r\n")
# if @@log.length>1024
PBDebug.flush
# end
end
end
def self.dump(msg)
if $DEBUG && $INTERNAL
File.open("Data/dumplog.txt", "a+b") { |f| f.write("#{msg}\r\n") }
end
end
end
@@ -0,0 +1,54 @@
# 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 "--------------------------------"
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 "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 ""
echoln "--------------------------------"
echoln "Debug Output:"
echoln "--------------------------------"
echoln ""
end
def self.readInput
return gets.strip
end
def self.readInput2
return self.readInput
end
def self.get_input
echo self.readInput2
end
end
module Kernel
def echo(string)
return unless $DEBUG
printf(string.is_a?(String) ? string : string.inspect)
end
def echoln(string)
caller_info = caller(1..1).first
file, line, method = caller_info.split(":")
echo "#{file}, #{line}:\t"
echo(string)
echo("\r\n")
end
end
Console.setup_console
@@ -0,0 +1,93 @@
#===============================================================================
# Exceptions and critical code
#===============================================================================
class Reset < Exception
end
def pbGetExceptionMessage(e,_script="")
emessage = e.message.dup
emessage.force_encoding(Encoding::UTF_8)
if e.is_a?(Hangup)
emessage = "The script is taking too long. The game will restart."
elsif e.is_a?(Errno::ENOENT)
filename = emessage.sub("No such file or directory - ", "")
emessage = "File #{filename} not found."
end
emessage.gsub!(/Section(\d+)/) { $RGSS_SCRIPTS[$1.to_i][1] } rescue nil
return emessage
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 = "[Infinite Fusion version #{Settings::GAME_VERSION_NUMBER}]\r\n"
if $game_switches
message += "Randomized trainers, " if $game_switches[SWITCH_RANDOM_TRAINERS]
message += "Randomized gym trainers, " if $game_switches[SWITCH_RANDOMIZE_GYMS_SEPARATELY]
message += "Randomized wild Pokemon (global), " if $game_switches[SWITCH_WILD_RANDOM_GLOBAL]
message += "Randomized wild Pokemon (area), " if $game_switches[RandomizerWildPokemonOptionsScene::RANDOM_WILD_AREA]
message += "All fused, " if $game_switches[SWITCH_RANDOM_TRAINERS]
message += "Randomized trainers, " if $game_switches[RandomizerWildPokemonOptionsScene::REGULAR_TO_FUSIONS]
end
message += "#{Essentials::ERROR_TEXT}\r\n" # For third party scripts to add to
message += "Exception: #{e.class}\r\n"
message += "Message: #{emessage}\r\n"
# show last 10/25 lines of backtrace
message += "\r\nBacktrace:\r\n"
btrace = ""
if e.backtrace
maxlength = ($INTERNAL) ? 25 : 10
e.backtrace[0, maxlength].each { |i| btrace += "#{i}\r\n" }
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)
File.open(errorlog, "ab") do |f|
f.write("\r\n=================\r\n\r\n[#{Time.now}]\r\n")
f.write(message)
end
# format/censor the error log directory
errorlogline = errorlog.gsub("/", "\\")
errorlogline.sub!(Dir.pwd + "\\", "")
errorlogline.sub!(pbGetUserName, "USERNAME")
errorlogline = "\r\n" + errorlogline if errorlogline.length > 20
# output message
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
Input.update
if Input.press?(Input::CTRL)
Input.clipboard = message
break
end
end
end
def pbCriticalCode
ret = 0
begin
yield
ret = 1
rescue Exception
e = $!
if e.is_a?(Reset) || e.is_a?(SystemExit)
raise
else
pbPrintException(e)
if e.is_a?(Hangup)
ret = 2
raise Reset.new
end
end
end
return ret
end
@@ -0,0 +1,31 @@
# The Kernel module is extended to include the validate method.
module Kernel
private
# Used to check whether method arguments are of a given class or respond to a method.
# @param value_pairs [Hash{Object => Class, Array<Class>, Symbol}] value pairs to validate
# @example Validate a class or method
# validate foo => Integer, baz => :to_s # raises an error if foo is not an Integer or if baz doesn't implement #to_s
# @example Validate a class from an array
# validate foo => [Sprite, Bitmap, Viewport] # raises an error if foo isn't a Sprite, Bitmap or Viewport
# @raise [ArgumentError] if validation fails
def validate(value_pairs)
unless value_pairs.is_a?(Hash)
raise ArgumentError, "Non-hash argument #{value_pairs.inspect} passed into validate."
end
errors = value_pairs.map do |value, condition|
if condition.is_a?(Array)
unless condition.any? { |klass| value.is_a?(klass) }
next "Expected #{value.inspect} to be one of #{condition.inspect}, but got #{value.class.name}."
end
elsif condition.is_a?(Symbol)
next "Expected #{value.inspect} to respond to #{condition}." unless value.respond_to?(condition)
elsif !value.is_a?(condition)
next "Expected #{value.inspect} to be a #{condition.name}, but got #{value.class.name}."
end
end
errors.compact!
return if errors.empty?
raise ArgumentError, "Invalid argument passed to method.\r\n" + errors.join("\r\n")
end
end
@@ -0,0 +1,53 @@
# The Deprecation module is used to warn game & plugin creators of deprecated
# methods.
module Deprecation
module_function
# Sends a warning of a deprecated method into the debug console.
# @param method_name [String] name of the deprecated method
# @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)
unless removal_version.nil?
text += _INTL("\nThe method is slated to be"\
" removed in Essentials {1}.", removal_version)
end
unless alternative.nil?
text += _INTL("\nUse \"{1}\" instead.", alternative)
end
echoln text
end
end
# The Module class is extended to allow easy deprecation of instance and class methods.
class Module
private
# Creates a deprecated alias for a method.
# Using it sends a warning to the debug console.
# @param name [Symbol] name of the new alias
# @param aliased_method [Symbol] name of the aliased method
# @param removal_in [String] version the alias is removed in
# @param class_method [Boolean] whether the method is a class method
def deprecated_method_alias(name, aliased_method, removal_in: nil, class_method: false)
validate name => Symbol, aliased_method => Symbol, removal_in => [NilClass, String],
class_method => [TrueClass, FalseClass]
target = class_method ? self.class : self
class_name = self.name
unless target.method_defined?(aliased_method)
raise ArgumentError, "#{class_name} does not have method #{aliased_method} defined"
end
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)
Deprecation.warn_method(alias_name, removal_in, aliased_method_name)
method(aliased_method).call(*args, **kvargs)
end
end
end
@@ -0,0 +1,48 @@
# Using mkxp-z v2.2.0 - https://gitlab.com/mkxp-z/mkxp-z/-/releases/v2.2.0
$VERBOSE = nil
Font.default_shadow = false if Font.respond_to?(:default_shadow)
Encoding.default_internal = Encoding::UTF_8
Encoding.default_external = Encoding::UTF_8
Graphics.frame_rate = 40
def pbSetWindowText(string)
System.set_window_title(string || System.game_title)
end
class Bitmap
attr_accessor :storedPath
alias mkxp_draw_text draw_text unless method_defined?(:mkxp_draw_text)
def draw_text(x, y, width, height, 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
return self.delta.to_f / 1_000_000
end
end
def pbSetResizeFactor(factor)
if !$ResizeInitialized
Graphics.resize_screen(Settings::SCREEN_WIDTH, Settings::SCREEN_HEIGHT)
$ResizeInitialized = true
end
if factor < 0 || factor == 4
Graphics.fullscreen = true if !Graphics.fullscreen
else
Graphics.fullscreen = false if Graphics.fullscreen
Graphics.scale = (factor + 1) * 0.5
Graphics.center
end
end
@@ -0,0 +1,490 @@
KNOWN_BITMAP_EXTENSIONS = /\.(bmp|png|gif|jpg|jpeg|dat)$/
#===============================================================================
# Reads files of certain format from a directory
#===============================================================================
class Dir
#-----------------------------------------------------------------------------
# Reads all files in a directory
#-----------------------------------------------------------------------------
def self.get(dir, filters = "*", full = true)
files = []
filters = [filters] if !filters.is_a?(Array)
self.chdir(dir) do
for filter in filters
self.glob(filter){ |f| files.push(full ? (dir + "/" + f) : f) }
end
end
return files.sort
end
#-----------------------------------------------------------------------------
# Generates entire file/folder tree from a certain directory
#-----------------------------------------------------------------------------
def self.all(dir, filters = "*", full = true)
# sets variables for starting
files = []
subfolders = []
for file in self.get(dir, filters, full)
# engages in recursion to read the entire file tree
if self.safe?(file) # Is a directory
subfolders += self.all(file, filters, full)
else # Is a file
files += [file]
end
end
# returns all found files
return files + subfolders
end
#-----------------------------------------------------------------------------
# Checks for existing directory, gets around accents
#-----------------------------------------------------------------------------
def self.safe?(dir)
return false if !FileTest.directory?(dir)
ret = false
self.chdir(dir) { ret = true } rescue nil
return ret
end
#-----------------------------------------------------------------------------
end
#===============================================================================
# extensions for file class
#===============================================================================
class File
#-----------------------------------------------------------------------------
# Checks for existing file, gets around accents
#-----------------------------------------------------------------------------
def self.safe?(file)
ret = false
self.open(file, 'rb') { ret = true } rescue nil
return ret
end
#-----------------------------------------------------------------------------
end
#===============================================================================
# Checking for files and directories
#===============================================================================
# Works around a problem with FileTest.directory if directory contains accent marks
def safeIsDirectory?(f)
ret = false
Dir.chdir(f) { ret = true } rescue nil
return ret
end
# Works around a problem with FileTest.exist if path contains accent marks
def safeExists?(f)
return FileTest.exist?(f) if f[/\A[\x20-\x7E]*\z/]
ret = false
begin
File.open(f,"rb") { ret = true }
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES
ret = false
end
return ret
end
# Similar to "Dir.glob", but designed to work around a problem with accessing
# files if a path contains accent marks.
# "dir" is the directory path, "wildcard" is the filename pattern to match.
def safeGlob(dir,wildcard)
ret = []
afterChdir = false
begin
Dir.chdir(dir) {
afterChdir = true
Dir.glob(wildcard) { |f| ret.push(dir+"/"+f) }
}
rescue Errno::ENOENT
raise if afterChdir
end
if block_given?
ret.each { |f| yield(f) }
end
return (block_given?) ? nil : ret
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"])
end
return nil
end
# Finds the real path for an image file. This includes paths in encrypted
# archives. Returns nil if the path can't be found.
def pbResolveBitmap(x)
return nil if !x
noext = x.gsub(KNOWN_BITMAP_EXTENSIONS,"")
noext = pbLocalizedBitmapFilename(noext)
filename = nil
RTP.eachPathFor(noext) { |path|
filename = pbTryString(path+".png") if !filename
filename = pbTryString(path+".gif") if !filename
filename = pbTryString(path+".dat") if !filename
}
return filename
end
# Finds the real path for an image file. This includes paths in encrypted
# archives. Returns _x_ if the path can't be found.
def pbBitmapName(x)
ret = pbResolveBitmap(x)
return (ret) ? ret : x
end
def strsplit(str, re)
ret = []
tstr = str
while re =~ tstr
ret[ret.length] = $~.pre_match
tstr = $~.post_match
end
ret[ret.length] = tstr if ret.length
return ret
end
def canonicalize(c)
csplit = strsplit(c, /[\/\\]/)
pos = -1
ret = []
retstr = ""
for x in csplit
if x == ".."
if pos >= 0
ret.delete_at(pos)
pos -= 1
end
elsif x != "."
ret.push(x)
pos += 1
end
end
for i in 0...ret.length
retstr += "/" if i > 0
retstr += ret[i]
end
return retstr
end
module RTP
@rtpPaths = nil
def self.exists?(filename,extensions=[])
return false if nil_or_empty?(filename)
eachPathFor(filename) { |path|
return true if safeExists?(path)
for ext in extensions
return true if safeExists?(path+ext)
end
}
return false
end
def self.getImagePath(filename)
return self.getPath(filename,["",".png",".gif"]) # ".jpg", ".jpeg", ".bmp"
end
def self.getAudioPath(filename)
return self.getPath(filename,["",".mp3",".wav",".wma",".mid",".ogg",".midi"])
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
file = path+ext
return file if safeExists?(file)
end
}
return filename
end
# Gets the absolute RGSS paths for the given file name
def self.eachPathFor(filename)
return if !filename
if filename[/^[A-Za-z]\:[\/\\]/] || filename[/^[\/\\]/]
# filename is already absolute
yield filename
else
# relative path
RTP.eachPath { |path|
if path=="./"
yield filename
else
yield path+filename
end
}
end
end
# Gets all RGSS search paths.
# This function basically does nothing now, because
# the passage of time and introduction of MKXP make
# it useless, but leaving it for compatibility
# reasons
def self.eachPath
# XXX: Use "." instead of Dir.pwd because of problems retrieving files if
# the current directory contains an accent mark
yield ".".gsub(/[\/\\]/,"/").gsub(/[\/\\]$/,"")+"/"
end
private
def self.getSaveFileName(fileName)
File.join(getSaveFolder, fileName)
end
def self.getSaveFolder
# MKXP makes sure that this folder has been created
# once it starts. The location differs depending on
# the operating system:
# Windows: %APPDATA%
# Linux: $HOME/.local/share
# macOS (unsandboxed): $HOME/Library/Application Support
System.data_directory
end
end
module FileTest
Image_ext = ['.png', '.gif'] # '.jpg', '.jpeg', '.bmp',
Audio_ext = ['.mp3', '.mid', '.midi', '.ogg', '.wav', '.wma']
def self.audio_exist?(filename)
return RTP.exists?(filename,Audio_ext)
end
def self.image_exist?(filename)
return RTP.exists?(filename,Image_ext)
end
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,
# and matching mount points added through System.mount
def pbRgssExists?(filename)
if safeExists?("./Game.rgssad")
return pbGetFileChar(filename)!=nil
else
filename = canonicalize(filename)
return safeExists?(filename)
end
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,
# 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") }
if !safeExists?("./Game.rgssad")
if block_given?
File.open(file,mode) { |f| yield f }
return nil
else
return File.open(file,mode)
end
end
file = canonicalize(file)
Marshal.neverload = true
str = load_data(file, true)
if block_given?
StringInput.open(str) { |f| yield f }
return nil
else
return StringInput.open(str)
end
end
# Gets at least the first byte of a file. Doesn't check RTP, but does check
# encrypted archives.
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
begin
File.open(canon_file, "rb") { |f| return f.read(1) } # read one byte
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES, Errno::EISDIR
return nil
end
end
str = nil
begin
str = load_data(canon_file, true)
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES, Errno::EISDIR, RGSSError, MKXPError
str = nil
end
return str
end
def pbTryString(x)
ret = pbGetFileChar(x)
return (ret!=nil && ret!="") ? x : nil
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,
# and matching mount points added through System.mount
def pbGetFileString(file)
file = canonicalize(file)
if !safeExists?("./Game.rgssad")
return nil if !safeExists?(file)
begin
File.open(file,"rb") { |f| return f.read } # read all data
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES
return nil
end
end
str = nil
begin
str = load_data(file, true)
rescue Errno::ENOENT, Errno::EINVAL, Errno::EACCES, RGSSError, MKXPError
str = nil
end
return str
end
#===============================================================================
#
#===============================================================================
class StringInput
include Enumerable
class << self
def new( str )
if block_given?
begin
f = super
yield f
ensure
f.close if f
end
else
super
end
end
alias open new
end
def initialize( str )
@string = str
@pos = 0
@closed = false
@lineno = 0
end
attr_reader :lineno,:string
def inspect
return "#<#{self.class}:#{@closed ? 'closed' : 'open'},src=#{@string[0,30].inspect}>"
end
def close
raise IOError, 'closed stream' if @closed
@pos = nil
@closed = true
end
def closed?; @closed; end
def pos
raise IOError, 'closed stream' if @closed
[@pos, @string.size].min
end
alias tell pos
def rewind; seek(0); end
def pos=(value); seek(value); end
def seek(offset, whence=IO::SEEK_SET)
raise IOError, 'closed stream' if @closed
case whence
when IO::SEEK_SET then @pos = offset
when IO::SEEK_CUR then @pos += offset
when IO::SEEK_END then @pos = @string.size - offset
else
raise ArgumentError, "unknown seek flag: #{whence}"
end
@pos = 0 if @pos < 0
@pos = [@pos, @string.size + 1].min
offset
end
def eof?
raise IOError, 'closed stream' if @closed
@pos > @string.size
end
def each( &block )
raise IOError, 'closed stream' if @closed
begin
@string.each(&block)
ensure
@pos = 0
end
end
def gets
raise IOError, 'closed stream' if @closed
if idx = @string.index(?\n, @pos)
idx += 1 # "\n".size
line = @string[ @pos ... idx ]
@pos = idx
@pos += 1 if @pos == @string.size
else
line = @string[ @pos .. -1 ]
@pos = @string.size + 1
end
@lineno += 1
line
end
def getc
raise IOError, 'closed stream' if @closed
ch = @string[@pos]
@pos += 1
@pos += 1 if @pos == @string.size
ch
end
def read( len = nil )
raise IOError, 'closed stream' if @closed
if !len
return nil if eof?
rest = @string[@pos ... @string.size]
@pos = @string.size + 1
return rest
end
str = @string[@pos, len]
@pos += len
@pos += 1 if @pos == @string.size
str
end
def read_all; read(); end
alias sysread read
end
@@ -0,0 +1,150 @@
module FileInputMixin
def fgetb
ret = 0
each_byte do |i|
ret = i || 0
break
end
return ret
end
def fgetw
x = 0
ret = 0
each_byte do |i|
break if !i
ret |= (i << x)
x += 8
break if x == 16
end
return ret
end
def fgetdw
x = 0
ret = 0
each_byte do |i|
break if !i
ret |= (i << x)
x += 8
break if x == 32
end
return ret
end
def fgetsb
ret = fgetb
ret -= 256 if (ret & 0x80) != 0
return ret
end
def xfgetb(offset)
self.pos = offset
return fgetb
end
def xfgetw(offset)
self.pos = offset
return fgetw
end
def xfgetdw(offset)
self.pos = offset
return fgetdw
end
def getOffset(index)
self.binmode
self.pos = 0
offset = fgetdw >> 3
return 0 if index >= offset
self.pos = index * 8
return fgetdw
end
def getLength(index)
self.binmode
self.pos = 0
offset = fgetdw >> 3
return 0 if index >= offset
self.pos = index * 8 + 4
return fgetdw
end
def readName(index)
self.binmode
self.pos = 0
offset = fgetdw >> 3
return "" if index >= offset
self.pos = index << 3
offset = fgetdw
length = fgetdw
return "" if length == 0
self.pos = offset
return read(length)
end
end
module FileOutputMixin
def fputb(b)
b &= 0xFF
write(b.chr)
end
def fputw(w)
2.times do
b = w & 0xFF
write(b.chr)
w >>= 8
end
end
def fputdw(w)
4.times do
b = w & 0xFF
write(b.chr)
w >>= 8
end
end
end
class File < IO
=begin
unless defined?(debugopen)
class << self
alias debugopen open
end
end
def open(f, m = "r")
debugopen("debug.txt", "ab") { |file| file.write([f, m, Time.now.to_f].inspect + "\r\n") }
if block_given?
debugopen(f, m) { |file| yield file }
else
return debugopen(f, m)
end
end
=end
include FileInputMixin
include FileOutputMixin
end
class StringInput
include FileInputMixin
def pos=(value)
seek(value)
end
def each_byte
while !eof?
yield getc
end
end
def binmode; end
end
class StringOutput
include FileOutputMixin
end
@@ -0,0 +1,222 @@
#############################
#
# HTTP utility functions
#
#############################
def pbPostData(url, postdata, filename=nil, depth=0)
return "" unless url =~ /^https?:\/\/([^\/]+)(.*)$/
host = $1
path = $2
path = "/" if path.empty?
userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14"
# Serialize as JSON
body = serialize_json(postdata)
ret = HTTPLite.post_body(
url,
body,
"application/json",
{
"Host" => host,
"Proxy-Connection" => "Close",
"Content-Length" => body.bytesize.to_s,
"Pragma" => "no-cache",
"User-Agent" => userAgent
}
) rescue ""
return "" if !ret.is_a?(Hash)
return "" if ret[:status] != 200
if filename
File.open(filename, "wb") { |f| f.write(ret[:body]) }
return ""
end
ret[:body]
end
def pbDownloadData(url, filename = nil, authorization = nil, depth = 0, &block)
return nil if !downloadAllowed?()
echoln "downloading data from #{url}"
headers = {
"Proxy-Connection" => "Close",
"Pragma" => "no-cache",
"User-Agent" => "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14"
}
headers["authorization"] = authorization if authorization
ret = HTTPLite.get(url, headers) rescue ""
return ret if !ret.is_a?(Hash)
return "" if ret[:status] != 200
return ret[:body] if !filename
File.open(filename, "wb") { |f| f.write(ret[:body]) }
return ""
end
def pbDownloadToString(url)
begin
data = pbDownloadData(url)
return data if data
return ""
rescue
return ""
end
end
def pbDownloadToFile(url, file)
begin
pbDownloadData(url,file)
rescue
end
end
def pbPostToString(url, postdata, timeout = 30)
safe_postdata = postdata.transform_values(&:to_s)
begin
data = pbPostData(url, safe_postdata)
return data || ""
rescue MKXPError => e
echoln("[Remote AI] Exception: #{e.message}")
return ""
end
end
def pbPostToFile(url, postdata, file)
begin
pbPostData(url, postdata,file)
rescue
end
end
def serialize_value_legacy(value)
if value.is_a?(Hash)
serialize_json(value)
elsif value.is_a?(String)
escaped_value = value.gsub(/\\/, '\\\\\\').gsub(/"/, '\\"').gsub(/\n/, '\\n').gsub(/\r/, '\\r')
"\"#{escaped_value}\""
else
value.to_s
end
end
def serialize_json(data)
if data.is_a?(Hash)
parts = ["{"]
data.each_with_index do |(key, value), index|
parts << "\"#{key}\":#{serialize_value(value)}"
parts << "," unless index == data.size - 1
end
parts << "}"
return parts.join
else
return serialize_value(data)
end
end
def serialize_value(value)
case value
when String
"\"#{escape_json_string(value)}\""
when Numeric
value.to_s
when TrueClass, FalseClass
value.to_s
when NilClass
"null"
when Array
"[" + value.map { |v| serialize_value(v) }.join(",") + "]"
when Hash
serialize_json(value)
else
raise "Unsupported type: #{value.class}"
end
end
def escape_json_string(str)
# Minimal escape handling
str.gsub(/["\\]/) { |m| "\\#{m}" }
.gsub("\n", "\\n")
.gsub("\t", "\\t")
.gsub("\r", "\\r")
end
def downloadAllowed?()
return $PokemonSystem.download_sprites==0
end
def clean_json_string(str)
#echoln str
#return str if $PokemonSystem.on_mobile
# Remove non-UTF-8 characters and unexpected control characters
#cleaned_str = str.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
cleaned_str = str
# Remove literal \n, \r, \t, etc.
cleaned_str = cleaned_str.gsub(/\\n|\\r|\\t/, '')
# Remove actual newlines and carriage returns
cleaned_str = cleaned_str.gsub(/[\n\r]/, '')
# Remove leading and trailing quotes
cleaned_str = cleaned_str.gsub(/\A"|"\Z/, '')
# Replace Unicode escape sequences with corresponding characters
cleaned_str = cleaned_str.gsub(/\\u([\da-fA-F]{4})/) { |match|
[$1.to_i(16)].pack("U")
}
return cleaned_str
end
# json.rb - lightweight JSON parser for MKXP/RGSS XP
# Lightweight JSON for MKXP/RGSS XP
module JSON
module_function
# Convert Ruby object (hash/array/etc) into JSON string
def generate(obj)
case obj
when Hash
"{" + obj.map { |k, v| "\"#{k}\":#{generate(v)}" }.join(",") + "}"
when Array
"[" + obj.map { |v| generate(v) }.join(",") + "]"
when String, Symbol
"\"#{obj.to_s}\""
when TrueClass, FalseClass
obj.to_s
when NilClass
"null"
when Numeric
obj.to_s
else
raise "Unsupported type #{obj.class}"
end
end
# Simple parser (not full JSON) — optional
def parse(str)
return nil if str.nil? || str.strip.empty?
eval(str)
end
end
@@ -0,0 +1,142 @@
#===============================================================================
# class Object
#===============================================================================
class Object
alias full_inspect inspect unless method_defined?(:full_inspect)
def inspect
return "#<#{self.class}>"
end
end
#===============================================================================
# class Class
#===============================================================================
class Class
def to_sym
return self.to_s.to_sym
end
end
#===============================================================================
# class String
#===============================================================================
class String
def starts_with_vowel?
return ['a', 'e', 'i', 'o', 'u'].include?(self[0, 1].downcase)
end
def first(n = 1)
return self[0...n]
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 cut(bitmap, width)
string = self
width -= bitmap.text_size("...").width
string_width = 0
text = []
for char in string.scan(/./)
wdh = bitmap.text_size(char).width
next if (wdh + string_width) > width
string_width += wdh
text.push(char)
end
text.push("...") if text.length < string.length
new_string = ""
for char in text
new_string += char
end
return new_string
end
end
#===============================================================================
# class Numeric
#===============================================================================
class Numeric
# Turns a number into a string formatted like 12,345,678.
def to_s_formatted
return self.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\1,').reverse
end
def to_word
ret = [_INTL("zero"), _INTL("one"), _INTL("two"), _INTL("three"),
_INTL("four"), _INTL("five"), _INTL("six"), _INTL("seven"),
_INTL("eight"), _INTL("nine"), _INTL("ten"), _INTL("eleven"),
_INTL("twelve"), _INTL("thirteen"), _INTL("fourteen"), _INTL("fifteen"),
_INTL("sixteen"), _INTL("seventeen"), _INTL("eighteen"), _INTL("nineteen"),
_INTL("twenty")]
return ret[self] if self.is_a?(Integer) && self >= 0 && self <= ret.length
return self.to_s
end
end
#===============================================================================
# class Array
#===============================================================================
class Array
def ^(other) # xor of two arrays
return (self|other) - (self&other)
end
def swap(val1, val2)
index1 = self.index(val1)
index2 = self.index(val2)
self[index1] = val2
self[index2] = val1
end
end
#===============================================================================
# module Enumerable
#===============================================================================
module Enumerable
def transform
ret = []
self.each { |item| ret.push(yield(item)) }
return ret
end
end
#===============================================================================
# Kernel methods
#===============================================================================
def rand(*args)
Kernel.rand(*args)
end
class << Kernel
alias oldRand rand unless method_defined?(:oldRand)
def rand(a = nil, b = nil)
if a.is_a?(Range)
lo = a.min
hi = a.max
return lo + oldRand(hi - lo + 1)
elsif a.is_a?(Numeric)
if b.is_a?(Numeric)
return a + oldRand(b - a + 1)
else
return oldRand(a)
end
elsif a.nil?
return (b) ? oldRand(b) : oldRand(2)
end
end
end
def nil_or_empty?(string)
return string.nil? || !string.is_a?(String) || string.size == 0
end
@@ -0,0 +1,856 @@
def pbAddScriptTexts(items, script)
script.force_encoding(Encoding::UTF_8)
script.scan(/(?:_I|sign)\s*\(\s*\"((?:[^\\\"]*\\\"?)*[^\"]*)\"/) do |s|
string = s[0]
string.gsub!(/\\\"/, "\"")
string.gsub!(/\\\\/, "\\")
items.push(string)
end
end
def pbAddRgssScriptTexts(items, script)
script.force_encoding(Encoding::UTF_8)
script.scan(/(?:_INTL|_ISPRINTF)\s*\(\s*\"((?:[^\\\"]*\\\"?)*[^\"]*)\"/) do |s|
string = s[0]
string.gsub!(/\\r/, "\r")
string.gsub!(/\\n/, "\n")
string.gsub!(/\\1/, "\1")
string.gsub!(/\\\"/, "\"")
string.gsub!(/\\\\/, "\\")
items.push(string)
end
end
def pbSetTextMessages
Graphics.update
begin
t = System.uptime
texts = []
# Get script texts from Scripts.rxdata
$RGSS_SCRIPTS.each do |script|
if System.uptime - t >= 5
t += 5
Graphics.update
end
scr = Zlib::Inflate.inflate(script[2])
pbAddRgssScriptTexts(texts, scr)
end
Dir.all("Data/Scripts").each do |script_file|
if System.uptime - t >= 5
t += 5
Graphics.update
end
File.open(script_file, "rb") do |f|
pbAddRgssScriptTexts(texts, f.read)
end
end
# Must add messages because this code is used by both game system and Editor
MessageTypes.addMessagesAsHash(MessageTypes::ScriptTexts, texts)
commonevents = load_data("Data/CommonEvents.rxdata")
items = []
choices = []
for event in commonevents.compact
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
end
begin
neednewline = false
lastitem = ""
for j in 0...event.list.size
list = event.list[j]
if neednewline && list.code != 401
if lastitem != ""
lastitem.gsub!(/([^\.\!\?])\s\s+/) { |m| $1 + " " }
items.push(lastitem)
lastitem = ""
end
neednewline = false
end
if list.code == 101
lastitem += "#{list.parameters[0]}"
neednewline = true
elsif list.code == 102
for k in 0...list.parameters[0].length
choices.push(list.parameters[0][k])
end
neednewline = false
elsif list.code == 401
lastitem += " " if lastitem != ""
lastitem += "#{list.parameters[0]}"
neednewline = true
elsif list.code == 355 || list.code == 655
pbAddScriptTexts(items, list.parameters[0])
elsif list.code == 111 && list.parameters[0] == 12
pbAddScriptTexts(items, list.parameters[1])
elsif list.code == 209
route = list.parameters[1]
for k in 0...route.list.size
if route.list[k].code == 45
pbAddScriptTexts(items, route.list[k].parameters[0])
end
end
end
end
if neednewline
if lastitem != ""
items.push(lastitem)
lastitem = ""
end
end
end
end
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
end
items |= []
choices |= []
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
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
end
filename = sprintf("Data/Map%03d.rxdata", id)
next if !pbRgssExists?(filename)
map = load_data(filename)
items = []
choices = []
for event in map.events.values
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
end
begin
for i in 0...event.pages.size
neednewline = false
lastitem = ""
for j in 0...event.pages[i].list.size
list = event.pages[i].list[j]
if neednewline && list.code != 401
if lastitem != ""
lastitem.gsub!(/([^\.\!\?])\s\s+/) { |m| $1 + " " }
items.push(lastitem)
lastitem = ""
end
neednewline = false
end
if list.code == 101
lastitem += "#{list.parameters[0]}"
neednewline = true
elsif list.code == 102
for k in 0...list.parameters[0].length
choices.push(list.parameters[0][k])
end
neednewline = false
elsif list.code == 401
lastitem += " " if lastitem != ""
lastitem += "#{list.parameters[0]}"
neednewline = true
elsif list.code == 355 || list.code == 655
pbAddScriptTexts(items, list.parameters[0])
elsif list.code == 111 && list.parameters[0] == 12
pbAddScriptTexts(items, list.parameters[1])
elsif list.code == 209
route = list.parameters[1]
for k in 0...route.list.size
if route.list[k].code == 45
pbAddScriptTexts(items, route.list[k].parameters[0])
end
end
end
end
if neednewline
if lastitem != ""
items.push(lastitem)
lastitem = ""
end
end
end
end
end
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
end
items |= []
choices |= []
items.concat(choices)
MessageTypes.setMapMessagesAsHash(id, items)
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
end
end
pbAddTrainerTextMessages
pbAddOutfitTextMessages
rescue Hangup
end
Graphics.update
end
def pbAddTrainerTextMessages
names = []
loseTexts = []
speeches = []
infoTexts = []
GameData::Trainer.each do |trainer|
names.push(trainer.real_name)
loseTexts.push(trainer.real_lose_text)
loseTexts.push(trainer.loseText_rematch) if trainer.loseText_rematch
loseTexts.push(trainer.loseText_rematch_double) if trainer.loseText_rematch_double
speeches.push(trainer.battleText) if trainer.battleText
speeches.push(trainer.preRematchText) if trainer.preRematchText
speeches.push(trainer.preRematchText_caught) if trainer.preRematchText_caught
speeches.push(trainer.preRematchText_evolved) if trainer.preRematchText_evolved
speeches.push(trainer.preRematchText_fused) if trainer.preRematchText_fused
speeches.push(trainer.preRematchText_unfused) if trainer.preRematchText_unfused
speeches.push(trainer.preRematchText_reversed) if trainer.preRematchText_reversed
speeches.push(trainer.preRematchText_gift) if trainer.preRematchText_gift
infoTexts.push(trainer.infoText) if trainer.infoText
end
MessageTypes.addMessagesAsHash(MessageTypes::TrainerNames, names)
MessageTypes.addMessagesAsHash(MessageTypes::TrainerLoseText, loseTexts)
MessageTypes.addMessagesAsHash(MessageTypes::BeginSpeech, speeches)
MessageTypes.addMessagesAsHash(MessageTypes::TrainerInfoText, infoTexts)
end
def pbCollectOutfitTexts(obj, texts)
case obj
when Hash
texts << obj["name"] if obj["name"].is_a?(String)
texts << obj["description"] if obj["description"].is_a?(String)
obj.each_value { |v| pbCollectOutfitTexts(v, texts) }
when Array
obj.each { |v| pbCollectOutfitTexts(v, texts) }
end
end
def pbAddOutfitTextMessages
texts = []
files = [
Settings::CLOTHES_DATA_PATH,
Settings::HAIRSTYLE_DATA_PATH,
Settings::HATS_DATA_PATH
]
files.each do |file|
json_data = File.read(file)
data = HTTPLite::JSON.parse(json_data)
data.each do |entry|
texts << entry["name"] if entry["name"]
texts << entry["description"] if entry["description"]
end
end
MessageTypes.addMessagesAsHash(MessageTypes::OutfitTexts, texts)
end
def pbEachIntlSection(file)
lineno = 1
re = /^\s*\[\s*([^\]]+)\s*\]\s*$/
havesection = false
sectionname = nil
lastsection = []
file.each_line { |line|
if lineno == 1 && line[0].ord == 0xEF && line[1].ord == 0xBB && line[2].ord == 0xBF
line = line[3, line.length - 3]
end
if !line[/^\#/] && !line[/^\s*$/]
if line[re]
if havesection
yield lastsection, sectionname
end
lastsection.clear
sectionname = $~[1]
havesection = true
else
if sectionname == nil
raise _INTL("Expected a section at the beginning of the file (line {1})", lineno)
end
lastsection.push(line.gsub(/\s+$/, ""))
end
end
lineno += 1
if lineno % 500 == 0
Graphics.update
end
}
if havesection
yield lastsection, sectionname
end
end
def pbGetText(infile)
begin
file = File.open(infile, "rb")
rescue
raise _INTL("Can't find {1}", infile)
end
intldat = []
begin
pbEachIntlSection(file) { |section, name|
next if section.length == 0
if !name[/^([Mm][Aa][Pp])?(\d+)$/]
raise _INTL("Invalid section name {1}", name)
end
ismap = $~[1] && $~[1] != ""
id = $~[2].to_i
itemlength = 0
if section[0][/^\d+$/]
intlhash = []
itemlength = 3
if ismap
raise _INTL("Section {1} can't be an ordered list (section was recognized as an ordered list because its first line is a number)", name)
end
if section.length % 3 != 0
raise _INTL("Section {1}'s line count is not divisible by 3 (section was recognized as an ordered list because its first line is a number)", name)
end
else
intlhash = OrderedHash.new
itemlength = 2
if section.length % 2 != 0
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
if itemlength == 3
if !section[i][/^\d+$/]
raise _INTL("Expected a number in section {1}, got {2} instead", name, section[i])
end
key = section[i].to_i
i += 1
else
key = MessageTypes.denormalizeValue(section[i])
end
intlhash[key] = MessageTypes.denormalizeValue(section[i + 1])
i += 2 end
if ismap
intldat[0] = [] if !intldat[0]
intldat[0][id] = intlhash
else
intldat[id] = intlhash
end
}
ensure
file.close
end
return intldat
end
def pbCompileText
outfile = File.open("intl.dat", "wb")
begin
intldat = pbGetText("intl.txt")
Marshal.dump(intldat, outfile)
rescue
raise
ensure
outfile.close
end
end
class OrderedHash < Hash
def initialize
@keys = []
super
end
def keys
return @keys.clone
end
def inspect
str = "{"
for i in 0...@keys.length
str += ", " if i > 0
str += @keys[i].inspect + "=>" + self[@keys[i]].inspect
end
str += "}"
return str
end
alias :to_s :inspect
def []=(key, value)
oldvalue = self[key]
if !oldvalue && value
@keys.push(key)
elsif !value
@keys |= []
@keys -= [key]
end
return super(key, value)
end
def self._load(string)
ret = self.new
keysvalues = Marshal.load(string)
keys = keysvalues[0]
values = keysvalues[1]
for i in 0...keys.length
ret[keys[i]] = values[i]
end
return ret
end
def _dump(_depth = 100)
values = []
for key in @keys
values.push(self[key])
end
return Marshal.dump([@keys, values])
end
end
class Messages
def initialize(filename = nil, delayLoad = false)
@messages = nil
@filename = filename
if @filename && !delayLoad
loadMessageFile(@filename)
end
end
def delayedLoad
if @filename && !@messages
loadMessageFile(@filename)
@filename = nil
end
end
def self.stringToKey(str)
if str && str[/[\r\n\t\1]|^\s+|\s+$|\s{2,}/]
key = str.clone
key.gsub!(/^\s+/, "")
key.gsub!(/\s+$/, "")
key.gsub!(/\s{2,}/, " ")
return key
end
return str
end
def self.normalizeValue(value)
if value[/[\r\n\t\x01]|^[\[\]]/]
ret = value.clone
ret.gsub!(/\r/, "<<r>>")
ret.gsub!(/\n/, "<<n>>")
ret.gsub!(/\t/, "<<t>>")
ret.gsub!(/\[/, "<<[>>")
ret.gsub!(/\]/, "<<]>>")
ret.gsub!(/\x01/, "<<1>>")
return ret
end
return value
end
def self.denormalizeValue(value)
if value[/<<[rnt1\[\]]>>/]
ret = value.clone
ret.gsub!(/<<1>>/, "\1")
ret.gsub!(/<<r>>/, "\r")
ret.gsub!(/<<n>>/, "\n")
ret.gsub!(/<<\[>>/, "[")
ret.gsub!(/<<\]>>/, "]")
ret.gsub!(/<<t>>/, "\t")
return ret
end
return value
end
def self.writeObject(f, msgs, secname, origMessages = nil)
return if !msgs
if msgs.is_a?(Array)
f.write("[#{secname}]\r\n")
for j in 0...msgs.length
next if nil_or_empty?(msgs[j])
value = Messages.normalizeValue(msgs[j])
origValue = ""
if origMessages
origValue = Messages.normalizeValue(origMessages.get(secname, j))
else
origValue = Messages.normalizeValue(MessageTypes.get(secname, j))
end
f.write("#{j}\r\n")
f.write(origValue + "\r\n")
f.write(value + "\r\n")
end
elsif msgs.is_a?(OrderedHash)
f.write("[#{secname}]\r\n")
keys = msgs.keys
for key in keys
next if nil_or_empty?(msgs[key])
value = Messages.normalizeValue(msgs[key])
valkey = Messages.normalizeValue(key)
# key is already serialized
f.write(valkey + "\r\n")
f.write(value + "\r\n")
end
end
end
def messages
return @messages || []
end
def extract(outfile)
# return if !@messages
origMessages = Messages.new("Data/messages.dat")
File.open(outfile, "wb") { |f|
f.write(0xef.chr)
f.write(0xbb.chr)
f.write(0xbf.chr)
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
msgs = origMessages.messages[0][i]
Messages.writeObject(f, msgs, "Map#{i}", origMessages)
end
end
for i in 1...origMessages.messages.length
msgs = origMessages.messages[i]
Messages.writeObject(f, msgs, i, origMessages)
end
}
end
def setMessages(type, array)
@messages = [] if !@messages
arr = []
for i in 0...array.length
arr[i] = (array[i]) ? array[i] : ""
end
@messages[type] = arr
end
def addMessages(type, array)
@messages = [] if !@messages
arr = (@messages[type]) ? @messages[type] : []
for i in 0...array.length
arr[i] = (array[i]) ? array[i] : (arr[i]) ? arr[i] : ""
end
@messages[type] = arr
end
def self.createHash(_type, array)
arr = OrderedHash.new
for i in 0...array.length
if array[i]
key = Messages.stringToKey(array[i])
arr[key] = array[i]
end
end
return arr
end
def self.addToHash(_type, array, hash)
hash = OrderedHash.new if !hash
for i in 0...array.length
if array[i]
key = Messages.stringToKey(array[i])
hash[key] = array[i]
end
end
return hash
end
def setMapMessagesAsHash(type, array)
@messages = [] if !@messages
@messages[0] = [] if !@messages[0]
@messages[0][type] = Messages.createHash(type, array)
end
def addMapMessagesAsHash(type, array)
@messages = [] if !@messages
@messages[0] = [] if !@messages[0]
@messages[0][type] = Messages.addToHash(type, array, @messages[0][type])
end
def setMessagesAsHash(type, array)
@messages = [] if !@messages
@messages[type] = Messages.createHash(type, array)
end
def addMessagesAsHash(type, array)
@messages = [] if !@messages
@messages[type] = Messages.addToHash(type, array, @messages[type])
end
def saveMessages(filename = nil)
filename = "Data/messages.dat" if !filename
raw = Marshal.dump(@messages)
File.open(filename, "wb") { |f| f.write(Encryption.xor(raw)) }
end
def loadMessageFile(filename)
begin
raw = File.open(filename, "rb") { |f| f.read }
begin
@messages = Marshal.load(Encryption.xor(raw))
rescue TypeError, ArgumentError
@messages = Marshal.load(raw) # fallback for old unencrypted file
end
if !@messages.is_a?(Array)
@messages = nil
raise "Corrupted data"
end
return @messages
rescue
@messages = nil
return nil
end
end
def set(type, id, value)
delayedLoad
return if !@messages
return if !@messages[type]
@messages[type][id] = value
end
def getCount(type)
delayedLoad
return 0 if !@messages
return 0 if !@messages[type]
return @messages[type].length
end
def get(type, id)
delayedLoad
return "" if !@messages
return "" if !@messages[type]
return "" if !@messages[type][id]
return @messages[type][id]
end
def getFromHash(type, key)
delayedLoad
return key if !@messages || !@messages[type] || !key
id = Messages.stringToKey(key)
return key if !@messages[type][id]
return @messages[type][id]
end
def getFromMapHash(type, key)
delayedLoad
return key if !@messages
return key if !@messages[0]
return key if !@messages[0][type] && !@messages[0][0]
id = Messages.stringToKey(key)
if @messages[0][type] && @messages[0][type][id]
return @messages[0][type][id]
elsif @messages[0][0] && @messages[0][0][id]
return @messages[0][0][id]
end
return key
end
end
module MessageTypes
# Value 0 is used for common event and map event text
Species = 1
Kinds = 2
Entries = 3
FormNames = 4
Moves = 5
MoveDescriptions = 6
Items = 7
ItemPlurals = 8
ItemDescriptions = 9
Abilities = 10
AbilityDescs = 11
Types = 12
TrainerTypes = 13
TrainerNames = 14
BeginSpeech = 15
EndSpeechWin = 16
EndSpeechLose = 17
RegionNames = 18
PlaceNames = 19
PlaceDescriptions = 20
MapNames = 21
PhoneMessages = 22
TrainerLoseText = 23
ScriptTexts = 24
RibbonNames = 25
RibbonDescriptions = 26
TrainerInfoText = 27
OutfitTexts = 28
@@messages = Messages.new
@@messagesFallback = Messages.new("Data/messages.dat", true)
def self.stringToKey(str)
return Messages.stringToKey(str)
end
def self.normalizeValue(value)
return Messages.normalizeValue(value)
end
def self.denormalizeValue(value)
Messages.denormalizeValue(value)
end
def self.writeObject(f, msgs, secname)
Messages.denormalizeValue(str)
end
def self.extract(outfile)
@@messages.extract(outfile)
end
def self.setMessages(type, array)
@@messages.setMessages(type, array)
end
def self.addMessages(type, array)
@@messages.addMessages(type, array)
end
def self.createHash(type, array)
Messages.createHash(type, array)
end
def self.addMapMessagesAsHash(type, array)
@@messages.addMapMessagesAsHash(type, array)
end
def self.setMapMessagesAsHash(type, array)
@@messages.setMapMessagesAsHash(type, array)
end
def self.addMessagesAsHash(type, array)
@@messages.addMessagesAsHash(type, array)
end
def self.setMessagesAsHash(type, array)
@@messages.setMessagesAsHash(type, array)
end
def self.saveMessages(filename = nil)
@@messages.saveMessages(filename)
end
def self.loadMessageFile(filename)
@@messages.loadMessageFile(filename)
end
def self.get(type, id)
ret = @@messages.get(type, id)
if ret == ""
ret = @@messagesFallback.get(type, id)
end
return ret
end
def self.getCount(type)
c1 = @@messages.getCount(type)
c2 = @@messagesFallback.getCount(type)
return c1 > c2 ? c1 : c2
end
def self.getOriginal(type, id)
return @@messagesFallback.get(type, id)
end
def self.getFromHash(type, key)
@@messages.getFromHash(type, key)
end
def self.getFromMapHash(type, key)
@@messages.getFromMapHash(type, key)
end
end
def pbLoadMessages(file)
return MessageTypes.loadMessageFile(file)
end
def pbGetMessageCount(type)
return MessageTypes.getCount(type)
end
def pbGetMessage(type, id)
return MessageTypes.get(type, id)
end
def pbGetMessageFromHash(type, id)
return MessageTypes.getFromHash(type, id)
end
# Replaces first argument with a localized version and formats the other
# parameters by replacing {1}, {2}, etc. with those placeholders.
def _OUTFIT_INTL(str)
return MessageTypes.getFromHash(MessageTypes::OutfitTexts, str)
end
def _INTL(*arg)
begin
string = MessageTypes.getFromHash(MessageTypes::ScriptTexts, arg[0])
rescue
string = arg[0]
end
string = string.clone
for i in 1...arg.length
string.gsub!(/\{#{i}\}/, "#{arg[i]}")
end
return string
end
# Replaces first argument with a localized version and formats the other
# parameters by replacing {1}, {2}, etc. with those placeholders.
# This version acts more like sprintf, supports e.g. {1:d} or {2:s}
def _ISPRINTF(*arg)
begin
string = MessageTypes.getFromHash(MessageTypes::ScriptTexts, arg[0])
rescue
string = arg[0]
end
string = string.clone
for i in 1...arg.length
string.gsub!(/\{#{i}\:([^\}]+?)\}/) { |m|
next sprintf("%" + $1, arg[i])
}
end
return string
end
def _I(str)
return _MAPINTL($game_map.map_id, str)
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]}")
end
return string
end
def _MAPISPRINTF(mapid, *arg)
string = MessageTypes.getFromMapHash(mapid, arg[0])
string = string.clone
for i in 1...arg.length
string.gsub!(/\{#{i}\:([^\}]+?)\}/) { |m|
next sprintf("%" + $1, arg[i])
}
end
return string
end

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