mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-24 18:05:08 +00:00
Compare commits
16 Commits
9dcbf2b910
...
6.6-prerel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47ea64728a | ||
|
|
937527828f | ||
|
|
b2f6901c6b | ||
|
|
a393ba1137 | ||
|
|
295a71dbcd | ||
|
|
a94f2f1169 | ||
|
|
eae5af977c | ||
|
|
2b3dae22ac | ||
|
|
3698cadb83 | ||
|
|
a1c1d37ceb | ||
|
|
28cccd884f | ||
|
|
0ad7b1a899 | ||
|
|
370814733b | ||
|
|
4bc79de9dd | ||
|
|
26312dfd6c | ||
|
|
53adec3526 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,6 +1,8 @@
|
|||||||
Graphics/CustomBattlers/local_sprites/*
|
Graphics/CustomBattlers/local_sprites/*
|
||||||
Graphics/Pokemon/FusionIcons/*
|
Graphics/Pokemon/FusionIcons/*
|
||||||
Graphics/CustomBattlers/spritesheets
|
Graphics/Battlers/Shiny/*
|
||||||
|
|
||||||
|
Graphics/CustomBattlers/spritesheets/*
|
||||||
Graphics/CustomBattlers/*
|
Graphics/CustomBattlers/*
|
||||||
Data/sprites/*
|
Data/sprites/*
|
||||||
Data/VERSION
|
Data/VERSION
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
|||||||
[submodule "Data/Scripts"]
|
|
||||||
path = Data/Scripts
|
|
||||||
url = https://github.com/infinitefusion/scripts.git
|
|
||||||
115
Credits.txt
115
Credits.txt
@@ -1,4 +1,5 @@
|
|||||||
########## CREDITS ###############
|
########## CREDITS ###############
|
||||||
|
Pok?mon Infinite Fusion: Hoenn
|
||||||
Game made by Chardub
|
Game made by Chardub
|
||||||
|
|
||||||
*This is NOT an official Pokemon game. The author of this game is not
|
*This is NOT an official Pokemon game. The author of this game is not
|
||||||
@@ -12,19 +13,29 @@ Chardub
|
|||||||
##############################
|
##############################
|
||||||
## Maps ##
|
## Maps ##
|
||||||
##############################
|
##############################
|
||||||
Chardub, Kiwikelly
|
Chardub, Kiwikelly, Payapon
|
||||||
|
|
||||||
Some of the maps were based on work by:
|
|
||||||
BenGames,Films, and More! (Pokemon Adventures in Kanto) http://www.pokecommunity.com/showthread.php?t=303850
|
|
||||||
Zeak6464 (Kanto Map pack) http://www.pokecommunity.com/showthread.php?t=345591
|
|
||||||
|
|
||||||
#################################
|
#################################
|
||||||
# Story / Dialogues #
|
# Story / Dialogues #
|
||||||
#################################
|
#################################
|
||||||
Chardub
|
Chardub
|
||||||
Kiwikelly
|
Kiwikelly
|
||||||
The story and dialogues were based off Pokémon Red and Blue, as well as
|
The story and dialogues were based off Pok?mon Ruby, Sapphire and Emerald, as well as Pok?mon
|
||||||
Pokémon Gold and Silver. Both games are made by Game Freak.
|
Omega Ruby and Alpha Sapphire, which are all made by Game Freak.
|
||||||
|
|
||||||
|
##############################
|
||||||
|
## Music ##
|
||||||
|
##############################
|
||||||
|
Pory
|
||||||
|
|
||||||
|
##############################
|
||||||
|
## Animation ##
|
||||||
|
#############################
|
||||||
|
-- Intro cinematic animation --
|
||||||
|
Kiwikelly
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###########################################################
|
###########################################################
|
||||||
### Fusion Sprites ###
|
### Fusion Sprites ###
|
||||||
@@ -35,47 +46,77 @@ Generated Sprites
|
|||||||
Pokefusion 2 (version 4.5+)
|
Pokefusion 2 (version 4.5+)
|
||||||
http://japeal.com/pkm
|
http://japeal.com/pkm
|
||||||
|
|
||||||
Pokefusion (version 4.0-4.4)
|
|
||||||
http://pokefusion.japeal.com/
|
|
||||||
|
|
||||||
Alexonsager (version 3.x and below)
|
|
||||||
http://pokemon.alexonsager.net/
|
|
||||||
|
|
||||||
Special thanks to Aegide and Reizod for helping to rip the sprites from the website
|
Special thanks to Aegide and Reizod for helping to rip the sprites from the website
|
||||||
and to the owners of the respective fusion websites for accepting to share
|
and to the owners of the respective fusion websites for accepting to share
|
||||||
their sprites.
|
their sprites.
|
||||||
|
|
||||||
Intro cinematic
|
Custom sprites
|
||||||
#####################
|
#####################
|
||||||
Kiwikelly
|
Individual sprite credits can be found in Data/SPRITE_CREDS file for full, up to date credits
|
||||||
|
|
||||||
|
|
||||||
Custom sprites collecting and handling
|
Custom sprites collecting and handling
|
||||||
Kiwikelly, Payapon, Thornsoflight
|
Kiwikelly, Payapon, Thornsoflight
|
||||||
|
|
||||||
Discord custom sprites coordination
|
Discord custom sprites coordination
|
||||||
|
--- Sprite Managers ---
|
||||||
avianAnnihilator<s>Blaquaza
|
avianAnnihilator<s>Blaquaza
|
||||||
BéBoutton<s>CaBiNE
|
BBoutton<s>CaBiNE
|
||||||
CoramSun<s>hero.drawing
|
CoramSun<s>hero.drawing
|
||||||
Howls<s>Ignus
|
Howlingstarr<s>Ignus
|
||||||
Kiwi<s>Maelmc
|
Kiwi<s>Maelmc
|
||||||
Milchik the Miltank<s>Payapon
|
Milchik the Miltank<s>Payapon
|
||||||
Pix<s>Rosemagwin
|
Pix<s>Rosemagwin
|
||||||
Thornsoflight
|
Thornsoflight<s>FauxBlue
|
||||||
|
|
||||||
Custom fusion sprites
|
### Spriter application reviews (Klefki)
|
||||||
#####################
|
007z3lda<s>barkey<s>the_cardinals
|
||||||
Check the Data/SPRITE_CREDS file for full, up to date credits
|
doodledoo<s>grafaiguy<s>gummy.frog
|
||||||
|
holgast<s>ignust<s>jcobe800
|
||||||
|
markusknight<s>monolithyk<s>stickieanimates
|
||||||
|
takopus<s>_woofa_<s>yumatei
|
||||||
|
|
||||||
|
### Sprites quality assurance (Chansey)
|
||||||
|
dodoowner_<s>fauxblue<s>fioretovi
|
||||||
|
<greystorm101<s>.payapon<s>smasllcutekitty
|
||||||
|
odditylad<s>midnightender6<s>toadettexmushina
|
||||||
|
|
||||||
|
### Spriting process checking (Swablu)
|
||||||
|
cataylor_01<s>pikahunter07<s>say_4732
|
||||||
|
justvince.<s>
|
||||||
|
|
||||||
|
### Abandoned sprites harvesting (Zigzagoon)
|
||||||
|
_testrun_<s>greystorm101<s>.izik
|
||||||
|
mystora<s>reddevil85<s>riberna
|
||||||
|
chespining<s>togepimax
|
||||||
|
|
||||||
|
|
||||||
Triple fusion sprites
|
|
||||||
########################
|
|
||||||
Legendary birds fusion sprite by Universez
|
|
||||||
Legendary beasts fusion sprite by Milchik
|
|
||||||
Weather trio fusion sprite by magnuzone
|
|
||||||
Creation and Tao trio trio fusion sprite by mammuth89
|
|
||||||
|
|
||||||
|
|
||||||
|
###################################
|
||||||
|
### Game quality assurance ###
|
||||||
|
###################################
|
||||||
|
### Tech support and bugs reporting management
|
||||||
|
sapphire_chuu<s>megaman.
|
||||||
|
ymirbot<s>
|
||||||
|
|
||||||
|
### Tech support and bugs reporting(Porygon)
|
||||||
|
sapphire_chu<s>ernesto_gaming<s>xiaoanemo
|
||||||
|
kitsuwren<s>lunarcharlotte<s>megaman.
|
||||||
|
casinoluck<s>ymirbot
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###################################
|
||||||
|
### Custom Pok?dex entries ###
|
||||||
|
###################################
|
||||||
|
### Pok?dex entries quality control (Unown)
|
||||||
|
luvischlo<s>char_latte3412<s>strawbearycandy
|
||||||
|
bobosmith01<s>griddle<s>.izik
|
||||||
|
knilk<s>lordjoostmeister<s>.realthree
|
||||||
|
wigglypon<s>wildheartrazorfangs<s>ziggaway
|
||||||
|
|
||||||
|
### Individual Pok?dex entries credits can be found in Data/pokedex/dex.json
|
||||||
|
|
||||||
###########################################################
|
###########################################################
|
||||||
#### Pokemon Essentials ###
|
#### Pokemon Essentials ###
|
||||||
###########################################################
|
###########################################################
|
||||||
@@ -104,8 +145,6 @@ The following ressources were also used
|
|||||||
with their respective authors' consent
|
with their respective authors' consent
|
||||||
#######################################################################
|
#######################################################################
|
||||||
### Sprites ###
|
### Sprites ###
|
||||||
|
|
||||||
|
|
||||||
Overworld Sprites:
|
Overworld Sprites:
|
||||||
Custom graphics:
|
Custom graphics:
|
||||||
Kiwikelly, Knuckles, UnworthyPie
|
Kiwikelly, Knuckles, UnworthyPie
|
||||||
@@ -116,7 +155,9 @@ with their respective authors' consent
|
|||||||
SailorVicious (Prof. Elm OW sprite) https://www.deviantart.com/sailorvicious
|
SailorVicious (Prof. Elm OW sprite) https://www.deviantart.com/sailorvicious
|
||||||
OceansLugiaSpirit (Koga OW sprite) http://oceanslugiaspirit.deviantart.com/
|
OceansLugiaSpirit (Koga OW sprite) http://oceanslugiaspirit.deviantart.com/
|
||||||
Wolfang62: https://www.deviantart.com/wolfang62/art/Wimpod-Sprite-Overworld-836704744
|
Wolfang62: https://www.deviantart.com/wolfang62/art/Wimpod-Sprite-Overworld-836704744
|
||||||
zender1752 (Sabrina OW sprite)
|
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
|
||||||
Battle sprites:
|
Battle sprites:
|
||||||
Custom graphics:
|
Custom graphics:
|
||||||
Kiwikelly, UnworthyPie
|
Kiwikelly, UnworthyPie
|
||||||
@@ -125,6 +166,9 @@ with their respective authors' consent
|
|||||||
luckygirl88 (Misty VS sprite) http://luckygirl88.deviantart.com/art/Pokemon-BW-Misty-Sprite-Sheet-268364830
|
luckygirl88 (Misty VS sprite) http://luckygirl88.deviantart.com/art/Pokemon-BW-Misty-Sprite-Sheet-268364830
|
||||||
Lorelei VS sprite by Nalty http://nalty.deviantart.com/art/Lorelei-VS-Sprite-177184960
|
Lorelei VS sprite by Nalty http://nalty.deviantart.com/art/Lorelei-VS-Sprite-177184960
|
||||||
x-5-4-5-2 (Sabrina sprite) https://www.deviantart.com/x-5-4-5-2/art/Game-Sabrina-204548703
|
x-5-4-5-2 (Sabrina sprite) https://www.deviantart.com/x-5-4-5-2/art/Game-Sabrina-204548703
|
||||||
|
|
||||||
|
Zender1752 (overworld mom sprite) https://www.deviantart.com/zender1752/art/Pokemon-Anime-Delia-Ketchum-Overworld-sprite-840038766
|
||||||
|
|
||||||
### Custom tileset graphics ###
|
### Custom tileset graphics ###
|
||||||
Kiwikelly
|
Kiwikelly
|
||||||
|
|
||||||
@@ -173,7 +217,7 @@ audreyeyeyeye https://www.deviantart.com/audreyeyeyeye/art/Pokemon-Type-Icons-FR
|
|||||||
|
|
||||||
|
|
||||||
### Other graphics
|
### Other graphics
|
||||||
Region map: Kiwikelly
|
Hoenn map: shivanking (Deviantart)
|
||||||
Move animations:
|
Move animations:
|
||||||
|
|
||||||
Augmented Reborn Animations Project
|
Augmented Reborn Animations Project
|
||||||
@@ -188,7 +232,12 @@ Move animations:
|
|||||||
### RPG Maker Scripts ###
|
### RPG Maker Scripts ###
|
||||||
###########################################################
|
###########################################################
|
||||||
|
|
||||||
andracass (Poké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
|
Luka S.J. Elite Battle System
|
||||||
Animated Title Screen (modified):
|
Animated Title Screen (modified):
|
||||||
shiney570 BW2 Summary script (+ graphics) http://reliccastle.com/forums/showthread.php?tid=1090
|
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Submodule Data/Scripts deleted from 69f15f20ab
Binary file not shown.
646
Data/Scripts/001_Settings.rb
Normal file
646
Data/Scripts/001_Settings.rb
Normal file
@@ -0,0 +1,646 @@
|
|||||||
|
#==============================================================================#
|
||||||
|
# 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.6.0'
|
||||||
|
GAME_VERSION_NUMBER = "6.6.0"
|
||||||
|
LATEST_GAME_RELEASE = "6.6"
|
||||||
|
|
||||||
|
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/Sprite Credits.csv"
|
||||||
|
CUSTOM_DEX_FILE_URL = "https://raw.githubusercontent.com/infinitefusion/pif-downloadables/refs/heads/master/dex.json"
|
||||||
|
|
||||||
|
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]
|
||||||
|
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
|
||||||
|
# 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 [
|
||||||
|
# [_INTL("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"],
|
||||||
|
# ["Deutsch", "deutsch.dat"]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
||||||
150
Data/Scripts/001_Technical/002_Files/003_HTTP_Utilities.rb
Normal file
150
Data/Scripts/001_Technical/002_Files/003_HTTP_Utilities.rb
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
#############################
|
||||||
|
#
|
||||||
|
# HTTP utility functions
|
||||||
|
#
|
||||||
|
#############################
|
||||||
|
#
|
||||||
|
|
||||||
|
def pbPostData(url, postdata, filename=nil, depth=0)
|
||||||
|
if url[/^http:\/\/([^\/]+)(.*)$/]
|
||||||
|
host = $1
|
||||||
|
path = $2
|
||||||
|
path = "/" if path.length==0
|
||||||
|
userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14"
|
||||||
|
body = postdata.map { |key, value|
|
||||||
|
keyString = key.to_s
|
||||||
|
valueString = value.to_s
|
||||||
|
keyString.gsub!(/[^a-zA-Z0-9_\.\-]/n) { |s| sprintf('%%%02x', s[0]) }
|
||||||
|
valueString.gsub!(/[^a-zA-Z0-9_\.\-]/n) { |s| sprintf('%%%02x', s[0]) }
|
||||||
|
next "#{keyString}=#{valueString}"
|
||||||
|
}.join('&')
|
||||||
|
ret = HTTPLite.post_body(
|
||||||
|
url,
|
||||||
|
body,
|
||||||
|
"application/x-www-form-urlencoded",
|
||||||
|
{
|
||||||
|
"Host" => host, # might not be necessary
|
||||||
|
"Proxy-Connection" => "Close",
|
||||||
|
"Content-Length" => body.bytesize.to_s,
|
||||||
|
"Pragma" => "no-cache",
|
||||||
|
"User-Agent" => userAgent
|
||||||
|
}
|
||||||
|
) 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
|
||||||
|
return ""
|
||||||
|
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)
|
||||||
|
begin
|
||||||
|
data = pbPostData(url, postdata)
|
||||||
|
return data
|
||||||
|
rescue
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbPostToFile(url, postdata, file)
|
||||||
|
begin
|
||||||
|
pbPostData(url, postdata,file)
|
||||||
|
rescue
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialize_value(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)
|
||||||
|
#echoln data
|
||||||
|
# Manually serialize the JSON data into a string
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
789
Data/Scripts/001_Technical/003_Intl_Messages.rb
Normal file
789
Data/Scripts/001_Technical/003_Intl_Messages.rb
Normal file
@@ -0,0 +1,789 @@
|
|||||||
|
def pbAddScriptTexts(items,script)
|
||||||
|
script.scan(/(?:_I)\s*\(\s*\"((?:[^\\\"]*\\\"?)*[^\"]*)\"/) { |s|
|
||||||
|
string=s[0]
|
||||||
|
string.gsub!(/\\\"/,"\"")
|
||||||
|
string.gsub!(/\\\\/,"\\")
|
||||||
|
items.push(string)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbAddRgssScriptTexts(items,script)
|
||||||
|
script.scan(/(?:_INTL|_ISPRINTF)\s*\(\s*\"((?:[^\\\"]*\\\"?)*[^\"]*)\"/) { |s|
|
||||||
|
string=s[0]
|
||||||
|
string.gsub!(/\\r/,"\r")
|
||||||
|
string.gsub!(/\\n/,"\n")
|
||||||
|
string.gsub!(/\\1/,"\1")
|
||||||
|
string.gsub!(/\\\"/,"\"")
|
||||||
|
string.gsub!(/\\\\/,"\\")
|
||||||
|
items.push(string)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbSetTextMessages
|
||||||
|
Graphics.update
|
||||||
|
begin
|
||||||
|
t = Time.now.to_i
|
||||||
|
texts=[]
|
||||||
|
for script in $RGSS_SCRIPTS
|
||||||
|
if Time.now.to_i - t >= 5
|
||||||
|
t = Time.now.to_i
|
||||||
|
Graphics.update
|
||||||
|
end
|
||||||
|
scr=Zlib::Inflate.inflate(script[2])
|
||||||
|
pbAddRgssScriptTexts(texts,scr)
|
||||||
|
end
|
||||||
|
if safeExists?("Data/PluginScripts.rxdata")
|
||||||
|
plugin_scripts = load_data("Data/PluginScripts.rxdata")
|
||||||
|
for plugin in plugin_scripts
|
||||||
|
for script in plugin[2]
|
||||||
|
if Time.now.to_i - t >= 5
|
||||||
|
t = Time.now.to_i
|
||||||
|
Graphics.update
|
||||||
|
end
|
||||||
|
scr = Zlib::Inflate.inflate(script[1]).force_encoding(Encoding::UTF_8)
|
||||||
|
pbAddRgssScriptTexts(texts,scr)
|
||||||
|
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
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user