mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-06 06:01:46 +00:00
Compare commits
18 Commits
develop-6.
...
6.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e11e62272c | ||
|
|
51f98b9cc7 | ||
|
|
318ff90d8d | ||
|
|
ef5e023ae0 | ||
|
|
d383af130b | ||
|
|
0c50a74a13 | ||
|
|
3e6e955070 | ||
|
|
4ba51c7473 | ||
|
|
aa795459b4 | ||
|
|
fd3429c3b5 | ||
|
|
a50151c4af | ||
|
|
3622cb9bed | ||
|
|
23de3cb6e4 | ||
|
|
451490edc7 | ||
|
|
30db0a406c | ||
|
|
937527828f | ||
|
|
b2f6901c6b | ||
|
|
a393ba1137 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,6 +1,6 @@
|
||||
Graphics/CustomBattlers/local_sprites/*
|
||||
Graphics/Battlers/Shiny/*
|
||||
Graphics/Pokemon/FusionIcons/*
|
||||
|
||||
Graphics/CustomBattlers/spritesheets/*
|
||||
Graphics/CustomBattlers/*
|
||||
Data/sprites/*
|
||||
@@ -14,5 +14,4 @@ Data/sprites/sprites_rate_limit.log
|
||||
Game.rxproj
|
||||
.DS_Store
|
||||
PBS/*
|
||||
Game.exe
|
||||
rpgmaker.sh
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -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.
27
Credits.txt
27
Credits.txt
@@ -1,5 +1,5 @@
|
||||
########## CREDITS ###############
|
||||
Pok?mon Infinite Fusion & Pok?mon Infinite Fusion: Hoenn
|
||||
Pok?mon Infinite Fusion: Hoenn
|
||||
Game made by Chardub
|
||||
|
||||
*This is NOT an official Pokemon game. The author of this game is not
|
||||
@@ -107,9 +107,9 @@ casinoluck<s>ymirbot
|
||||
|
||||
|
||||
###################################
|
||||
### Custom Pok?dex entries ###
|
||||
### Custom Pokedex entries ###
|
||||
###################################
|
||||
### Pok?dex entries quality control (Unown)
|
||||
### Pokedex entries quality control (Unown)
|
||||
luvischlo<s>char_latte3412<s>strawbearycandy
|
||||
bobosmith01<s>griddle<s>.izik
|
||||
knilk<s>lordjoostmeister<s>.realthree
|
||||
@@ -127,6 +127,10 @@ Maruno (http://pokemonessentials.wikia.com/wiki/Pok%C3%A9mon_Essentials_Wiki)
|
||||
###########################################################
|
||||
Playtesting was done by various members of the Discord channel.
|
||||
Special thanks to all of you!
|
||||
|
||||
Elite 4 rematch teams
|
||||
duskrd<s>anaconja
|
||||
|
||||
###########################################################
|
||||
### Graphics #
|
||||
###########################################################
|
||||
@@ -139,13 +143,14 @@ Gen 4 Legendary trio eggs by calicorn
|
||||
Nintendo
|
||||
GameFreak
|
||||
|
||||
###########################################################
|
||||
### French translation #
|
||||
###########################################################
|
||||
|
||||
########################
|
||||
### Translations #
|
||||
########################
|
||||
French translation:
|
||||
anthonygourmand
|
||||
locpic_
|
||||
blood.wolf58 (Willi)
|
||||
ragzzh
|
||||
|
||||
#######################################################################
|
||||
The following ressources were also used
|
||||
@@ -165,7 +170,6 @@ with their respective authors' consent
|
||||
zender1752 (Sabrina OW sprite) https://www.deviantart.com/zender1752/art/Pokemon-Anime-Delia-Ketchum-Overworld-sprite-840038766
|
||||
wesleyfg (Hoenn overworld NPCs) https://www.deviantart.com/wesleyfg/art/Hoenn-People-OW-in-BW-style-274475232
|
||||
Wergan https://www.deviantart.com/wergan/art/Pokemon-Random-characters-002-959395621
|
||||
TooManyLuigis, Mortedes, Billla,WolfPP: Golurk overworld sprite https://www.deviantart.com/wolfang62/art/Golurk-Sprite-Overworld-834611476
|
||||
Battle sprites:
|
||||
Custom graphics:
|
||||
Kiwikelly, UnworthyPie
|
||||
@@ -240,7 +244,12 @@ Move animations:
|
||||
### RPG Maker Scripts ###
|
||||
###########################################################
|
||||
|
||||
andracass (Pok<6F>mon Reborn) Compiler optimization
|
||||
#Custom Infinite fusion scripts:
|
||||
Improved Shinies: anthonygourmand
|
||||
andracass (Pok?on Reborn) Compiler optimization (legacy)
|
||||
|
||||
#Public use scripts:
|
||||
|
||||
Luka S.J. Elite Battle System
|
||||
Animated Title Screen (modified):
|
||||
shiney570 BW2 Summary script (+ graphics) http://reliccastle.com/forums/showthread.php?tid=1090
|
||||
|
||||
BIN
Data/.DS_Store
vendored
BIN
Data/.DS_Store
vendored
Binary file not shown.
8
Data/.idea/.gitignore
generated
vendored
8
Data/.idea/.gitignore
generated
vendored
@@ -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.
BIN
Data/Map205.rxdata
Normal file
BIN
Data/Map205.rxdata
Normal file
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 52c7e25e82
664
Data/Scripts/001_Settings.rb
Normal file
664
Data/Scripts/001_Settings.rb
Normal file
@@ -0,0 +1,664 @@
|
||||
#==============================================================================#
|
||||
# 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 = '6.7.0'
|
||||
GAME_VERSION_NUMBER = "6.7.0"
|
||||
LATEST_GAME_RELEASE = "6.6"
|
||||
|
||||
KANTO = GAME_ID == :IF_KANTO
|
||||
HOENN = GAME_ID == :IF_HOENN
|
||||
|
||||
POKERADAR_LIGHT_ANIMATION_RED_ID = 17
|
||||
POKERADAR_LIGHT_ANIMATION_GREEN_ID = 18
|
||||
POKERADAR_HIDDEN_ABILITY_POKE_CHANCE = 32
|
||||
POKERADAR_BATTERY_STEPS = 0
|
||||
|
||||
LEADER_VICTORY_MUSIC="Battle victory leader"
|
||||
TRAINER_VICTORY_MUSIC="trainer-victory"
|
||||
WILD_VICTORY_MUSIC="wild-victory"
|
||||
|
||||
#getRandomCustomFusionForIntro
|
||||
FUSION_ICON_SPRITE_OFFSET = 10
|
||||
|
||||
ANIMATE_REFLECTIONS= false#GAME_ID == :IF_HOENN #true
|
||||
USE_REFLECTIONS = false
|
||||
#Infinite fusion settings
|
||||
NB_POKEMON = Settings::GAME_ID == :IF_HOENN ? 565 : 501
|
||||
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
|
||||
|
||||
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 = ""
|
||||
|
||||
LEVEL_CAPS=[12,22,26,35,38,45,51,54,62,62,63,64,64,65,67,68]
|
||||
|
||||
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
|
||||
|
||||
SAVEFILE_NB_BACKUPS=10
|
||||
|
||||
DISCORD_URL = "https://discord.com/invite/infinitefusion"
|
||||
WIKI_URL = "https://infinitefusion.fandom.com/"
|
||||
|
||||
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
|
||||
|
||||
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]
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# 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 = 1
|
||||
BADGE_FOR_ROCKSMASH = 0
|
||||
BADGE_FOR_SURF = 6
|
||||
BADGE_FOR_FLY = 3
|
||||
BADGE_FOR_STRENGTH = 5
|
||||
BADGE_FOR_DIVE = 9
|
||||
BADGE_FOR_WATERFALL = 9
|
||||
BADGE_FOR_TELEPORT = 3
|
||||
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=[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
|
||||
# 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 = [
|
||||
["English", "english.dat"],
|
||||
["Français", "french.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:5000"
|
||||
#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
|
||||
|
||||
# DO NOT EDIT THESE!
|
||||
module Essentials
|
||||
VERSION = "19.1.dev"
|
||||
ERROR_TEXT = ""
|
||||
end
|
||||
40
Data/Scripts/001_Technical/001_Debugging/001_PBDebug.rb
Normal file
40
Data/Scripts/001_Technical/001_Debugging/001_PBDebug.rb
Normal file
@@ -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
|
||||
54
Data/Scripts/001_Technical/001_Debugging/002_DebugConsole.rb
Normal file
54
Data/Scripts/001_Technical/001_Debugging/002_DebugConsole.rb
Normal file
@@ -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
|
||||
93
Data/Scripts/001_Technical/001_Debugging/003_Errors.rb
Normal file
93
Data/Scripts/001_Technical/001_Debugging/003_Errors.rb
Normal file
@@ -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
|
||||
31
Data/Scripts/001_Technical/001_Debugging/004_Validation.rb
Normal file
31
Data/Scripts/001_Technical/001_Debugging/004_Validation.rb
Normal file
@@ -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
|
||||
53
Data/Scripts/001_Technical/001_Debugging/005_Deprecation.rb
Normal file
53
Data/Scripts/001_Technical/001_Debugging/005_Deprecation.rb
Normal file
@@ -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
|
||||
48
Data/Scripts/001_Technical/001_MKXP_Compatibility.rb
Normal file
48
Data/Scripts/001_Technical/001_MKXP_Compatibility.rb
Normal file
@@ -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
|
||||
492
Data/Scripts/001_Technical/002_Files/001_FileTests.rb
Normal file
492
Data/Scripts/001_Technical/002_Files/001_FileTests.rb
Normal file
@@ -0,0 +1,492 @@
|
||||
#===============================================================================
|
||||
# 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(/\.(bmp|png|gif|jpg|jpeg)$/,"")
|
||||
filename = nil
|
||||
# RTP.eachPathFor(x) { |path|
|
||||
# filename = pbTryString(path) if !filename
|
||||
# filename = pbTryString(path+".gif") if !filename
|
||||
# }
|
||||
RTP.eachPathFor(noext) { |path|
|
||||
filename = pbTryString(path+".png") if !filename
|
||||
filename = pbTryString(path+".gif") if !filename
|
||||
# filename = pbTryString(path+".jpg") if !filename
|
||||
# filename = pbTryString(path+".jpeg") if !filename
|
||||
# filename = pbTryString(path+".bmp") 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
|
||||
150
Data/Scripts/001_Technical/002_Files/002_FileMixins.rb
Normal file
150
Data/Scripts/001_Technical/002_Files/002_FileMixins.rb
Normal file
@@ -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
|
||||
222
Data/Scripts/001_Technical/002_Files/003_HTTP_Utilities.rb
Normal file
222
Data/Scripts/001_Technical/002_Files/003_HTTP_Utilities.rb
Normal file
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
142
Data/Scripts/001_Technical/002_RubyUtilities.rb
Normal file
142
Data/Scripts/001_Technical/002_RubyUtilities.rb
Normal file
@@ -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
|
||||
783
Data/Scripts/001_Technical/003_Intl_Messages.rb
Normal file
783
Data/Scripts/001_Technical/003_Intl_Messages.rb
Normal file
@@ -0,0 +1,783 @@
|
||||
def pbAddScriptTexts(items, script)
|
||||
script.force_encoding(Encoding::UTF_8)
|
||||
script.scan(/(?:_I)\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
|
||||
# If Scripts.rxdata only has 1 section, scripts have been extracted. Get
|
||||
# script texts from .rb files in Data/Scripts
|
||||
if $RGSS_SCRIPTS.length == 1
|
||||
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
|
||||
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
|
||||
rescue Hangup
|
||||
end
|
||||
Graphics.update
|
||||
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
|
||||
File.open(filename, "wb") { |f| Marshal.dump(@messages, f) }
|
||||
end
|
||||
|
||||
def loadMessageFile(filename)
|
||||
begin
|
||||
pbRgssOpen(filename, "rb") { |f| @messages = Marshal.load(f) }
|
||||
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
|
||||
@@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 _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
|
||||
33
Data/Scripts/001_Technical/004_Input.rb
Normal file
33
Data/Scripts/001_Technical/004_Input.rb
Normal file
@@ -0,0 +1,33 @@
|
||||
module Input
|
||||
USE = C
|
||||
BACK = B
|
||||
ACTION = A
|
||||
JUMPUP = X
|
||||
JUMPDOWN = Y
|
||||
SPECIAL = Z
|
||||
AUX1 = L
|
||||
AUX2 = R
|
||||
|
||||
unless defined?(update_KGC_ScreenCapture)
|
||||
class << Input
|
||||
alias update_KGC_ScreenCapture update
|
||||
end
|
||||
end
|
||||
|
||||
def self.update
|
||||
update_KGC_ScreenCapture
|
||||
if trigger?(Input::F8)
|
||||
pbScreenCapture
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Mouse
|
||||
module_function
|
||||
|
||||
# Returns the position of the mouse relative to the game window.
|
||||
def getMousePos(catch_anywhere = false)
|
||||
return nil unless Input.mouse_in_window || catch_anywhere
|
||||
return Input.mouse_x, Input.mouse_y
|
||||
end
|
||||
end
|
||||
712
Data/Scripts/001_Technical/005_PluginManager.rb
Normal file
712
Data/Scripts/001_Technical/005_PluginManager.rb
Normal file
@@ -0,0 +1,712 @@
|
||||
#==============================================================================#
|
||||
# Plugin Manager #
|
||||
# by Marin #
|
||||
# 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. #
|
||||
# #
|
||||
# Supports external scripts that are in .rb files in folders within the #
|
||||
# Plugins folder. #
|
||||
#------------------------------------------------------------------------------#
|
||||
# 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: #
|
||||
# #
|
||||
# PluginManager.register({ #
|
||||
# :name => "Basic Plugin", #
|
||||
# :version => "1.0", #
|
||||
# :link => "https://reliccastle.com/link-to-the-plugin/", #
|
||||
# :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. #
|
||||
# #
|
||||
# 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: #
|
||||
# #
|
||||
# PluginManager.register({ #
|
||||
# :name => "Simple Extension", #
|
||||
# :version => "1.0", #
|
||||
# :link => "https://reliccastle.com/link-to-the-plugin/", #
|
||||
# :credits => ["Marin", "Maruno"], #
|
||||
# :dependencies => ["Basic Plugin"] #
|
||||
# }) #
|
||||
# #
|
||||
# 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. #
|
||||
# #
|
||||
#------------------------------------------------------------------------------#
|
||||
# Please give credit when using this. #
|
||||
#==============================================================================#
|
||||
|
||||
module PluginManager
|
||||
# Holds all registered plugin data.
|
||||
@@Plugins = {}
|
||||
#-----------------------------------------------------------------------------
|
||||
# Registers a plugin and tests its dependencies and incompatibilities.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.register(options)
|
||||
name = nil
|
||||
version = nil
|
||||
link = nil
|
||||
dependencies = nil
|
||||
incompats = nil
|
||||
credits = []
|
||||
order = [:name, :version, :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
|
||||
next idx_a <=> idx_b
|
||||
end
|
||||
for key in keys
|
||||
value = options[key]
|
||||
case key
|
||||
when :name # Plugin name
|
||||
if nil_or_empty?(value)
|
||||
self.error("Plugin name must be a non-empty string.")
|
||||
end
|
||||
if !@@Plugins[value].nil?
|
||||
self.error("A plugin called '#{value}' already exists.")
|
||||
end
|
||||
name = value
|
||||
when :version # Plugin version
|
||||
if nil_or_empty?(value)
|
||||
self.error("Plugin version must be a string.")
|
||||
end
|
||||
version = value
|
||||
when :link # Plugin website
|
||||
if nil_or_empty?(value)
|
||||
self.error("Plugin link must be a non-empty string.")
|
||||
end
|
||||
link = value
|
||||
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"
|
||||
if !self.installed?(dep)
|
||||
self.error("Plugin '#{name}' requires plugin '#{dep}' to be installed above it.")
|
||||
end
|
||||
elsif dep.is_a?(Array)
|
||||
case dep.size
|
||||
when 1 # ["plugin name"]
|
||||
if dep[0].is_a?(String)
|
||||
dep_name = dep[0]
|
||||
if !self.installed?(dep_name)
|
||||
self.error("Plugin '#{name}' requires plugin '#{dep_name}' to be installed above it.")
|
||||
end
|
||||
else
|
||||
self.error("Expected the plugin name as a string, but got #{dep[0].inspect}.")
|
||||
end
|
||||
when 2 # ["plugin name", "version"]
|
||||
if dep[0].is_a?(Symbol)
|
||||
self.error("A plugin version comparator symbol was given but no version was given.")
|
||||
elsif dep[0].is_a?(String) && dep[1].is_a?(String)
|
||||
dep_name = dep[0]
|
||||
dep_version = dep[1]
|
||||
next if self.installed?(dep_name, dep_version)
|
||||
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)
|
||||
msg += "\r\nCheck #{dep_link} for an update to plugin '#{dep_name}'."
|
||||
end
|
||||
self.error(msg)
|
||||
else # Don't have plugin
|
||||
self.error("Plugin '#{name}' requires plugin '#{dep_name}' version #{dep_version} " +
|
||||
"or higher to be installed above it.")
|
||||
end
|
||||
end
|
||||
when 3 # [:optional/:exact/:optional_exact, "plugin name", "version"]
|
||||
if !dep[0].is_a?(Symbol)
|
||||
self.error("Expected first dependency argument to be a symbol, but got #{dep[0].inspect}.")
|
||||
end
|
||||
if !dep[1].is_a?(String)
|
||||
self.error("Expected second dependency argument to be a plugin name, but got #{dep[1].inspect}.")
|
||||
end
|
||||
if !dep[2].is_a?(String)
|
||||
self.error("Expected third dependency argument to be the plugin version, but got #{dep[2].inspect}.")
|
||||
end
|
||||
dep_arg = dep[0]
|
||||
dep_name = dep[1]
|
||||
dep_version = dep[2]
|
||||
optional = false
|
||||
exact = false
|
||||
case dep_arg
|
||||
when :optional
|
||||
optional = true
|
||||
when :exact
|
||||
exact = true
|
||||
when :optional_exact
|
||||
optional = true
|
||||
exact = true
|
||||
else
|
||||
self.error("Expected first dependency argument to be one of " +
|
||||
":optional, :exact or :optional_exact, but got #{dep_arg.inspect}.")
|
||||
end
|
||||
if optional
|
||||
if self.installed?(dep_name) && # Have plugin but lower version
|
||||
!self.installed?(dep_name, dep_version, exact)
|
||||
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)
|
||||
msg << "\r\nCheck #{dep_link} for an update to plugin '#{dep_name}'."
|
||||
end
|
||||
self.error(msg)
|
||||
end
|
||||
elsif !self.installed?(dep_name, dep_version, exact)
|
||||
if self.installed?(dep_name) # Have plugin but lower version
|
||||
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)
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
when :incompatibilities # Plugin incompatibilities
|
||||
incompats = value
|
||||
incompats = [incompats] if !incompats.is_a?(Array)
|
||||
for incompat in incompats
|
||||
if self.installed?(incompat)
|
||||
self.error("Plugin '#{name}' is incompatible with '#{incompat}'. " +
|
||||
"They cannot both be used at the same time.")
|
||||
end
|
||||
end
|
||||
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
|
||||
credits << entry
|
||||
end
|
||||
end
|
||||
else
|
||||
self.error("Plugin '#{name}'s credits field must contain a string, or a string array.")
|
||||
end
|
||||
else
|
||||
self.error("Invalid plugin registry key '#{key}'.")
|
||||
end
|
||||
end
|
||||
for plugin in @@Plugins.values
|
||||
if plugin[:incompatibilities] && plugin[:incompatibilities].include?(name)
|
||||
self.error("Plugin '#{plugin[:name]}' is incompatible with '#{name}'. " +
|
||||
"They cannot both be used at the same time.")
|
||||
end
|
||||
end
|
||||
# Add plugin to class variable
|
||||
@@Plugins[name] = {
|
||||
:name => name,
|
||||
:version => version,
|
||||
:link => link,
|
||||
:dependencies => dependencies,
|
||||
:incompatibilities => incompats,
|
||||
:credits => credits
|
||||
}
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Throws a pure error message without stack trace or any other useless info.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.error(msg)
|
||||
Graphics.update
|
||||
t = Thread.new do
|
||||
echoln "Plugin Error:\r\n#{msg}"
|
||||
p "Plugin Error: #{msg}"
|
||||
Thread.exit
|
||||
end
|
||||
while t.status
|
||||
Graphics.update
|
||||
end
|
||||
Kernel.exit! true
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Returns true if the specified plugin is installed.
|
||||
# If the version is specified, this version is taken into account.
|
||||
# If mustequal is true, the version must be a match with the specified version.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.installed?(plugin_name, plugin_version = nil, mustequal = false)
|
||||
plugin = @@Plugins[plugin_name]
|
||||
return false if plugin.nil?
|
||||
return true if plugin_version.nil?
|
||||
comparison = compare_versions(plugin[:version], plugin_version)
|
||||
return true if !mustequal && comparison >= 0
|
||||
return true if mustequal && comparison == 0
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Returns the string names of all installed plugins.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.plugins
|
||||
return @@Plugins.keys
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Returns the installed version of the specified plugin.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.version(plugin_name)
|
||||
return if !installed?(plugin_name)
|
||||
return @@Plugins[plugin_name][:version]
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Returns the link of the specified plugin.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.link(plugin_name)
|
||||
return if !installed?(plugin_name)
|
||||
return @@Plugins[plugin_name][:link]
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Returns the credits of the specified plugin.
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.credits(plugin_name)
|
||||
return if !installed?(plugin_name)
|
||||
return @@Plugins[plugin_name][:credits]
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Compares two versions given in string form. v1 should be the plugin version
|
||||
# you actually have, and v2 should be the minimum/desired plugin version.
|
||||
# Return values:
|
||||
# 1 if v1 is higher than v2
|
||||
# 0 if v1 is equal to v2
|
||||
# -1 if v1 is lower than v2
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.compare_versions(v1, v2)
|
||||
d1 = v1.split("")
|
||||
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("")
|
||||
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
|
||||
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
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# formats the error message
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.pluginErrorMsg(name, script)
|
||||
# begin message formatting
|
||||
message = "[Infinite Fusion version #{Settings::GAME_VERSION_NUMBER}]\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
|
||||
# show last 10 lines of backtrace
|
||||
message += "\r\nBacktrace:\r\n"
|
||||
$!.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)
|
||||
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
|
||||
#-----------------------------------------------------------------------------
|
||||
# Used to read the metadata file
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.readMeta(dir, file)
|
||||
filename = "#{dir}/#{file}"
|
||||
meta = {}
|
||||
# read file
|
||||
Compiler.pbCompilerEachPreppedLine(filename) { |line, line_no|
|
||||
# split line up into property name and values
|
||||
if !line[/^\s*(\w+)\s*=\s*(.*)$/]
|
||||
raise _INTL("Bad line syntax (expected syntax like XXX=YYY)\r\n{1}", FileLineData.linereport)
|
||||
end
|
||||
property = $~[1].upcase
|
||||
data = $~[2].split(',')
|
||||
data.each_with_index { |value, i| data[i] = value.strip }
|
||||
# begin formatting data hash
|
||||
case property
|
||||
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])
|
||||
next
|
||||
elsif data.length == 2 # Push name and version of plugin dependency
|
||||
meta[:dependencies].push([data[0], data[1]])
|
||||
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'
|
||||
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'
|
||||
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'
|
||||
meta[:incompatibilities] = [] if !meta[:incompatibilities]
|
||||
data.each { |value| meta[:incompatibilities].push(value) if value && !value.empty? }
|
||||
when 'SCRIPTS'
|
||||
meta[:scripts] = [] if !meta[:scripts]
|
||||
data.each { |scr| meta[:scripts].push(scr) }
|
||||
when 'CREDITS'
|
||||
meta[:credits] = data
|
||||
when 'LINK', 'WEBSITE'
|
||||
meta[:link] = data[0]
|
||||
else
|
||||
meta[property.downcase.to_sym] = data[0]
|
||||
end
|
||||
}
|
||||
# generate a list of all script files to be loaded, in the order they are to
|
||||
# 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)
|
||||
next if !fl.include?(".rb")
|
||||
meta[:scripts].push(fl.gsub("#{dir}/", ""))
|
||||
end
|
||||
# ensure no duplicate script files are queued
|
||||
meta[:scripts].uniq!
|
||||
# return meta hash
|
||||
return meta
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Get a list of all the plugin directories to inspect
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.listAll
|
||||
return []
|
||||
return [] if !$DEBUG || safeExists?("Game.rgssad")
|
||||
# get a list of all directories in the `Plugins/` folder
|
||||
dirs = []
|
||||
Dir.get("Plugins").each { |d| dirs.push(d) if Dir.safe?(d) }
|
||||
# return all plugins
|
||||
return dirs
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Catch any potential loop with dependencies and raise an error
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.validateDependencies(name, meta, og = nil)
|
||||
# exit if no registered dependency
|
||||
return nil if !meta[name] || !meta[name][:dependencies]
|
||||
og = [name] if !og
|
||||
# go through all dependencies
|
||||
for dname in meta[name][:dependencies]
|
||||
# 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
|
||||
# catch looping dependency issue
|
||||
self.error("Plugin '#{og[0]}' has looping dependencies which cannot be resolved automatically.") if !og.nil? && og.include?(dname)
|
||||
new_og = og.clone
|
||||
new_og.push(dname)
|
||||
self.validateDependencies(dname, meta, new_og)
|
||||
end
|
||||
return name
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Sort load order based on dependencies (this ends up in reverse order)
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.sortLoadOrder(order, plugins)
|
||||
# go through the load order
|
||||
for o in order
|
||||
next if !plugins[o] || !plugins[o][:dependencies]
|
||||
# go through all dependencies
|
||||
for dname in plugins[o][:dependencies]
|
||||
# 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
|
||||
# catch missing dependency
|
||||
self.error("Plugin '#{o}' requires plugin '#{dname}' to work properly.") if !order.include?(dname)
|
||||
# skip if already sorted
|
||||
next if order.index(dname) > order.index(o)
|
||||
# catch looping dependency issue
|
||||
order.swap(o, dname)
|
||||
order = self.sortLoadOrder(order, plugins)
|
||||
end
|
||||
end
|
||||
return order
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Get the order in which to load plugins
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.getPluginOrder
|
||||
plugins = {}
|
||||
order = []
|
||||
# Find all plugin folders that have a meta.txt and add them to the list of
|
||||
# plugins.
|
||||
for dir in self.listAll
|
||||
# skip if there is no meta file
|
||||
next if !safeExists?(dir + "/meta.txt")
|
||||
ndx = order.length
|
||||
meta = self.readMeta(dir, "meta.txt")
|
||||
meta[:dir] = dir
|
||||
# raise error if no name defined for plugin
|
||||
self.error("No 'Name' metadata defined for plugin located at '#{dir}'.") if !meta[:name]
|
||||
# raise error if no script defined for plugin
|
||||
self.error("No 'Scripts' metadata defined for plugin located at '#{dir}'.") if !meta[:scripts]
|
||||
plugins[meta[:name]] = meta
|
||||
# raise error if a plugin with the same name already exists
|
||||
self.error("A plugin called '#{meta[:name]}' already exists in the load order.") if order.include?(meta[:name])
|
||||
order.insert(ndx, meta[:name])
|
||||
end
|
||||
# validate all dependencies
|
||||
order.each { |o| self.validateDependencies(o, plugins) }
|
||||
# sort the load order
|
||||
return self.sortLoadOrder(order, plugins).reverse, plugins
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Check if plugins need compiling
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.needCompiling?(order, plugins)
|
||||
# fixed actions
|
||||
return false if !$DEBUG || safeExists?("Game.rgssad")
|
||||
return true if !safeExists?("Data/PluginScripts.rxdata")
|
||||
Input.update
|
||||
return true if Input.press?(Input::CTRL)
|
||||
# analyze whether or not to push recompile
|
||||
mtime = File.mtime("Data/PluginScripts.rxdata")
|
||||
for o in order
|
||||
# go through all the registered plugin scripts
|
||||
scr = plugins[o][:scripts]
|
||||
dir = plugins[o][:dir]
|
||||
for sc in scr
|
||||
return true if File.mtime("#{dir}/#{sc}") > mtime
|
||||
end
|
||||
return true if File.mtime("#{dir}/meta.txt") > mtime
|
||||
end
|
||||
return false
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Check if plugins need compiling
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.compilePlugins(order, plugins)
|
||||
echo 'Compiling plugin scripts...'
|
||||
scripts = []
|
||||
# go through the entire order one by one
|
||||
for o in order
|
||||
# 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|
|
||||
dat[2].push([file, Zlib::Deflate.deflate(f.read)])
|
||||
end
|
||||
end
|
||||
# push to the main scripts array
|
||||
scripts.push(dat)
|
||||
end
|
||||
# save to main `PluginScripts.rxdata` file
|
||||
File.open("Data/PluginScripts.rxdata", 'wb') { |f| Marshal.dump(scripts, f) }
|
||||
# collect garbage
|
||||
GC.start
|
||||
echoln ' done.'
|
||||
echoln ''
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# Check if plugins need compiling
|
||||
#-----------------------------------------------------------------------------
|
||||
def self.runPlugins
|
||||
# get the order of plugins to interpret
|
||||
order, plugins = self.getPluginOrder
|
||||
# compile if necessary
|
||||
self.compilePlugins(order, plugins) if self.needCompiling?(order, plugins)
|
||||
# load plugins
|
||||
scripts = load_data("Data/PluginScripts.rxdata")
|
||||
echoed_plugins = []
|
||||
for plugin in scripts
|
||||
# get the required data
|
||||
name, meta, script = plugin
|
||||
# register plugin
|
||||
self.register(meta)
|
||||
# go through each script and interpret
|
||||
for scr in script
|
||||
# turn code into plaintext
|
||||
code = Zlib::Inflate.inflate(scr[1]).force_encoding(Encoding::UTF_8)
|
||||
# get rid of tabs
|
||||
code.gsub!("\t", " ")
|
||||
# construct filename
|
||||
sname = scr[0].gsub("\\","/").split("/")[-1]
|
||||
fname = "[#{name}] #{sname}"
|
||||
# try to run the code
|
||||
begin
|
||||
eval(code, TOPLEVEL_BINDING, fname)
|
||||
echoln "Loaded plugin: #{name}" if !echoed_plugins.include?(name)
|
||||
echoed_plugins.push(name)
|
||||
rescue Exception # format error message to display
|
||||
self.pluginErrorMsg(name, sname)
|
||||
Kernel.exit! true
|
||||
end
|
||||
end
|
||||
end
|
||||
echoln '' if !echoed_plugins.empty?
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
end
|
||||
534
Data/Scripts/001_Technical/006_RPG_Sprite.rb
Normal file
534
Data/Scripts/001_Technical/006_RPG_Sprite.rb
Normal file
@@ -0,0 +1,534 @@
|
||||
class SpriteAnimation
|
||||
@@_animations = []
|
||||
@@_reference_count = {}
|
||||
|
||||
def initialize(sprite)
|
||||
@sprite = sprite
|
||||
end
|
||||
|
||||
%w[
|
||||
x y ox oy viewport flash src_rect opacity tone
|
||||
].each_with_index do |s, _i|
|
||||
eval <<-__END__
|
||||
|
||||
def #{s}(*arg)
|
||||
@sprite.#{s}(*arg)
|
||||
end
|
||||
|
||||
__END__
|
||||
end
|
||||
|
||||
def self.clear
|
||||
@@_animations.clear
|
||||
end
|
||||
|
||||
def dispose
|
||||
dispose_animation
|
||||
dispose_loop_animation
|
||||
end
|
||||
|
||||
def animation(animation, hit, height = 3)
|
||||
dispose_animation
|
||||
@_animation = animation
|
||||
return if @_animation == nil
|
||||
@_animation_hit = hit
|
||||
@_animation_height = height
|
||||
@_animation_duration = @_animation.frame_max
|
||||
fr = 20
|
||||
if @_animation.name[/\[\s*(\d+?)\s*\]\s*$/]
|
||||
fr = $~[1].to_i
|
||||
end
|
||||
@_animation_frame_skip = Graphics.frame_rate / fr
|
||||
animation_name = @_animation.animation_name
|
||||
animation_hue = @_animation.animation_hue
|
||||
bitmap = pbGetAnimation(animation_name, animation_hue)
|
||||
if @@_reference_count.include?(bitmap)
|
||||
@@_reference_count[bitmap] += 1
|
||||
else
|
||||
@@_reference_count[bitmap] = 1
|
||||
end
|
||||
@_animation_sprites = []
|
||||
if @_animation.position != 3 || !@@_animations.include?(animation)
|
||||
16.times do
|
||||
sprite = ::Sprite.new(self.viewport)
|
||||
sprite.bitmap = bitmap
|
||||
sprite.visible = false
|
||||
@_animation_sprites.push(sprite)
|
||||
end
|
||||
unless @@_animations.include?(animation)
|
||||
@@_animations.push(animation)
|
||||
end
|
||||
end
|
||||
update_animation
|
||||
end
|
||||
|
||||
def loop_animation(animation)
|
||||
return if animation == @_loop_animation
|
||||
dispose_loop_animation
|
||||
@_loop_animation = animation
|
||||
return if @_loop_animation == nil
|
||||
@_loop_animation_index = 0
|
||||
fr = 20
|
||||
if @_animation.name[/\[\s*(\d+?)\s*\]\s*$/]
|
||||
fr = $~[1].to_i
|
||||
end
|
||||
@_loop_animation_frame_skip = Graphics.frame_rate / fr
|
||||
animation_name = @_loop_animation.animation_name
|
||||
animation_hue = @_loop_animation.animation_hue
|
||||
bitmap = pbGetAnimation(animation_name, animation_hue)
|
||||
if @@_reference_count.include?(bitmap)
|
||||
@@_reference_count[bitmap] += 1
|
||||
else
|
||||
@@_reference_count[bitmap] = 1
|
||||
end
|
||||
@_loop_animation_sprites = []
|
||||
16.times do
|
||||
sprite = ::Sprite.new(self.viewport)
|
||||
sprite.bitmap = bitmap
|
||||
sprite.visible = false
|
||||
@_loop_animation_sprites.push(sprite)
|
||||
end
|
||||
update_loop_animation
|
||||
end
|
||||
|
||||
def dispose_animation
|
||||
return if @_animation_sprites == nil
|
||||
sprite = @_animation_sprites[0]
|
||||
if sprite != nil
|
||||
@@_reference_count[sprite.bitmap] -= 1
|
||||
if @@_reference_count[sprite.bitmap] == 0
|
||||
sprite.bitmap.dispose
|
||||
end
|
||||
end
|
||||
for sprite in @_animation_sprites
|
||||
sprite.dispose
|
||||
end
|
||||
@_animation_sprites = nil
|
||||
@_animation = nil
|
||||
end
|
||||
|
||||
def dispose_loop_animation
|
||||
return if @_loop_animation_sprites == nil
|
||||
sprite = @_loop_animation_sprites[0]
|
||||
if sprite != nil
|
||||
@@_reference_count[sprite.bitmap] -= 1
|
||||
if @@_reference_count[sprite.bitmap] == 0
|
||||
sprite.bitmap.dispose
|
||||
end
|
||||
end
|
||||
for sprite in @_loop_animation_sprites
|
||||
sprite.dispose
|
||||
end
|
||||
@_loop_animation_sprites = nil
|
||||
@_loop_animation = nil
|
||||
end
|
||||
|
||||
def active?
|
||||
return @_loop_animation_sprites != nil || @_animation_sprites != nil
|
||||
end
|
||||
|
||||
def effect?
|
||||
return @_animation_duration > 0
|
||||
end
|
||||
|
||||
def update
|
||||
if @_animation != nil
|
||||
quick_update = true
|
||||
if Graphics.frame_count % @_animation_frame_skip == 0
|
||||
@_animation_duration -= 1
|
||||
quick_update = false
|
||||
end
|
||||
update_animation(quick_update)
|
||||
end
|
||||
if @_loop_animation != nil
|
||||
quick_update = (Graphics.frame_count % @_loop_animation_frame_skip != 0)
|
||||
update_loop_animation(quick_update)
|
||||
if !quick_update
|
||||
@_loop_animation_index += 1
|
||||
@_loop_animation_index %= @_loop_animation.frame_max
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update_animation(quick_update = false)
|
||||
if @_animation_duration <= 0
|
||||
dispose_animation
|
||||
return
|
||||
end
|
||||
frame_index = @_animation.frame_max - @_animation_duration
|
||||
cell_data = @_animation.frames[frame_index].cell_data
|
||||
position = @_animation.position
|
||||
animation_set_sprites(@_animation_sprites, cell_data, position, quick_update)
|
||||
return if quick_update
|
||||
for timing in @_animation.timings
|
||||
next if timing.frame != frame_index
|
||||
animation_process_timing(timing, @_animation_hit)
|
||||
end
|
||||
end
|
||||
|
||||
def update_loop_animation(quick_update = false)
|
||||
frame_index = @_loop_animation_index
|
||||
cell_data = @_loop_animation.frames[frame_index].cell_data
|
||||
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
|
||||
next if timing.frame != frame_index
|
||||
animation_process_timing(timing, true)
|
||||
end
|
||||
end
|
||||
|
||||
def animation_set_sprites(sprites, cell_data, position, quick_update = false)
|
||||
sprite_x = 320
|
||||
sprite_y = 240
|
||||
if position == 3
|
||||
if self.viewport != nil
|
||||
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_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
|
||||
sprite = sprites[i]
|
||||
pattern = cell_data[i, 0]
|
||||
if sprite == nil || pattern == nil || pattern == -1
|
||||
sprite.visible = false if sprite != nil
|
||||
next
|
||||
end
|
||||
sprite.x = sprite_x + cell_data[i, 1]
|
||||
sprite.y = sprite_y + cell_data[i, 2]
|
||||
next if quick_update
|
||||
sprite.visible = true
|
||||
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
|
||||
else sprite.z = 2000
|
||||
end
|
||||
sprite.ox = 96
|
||||
sprite.oy = 96
|
||||
sprite.zoom_x = cell_data[i, 3] / 100.0
|
||||
sprite.zoom_y = cell_data[i, 3] / 100.0
|
||||
sprite.angle = cell_data[i, 4]
|
||||
sprite.mirror = (cell_data[i, 5] == 1)
|
||||
sprite.tone = self.tone
|
||||
sprite.opacity = cell_data[i, 6] * self.opacity / 255.0
|
||||
sprite.blend_type = cell_data[i, 7]
|
||||
end
|
||||
end
|
||||
|
||||
def animation_process_timing(timing, hit)
|
||||
if timing.condition == 0 ||
|
||||
(timing.condition == 1 && hit == true) ||
|
||||
(timing.condition == 2 && hit == false)
|
||||
if timing.se.name != ""
|
||||
se = timing.se
|
||||
pbSEPlay(se)
|
||||
end
|
||||
case timing.flash_scope
|
||||
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
|
||||
when 3
|
||||
self.flash(nil, timing.flash_duration * 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
end
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
module RPG
|
||||
class Sprite < ::Sprite
|
||||
def initialize(viewport = nil)
|
||||
super(viewport)
|
||||
@_whiten_duration = 0
|
||||
@_appear_duration = 0
|
||||
@_escape_duration = 0
|
||||
@_collapse_duration = 0
|
||||
@_damage_duration = 0
|
||||
@_animation_duration = 0
|
||||
@_blink = false
|
||||
@animations = []
|
||||
@loopAnimations = []
|
||||
end
|
||||
|
||||
def dispose
|
||||
dispose_damage
|
||||
dispose_animation
|
||||
dispose_loop_animation
|
||||
super
|
||||
end
|
||||
|
||||
def whiten
|
||||
self.blend_type = 0
|
||||
self.color.set(255, 255, 255, 128)
|
||||
self.opacity = 255
|
||||
@_whiten_duration = 16
|
||||
@_appear_duration = 0
|
||||
@_escape_duration = 0
|
||||
@_collapse_duration = 0
|
||||
end
|
||||
|
||||
def appear
|
||||
self.blend_type = 0
|
||||
self.color.set(0, 0, 0, 0)
|
||||
self.opacity = 0
|
||||
@_appear_duration = 16
|
||||
@_whiten_duration = 0
|
||||
@_escape_duration = 0
|
||||
@_collapse_duration = 0
|
||||
end
|
||||
|
||||
def escape
|
||||
self.blend_type = 0
|
||||
self.color.set(0, 0, 0, 0)
|
||||
self.opacity = 255
|
||||
@_escape_duration = 32
|
||||
@_whiten_duration = 0
|
||||
@_appear_duration = 0
|
||||
@_collapse_duration = 0
|
||||
end
|
||||
|
||||
def collapse
|
||||
self.blend_type = 1
|
||||
self.color.set(255, 64, 64, 255)
|
||||
self.opacity = 255
|
||||
@_collapse_duration = 48
|
||||
@_whiten_duration = 0
|
||||
@_appear_duration = 0
|
||||
@_escape_duration = 0
|
||||
end
|
||||
|
||||
def damage(value, critical)
|
||||
dispose_damage
|
||||
damage_string = (value.is_a?(Numeric)) ? value.abs.to_s : value.to_s
|
||||
bitmap = Bitmap.new(160, 48)
|
||||
bitmap.font.name = "Arial Black"
|
||||
bitmap.font.size = 32
|
||||
bitmap.font.color.set(0, 0, 0)
|
||||
bitmap.draw_text(-1, 12-1, 160, 36, damage_string, 1)
|
||||
bitmap.draw_text(+1, 12-1, 160, 36, damage_string, 1)
|
||||
bitmap.draw_text(-1, 12+1, 160, 36, damage_string, 1)
|
||||
bitmap.draw_text(+1, 12+1, 160, 36, damage_string, 1)
|
||||
if value.is_a?(Numeric) && value < 0
|
||||
bitmap.font.color.set(176, 255, 144)
|
||||
else
|
||||
bitmap.font.color.set(255, 255, 255)
|
||||
end
|
||||
bitmap.draw_text(0, 12, 160, 36, damage_string, 1)
|
||||
if critical
|
||||
bitmap.font.size = 20
|
||||
bitmap.font.color.set(0, 0, 0)
|
||||
bitmap.draw_text(-1, -1, 160, 20, "CRITICAL", 1)
|
||||
bitmap.draw_text(+1, -1, 160, 20, "CRITICAL", 1)
|
||||
bitmap.draw_text(-1, +1, 160, 20, "CRITICAL", 1)
|
||||
bitmap.draw_text(+1, +1, 160, 20, "CRITICAL", 1)
|
||||
bitmap.font.color.set(255, 255, 255)
|
||||
bitmap.draw_text(0, 0, 160, 20, "CRITICAL", 1)
|
||||
end
|
||||
@_damage_sprite = ::Sprite.new(self.viewport)
|
||||
@_damage_sprite.bitmap = bitmap
|
||||
@_damage_sprite.ox = 80
|
||||
@_damage_sprite.oy = 20
|
||||
@_damage_sprite.x = self.x
|
||||
@_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[i] = anim
|
||||
return
|
||||
end
|
||||
array.push(anim)
|
||||
end
|
||||
|
||||
def animation(animation, hit, height = 3)
|
||||
anim = SpriteAnimation.new(self)
|
||||
anim.animation(animation,hit,height)
|
||||
pushAnimation(@animations,anim)
|
||||
end
|
||||
|
||||
def loop_animation(animation)
|
||||
anim = SpriteAnimation.new(self)
|
||||
anim.loop_animation(animation)
|
||||
pushAnimation(@loopAnimations,anim)
|
||||
end
|
||||
|
||||
def dispose_damage
|
||||
return if @_damage_sprite == nil
|
||||
@_damage_sprite.bitmap.dispose
|
||||
@_damage_sprite.dispose
|
||||
@_damage_sprite = nil
|
||||
@_damage_duration = 0
|
||||
end
|
||||
|
||||
def dispose_animation
|
||||
for a in @animations
|
||||
a.dispose_animation if a
|
||||
end
|
||||
@animations.clear
|
||||
end
|
||||
|
||||
def dispose_loop_animation
|
||||
for a in @loopAnimations
|
||||
a.dispose_loop_animation if a
|
||||
end
|
||||
@loopAnimations.clear
|
||||
end
|
||||
|
||||
def blink_on
|
||||
return if @_blink
|
||||
@_blink = true
|
||||
@_blink_count = 0
|
||||
end
|
||||
|
||||
def blink_off
|
||||
return unless @_blink
|
||||
@_blink = false
|
||||
self.color.set(0, 0, 0, 0)
|
||||
end
|
||||
|
||||
def blink?
|
||||
return @_blink
|
||||
end
|
||||
|
||||
def effect?
|
||||
return true if @_whiten_duration > 0
|
||||
return true if @_appear_duration > 0
|
||||
return true if @_escape_duration > 0
|
||||
return true if @_collapse_duration > 0
|
||||
return true if @_damage_duration > 0
|
||||
for a in @animations
|
||||
return true if a.effect?
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
if @_whiten_duration > 0
|
||||
@_whiten_duration -= 1
|
||||
self.color.alpha = 128 - (16 - @_whiten_duration) * 10
|
||||
end
|
||||
if @_appear_duration > 0
|
||||
@_appear_duration -= 1
|
||||
self.opacity = (16 - @_appear_duration) * 16
|
||||
end
|
||||
if @_escape_duration > 0
|
||||
@_escape_duration -= 1
|
||||
self.opacity = 256 - (32 - @_escape_duration) * 10
|
||||
end
|
||||
if @_collapse_duration > 0
|
||||
@_collapse_duration -= 1
|
||||
self.opacity = 256 - (48 - @_collapse_duration) * 6
|
||||
end
|
||||
if @_damage_duration > 0
|
||||
@_damage_duration -= 1
|
||||
case @_damage_duration
|
||||
when 38..39
|
||||
@_damage_sprite.y -= 4
|
||||
when 36..37
|
||||
@_damage_sprite.y -= 2
|
||||
when 34..35
|
||||
@_damage_sprite.y += 2
|
||||
when 28..33
|
||||
@_damage_sprite.y += 4
|
||||
end
|
||||
@_damage_sprite.opacity = 256 - (12 - @_damage_duration) * 32
|
||||
if @_damage_duration == 0
|
||||
dispose_damage
|
||||
end
|
||||
end
|
||||
for a in @animations
|
||||
a.update
|
||||
end
|
||||
for a in @loopAnimations
|
||||
a.update
|
||||
end
|
||||
if @_blink
|
||||
@_blink_count = (@_blink_count + 1) % 32
|
||||
if @_blink_count < 16
|
||||
alpha = (16 - @_blink_count) * 6
|
||||
else
|
||||
alpha = (@_blink_count - 16) * 6
|
||||
end
|
||||
self.color.set(255, 255, 255, alpha)
|
||||
end
|
||||
SpriteAnimation.clear
|
||||
end
|
||||
|
||||
def update_animation
|
||||
for a in @animations
|
||||
a.update_animation if a && a.active?
|
||||
end
|
||||
end
|
||||
|
||||
def update_loop_animation
|
||||
for a in @loopAnimations
|
||||
a.update_loop_animation if a && a.active?
|
||||
end
|
||||
end
|
||||
|
||||
def x=(x)
|
||||
for a in @animations
|
||||
a.x = x if a
|
||||
end
|
||||
for a in @loopAnimations
|
||||
a.x = x if a
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
def y=(y)
|
||||
for a in @animations
|
||||
a.y = y if a
|
||||
end
|
||||
for a in @loopAnimations
|
||||
a.y = y if a
|
||||
end
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
78
Data/Scripts/002_BattleSettings.rb
Normal file
78
Data/Scripts/002_BattleSettings.rb
Normal file
@@ -0,0 +1,78 @@
|
||||
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 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 >= 5)
|
||||
# Whether several effects apply relating to a Pokémon's type:
|
||||
# * Electric-type immunity to paralysis
|
||||
# * Ghost-type immunity to being trapped
|
||||
# * Grass-type immunity to powder moves and Effect Spore
|
||||
# * Poison-type Pokémon can't miss when using Toxic
|
||||
MORE_TYPE_EFFECTS = (MECHANICS_GENERATION >= 5)
|
||||
# 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)
|
||||
# Whether some Poké Balls have catch rate multipliers from Gen 7 (true) or
|
||||
# from earlier generations (false).
|
||||
NEW_POKE_BALL_CATCH_RATES = (MECHANICS_GENERATION >= 7)
|
||||
# Whether Soul Dew powers up Psychic and Dragon-type moves by 20% (true) or
|
||||
# raises the holder's Special Attack and Special Defense by 50% (false).
|
||||
SOUL_DEW_POWERS_UP_TYPES = (MECHANICS_GENERATION >= 7)
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# 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
|
||||
NUM_BADGES_BOOST_DEFENSE = (MECHANICS_GENERATION >= 4) ? 999 : 5
|
||||
NUM_BADGES_BOOST_SPATK = (MECHANICS_GENERATION >= 4) ? 999 : 7
|
||||
NUM_BADGES_BOOST_SPDEF = (MECHANICS_GENERATION >= 4) ? 999 : 7
|
||||
NUM_BADGES_BOOST_SPEED = (MECHANICS_GENERATION >= 4) ? 999 : 3
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# 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
|
||||
|
||||
#=============================================================================
|
||||
|
||||
# Whether the Exp gained from beating a Pokémon should be scaled depending on
|
||||
# the gainer's level.
|
||||
SCALED_EXP_FORMULA = (MECHANICS_GENERATION == 5 || MECHANICS_GENERATION >= 7)
|
||||
# Whether the Exp gained from beating a Pokémon should be divided equally
|
||||
# between each participant (true), or whether each participant should gain
|
||||
# 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 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
|
||||
# fewer species in your game.
|
||||
ENABLE_CRITICAL_CAPTURES = false#(MECHANICS_GENERATION >= 5)
|
||||
# Whether Pokémon gain Exp for capturing a Pokémon.
|
||||
GAIN_EXP_FOR_CAPTURE = (MECHANICS_GENERATION >= 5)
|
||||
# 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
|
||||
# Whether party Pokémon check whether they can evolve after all battles
|
||||
# regardless of the outcome (true), or only after battles the player won (false).
|
||||
CHECK_EVOLUTION_AFTER_ALL_BATTLES = (MECHANICS_GENERATION >= 6)
|
||||
# Whether fainted Pokémon can try to evolve after a battle.
|
||||
CHECK_EVOLUTION_FOR_FAINTED_POKEMON = true
|
||||
end
|
||||
96
Data/Scripts/002_Save data/001_SaveData.rb
Normal file
96
Data/Scripts/002_Save data/001_SaveData.rb
Normal file
@@ -0,0 +1,96 @@
|
||||
# The SaveData module is used to manipulate save data. It contains the {Value}s
|
||||
# that make up the save data and {Conversion}s for resolving incompatibilities
|
||||
# between Essentials and game versions.
|
||||
# @see SaveData.register
|
||||
# @see SaveData.register_conversion
|
||||
module SaveData
|
||||
# Contains the file path of the save file.
|
||||
FILE_PATH = if File.directory?(System.data_directory)
|
||||
System.data_directory + '/Game.rxdata'
|
||||
else
|
||||
'./Game.rxdata'
|
||||
end
|
||||
|
||||
# @return [Boolean] whether the save file exists
|
||||
def self.exists?
|
||||
return File.file?(FILE_PATH)
|
||||
end
|
||||
|
||||
# Fetches the save data from the given file.
|
||||
# Returns an Array in the case of a pre-v19 save file.
|
||||
# @param file_path [String] path of the file to load from
|
||||
# @return [Hash, Array] loaded save data
|
||||
# @raise [IOError, SystemCallError] if file opening fails
|
||||
def self.get_data_from_file(file_path) validate file_path => String
|
||||
save_data = nil
|
||||
File.open(file_path) do |file|
|
||||
data = Marshal.load(file)
|
||||
if data.is_a?(Hash)
|
||||
save_data = data
|
||||
next
|
||||
end
|
||||
save_data = [data]
|
||||
save_data << Marshal.load(file) until file.eof?
|
||||
end
|
||||
return save_data
|
||||
end
|
||||
|
||||
# Fetches save data from the given file. If it needed converting, resaves it.
|
||||
# @param file_path [String] path of the file to read from
|
||||
# @return [Hash] save data in Hash format
|
||||
# @raise (see .get_data_from_file)
|
||||
def self.read_from_file(file_path)
|
||||
validate file_path => String
|
||||
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) }
|
||||
end
|
||||
return save_data
|
||||
end
|
||||
|
||||
# Compiles the save data and saves a marshaled version of it into
|
||||
# the given file.
|
||||
# @param file_path [String] path of the file to save into
|
||||
# @raise [InvalidValueError] if an invalid value is being saved
|
||||
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) }
|
||||
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')
|
||||
end
|
||||
|
||||
# Converts the pre-v19 format data to the new format.
|
||||
# @param old_format [Array] pre-v19 format save data
|
||||
# @return [Hash] save data in new format
|
||||
def self.to_hash_format(old_format)
|
||||
validate old_format => Array
|
||||
hash = {}
|
||||
@values.each do |value|
|
||||
data = value.get_from_old_format(old_format)
|
||||
hash[value.id] = data unless data.nil?
|
||||
end
|
||||
return hash
|
||||
end
|
||||
|
||||
# Moves a save file from the old Saved Games folder to the new
|
||||
# location specified by {FILE_PATH}. Does nothing if a save file
|
||||
# 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']
|
||||
return if home.nil?
|
||||
old_location = File.join(home, 'Saved Games', game_title)
|
||||
return unless File.directory?(old_location)
|
||||
old_file = File.join(old_location, 'Game.rxdata')
|
||||
return unless File.file?(old_file)
|
||||
File.move(old_file, FILE_PATH)
|
||||
end
|
||||
end
|
||||
269
Data/Scripts/002_Save data/002_SaveData_Value.rb
Normal file
269
Data/Scripts/002_Save data/002_SaveData_Value.rb
Normal file
@@ -0,0 +1,269 @@
|
||||
module SaveData
|
||||
# Contains Value objects for each save element.
|
||||
# Populated during runtime by SaveData.register calls.
|
||||
# @type [Array<Value>]
|
||||
@values = []
|
||||
|
||||
# An error raised if an invalid save value is being saved or loaded.
|
||||
class InvalidValueError < RuntimeError; end
|
||||
|
||||
#=============================================================================
|
||||
# Represents a single value in save data.
|
||||
# New values are added using {SaveData.register}.
|
||||
class Value
|
||||
# @return [Symbol] the value id
|
||||
attr_reader :id
|
||||
|
||||
# @param id [Symbol] value id
|
||||
def initialize(id, &block)
|
||||
validate id => Symbol, block => Proc
|
||||
@id = id
|
||||
@loaded = false
|
||||
@load_in_bootup = false
|
||||
instance_eval(&block)
|
||||
raise "No save_value defined for save value #{id.inspect}" if @save_proc.nil?
|
||||
raise "No load_value defined for save value #{id.inspect}" if @load_proc.nil?
|
||||
end
|
||||
|
||||
# @param value [Object] value to check
|
||||
# @return [Boolean] whether the given value is valid
|
||||
def valid?(value)
|
||||
return true if @ensured_class.nil?
|
||||
return value.is_a?(Object.const_get(@ensured_class))
|
||||
end
|
||||
|
||||
# Calls the value's load proc with the given argument passed into it.
|
||||
# @param value [Object] load proc argument
|
||||
# @raise [InvalidValueError] if an invalid value is being loaded
|
||||
def load(value)
|
||||
validate_value(value)
|
||||
@load_proc.call(value)
|
||||
@loaded = true
|
||||
end
|
||||
|
||||
# Calls the value's save proc and returns its value.
|
||||
# @return [Object] save proc value
|
||||
# @raise [InvalidValueError] if an invalid value is being saved
|
||||
def save
|
||||
value = @save_proc.call
|
||||
validate_value(value)
|
||||
return value
|
||||
end
|
||||
|
||||
# @return [Boolean] whether the value has a new game value proc defined
|
||||
def has_new_game_proc?
|
||||
return @new_game_value_proc.is_a?(Proc)
|
||||
end
|
||||
|
||||
# Calls the save value's load proc with the value fetched
|
||||
# from the defined new game value proc.
|
||||
# @raise (see #load)
|
||||
def load_new_game_value
|
||||
unless self.has_new_game_proc?
|
||||
raise "Save value #{@id.inspect} has no new_game_value defined"
|
||||
end
|
||||
self.load(@new_game_value_proc.call)
|
||||
end
|
||||
|
||||
# @return [Boolean] whether the value should be loaded during bootup
|
||||
def load_in_bootup?
|
||||
return @load_in_bootup
|
||||
end
|
||||
|
||||
# @return [Boolean] whether the value has been loaded
|
||||
def loaded?
|
||||
return @loaded
|
||||
end
|
||||
|
||||
# Marks value as unloaded.
|
||||
def mark_as_unloaded
|
||||
@loaded = false
|
||||
end
|
||||
|
||||
# Uses the {#from_old_format} proc to select the correct data from
|
||||
# +old_format+ and return it.
|
||||
# Returns nil if the proc is undefined.
|
||||
# @param old_format [Array] old format to load value from
|
||||
# @return [Object] data from the old format
|
||||
def get_from_old_format(old_format)
|
||||
return nil if @old_format_get_proc.nil?
|
||||
return @old_format_get_proc.call(old_format)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Raises an {InvalidValueError} if the given value is invalid.
|
||||
# @param value [Object] value to check
|
||||
# @raise [InvalidValueError] if the value is invalid
|
||||
def validate_value(value)
|
||||
return if self.valid?(value)
|
||||
raise InvalidValueError, "Save value #{@id.inspect} is not a #{@ensured_class} (#{value.class.name} given)"
|
||||
end
|
||||
|
||||
# @!group Configuration
|
||||
|
||||
# If present, ensures that the value is of the given class.
|
||||
# @param class_name [Symbol] class to enforce
|
||||
# @see SaveData.register
|
||||
def ensure_class(class_name)
|
||||
validate class_name => Symbol
|
||||
@ensured_class = class_name
|
||||
end
|
||||
|
||||
# Defines how the loaded value is placed into a global variable.
|
||||
# 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?
|
||||
@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?
|
||||
@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?
|
||||
@new_game_value_proc = block
|
||||
end
|
||||
|
||||
# If present, sets the value to be loaded during bootup.
|
||||
# @see SaveData.register
|
||||
def load_in_bootup
|
||||
@load_in_bootup = true
|
||||
end
|
||||
|
||||
# If present, defines how the value should be fetched from the pre-v19
|
||||
# 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?
|
||||
@old_format_get_proc = block
|
||||
end
|
||||
|
||||
# @!endgroup
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Registers a {Value} to be saved into save data.
|
||||
# Takes a block which defines the value's saving ({Value#save_value})
|
||||
# and loading ({Value#load_value}) procedures.
|
||||
#
|
||||
# It is also possible to provide a proc for fetching the value
|
||||
# from the pre-v19 format ({Value#from_old_format}), define
|
||||
# a value to be set upon starting a new game with {Value#new_game_value}
|
||||
# and ensure that the saved and loaded value is of the correct
|
||||
# class with {Value#ensure_class}.
|
||||
#
|
||||
# Values can be registered to be loaded on bootup with
|
||||
# {Value#load_in_bootup}. If a new_game_value proc is defined, it
|
||||
# will be called when the game is launched for the first time,
|
||||
# or if the save data does not contain the value in question.
|
||||
#
|
||||
# @example Registering a new value
|
||||
# SaveData.register(:foo) do
|
||||
# ensure_class :Foo
|
||||
# save_value { $foo }
|
||||
# load_value { |value| $foo = value }
|
||||
# new_game_value { Foo.new }
|
||||
# from_old_format { |old_format| old_format[16] if old_format[16].is_a?(Foo) }
|
||||
# end
|
||||
# @example Registering a value to be loaded on bootup
|
||||
# SaveData.register(:bar) do
|
||||
# load_in_bootup
|
||||
# save_value { $bar }
|
||||
# load_value { |value| $bar = value }
|
||||
# new_game_value { Bar.new }
|
||||
# end
|
||||
# @param id [Symbol] value id
|
||||
# @yieldself [Value]
|
||||
def self.register(id, &block)
|
||||
validate id => Symbol
|
||||
unless block_given?
|
||||
raise ArgumentError, 'No block given to SaveData.register'
|
||||
end
|
||||
@values << Value.new(id, &block)
|
||||
end
|
||||
|
||||
# @param save_data [Hash] save data to validate
|
||||
# @return [Boolean] whether the given save data is valid
|
||||
def self.valid?(save_data)
|
||||
validate save_data => Hash
|
||||
return @values.all? { |value| value.valid?(save_data[value.id]) }
|
||||
end
|
||||
|
||||
# Loads values from the given save data.
|
||||
# An optional condition can be passed.
|
||||
# @param save_data [Hash] save data to load from
|
||||
# @param condition_block [Proc] optional condition
|
||||
# @api private
|
||||
def self.load_values(save_data, &condition_block)
|
||||
@values.each do |value|
|
||||
next if block_given? && !condition_block.call(value)
|
||||
if save_data.has_key?(value.id)
|
||||
value.load(save_data[value.id])
|
||||
elsif value.has_new_game_proc?
|
||||
value.load_new_game_value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Loads the values from the given save data by
|
||||
# calling each {Value} object's {Value#load_value} proc.
|
||||
# Values that are already loaded are skipped.
|
||||
# If a value does not exist in the save data and has
|
||||
# a {Value#new_game_value} proc defined, that value
|
||||
# is loaded instead.
|
||||
# @param save_data [Hash] save data to load
|
||||
# @raise [InvalidValueError] if an invalid value is being loaded
|
||||
def self.load_all_values(save_data)
|
||||
validate save_data => Hash
|
||||
load_values(save_data) { |value| !value.loaded? }
|
||||
end
|
||||
|
||||
# Marks all values that aren't loaded on bootup as unloaded.
|
||||
def self.mark_values_as_unloaded
|
||||
@values.each do |value|
|
||||
value.mark_as_unloaded unless value.load_in_bootup?
|
||||
end
|
||||
end
|
||||
|
||||
# Loads each value from the given save data that has
|
||||
# been set to be loaded during bootup. Done when a save file exists.
|
||||
# @param save_data [Hash] save data to load
|
||||
# @raise [InvalidValueError] if an invalid value is being loaded
|
||||
def self.load_bootup_values(save_data)
|
||||
validate save_data => Hash
|
||||
load_values(save_data) { |value| !value.loaded? && value.load_in_bootup? }
|
||||
end
|
||||
|
||||
# Goes through each value with {Value#load_in_bootup} enabled and loads their
|
||||
# new game value, if one is defined. Done when no save file exists.
|
||||
def self.initialize_bootup_values
|
||||
@values.each do |value|
|
||||
next unless value.load_in_bootup?
|
||||
value.load_new_game_value if value.has_new_game_proc? && !value.loaded?
|
||||
end
|
||||
end
|
||||
|
||||
# Loads each {Value}'s new game value, if one is defined. Done when starting a
|
||||
# new game.
|
||||
def self.load_new_game_values
|
||||
@values.each do |value|
|
||||
value.load_new_game_value if value.has_new_game_proc? && !value.loaded?
|
||||
end
|
||||
end
|
||||
|
||||
# @return [Hash{Symbol => Object}] a hash representation of the save data
|
||||
# @raise [InvalidValueError] if an invalid value is being saved
|
||||
def self.compile_save_hash
|
||||
save_data = {}
|
||||
@values.each { |value| save_data[value.id] = value.save }
|
||||
return save_data
|
||||
end
|
||||
end
|
||||
221
Data/Scripts/002_Save data/003_SaveData_Conversion.rb
Normal file
221
Data/Scripts/002_Save data/003_SaveData_Conversion.rb
Normal file
@@ -0,0 +1,221 @@
|
||||
module SaveData
|
||||
# Contains Conversion objects for each defined conversion:
|
||||
# {
|
||||
# :essentials => {
|
||||
# '19' => [<Conversion>, ...],
|
||||
# '19.1' => [<Conversion>, ...],
|
||||
# ...
|
||||
# },
|
||||
# :game => {
|
||||
# '1.1.0' => [<Conversion>, ...],
|
||||
# '1.2.0' => [<Conversion>, ...],
|
||||
# ...
|
||||
# }
|
||||
# }
|
||||
# Populated during runtime by SaveData.register_conversion calls.
|
||||
@conversions = {
|
||||
essentials: {},
|
||||
game: {}
|
||||
}
|
||||
|
||||
#=============================================================================
|
||||
# Represents a conversion made to save data.
|
||||
# New conversions are added using {SaveData.register_conversion}.
|
||||
class Conversion
|
||||
# @return [Symbol] conversion ID
|
||||
attr_reader :id
|
||||
# @return [String] conversion title
|
||||
attr_reader :title
|
||||
# @return [Symbol] trigger type of the conversion (+:essentials+ or +:game+)
|
||||
attr_reader :trigger_type
|
||||
# @return [String] trigger version of the conversion
|
||||
attr_reader :version
|
||||
|
||||
# @param id [String] conversion ID
|
||||
def initialize(id, &block)
|
||||
@id = id
|
||||
@value_procs = {}
|
||||
@all_proc = nil
|
||||
@title = "Running conversion #{@id}"
|
||||
@trigger_type = nil
|
||||
@version = nil
|
||||
instance_eval(&block)
|
||||
if @trigger_type.nil? || @version.nil?
|
||||
raise "Conversion #{@id} is missing a condition"
|
||||
end
|
||||
end
|
||||
|
||||
# Returns whether the conversion should be run with the given version.
|
||||
# @param version [String] version to check
|
||||
# @return [Boolean] whether the conversion should be run
|
||||
def should_run?(version)
|
||||
return PluginManager.compare_versions(version, @version) < 0
|
||||
end
|
||||
|
||||
# Runs the conversion on the given save data.
|
||||
# @param save_data [Hash]
|
||||
def run(save_data)
|
||||
@value_procs.each do |value_id, proc|
|
||||
unless save_data.has_key?(value_id)
|
||||
raise "Save data does not have value #{value_id.inspect}"
|
||||
end
|
||||
proc.call(save_data[value_id])
|
||||
end
|
||||
@all_proc.call(save_data) if @all_proc.is_a?(Proc)
|
||||
end
|
||||
|
||||
# Runs the conversion on the given object.
|
||||
# @param object
|
||||
# @param key [Symbol]
|
||||
def run_single(object, key)
|
||||
@value_procs[key].call(object) if @value_procs[key].is_a?(Proc)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# @!group Configuration
|
||||
|
||||
# Sets the conversion's title.
|
||||
# @param new_title [String] conversion title
|
||||
# @note Since conversions are run before loading the player's chosen language,
|
||||
# conversion titles can not be localized.
|
||||
# @see SaveData.register_conversion
|
||||
def display_title(new_title)
|
||||
validate new_title => String
|
||||
@title = new_title
|
||||
end
|
||||
|
||||
# Sets the conversion to trigger for save files created below
|
||||
# the given Essentials version.
|
||||
# @param version [Numeric, String]
|
||||
# @see SaveData.register_conversion
|
||||
def essentials_version(version)
|
||||
validate version => [Numeric, String]
|
||||
raise "Multiple conditions in conversion #{@id}" unless @version.nil?
|
||||
@trigger_type = :essentials
|
||||
@version = version.to_s
|
||||
end
|
||||
|
||||
# Sets the conversion to trigger for save files created below
|
||||
# the given game version.
|
||||
# @param version [Numeric, String]
|
||||
# @see SaveData.register_conversion
|
||||
def game_version(version)
|
||||
validate version => [Numeric, String]
|
||||
raise "Multiple conditions in conversion #{@id}" unless @version.nil?
|
||||
@trigger_type = :game
|
||||
@version = version.to_s
|
||||
end
|
||||
|
||||
# Defines a conversion to the given save value.
|
||||
# @param value_id [Symbol] save value ID
|
||||
# @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?
|
||||
if @value_procs[value_id].is_a?(Proc)
|
||||
raise "Multiple to_value definitions in conversion #{@id} for #{value_id}"
|
||||
end
|
||||
@value_procs[value_id] = block
|
||||
end
|
||||
|
||||
# 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?
|
||||
if @all_proc.is_a?(Proc)
|
||||
raise "Multiple to_all definitions in conversion #{@id}"
|
||||
end
|
||||
@all_proc = block
|
||||
end
|
||||
|
||||
# @!endgroup
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Registers a {Conversion} to occur for save data that meets the given criteria.
|
||||
# Two types of criteria can be defined: {Conversion#essentials_version} and
|
||||
# {Conversion#game_version}. The conversion is automatically run on save data
|
||||
# that contains an older version number.
|
||||
#
|
||||
# A single value can be modified with {Conversion#to_value}. The entire save data
|
||||
# is accessed with {Conversion#to_all}, and a conversion title can be specified
|
||||
# with {Conversion#display_title}.
|
||||
# @example Registering a new conversion
|
||||
# SaveData.register_conversion(:my_conversion) do
|
||||
# game_version '1.1.0'
|
||||
# display_title 'Converting some stuff'
|
||||
# to_value :player do |player|
|
||||
# # code that modifies the :player value
|
||||
# end
|
||||
# to_all do |save_data|
|
||||
# save_data[:new_value] = Foo.new
|
||||
# end
|
||||
# end
|
||||
# @yield self [Conversion]
|
||||
def self.register_conversion(id, &block)
|
||||
validate id => Symbol
|
||||
unless block_given?
|
||||
raise ArgumentError, 'No block given to SaveData.register_conversion'
|
||||
end
|
||||
conversion = Conversion.new(id, &block)
|
||||
@conversions[conversion.trigger_type][conversion.version] ||= []
|
||||
@conversions[conversion.trigger_type][conversion.version] << conversion
|
||||
end
|
||||
|
||||
# @param save_data [Hash] save data to get conversions for
|
||||
# @return [Array<Conversion>] all conversions that should be run on the data
|
||||
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, :game].each do |trigger_type|
|
||||
# Ensure the versions are sorted from lowest to highest
|
||||
sorted_versions = @conversions[trigger_type].keys.sort do |v1, v2|
|
||||
PluginManager.compare_versions(v1, v2)
|
||||
end
|
||||
sorted_versions.each do |version|
|
||||
@conversions[trigger_type][version].each do |conversion|
|
||||
next unless conversion.should_run?(versions[trigger_type])
|
||||
conversions_to_run << conversion
|
||||
end
|
||||
end
|
||||
end
|
||||
return conversions_to_run
|
||||
end
|
||||
|
||||
# Runs all possible conversions on the given save data.
|
||||
# Saves a backup before running conversions.
|
||||
# @param save_data [Hash] save data to run conversions on
|
||||
# @return [Boolean] whether conversions were run
|
||||
def self.run_conversions(save_data)
|
||||
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..."
|
||||
conversions_to_run.each do |conversion|
|
||||
echo "#{conversion.title}..."
|
||||
conversion.run(save_data)
|
||||
echoln ' done.'
|
||||
end
|
||||
echoln '' if conversions_to_run.length > 0
|
||||
save_data[:essentials_version] = Essentials::VERSION
|
||||
save_data[:game_version] = Settings::GAME_VERSION
|
||||
return true
|
||||
end
|
||||
|
||||
# Runs all possible conversions on the given object.
|
||||
# @param object [Hash] object to run conversions on
|
||||
# @param key [Hash] object's key in save data
|
||||
# @param save_data [Hash] save data to run conversions on
|
||||
def self.run_single_conversions(object, key, save_data)
|
||||
validate key => Symbol
|
||||
conversions_to_run = self.get_conversions(save_data)
|
||||
conversions_to_run.each do |conversion|
|
||||
conversion.run_single(object, key)
|
||||
end
|
||||
end
|
||||
end
|
||||
135
Data/Scripts/002_Save data/004_Game_SaveValues.rb
Normal file
135
Data/Scripts/002_Save data/004_Game_SaveValues.rb
Normal file
@@ -0,0 +1,135 @@
|
||||
# Contains the save values defined in Essentials by default.
|
||||
|
||||
SaveData.register(:player) do
|
||||
ensure_class :Player
|
||||
save_value { $Trainer }
|
||||
load_value { |value| $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 }
|
||||
Player.new("Unnamed", trainer_type)
|
||||
}
|
||||
from_old_format { |old_format| old_format[0] }
|
||||
end
|
||||
|
||||
SaveData.register(:frame_count) do
|
||||
ensure_class :Integer
|
||||
save_value { Graphics.frame_count }
|
||||
load_value { |value| Graphics.frame_count = value }
|
||||
new_game_value { 0 }
|
||||
from_old_format { |old_format| old_format[1] }
|
||||
end
|
||||
|
||||
SaveData.register(:game_system) do
|
||||
load_in_bootup
|
||||
ensure_class :Game_System
|
||||
save_value { $game_system }
|
||||
load_value { |value| $game_system = value }
|
||||
new_game_value { Game_System.new }
|
||||
from_old_format { |old_format| old_format[2] }
|
||||
end
|
||||
|
||||
SaveData.register(:pokemon_system) do
|
||||
load_in_bootup
|
||||
ensure_class :PokemonSystem
|
||||
save_value { $PokemonSystem }
|
||||
load_value { |value| $PokemonSystem = value }
|
||||
new_game_value { PokemonSystem.new }
|
||||
from_old_format { |old_format| old_format[3] }
|
||||
end
|
||||
|
||||
SaveData.register(:switches) do
|
||||
ensure_class :Game_Switches
|
||||
save_value { $game_switches }
|
||||
load_value { |value| $game_switches = value }
|
||||
new_game_value { Game_Switches.new }
|
||||
from_old_format { |old_format| old_format[5] }
|
||||
end
|
||||
|
||||
SaveData.register(:variables) do
|
||||
ensure_class :Game_Variables
|
||||
save_value { $game_variables }
|
||||
load_value { |value| $game_variables = value }
|
||||
new_game_value { Game_Variables.new }
|
||||
from_old_format { |old_format| old_format[6] }
|
||||
end
|
||||
|
||||
SaveData.register(:self_switches) do
|
||||
ensure_class :Game_SelfSwitches
|
||||
save_value { $game_self_switches }
|
||||
load_value { |value| $game_self_switches = value }
|
||||
new_game_value { Game_SelfSwitches.new }
|
||||
from_old_format { |old_format| old_format[7] }
|
||||
end
|
||||
|
||||
SaveData.register(:game_screen) do
|
||||
ensure_class :Game_Screen
|
||||
save_value { $game_screen }
|
||||
load_value { |value| $game_screen = value }
|
||||
new_game_value { Game_Screen.new }
|
||||
from_old_format { |old_format| old_format[8] }
|
||||
end
|
||||
|
||||
SaveData.register(:map_factory) do
|
||||
ensure_class :PokemonMapFactory
|
||||
save_value { $MapFactory }
|
||||
load_value { |value| $MapFactory = value }
|
||||
from_old_format { |old_format| old_format[9] }
|
||||
end
|
||||
|
||||
SaveData.register(:game_player) do
|
||||
ensure_class :Game_Player
|
||||
save_value { $game_player }
|
||||
load_value { |value| $game_player = value }
|
||||
new_game_value { Game_Player.new }
|
||||
from_old_format { |old_format| old_format[10] }
|
||||
end
|
||||
|
||||
SaveData.register(:global_metadata) do
|
||||
ensure_class :PokemonGlobalMetadata
|
||||
save_value { $PokemonGlobal }
|
||||
load_value { |value| $PokemonGlobal = value }
|
||||
new_game_value { PokemonGlobalMetadata.new }
|
||||
from_old_format { |old_format| old_format[11] }
|
||||
end
|
||||
|
||||
SaveData.register(:map_metadata) do
|
||||
ensure_class :PokemonMapMetadata
|
||||
save_value { $PokemonMap }
|
||||
load_value { |value| $PokemonMap = value }
|
||||
new_game_value { PokemonMapMetadata.new }
|
||||
from_old_format { |old_format| old_format[12] }
|
||||
end
|
||||
|
||||
SaveData.register(:bag) do
|
||||
ensure_class :PokemonBag
|
||||
save_value { $PokemonBag }
|
||||
load_value { |value| $PokemonBag = value }
|
||||
new_game_value { PokemonBag.new }
|
||||
from_old_format { |old_format| old_format[13] }
|
||||
end
|
||||
|
||||
SaveData.register(:storage_system) do
|
||||
ensure_class :PokemonStorage
|
||||
save_value { $PokemonStorage }
|
||||
load_value { |value| $PokemonStorage = value }
|
||||
new_game_value { PokemonStorage.new }
|
||||
from_old_format { |old_format| old_format[14] }
|
||||
end
|
||||
|
||||
SaveData.register(:essentials_version) do
|
||||
load_in_bootup
|
||||
ensure_class :String
|
||||
save_value { Essentials::VERSION }
|
||||
load_value { |value| $SaveVersion = value }
|
||||
new_game_value { Essentials::VERSION }
|
||||
from_old_format { |old_format| old_format[15] }
|
||||
end
|
||||
|
||||
SaveData.register(:game_version) do
|
||||
load_in_bootup
|
||||
ensure_class :String
|
||||
save_value { Settings::GAME_VERSION }
|
||||
load_value { |value| $game_version = value }
|
||||
new_game_value { Settings::GAME_VERSION }
|
||||
end
|
||||
242
Data/Scripts/002_Save data/005_Game_SaveConversions.rb
Normal file
242
Data/Scripts/002_Save data/005_Game_SaveConversions.rb
Normal file
@@ -0,0 +1,242 @@
|
||||
# Contains conversions defined in Essentials by default.
|
||||
|
||||
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'
|
||||
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
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SaveData.register_conversion(:v19_1_fix_phone_contacts) do
|
||||
essentials_version 19.1
|
||||
display_title 'Fixing phone contacts data'
|
||||
to_value :global_metadata do |global|
|
||||
global.phoneNumbers.each do |contact|
|
||||
contact[1] = GameData::TrainerType.get(contact[1]).id if contact && contact.length == 8
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SaveData.register_conversion(:v19_convert_bag) do
|
||||
essentials_version 19
|
||||
display_title 'Converting item IDs in Bag'
|
||||
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
|
||||
end
|
||||
end
|
||||
pocket.compact!
|
||||
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)
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
SaveData.register_conversion(:v19_convert_game_screen) do
|
||||
essentials_version 19
|
||||
display_title 'Converting game screen'
|
||||
to_value :game_screen do |game_screen|
|
||||
game_screen.weather(game_screen.weather_type, game_screen.weather_max, 0)
|
||||
end
|
||||
end
|
||||
266
Data/Scripts/003_Game processing/001_StartGame.rb
Normal file
266
Data/Scripts/003_Game processing/001_StartGame.rb
Normal file
@@ -0,0 +1,266 @@
|
||||
# The Game module contains methods for saving and loading the game.
|
||||
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')
|
||||
pbLoadBattleAnimations
|
||||
load_sprites_list_caches()
|
||||
$updated_spritesheets = load_updated_spritesheets()
|
||||
GameData.load_all
|
||||
map_file = format('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.')
|
||||
end
|
||||
end
|
||||
|
||||
def self.load_updated_spritesheets
|
||||
updated_spritesheets_file = Settings::UPDATED_SPRITESHEETS_CACHE
|
||||
updated_spritesheets = []
|
||||
if File.exist?(updated_spritesheets_file)
|
||||
File.open(updated_spritesheets_file, "r") do |file|
|
||||
file.each_line { |line| updated_spritesheets << line.chomp }
|
||||
end
|
||||
end
|
||||
return updated_spritesheets
|
||||
end
|
||||
|
||||
def self.load_sprites_list_caches()
|
||||
self.load_custom_sprites_list_cache() if File.exists?(Settings::CUSTOM_SPRITES_FILE_PATH)
|
||||
self.load_base_sprites_list_cache() if File.exists?(Settings::BASE_SPRITES_FILE_PATH)
|
||||
end
|
||||
|
||||
def self.load_custom_sprites_list_cache()
|
||||
return if !$game_temp.custom_sprites_list.keys.empty? #only load once at loadup
|
||||
echoln "loading custom sprites cache"
|
||||
sprite_index = {}
|
||||
File.foreach(Settings::CUSTOM_SPRITES_FILE_PATH) do |line|
|
||||
filename = line.strip
|
||||
next unless filename =~ /^(\d+)\.(\d+)([a-zA-Z]*)\.png$/ # Regex: Captures the numbers and any trailing letters
|
||||
|
||||
# Match groups
|
||||
head_number = $1.to_i # Head (e.g., "1" in "1.2.png")
|
||||
body_number = $2.to_i # Body (e.g., "2" in "1.2.png")
|
||||
letters = $3 # Letters after the second number (e.g., "a", "b", etc.)
|
||||
|
||||
key = "B#{body_number}H#{head_number}".to_sym
|
||||
sprite_index[key] ||= []
|
||||
if letters.empty?
|
||||
sprite_index[key] << ""
|
||||
else
|
||||
sprite_index[key] << letters
|
||||
end
|
||||
end
|
||||
$game_temp.custom_sprites_list = sprite_index
|
||||
echoln "custom sprites loaded"
|
||||
end
|
||||
|
||||
#
|
||||
# {1 => ["","a","b"]
|
||||
#etc.
|
||||
#
|
||||
def self.load_base_sprites_list_cache()
|
||||
return if !$game_temp.base_sprites_list.keys.empty? #only load once at loadup
|
||||
echoln "loading base sprites cache"
|
||||
sprite_index = {}
|
||||
File.foreach(Settings::BASE_SPRITES_FILE_PATH) do |line|
|
||||
filename = line.strip
|
||||
next unless filename =~ /^(\d+)([a-zA-Z]*)\.png$/ # Regex: Captures the numbers and any trailing letters
|
||||
|
||||
# Match groups
|
||||
dex_number = $1.to_i # Head (e.g., "1" in "1.2.png")
|
||||
letters = $2 # Letters after the second number (e.g., "a", "b", etc.)
|
||||
|
||||
key = dex_number
|
||||
sprite_index[key] ||= []
|
||||
if letters.empty?
|
||||
sprite_index[key] << ""
|
||||
else
|
||||
sprite_index[key] << letters
|
||||
end
|
||||
end
|
||||
$game_temp.base_sprites_list = sprite_index
|
||||
echoln "custom sprites loaded"
|
||||
end
|
||||
|
||||
#
|
||||
# {:B10H10 => ["","a","b"]
|
||||
#etc.
|
||||
#
|
||||
def self.set_up_system
|
||||
SaveData.move_old_windows_save if System.platform[/Windows/]
|
||||
save_data = (SaveData.exists?) ? SaveData.read_from_file(SaveData::FILE_PATH) : {}
|
||||
if save_data.empty?
|
||||
SaveData.initialize_bootup_values
|
||||
else
|
||||
SaveData.load_bootup_values(save_data)
|
||||
end
|
||||
# Set resize factor
|
||||
pbSetResizeFactor([$PokemonSystem.screensize, 4].min)
|
||||
# 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])
|
||||
end
|
||||
end
|
||||
|
||||
#For new game plus - resets everything in boxes/party to level 5 and 1st stage
|
||||
def self.ngp_clean_pc_data(old_storage, old_party)
|
||||
new_storage = old_storage
|
||||
for pokemon in old_party
|
||||
new_storage.pbStoreCaught(pokemon)
|
||||
end
|
||||
|
||||
for box in new_storage.boxes
|
||||
for pokemon in box.pokemon
|
||||
if pokemon != nil
|
||||
if !pokemon.egg?
|
||||
pokemon.exp_when_fused_head=nil
|
||||
pokemon.exp_when_fused_body=nil
|
||||
pokemon.exp_gained_since_fused=nil
|
||||
pokemon.level = 5
|
||||
|
||||
echoln pokemon.owner.id
|
||||
pokemon.owner.id = $Trainer.id
|
||||
pokemon.ot=$Trainer.name
|
||||
pokemon.obtain_method = 0
|
||||
pokemon.species = GameData::Species.get(pokemon.species).get_baby_species(false)
|
||||
$Trainer.pokedex.set_seen(pokemon.species)
|
||||
$Trainer.pokedex.set_owned(pokemon.species)
|
||||
pokemon.reset_moves
|
||||
pokemon.calc_stats
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return new_storage
|
||||
end
|
||||
|
||||
#For new game plus - removes key items
|
||||
def self.ngp_clean_item_data(old_bag)
|
||||
new_storage = old_bag
|
||||
new_storage.clear
|
||||
|
||||
for pocket in old_bag.pockets
|
||||
for bagElement in pocket
|
||||
item_id = bagElement[0]
|
||||
item_qt = bagElement[1]
|
||||
item = GameData::Item.get(item_id)
|
||||
if !item.is_key_item? && !item.is_HM?
|
||||
new_storage.pbStoreItem(item, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
return new_storage
|
||||
end
|
||||
|
||||
# Called when starting a new game. Initializes global variables
|
||||
# and transfers the player into the map scene.
|
||||
def self.start_new(ngp_bag = nil, ngp_storage = nil, ngp_trainer = nil)
|
||||
|
||||
if $game_map && $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
|
||||
$scene = Scene_Map.new
|
||||
SaveData.load_new_game_values
|
||||
$MapFactory = PokemonMapFactory.new($data_system.start_map_id)
|
||||
$game_player.moveto($data_system.start_x, $data_system.start_y)
|
||||
$game_player.refresh
|
||||
$PokemonEncounters = PokemonEncounters.new
|
||||
$PokemonEncounters.setup($game_map.map_id)
|
||||
$game_map.autoplay
|
||||
$game_map.update
|
||||
#
|
||||
# if ngp_bag != nil
|
||||
# $PokemonBag = ngp_clean_item_data(ngp_bag)
|
||||
# end
|
||||
if ngp_storage != nil
|
||||
$PokemonStorage = ngp_clean_pc_data(ngp_storage, ngp_trainer.party)
|
||||
end
|
||||
onStartingNewGame()
|
||||
end
|
||||
|
||||
# Loads the game from the given save data and starts the map scene.
|
||||
# @param save_data [Hash] hash containing the save data
|
||||
# @raise [SaveData::InvalidValueError] if an invalid value is being loaded
|
||||
def self.load(save_data)
|
||||
validate save_data => Hash
|
||||
SaveData.load_all_values(save_data)
|
||||
self.load_map
|
||||
pbAutoplayOnSave
|
||||
$game_map.update
|
||||
$PokemonMap.updateMap
|
||||
$scene = Scene_Map.new
|
||||
onLoadExistingGame()
|
||||
|
||||
end
|
||||
|
||||
# Loads and validates the map. Called when loading a saved game.
|
||||
def self.load_map
|
||||
$game_map = $MapFactory.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)
|
||||
rescue Errno::ENOENT
|
||||
if $DEBUG
|
||||
pbMessage(_INTL('Map {1} was not found.', $game_map.map_id))
|
||||
map = pbWarpToMapList
|
||||
exit unless map
|
||||
$MapFactory.setup(map[0])
|
||||
$game_player.moveto(map[1], map[2])
|
||||
else
|
||||
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)
|
||||
end
|
||||
if $game_map.events.nil?
|
||||
raise _INTL('The map is corrupt. The game cannot continue.')
|
||||
end
|
||||
$PokemonEncounters = PokemonEncounters.new
|
||||
$PokemonEncounters.setup($game_map.map_id)
|
||||
self.load_secret_bases if Settings::HOENN
|
||||
pbUpdateVehicle
|
||||
end
|
||||
|
||||
def self.load_secret_bases
|
||||
loader = SecretBaseLoader.new
|
||||
loader.load_visitor_bases
|
||||
end
|
||||
|
||||
# Saves the game. Returns whether the operation was successful.
|
||||
# @param save_file [String] the save file path
|
||||
# @param safe [Boolean] whether $PokemonGlobal.safesave should be set to true
|
||||
# @return [Boolean] whether the operation was successful
|
||||
# @raise [SaveData::InvalidValueError] if an invalid value is being saved
|
||||
def self.save(save_file = SaveData::FILE_PATH, safe: false)
|
||||
validate save_file => String, safe => [TrueClass, FalseClass]
|
||||
$PokemonGlobal.safesave = safe
|
||||
$game_system.save_count += 1
|
||||
$game_system.magic_number = $data_system.magic_number
|
||||
begin
|
||||
SaveData.save_to_file(save_file)
|
||||
Graphics.frame_reset
|
||||
rescue IOError, SystemCallError
|
||||
$game_system.save_count -= 1
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
298
Data/Scripts/003_Game processing/002_Scene_Map.rb
Normal file
298
Data/Scripts/003_Game processing/002_Scene_Map.rb
Normal file
@@ -0,0 +1,298 @@
|
||||
#===============================================================================
|
||||
# ** Modified Scene_Map class for Pokémon.
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
#===============================================================================
|
||||
class Scene_Map
|
||||
attr_reader :spritesetGlobal
|
||||
attr_reader :map_renderer
|
||||
attr_accessor :spritesets
|
||||
|
||||
def spriteset
|
||||
for i in @spritesets.values
|
||||
return i if i.map == $game_map
|
||||
end
|
||||
return @spritesets.values[0]
|
||||
end
|
||||
|
||||
def createSpritesets
|
||||
@map_renderer = TilemapRenderer.new(Spriteset_Map.viewport) if !@map_renderer || @map_renderer.disposed?
|
||||
@spritesetGlobal = Spriteset_Global.new if !@spritesetGlobal
|
||||
@spritesets = {}
|
||||
for map in $MapFactory.maps
|
||||
@spritesets[map.map_id] = Spriteset_Map.new(map)
|
||||
end
|
||||
$MapFactory.setSceneStarted(self)
|
||||
updateSpritesets(true)
|
||||
end
|
||||
|
||||
def createSingleSpriteset(map)
|
||||
temp = $scene.spriteset.getAnimations
|
||||
@spritesets[map] = Spriteset_Map.new($MapFactory.maps[map])
|
||||
$scene.spriteset.restoreAnimations(temp)
|
||||
$MapFactory.setSceneStarted(self)
|
||||
updateSpritesets(true)
|
||||
end
|
||||
|
||||
def disposeSpritesets
|
||||
return if !@spritesets
|
||||
for i in @spritesets.keys
|
||||
next if !@spritesets[i]
|
||||
@spritesets[i].dispose
|
||||
@spritesets[i] = nil
|
||||
end
|
||||
@spritesets.clear
|
||||
@spritesets = {}
|
||||
end
|
||||
|
||||
def dispose
|
||||
disposeSpritesets
|
||||
@map_renderer.dispose
|
||||
@map_renderer = nil
|
||||
@spritesetGlobal.dispose
|
||||
@spritesetGlobal = nil
|
||||
end
|
||||
|
||||
def autofade(mapid)
|
||||
playingBGM = $game_system.playing_bgm
|
||||
playingBGS = $game_system.playing_bgs
|
||||
return if playingBGM && playingBGM.name == "ultra_metropolis" && darknessEffectOnMap(mapid)
|
||||
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
|
||||
end
|
||||
end
|
||||
if playingBGS && map.autoplay_bgs
|
||||
pbBGMFade(0.8) if playingBGS.name != map.bgs.name
|
||||
end
|
||||
Graphics.frame_reset
|
||||
end
|
||||
|
||||
#todo
|
||||
def cacheNeedsClearing
|
||||
return RPG::Cache.size >= 100
|
||||
end
|
||||
|
||||
def reset_switches_for_map_transfer
|
||||
$game_switches[SWITCH_ILEX_FOREST_SPOOKED_POKEMON] = false
|
||||
end
|
||||
|
||||
def clear_quest_icons()
|
||||
for sprite in $scene.spriteset.character_sprites
|
||||
if sprite.is_a?(Sprite_Character) && sprite.questIcon
|
||||
sprite.removeQuestIcon
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def transfer_player(cancelVehicles = true)
|
||||
reset_switches_for_map_transfer()
|
||||
$game_temp.player_transferring = false
|
||||
pbCancelVehicles($game_temp.player_new_map_id) if cancelVehicles
|
||||
autofade($game_temp.player_new_map_id)
|
||||
pbBridgeOff
|
||||
@spritesetGlobal.playersprite.clearShadows
|
||||
clear_quest_icons()
|
||||
if $game_map.map_id != $game_temp.player_new_map_id
|
||||
$MapFactory.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
|
||||
when 2 then
|
||||
$game_player.turn_down
|
||||
when 4 then
|
||||
$game_player.turn_left
|
||||
when 6 then
|
||||
$game_player.turn_right
|
||||
when 8 then
|
||||
$game_player.turn_up
|
||||
end
|
||||
|
||||
$game_player.straighten
|
||||
$game_map.update
|
||||
disposeSpritesets
|
||||
if RPG::Cache.need_clearing
|
||||
RPG::Cache.clear
|
||||
end
|
||||
createSpritesets
|
||||
if $game_temp.transition_processing
|
||||
$game_temp.transition_processing = false
|
||||
Graphics.transition(20)
|
||||
end
|
||||
$game_map.autoplay
|
||||
Graphics.frame_reset
|
||||
Input.update
|
||||
end
|
||||
|
||||
def call_menu
|
||||
$game_temp.menu_calling = false
|
||||
$game_temp.in_menu = true
|
||||
$game_player.straighten
|
||||
$game_map.update
|
||||
sscene = PokemonPauseMenu_Scene.new
|
||||
sscreen = PokemonPauseMenu.new(sscene)
|
||||
sscreen.pbStartPokemonMenu
|
||||
$game_temp.in_menu = false
|
||||
end
|
||||
|
||||
def call_debug
|
||||
$game_temp.debug_calling = false
|
||||
pbPlayDecisionSE
|
||||
$game_player.straighten
|
||||
pbFadeOutIn { pbDebugMenu }
|
||||
end
|
||||
|
||||
def miniupdate
|
||||
$PokemonTemp.miniupdate = true
|
||||
loop do
|
||||
$game_player.update
|
||||
updateMaps
|
||||
$game_system.update
|
||||
$game_screen.update
|
||||
break unless $game_temp.player_transferring
|
||||
transfer_player
|
||||
break if $game_temp.transition_processing
|
||||
end
|
||||
updateSpritesets
|
||||
$PokemonTemp.miniupdate = false
|
||||
end
|
||||
|
||||
def updateMaps
|
||||
for map in $MapFactory.maps
|
||||
map.update
|
||||
end
|
||||
$MapFactory.updateMaps(self)
|
||||
end
|
||||
|
||||
def updateSpritesets(refresh = false)
|
||||
@spritesets = {} if !@spritesets
|
||||
keys = @spritesets.keys.clone
|
||||
for i in keys
|
||||
if !$MapFactory.hasMap?(i)
|
||||
@spritesets[i].dispose if @spritesets[i]
|
||||
@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
|
||||
pbDayNightTint(@map_renderer)
|
||||
@map_renderer.refresh if refresh
|
||||
@map_renderer.update
|
||||
Events.onMapUpdate.trigger(self)
|
||||
end
|
||||
|
||||
def update
|
||||
loop do
|
||||
pbMapInterpreter.update
|
||||
$game_player.update
|
||||
updateMaps
|
||||
$game_system.update
|
||||
$game_screen.update
|
||||
break unless $game_temp.player_transferring
|
||||
transfer_player
|
||||
break if $game_temp.transition_processing
|
||||
end
|
||||
updateSpritesets
|
||||
if $game_temp.to_title
|
||||
$game_temp.to_title = false
|
||||
SaveData.mark_values_as_unloaded
|
||||
$scene = pbCallTitle
|
||||
return
|
||||
end
|
||||
if $game_temp.transition_processing
|
||||
$game_temp.transition_processing = false
|
||||
if $game_temp.transition_name == ""
|
||||
Graphics.transition(20)
|
||||
else
|
||||
Graphics.transition(40, "Graphics/Transitions/" + $game_temp.transition_name)
|
||||
end
|
||||
end
|
||||
return if $game_temp.message_window_showing
|
||||
if !pbMapInterpreterRunning?
|
||||
if $game_temp.moving_furniture
|
||||
placeFurnitureMenu() if Input.trigger?(Input::USE)
|
||||
rotate__held_furniture_left if Input.trigger?(Input::JUMPDOWN)
|
||||
rotate_held_furniture_right if Input.trigger?(Input::JUMPUP)
|
||||
end
|
||||
|
||||
if Input.trigger?(Input::USE)
|
||||
$PokemonTemp.hiddenMoveEventCalling = true
|
||||
elsif Input.trigger?(Input::BACK)
|
||||
unless $game_system.menu_disabled || $game_player.moving?
|
||||
$game_temp.menu_calling = true
|
||||
$game_temp.menu_beep = true
|
||||
dayOfWeek = getDayOfTheWeek().to_s
|
||||
$scene.spriteset.addUserSprite(LocationWindow.new($game_map.name+ "\n"+ pbGetTimeNow.strftime(_INTL("%I:%M %p")) + "\n" + dayOfWeek))
|
||||
end
|
||||
elsif Input.trigger?(Input::SPECIAL)
|
||||
unless $game_system.menu_disabled || $game_player.moving?
|
||||
$PokemonTemp.keyItemCalling = true
|
||||
end
|
||||
elsif Input.press?(Input::F9)
|
||||
$game_temp.debug_calling = true if $DEBUG
|
||||
end
|
||||
end
|
||||
unless $game_player.moving?
|
||||
if $game_temp.menu_calling
|
||||
call_menu
|
||||
elsif $game_temp.debug_calling
|
||||
call_debug
|
||||
elsif $PokemonTemp.keyItemCalling
|
||||
$PokemonTemp.keyItemCalling = false
|
||||
$game_player.straighten
|
||||
pbUseKeyItem
|
||||
elsif $PokemonTemp.hiddenMoveEventCalling
|
||||
$PokemonTemp.hiddenMoveEventCalling = false
|
||||
$game_player.straighten
|
||||
Events.onAction.trigger(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def reset_player_sprite
|
||||
@spritesetGlobal.playersprite.updateBitmap
|
||||
end
|
||||
|
||||
def reset_map(fadeout = false,reset_music=true)
|
||||
$MapFactory.setup($game_map.map_id)
|
||||
$game_player.moveto($game_player.x, $game_player.y)
|
||||
$game_player.straighten
|
||||
$game_map.update
|
||||
disposeSpritesets
|
||||
GC.start
|
||||
createSpritesets
|
||||
if fadeout
|
||||
$game_temp.transition_processing = false
|
||||
Graphics.transition(20)
|
||||
end
|
||||
$game_map.autoplay if reset_music
|
||||
Graphics.frame_reset
|
||||
Input.update
|
||||
end
|
||||
|
||||
def main
|
||||
createSpritesets
|
||||
Graphics.transition(20)
|
||||
loop do
|
||||
Graphics.update
|
||||
Input.update
|
||||
update
|
||||
break if $scene != self
|
||||
end
|
||||
Graphics.freeze
|
||||
dispose
|
||||
if $game_temp.to_title
|
||||
Graphics.transition(20)
|
||||
Graphics.freeze
|
||||
end
|
||||
end
|
||||
end
|
||||
457
Data/Scripts/003_Game processing/003_Interpreter.rb
Normal file
457
Data/Scripts/003_Game processing/003_Interpreter.rb
Normal file
@@ -0,0 +1,457 @@
|
||||
#===============================================================================
|
||||
# ** Interpreter
|
||||
#-------------------------------------------------------------------------------
|
||||
# This interpreter runs event commands. This class is used within the
|
||||
# Game_System class and the Game_Event class.
|
||||
#===============================================================================
|
||||
class Interpreter
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
# depth : nest depth
|
||||
# main : main flag
|
||||
#-----------------------------------------------------------------------------
|
||||
def initialize(depth = 0, main = false)
|
||||
@depth = depth
|
||||
@main = main
|
||||
if depth > 100
|
||||
print("Common event call has exceeded maximum limit.")
|
||||
exit
|
||||
end
|
||||
clear
|
||||
end
|
||||
|
||||
def inspect
|
||||
str = super.chop
|
||||
str << format(' @event_id: %d>', @event_id)
|
||||
return str
|
||||
end
|
||||
|
||||
def clear
|
||||
@map_id = 0 # map ID when starting up
|
||||
@event_id = 0 # event ID
|
||||
@message_waiting = false # waiting for message to end
|
||||
@move_route_waiting = false # waiting for move completion
|
||||
@wait_count = 0 # wait count
|
||||
@child_interpreter = nil # child interpreter
|
||||
@branch = {} # branch data
|
||||
@buttonInput = false
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Event Setup
|
||||
# list : list of event commands
|
||||
# event_id : event ID
|
||||
#-----------------------------------------------------------------------------
|
||||
def setup(list, event_id, map_id = nil)
|
||||
clear
|
||||
@map_id = map_id || $game_map.map_id
|
||||
@event_id = event_id
|
||||
@list = list
|
||||
@index = 0
|
||||
@branch.clear
|
||||
end
|
||||
|
||||
def setup_starting_event
|
||||
$game_map.refresh if $game_map.need_refresh
|
||||
# Set up common event if one wants to start
|
||||
if $game_temp.common_event_id > 0
|
||||
setup($data_common_events[$game_temp.common_event_id].list, 0)
|
||||
$game_temp.common_event_id = 0
|
||||
return
|
||||
end
|
||||
# Check all map events for one that wants to start, and set it up
|
||||
for event in $game_map.events.values
|
||||
next if !event.starting
|
||||
if event.trigger < 3 # Isn't autorun or parallel processing
|
||||
event.lock
|
||||
event.clear_starting
|
||||
end
|
||||
setup(event.list, event.id, event.map.map_id)
|
||||
return
|
||||
end
|
||||
# Check all common events for one that is autorun, and set it up
|
||||
for common_event in $data_common_events.compact
|
||||
next if common_event.trigger != 1 || !$game_switches[common_event.switch_id]
|
||||
setup(common_event.list, 0)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
def running?
|
||||
return @list != nil
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Frame Update
|
||||
#-----------------------------------------------------------------------------
|
||||
def update
|
||||
@loop_count = 0
|
||||
loop do
|
||||
@loop_count += 1
|
||||
if @loop_count > 100 # Call Graphics.update for freeze prevention
|
||||
Graphics.update
|
||||
@loop_count = 0
|
||||
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)
|
||||
@event_id = 0
|
||||
end
|
||||
# Update child interpreter if one exists
|
||||
if @child_interpreter
|
||||
@child_interpreter.update
|
||||
@child_interpreter = nil if !@child_interpreter.running?
|
||||
return if @child_interpreter
|
||||
end
|
||||
# Do nothing if a message is being shown
|
||||
return if @message_waiting
|
||||
# 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
|
||||
return if event.move_route_forcing
|
||||
end
|
||||
@move_route_waiting = false
|
||||
end
|
||||
# Do nothing while waiting
|
||||
if @wait_count > 0
|
||||
@wait_count -= 1
|
||||
return
|
||||
end
|
||||
# Do nothing if the pause menu is going to open
|
||||
return if $game_temp.menu_calling
|
||||
# If there are no commands in the list, try to find something that wants to run
|
||||
if @list.nil?
|
||||
setup_starting_event if @main
|
||||
return if @list.nil? # Couldn't find anything that wants to run
|
||||
end
|
||||
# Execute the next command
|
||||
return if execute_command == false
|
||||
# Move to the next @index
|
||||
@index += 1
|
||||
end
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Execute script
|
||||
#-----------------------------------------------------------------------------
|
||||
def execute_script(script)
|
||||
begin
|
||||
result = eval(script)
|
||||
return result
|
||||
rescue Exception
|
||||
e = $!
|
||||
raise if e.is_a?(SystemExit) || "#{e.class}" == "Reset"
|
||||
event = get_self
|
||||
s = "Backtrace:\r\n"
|
||||
message = pbGetExceptionMessage(e)
|
||||
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'"
|
||||
end
|
||||
}
|
||||
else
|
||||
for bt in e.backtrace[0, 10]
|
||||
s += bt + "\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
|
||||
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
|
||||
else
|
||||
err = "Script error in interpreter:\r\n#{message}\r\n#{s}"
|
||||
if e.is_a?(Hangup)
|
||||
$EVENTHANGUPMSG = err
|
||||
raise
|
||||
end
|
||||
end
|
||||
raise err
|
||||
end
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Get Character
|
||||
# parameter : parameter
|
||||
#-----------------------------------------------------------------------------
|
||||
def get_character(parameter = 0)
|
||||
case parameter
|
||||
when -1 # player
|
||||
return $game_player
|
||||
when 0 # this event
|
||||
events = $game_map.events
|
||||
return (events) ? events[@event_id] : nil
|
||||
else # specific event
|
||||
events = $game_map.events
|
||||
return (events) ? events[parameter] : nil
|
||||
end
|
||||
end
|
||||
|
||||
def get_player
|
||||
return get_character(-1)
|
||||
end
|
||||
|
||||
def get_self
|
||||
return get_character(0)
|
||||
end
|
||||
|
||||
def get_event(parameter)
|
||||
return get_character(parameter)
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Freezes all events on the map (for use at the beginning of common events)
|
||||
#-----------------------------------------------------------------------------
|
||||
def pbGlobalLock
|
||||
$game_map.events.values.each { |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 }
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Gets the next index in the interpreter, ignoring certain commands between messages
|
||||
#-----------------------------------------------------------------------------
|
||||
def pbNextIndex(index)
|
||||
return -1 if !@list || @list.length == 0
|
||||
i = index + 1
|
||||
loop do
|
||||
return i if i >= @list.length - 1
|
||||
case @list[i].code
|
||||
when 118, 108, 408 # Label, Comment
|
||||
i += 1
|
||||
when 413 # Repeat Above
|
||||
i = pbRepeatAbove(i)
|
||||
when 113 # Break Loop
|
||||
i = pbBreakLoop(i)
|
||||
when 119 # Jump to Label
|
||||
newI = pbJumpToLabel(i, @list[i].parameters[0])
|
||||
i = (newI > i) ? newI : i + 1
|
||||
else
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbRepeatAbove(index)
|
||||
index = @list[index].indent
|
||||
loop do
|
||||
index -= 1
|
||||
return index + 1 if @list[index].indent == indent
|
||||
end
|
||||
end
|
||||
|
||||
def pbBreakLoop(index)
|
||||
indent = @list[index].indent
|
||||
temp_index = index
|
||||
loop do
|
||||
temp_index += 1
|
||||
return index + 1 if temp_index >= @list.size - 1
|
||||
return temp_index + 1 if @list[temp_index].code == 413 &&
|
||||
@list[temp_index].indent < indent
|
||||
end
|
||||
end
|
||||
|
||||
def pbJumpToLabel(index, label_name)
|
||||
temp_index = 0
|
||||
loop do
|
||||
return index + 1 if temp_index >= @list.size - 1
|
||||
return temp_index + 1 if @list[temp_index].code == 118 &&
|
||||
@list[temp_index].parameters[0] == label_name
|
||||
temp_index += 1
|
||||
end
|
||||
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)
|
||||
$game_screen.pictures[number].show(name, origin, x, y, zoomX, zoomY, opacity, blendType)
|
||||
end
|
||||
|
||||
# Erases an event and adds it to the list of erased events so that
|
||||
# it can stay erased when the game is saved then loaded again.
|
||||
def pbEraseThisEvent
|
||||
if $game_map.events[@event_id]
|
||||
if $game_map.events[@event_id].name[/cuttree/i]
|
||||
pbSmashThisEvent()
|
||||
end
|
||||
$game_map.events[@event_id].erase
|
||||
$PokemonMap.addErasedEvent(@event_id) if $PokemonMap
|
||||
end
|
||||
@index += 1
|
||||
return true
|
||||
end
|
||||
|
||||
# Runs a common event.
|
||||
def pbCommonEvent(id)
|
||||
common_event = $data_common_events[id]
|
||||
return if !common_event
|
||||
if $game_temp.in_battle
|
||||
$game_system.battle_interpreter.setup(common_event.list, 0)
|
||||
else
|
||||
interp = Interpreter.new
|
||||
interp.setup(common_event.list, 0)
|
||||
loop do
|
||||
Graphics.update
|
||||
Input.update
|
||||
interp.update
|
||||
pbUpdateSceneMap
|
||||
break if !interp.running?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Sets another event's self switch (eg. pbSetSelfSwitch(20, "A", true) ).
|
||||
def pbSetSelfSwitch(eventid, switch_name, value, mapid = -1)
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
def tsOff?(c)
|
||||
return get_self.tsOff?(c)
|
||||
end
|
||||
alias isTempSwitchOff? tsOff?
|
||||
|
||||
def tsOn?(c)
|
||||
return get_self.tsOn?(c)
|
||||
end
|
||||
alias isTempSwitchOn? tsOn?
|
||||
|
||||
def setTempSwitchOn(c)
|
||||
get_self.setTempSwitchOn(c)
|
||||
end
|
||||
|
||||
def setTempSwitchOff(c)
|
||||
get_self.setTempSwitchOff(c)
|
||||
end
|
||||
|
||||
def getVariable(*arg)
|
||||
if arg.length == 0
|
||||
return nil if !$PokemonGlobal.eventvars
|
||||
return $PokemonGlobal.eventvars[[@map_id, @event_id]]
|
||||
else
|
||||
return $game_variables[arg[0]]
|
||||
end
|
||||
end
|
||||
|
||||
def setVariable(*arg)
|
||||
if arg.length == 1
|
||||
$PokemonGlobal.eventvars = {} if !$PokemonGlobal.eventvars
|
||||
$PokemonGlobal.eventvars[[@map_id, @event_id]] = arg[0]
|
||||
else
|
||||
$game_variables[arg[0]] = arg[1]
|
||||
$game_map.need_refresh = true
|
||||
end
|
||||
end
|
||||
|
||||
def pbGetPokemon(id)
|
||||
return $Trainer.party[pbGet(id)]
|
||||
end
|
||||
|
||||
def pbSetEventTime(*arg)
|
||||
$PokemonGlobal.eventvars = {} if !$PokemonGlobal.eventvars
|
||||
time = pbGetTimeNow
|
||||
time = time.to_i
|
||||
pbSetSelfSwitch(@event_id, "A", true)
|
||||
$PokemonGlobal.eventvars[[@map_id, @event_id]] = time
|
||||
for otherevt in arg
|
||||
pbSetSelfSwitch(otherevt, "A", true)
|
||||
$PokemonGlobal.eventvars[[@map_id, otherevt]] = time
|
||||
end
|
||||
end
|
||||
|
||||
# Used in boulder events. Allows an event to be pushed.
|
||||
def pbPushThisEvent
|
||||
event = get_self
|
||||
old_x = event.x
|
||||
old_y = event.y
|
||||
# Apply strict version of passable, which treats tiles that are passable
|
||||
# only from certain directions as fully impassible
|
||||
# ^why?? - no
|
||||
return if !event.can_move_in_direction?($game_player.direction, false)
|
||||
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
|
||||
|
||||
if old_x != event.x || old_y != event.y
|
||||
$game_player.lock
|
||||
loop do
|
||||
Graphics.update
|
||||
Input.update
|
||||
pbUpdateSceneMap
|
||||
break if !event.moving?
|
||||
end
|
||||
$game_player.unlock
|
||||
end
|
||||
end
|
||||
|
||||
def pbPushThisBoulder
|
||||
pbPushThisEvent if $PokemonMap.strengthUsed
|
||||
return true
|
||||
end
|
||||
|
||||
def pbSmashThisEvent
|
||||
event = get_self
|
||||
pbSmashEvent(event) if event
|
||||
@index += 1
|
||||
return true
|
||||
end
|
||||
|
||||
def pbTrainerIntro(symbol)
|
||||
return true if $DEBUG && !GameData::TrainerType.exists?(symbol)
|
||||
tr_type = GameData::TrainerType.get(symbol).id
|
||||
pbGlobalLock
|
||||
pbPlayTrainerIntroME(tr_type)
|
||||
return true
|
||||
end
|
||||
|
||||
def pbTrainerEnd
|
||||
pbGlobalUnlock
|
||||
event = get_self
|
||||
event.erase_route if event
|
||||
end
|
||||
|
||||
def setPrice(item, buy_price = -1, sell_price = -1)
|
||||
item = GameData::Item.get(item).id
|
||||
$game_temp.mart_prices[item] = [-1, -1] if !$game_temp.mart_prices[item]
|
||||
$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
|
||||
end
|
||||
end
|
||||
|
||||
def setSellPrice(item, sell_price)
|
||||
setPrice(item, -1, sell_price)
|
||||
end
|
||||
end
|
||||
1027
Data/Scripts/003_Game processing/004_Interpreter_Commands.rb
Normal file
1027
Data/Scripts/003_Game processing/004_Interpreter_Commands.rb
Normal file
File diff suppressed because it is too large
Load Diff
275
Data/Scripts/003_Game processing/005_Event_Handlers.rb
Normal file
275
Data/Scripts/003_Game processing/005_Event_Handlers.rb
Normal file
@@ -0,0 +1,275 @@
|
||||
#===============================================================================
|
||||
# Defines an event that procedures can subscribe to.
|
||||
#===============================================================================
|
||||
class Event
|
||||
def initialize
|
||||
@callbacks = []
|
||||
end
|
||||
|
||||
# Sets an event handler for this event and removes all other event handlers.
|
||||
def set(method)
|
||||
@callbacks.clear
|
||||
@callbacks.push(method)
|
||||
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
|
||||
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)
|
||||
return self
|
||||
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.
|
||||
# The first argument is the sender of the event, the second argument contains
|
||||
# the event's parameters. If three or more arguments are given, this method
|
||||
# supports the following callbacks:
|
||||
# proc { |sender,params| } where params is an array of the other parameters, and
|
||||
# proc { |sender,arg0,arg1,...| }
|
||||
def trigger(*arg)
|
||||
arglist = arg[1,arg.length]
|
||||
for callback in @callbacks
|
||||
if callback.arity>2 && arg.length==callback.arity
|
||||
# Retrofitted for callbacks that take three or more arguments
|
||||
callback.call(*arg)
|
||||
else
|
||||
callback.call(arg[0],arglist)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Triggers the event and calls all its event handlers. Normally called only
|
||||
# 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
|
||||
callback.call(*arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class HandlerHash
|
||||
def initialize(mod)
|
||||
@mod = mod
|
||||
@hash = {}
|
||||
@addIfs = []
|
||||
@symbolCache = {}
|
||||
end
|
||||
|
||||
def fromSymbol(sym)
|
||||
return sym unless sym.is_a?(Symbol) || sym.is_a?(String)
|
||||
mod = Object.const_get(@mod) rescue nil
|
||||
return nil if !mod
|
||||
return mod.const_get(sym.to_sym) rescue nil
|
||||
end
|
||||
|
||||
def toSymbol(sym)
|
||||
return sym.to_sym if sym.is_a?(Symbol) || sym.is_a?(String)
|
||||
ret = @symbolCache[sym]
|
||||
return ret if ret
|
||||
mod = Object.const_get(@mod) rescue nil
|
||||
return nil if !mod
|
||||
for key in mod.constants
|
||||
next if mod.const_get(key)!=sym
|
||||
ret = key.to_sym
|
||||
@symbolCache[sym] = ret
|
||||
break
|
||||
end
|
||||
return ret
|
||||
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
|
||||
@addIfs.push([conditionProc,handler || handlerBlock])
|
||||
end
|
||||
|
||||
def add(sym,handler=nil,&handlerBlock) # 'sym' can be an ID or symbol
|
||||
if ![Proc,Hash].include?(handler.class) && !block_given?
|
||||
raise ArgumentError, "#{self.class.name} for #{sym.inspect} has no valid handler (#{handler.inspect} was given)"
|
||||
end
|
||||
id = fromSymbol(sym)
|
||||
@hash[id] = handler || handlerBlock if id
|
||||
symbol = toSymbol(sym)
|
||||
@hash[symbol] = handler || handlerBlock if symbol
|
||||
end
|
||||
|
||||
def copy(src,*dests)
|
||||
handler = self[src]
|
||||
if handler
|
||||
for dest in dests
|
||||
self.add(dest,handler)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def [](sym) # 'sym' can be an ID or symbol
|
||||
id = fromSymbol(sym)
|
||||
ret = nil
|
||||
ret = @hash[id] if id && @hash[id] # Real ID from the item
|
||||
symbol = toSymbol(sym)
|
||||
ret = @hash[symbol] if symbol && @hash[symbol] # Symbol or string
|
||||
unless ret
|
||||
for addif in @addIfs
|
||||
return addif[1] if addif[0].call(id)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def trigger(sym,*args)
|
||||
handler = self[sym]
|
||||
return (handler) ? handler.call(fromSymbol(sym),*args) : nil
|
||||
end
|
||||
|
||||
def clear
|
||||
@hash.clear
|
||||
end
|
||||
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.
|
||||
#===============================================================================
|
||||
class HandlerHash2
|
||||
def initialize
|
||||
@hash = {}
|
||||
@add_ifs = []
|
||||
end
|
||||
|
||||
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
|
||||
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)"
|
||||
end
|
||||
@hash[sym] = handler || handlerBlock if sym
|
||||
end
|
||||
|
||||
def copy(src, *dests)
|
||||
handler = self[src]
|
||||
return if !handler
|
||||
for dest in dests
|
||||
self.add(dest, handler)
|
||||
end
|
||||
end
|
||||
|
||||
def clear
|
||||
@hash.clear
|
||||
end
|
||||
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# An even more stripped down version of class HandlerHash which just takes
|
||||
# hashes with keys, no matter what the keys are.
|
||||
#===============================================================================
|
||||
class HandlerHashBasic
|
||||
def initialize
|
||||
@ordered_keys = []
|
||||
@hash = {}
|
||||
@addIfs = []
|
||||
end
|
||||
|
||||
def [](entry)
|
||||
ret = nil
|
||||
ret = @hash[entry] if entry && @hash[entry]
|
||||
unless ret
|
||||
for addif in @addIfs
|
||||
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
|
||||
|
||||
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
|
||||
@addIfs.push([conditionProc, handler || handlerBlock])
|
||||
end
|
||||
|
||||
def copy(src, *dests)
|
||||
handler = self[src]
|
||||
return if !handler
|
||||
dests.each { |dest| self.add(dest, handler) }
|
||||
end
|
||||
|
||||
def clear
|
||||
@hash.clear
|
||||
@ordered_keys.clear
|
||||
end
|
||||
|
||||
def trigger(entry, *args)
|
||||
handler = self[entry]
|
||||
return (handler) ? handler.call(*args) : nil
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class SpeciesHandlerHash < HandlerHash2
|
||||
end
|
||||
|
||||
class AbilityHandlerHash < HandlerHash2
|
||||
end
|
||||
|
||||
class ItemHandlerHash < HandlerHash2
|
||||
end
|
||||
|
||||
class MoveHandlerHash < HandlerHash2
|
||||
end
|
||||
172
Data/Scripts/003_Game processing/006_Event_OverworldEvents.rb
Normal file
172
Data/Scripts/003_Game processing/006_Event_OverworldEvents.rb
Normal file
@@ -0,0 +1,172 @@
|
||||
#===============================================================================
|
||||
# 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
|
||||
157
Data/Scripts/004_Game classes/001_Game_Screen.rb
Normal file
157
Data/Scripts/004_Game classes/001_Game_Screen.rb
Normal file
@@ -0,0 +1,157 @@
|
||||
#===============================================================================
|
||||
# ** Game_Screen
|
||||
#-------------------------------------------------------------------------------
|
||||
# This class handles screen maintenance data, such as change in color tone,
|
||||
# flashing, etc. Refer to "$game_screen" for the instance of this class.
|
||||
#===============================================================================
|
||||
|
||||
class Game_Screen
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Public Instance Variables
|
||||
#-----------------------------------------------------------------------------
|
||||
attr_reader :brightness # brightness
|
||||
attr_reader :tone # color tone
|
||||
attr_reader :flash_color # flash color
|
||||
attr_reader :shake # shake positioning
|
||||
attr_reader :pictures # pictures
|
||||
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
|
||||
attr_accessor :weather_power
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
#-----------------------------------------------------------------------------
|
||||
def initialize
|
||||
@brightness = 255
|
||||
@fadeout_duration = 0
|
||||
@fadein_duration = 0
|
||||
@tone = Tone.new(0, 0, 0, 0)
|
||||
@tone_target = Tone.new(0, 0, 0, 0)
|
||||
@tone_duration = 0
|
||||
@flash_color = Color.new(0, 0, 0, 0)
|
||||
@flash_duration = 0
|
||||
@shake_power = 0
|
||||
@shake_speed = 0
|
||||
@shake_duration = 0
|
||||
@shake_direction = 1
|
||||
@shake = 0
|
||||
@pictures = [nil]
|
||||
for i in 1..100
|
||||
@pictures.push(Game_Picture.new(i))
|
||||
end
|
||||
@weather_type = 0
|
||||
@weather_max = 0.0
|
||||
@weather_duration = 0
|
||||
@weather_power = 0
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Start Changing Color Tone
|
||||
# tone : color tone
|
||||
# duration : time
|
||||
#-----------------------------------------------------------------------------
|
||||
def start_tone_change(tone, duration)
|
||||
@tone_target = tone.clone
|
||||
@tone_duration = duration
|
||||
if @tone_duration == 0
|
||||
@tone = @tone_target.clone
|
||||
end
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Start Flashing
|
||||
# color : color
|
||||
# duration : time
|
||||
#-----------------------------------------------------------------------------
|
||||
def start_flash(color, duration)
|
||||
@flash_color = color.clone
|
||||
@flash_duration = duration
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Start Shaking
|
||||
# power : strength
|
||||
# speed : speed
|
||||
# duration : time
|
||||
#-----------------------------------------------------------------------------
|
||||
def start_shake(power, speed, duration)
|
||||
@shake_power = power
|
||||
@shake_speed = speed
|
||||
@shake_duration = duration
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Set Weather
|
||||
# type : type
|
||||
# power : strength
|
||||
# duration : time
|
||||
#-----------------------------------------------------------------------------
|
||||
def weather(type, power, duration)
|
||||
@weather_type = GameData::Weather.get(type).id
|
||||
@weather_power = power
|
||||
@weather_max = (power + 1) * RPG::Weather::MAX_SPRITES / 10
|
||||
@weather_duration = duration # In 1/20ths of a seconds
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Frame Update
|
||||
#-----------------------------------------------------------------------------
|
||||
def update
|
||||
if @fadeout_duration && @fadeout_duration>=1
|
||||
d = @fadeout_duration
|
||||
@brightness = (@brightness*(d-1))/d
|
||||
@fadeout_duration -= 1
|
||||
end
|
||||
if @fadein_duration && @fadein_duration>=1
|
||||
d = @fadein_duration
|
||||
@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_duration -= 1
|
||||
end
|
||||
if @flash_duration>=1
|
||||
d = @flash_duration
|
||||
@flash_color.alpha = @flash_color.alpha*(d-1)/d
|
||||
@flash_duration -= 1
|
||||
end
|
||||
if @shake_duration>=1 || @shake!=0
|
||||
delta = (@shake_power*@shake_speed*@shake_direction)/10.0
|
||||
if @shake_duration<=1 && @shake*(@shake+delta)<0
|
||||
@shake = 0
|
||||
else
|
||||
@shake += delta
|
||||
end
|
||||
@shake_direction = -1 if @shake>@shake_power*2
|
||||
@shake_direction = 1 if @shake<-@shake_power*2
|
||||
@shake_duration -= 1 if @shake_duration>=1
|
||||
end
|
||||
if $game_temp.in_battle
|
||||
for i in 51..100
|
||||
@pictures[i].update
|
||||
end
|
||||
else
|
||||
for i in 1..50
|
||||
@pictures[i].update
|
||||
end
|
||||
end
|
||||
end
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
def pbShake(power,speed,frames)
|
||||
$game_screen.start_shake(power,speed,frames*Graphics.frame_rate/20)
|
||||
end
|
||||
|
||||
def pbFlash(color,frames)
|
||||
$game_screen.start_flash(color,frames*Graphics.frame_rate/20)
|
||||
end
|
||||
@@ -0,0 +1,60 @@
|
||||
#===============================================================================
|
||||
# ** Game_Temp
|
||||
#-------------------------------------------------------------------------------
|
||||
# This class handles temporary data that is not included with save data.
|
||||
# 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
|
||||
attr_accessor :menu_calling # menu calling flag
|
||||
attr_accessor :debug_calling # debug calling flag
|
||||
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 :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 :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
|
||||
@menu_calling = false
|
||||
@debug_calling = false
|
||||
@player_transferring = false
|
||||
@player_new_map_id = 0
|
||||
@player_new_x = 0
|
||||
@player_new_y = 0
|
||||
@player_new_direction = 0
|
||||
@transition_processing = false
|
||||
@transition_name = ""
|
||||
@to_title = false
|
||||
@fadestate = 0
|
||||
@background_bitmap = nil
|
||||
@message_window_showing = false
|
||||
@transition_processing = false
|
||||
@mart_prices = {}
|
||||
end
|
||||
|
||||
def clear_mart_prices
|
||||
@mart_prices = {}
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,30 @@
|
||||
#===============================================================================
|
||||
# ** Game_Switches
|
||||
#-------------------------------------------------------------------------------
|
||||
# This class handles switches. It's a wrapper for the built-in class "Array."
|
||||
# Refer to "$game_switches" for the instance of this class.
|
||||
#===============================================================================
|
||||
class Game_Switches
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
#-----------------------------------------------------------------------------
|
||||
def initialize
|
||||
@data = []
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Get Switch
|
||||
# switch_id : switch ID
|
||||
#-----------------------------------------------------------------------------
|
||||
def [](switch_id)
|
||||
return @data[switch_id] if switch_id <= 5000 && @data[switch_id] != nil
|
||||
return false
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Set Switch
|
||||
# switch_id : switch ID
|
||||
# value : ON (true) / OFF (false)
|
||||
#-----------------------------------------------------------------------------
|
||||
def []=(switch_id, value)
|
||||
@data[switch_id] = value if switch_id <= 5000
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,30 @@
|
||||
#===============================================================================
|
||||
# ** Game_Variables
|
||||
#-------------------------------------------------------------------------------
|
||||
# This class handles variables. It's a wrapper for the built-in class "Array."
|
||||
# Refer to "$game_variables" for the instance of this class.
|
||||
#===============================================================================
|
||||
class Game_Variables
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
#-----------------------------------------------------------------------------
|
||||
def initialize
|
||||
@data = []
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Get Variable
|
||||
# variable_id : variable ID
|
||||
#-----------------------------------------------------------------------------
|
||||
def [](variable_id)
|
||||
return @data[variable_id] if variable_id <= 5000 && !@data[variable_id].nil?
|
||||
return 0
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Set Variable
|
||||
# variable_id : variable ID
|
||||
# value : the variable's value
|
||||
#-----------------------------------------------------------------------------
|
||||
def []=(variable_id, value)
|
||||
@data[variable_id] = value if variable_id <= 5000
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,29 @@
|
||||
#===============================================================================
|
||||
# ** Game_SelfSwitches
|
||||
#-------------------------------------------------------------------------------
|
||||
# This class handles self switches. It's a wrapper for the built-in class
|
||||
# "Hash." Refer to "$game_self_switches" for the instance of this class.
|
||||
#===============================================================================
|
||||
class Game_SelfSwitches
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
#-----------------------------------------------------------------------------
|
||||
def initialize
|
||||
@data = {}
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Get Self Switch
|
||||
# key : key
|
||||
#-----------------------------------------------------------------------------
|
||||
def [](key)
|
||||
return (@data[key]==true) ? true : false
|
||||
end
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Set Self Switch
|
||||
# key : key
|
||||
# value : ON (true) / OFF (false)
|
||||
#-----------------------------------------------------------------------------
|
||||
def []=(key, value)
|
||||
@data[key] = value
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user