mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2026-01-23 06:46:00 +00:00
update 6.7
This commit is contained in:
133
Data/Scripts/052_InfiniteFusion/System/Autosave.rb
Normal file
133
Data/Scripts/052_InfiniteFusion/System/Autosave.rb
Normal file
@@ -0,0 +1,133 @@
|
||||
|
||||
AUTOSAVE_ENABLED_SWITCH = 48
|
||||
AUTOSAVE_HEALING_VAR = 24
|
||||
AUTOSAVE_CATCH_SWITCH = 782
|
||||
AUTOSAVE_WIN_SWITCH = 783
|
||||
AUTOSAVE_STEPS_SWITCH = 784
|
||||
AUTOSAVE_STEPS_VAR = 236
|
||||
DEFAULT_AUTOSAVE_STEPS = 500
|
||||
|
||||
def pbSetPokemonCenter
|
||||
$PokemonGlobal.pokecenterMapId = $game_map.map_id
|
||||
$PokemonGlobal.pokecenterX = $game_player.x
|
||||
$PokemonGlobal.pokecenterY = $game_player.y
|
||||
$PokemonGlobal.pokecenterDirection = $game_player.direction
|
||||
if $game_variables[AUTOSAVE_HEALING_VAR]==0 && Settings::GAME_ID == :IF_KANTO
|
||||
pbSEPlay("save",100,100)
|
||||
Kernel.tryAutosave()
|
||||
end
|
||||
end
|
||||
|
||||
def Kernel.Autosave
|
||||
#Game.auto_save
|
||||
#showSaveIcon()
|
||||
pbSave(false)
|
||||
# #hideSaveIcon()
|
||||
end
|
||||
|
||||
|
||||
def Kernel.tryAutosave()
|
||||
return if !$Trainer.save_slot
|
||||
Kernel.Autosave if $game_switches[AUTOSAVE_ENABLED_SWITCH]
|
||||
end
|
||||
|
||||
Events.onMapUpdate += proc { |sender, e|
|
||||
next if !$game_switches
|
||||
next if !$game_switches[AUTOSAVE_STEPS_SWITCH]
|
||||
stepsNum = pbGet(AUTOSAVE_STEPS_VAR)
|
||||
if stepsNum > 0 && !$PokemonGlobal.sliding
|
||||
next if $PokemonGlobal.stepcount < 100
|
||||
if $PokemonGlobal.stepcount % stepsNum == 0
|
||||
$PokemonGlobal.stepcount += 1
|
||||
Kernel.tryAutosave()
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
|
||||
class AutosaveOptionsScene < PokemonOption_Scene
|
||||
def initialize
|
||||
@changedColor = false
|
||||
end
|
||||
|
||||
def pbStartScene(inloadscreen = false)
|
||||
super
|
||||
@sprites["option"].nameBaseColor = Color.new(35, 130, 200)
|
||||
@sprites["option"].nameShadowColor = Color.new(20, 75, 115)
|
||||
@changedColor = true
|
||||
for i in 0...@PokemonOptions.length
|
||||
@sprites["option"][i] = (@PokemonOptions[i].get || 0)
|
||||
end
|
||||
@sprites["title"]=Window_UnformattedTextPokemon.newWithSize(
|
||||
_INTL("Autosave settings"),0,0,Graphics.width,64,@viewport)
|
||||
@sprites["textbox"].text=_INTL("Customize the autosave settings")
|
||||
|
||||
|
||||
pbFadeInAndShow(@sprites) { pbUpdate }
|
||||
end
|
||||
|
||||
def pbFadeInAndShow(sprites, visiblesprites = nil)
|
||||
return if !@changedColor
|
||||
super
|
||||
end
|
||||
|
||||
def pbGetOptions(inloadscreen = false)
|
||||
options = [
|
||||
EnumOption.new(_INTL("When healing"), [_INTL("On"), _INTL("Off")],
|
||||
proc { $game_variables[AUTOSAVE_HEALING_VAR]},
|
||||
proc { |value|
|
||||
$game_variables[AUTOSAVE_HEALING_VAR]=value
|
||||
},
|
||||
_INTL("Autosave when healing at a Pokémon Center")
|
||||
),
|
||||
EnumOption.new(_INTL("When catching Pokémon"), [_INTL("On"), _INTL("Off")],
|
||||
proc { $game_switches[AUTOSAVE_CATCH_SWITCH] ? 0 : 1 },
|
||||
proc { |value|
|
||||
$game_switches[AUTOSAVE_CATCH_SWITCH] = value == 0
|
||||
},
|
||||
_INTL("Autosave everytime a new Pokémon is caught")
|
||||
),
|
||||
EnumOption.new(_INTL("After trainer battles"), [_INTL("On"), _INTL("Off")],
|
||||
proc { $game_switches[AUTOSAVE_WIN_SWITCH] ? 0 : 1 },
|
||||
proc { |value|
|
||||
$game_switches[AUTOSAVE_WIN_SWITCH] = value == 0
|
||||
},
|
||||
_INTL("Autosave after each trainer battle")
|
||||
),
|
||||
EnumOption.new(_INTL("Every x steps"), [_INTL("On"), _INTL("Off")],
|
||||
proc { $game_switches[AUTOSAVE_STEPS_SWITCH] ? 0 : 1 },
|
||||
proc { |value|
|
||||
if !$game_switches[AUTOSAVE_STEPS_SWITCH] && value == 0
|
||||
@set_steps = true
|
||||
selectAutosaveSteps()
|
||||
end
|
||||
$game_switches[AUTOSAVE_STEPS_SWITCH] = value == 0
|
||||
}, _INTL("Autosave after a defined amount of steps")
|
||||
)
|
||||
]
|
||||
return options
|
||||
end
|
||||
|
||||
|
||||
def selectAutosaveSteps()
|
||||
if pbGet(AUTOSAVE_STEPS_VAR) == 0
|
||||
pbSet(AUTOSAVE_STEPS_VAR,DEFAULT_AUTOSAVE_STEPS)
|
||||
end
|
||||
params=ChooseNumberParams.new
|
||||
params.setRange(20,999999)
|
||||
params.setInitialValue(pbGet(AUTOSAVE_STEPS_VAR))
|
||||
params.setCancelValue(0)
|
||||
val = Kernel.pbMessageChooseNumber(_INTL("Autosave every how many steps?"),params)
|
||||
if val < 200
|
||||
Kernel.pbMessage(_INTL("Warning: Choosing a low number of steps may decrease performance."))
|
||||
end
|
||||
if val == 0
|
||||
val = 1
|
||||
end
|
||||
pbSet(AUTOSAVE_STEPS_VAR,val)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
51
Data/Scripts/052_InfiniteFusion/System/DisplayText.rb
Normal file
51
Data/Scripts/052_InfiniteFusion/System/DisplayText.rb
Normal file
@@ -0,0 +1,51 @@
|
||||
def Kernel.pbDisplayText(message,xposition,yposition,z=nil, baseColor=nil, shadowColor=nil)
|
||||
if @hud==nil
|
||||
@hud = []
|
||||
end
|
||||
# Draw the text
|
||||
baseColor= baseColor ? baseColor : Color.new(72,72,72)
|
||||
shadowColor= shadowColor ? shadowColor : Color.new(160,160,160)
|
||||
sprite = BitmapSprite.new(Graphics.width,Graphics.height,@viewport1)
|
||||
if z != nil
|
||||
sprite.z=z
|
||||
end
|
||||
@hud.push(sprite)
|
||||
|
||||
text1=_INTL(message)
|
||||
textPosition=[
|
||||
[text1,xposition,yposition,2,baseColor,shadowColor],
|
||||
]
|
||||
pbSetSystemFont(@hud[-1].bitmap)
|
||||
pbDrawTextPositions(@hud[0].bitmap,textPosition)
|
||||
end
|
||||
|
||||
def Kernel.pbDisplayNumber(number,xposition,yposition)
|
||||
@numT = []
|
||||
# Draw the text
|
||||
baseColor=Color.new(72,72,72)
|
||||
shadowColor=Color.new(160,160,160)
|
||||
@numT.push(BitmapSprite.new(Graphics.width,Graphics.height,@viewport1))
|
||||
text1=_INTL(number.to_s)
|
||||
textPosition=[
|
||||
[text1,xposition,yposition,2,baseColor,shadowColor],
|
||||
]
|
||||
pbSetSystemFont(@numT[-1].bitmap)
|
||||
pbDrawTextPositions(@numT[0].bitmap,textPosition)
|
||||
end
|
||||
|
||||
def Kernel.pbClearNumber()
|
||||
if @numT != nil then
|
||||
for sprite in @numT
|
||||
sprite.dispose
|
||||
end
|
||||
@numT.clear
|
||||
end
|
||||
end
|
||||
def Kernel.pbClearText()
|
||||
if @hud != nil then
|
||||
for sprite in @hud
|
||||
sprite.dispose
|
||||
end
|
||||
@hud.clear
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,83 @@
|
||||
def setDifficulty(index)
|
||||
$Trainer.selected_difficulty = index
|
||||
case index
|
||||
when 0 # EASY
|
||||
$game_switches[SWITCH_GAME_DIFFICULTY_EASY] = true
|
||||
$game_switches[SWITCH_GAME_DIFFICULTY_HARD] = false
|
||||
when 1 # NORMAL
|
||||
$game_switches[SWITCH_GAME_DIFFICULTY_EASY] = false
|
||||
$game_switches[SWITCH_GAME_DIFFICULTY_HARD] = false
|
||||
when 2 # HARD
|
||||
$game_switches[SWITCH_GAME_DIFFICULTY_EASY] = false
|
||||
$game_switches[SWITCH_GAME_DIFFICULTY_HARD] = true
|
||||
end
|
||||
end
|
||||
|
||||
# Old menu for changing difficulty - unused
|
||||
def change_game_difficulty(down_only = false)
|
||||
message = _INTL("The game is currently on {1} difficulty.",get_difficulty_text())
|
||||
pbMessage(message)
|
||||
|
||||
choice_easy = _INTL("Easy")
|
||||
choice_normal = _INTL("Normal")
|
||||
choice_hard = _INTL("Hard")
|
||||
choice_cancel = _INTL("Cancel")
|
||||
|
||||
available_difficulties = []
|
||||
currentDifficulty = get_current_game_difficulty
|
||||
if down_only
|
||||
if currentDifficulty == :HARD
|
||||
available_difficulties << choice_hard
|
||||
available_difficulties << choice_normal
|
||||
available_difficulties << choice_easy
|
||||
elsif currentDifficulty == :NORMAL
|
||||
available_difficulties << choice_normal
|
||||
available_difficulties << choice_easy
|
||||
elsif currentDifficulty == :EASY
|
||||
available_difficulties << choice_easy
|
||||
end
|
||||
else
|
||||
available_difficulties << choice_easy
|
||||
available_difficulties << choice_normal
|
||||
available_difficulties << choice_hard
|
||||
end
|
||||
available_difficulties << choice_cancel
|
||||
index = pbMessage(_INTL("Select a new difficulty"), available_difficulties, available_difficulties[-1])
|
||||
choice = available_difficulties[index]
|
||||
case choice
|
||||
when choice_easy
|
||||
$game_switches[SWITCH_GAME_DIFFICULTY_EASY] = true
|
||||
$game_switches[SWITCH_GAME_DIFFICULTY_HARD] = false
|
||||
when choice_normal
|
||||
$game_switches[SWITCH_GAME_DIFFICULTY_EASY] = false
|
||||
$game_switches[SWITCH_GAME_DIFFICULTY_HARD] = false
|
||||
when choice_hard
|
||||
$game_switches[SWITCH_GAME_DIFFICULTY_EASY] = false
|
||||
$game_switches[SWITCH_GAME_DIFFICULTY_HARD] = true
|
||||
when choice_cancel
|
||||
return
|
||||
end
|
||||
|
||||
message = _INTL("The game is currently on {1} difficulty.",get_difficulty_text())
|
||||
pbMessage(message)
|
||||
end
|
||||
|
||||
# Get difficulty for displaying in-game
|
||||
def getDisplayDifficulty
|
||||
if $game_switches[SWITCH_GAME_DIFFICULTY_EASY] || $Trainer.lowest_difficulty <= 0
|
||||
return getDisplayDifficultyFromIndex(0)
|
||||
elsif $Trainer.lowest_difficulty <= 1
|
||||
return getDisplayDifficultyFromIndex(1)
|
||||
elsif $game_switches[SWITCH_GAME_DIFFICULTY_HARD]
|
||||
return getDisplayDifficultyFromIndex(2)
|
||||
else
|
||||
return getDisplayDifficultyFromIndex(1)
|
||||
end
|
||||
end
|
||||
|
||||
def getDisplayDifficultyFromIndex(difficultyIndex)
|
||||
return _INTL("Easy") if difficultyIndex == 0
|
||||
return _INTL("Normal") if difficultyIndex == 1
|
||||
return _INTL("Hard") if difficultyIndex == 2
|
||||
return "???"
|
||||
end
|
||||
@@ -0,0 +1,35 @@
|
||||
def getGameModeFromIndex(index)
|
||||
return _INTL("Classic") if index == 0
|
||||
return _INTL("Random") if index == 1
|
||||
return _INTL("Remix") if index == 2
|
||||
return _INTL("Expert") if index == 3
|
||||
return _INTL("Species") if index == 4
|
||||
return _INTL("Debug") if index == 5
|
||||
return ""
|
||||
end
|
||||
|
||||
def getCurrentGameModeSymbol()
|
||||
gameMode = :CLASSIC
|
||||
if $game_switches[SWITCH_MODERN_MODE]
|
||||
gameMode = :REMIX
|
||||
end
|
||||
if $game_switches[SWITCH_EXPERT_MODE]
|
||||
gameMode = :EXPERT
|
||||
end
|
||||
if $game_switches[SWITCH_SINGLE_POKEMON_MODE]
|
||||
pokemon_number = pbGet(VAR_SINGLE_POKEMON_MODE)
|
||||
if pokemon_number.is_a?(Integer) && pokemon_number > 0
|
||||
gameMode = :SINGLE_SPECIES
|
||||
else
|
||||
gameMode = :DEBUG
|
||||
end
|
||||
end
|
||||
if $game_switches[SWITCH_RANDOMIZED_AT_LEAST_ONCE]
|
||||
gameMode = :RANDOMIZED
|
||||
end
|
||||
|
||||
if $game_switches[SWITCH_LEGENDARY_MODE]
|
||||
gameMode = :LEGENDARY
|
||||
end
|
||||
return gameMode
|
||||
end
|
||||
@@ -0,0 +1,170 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
GYM_TRAINERS = []
|
||||
GYM_LEADER_MAX_RETRIES = 20
|
||||
# def generate_legendaries_mode_trainers()
|
||||
# echoln "Converting trainers to legendary mode..."
|
||||
# trainers_list = getTrainersDataMode.list_all
|
||||
# for trainer_array in trainers_list
|
||||
# trainer = trainer_array[1]
|
||||
# echoln "------"
|
||||
# echoln "Processing [#{trainer.id}#] {trainer.traiàner_type} ##{trainer.real_name}"
|
||||
# new_party=[]
|
||||
# old_party = trainer.pokemon
|
||||
# for pokemon in old_party
|
||||
# species = pokemon[:species]
|
||||
# new_species = convert_species_to_legendary(species)
|
||||
# #echoln "#{get_readable_fusion_name(species)} -> #{get_readable_fusion_name(new_species)}"
|
||||
# end
|
||||
#
|
||||
# end
|
||||
# end
|
||||
|
||||
def initializeLegendaryMode()
|
||||
$game_variables[VAR_CURRENT_GYM_TYPE] = -1
|
||||
$game_switches[SWITCH_RANDOM_TRAINERS] = true
|
||||
$game_switches[SWITCH_RANDOMIZE_GYMS_SEPARATELY] = true
|
||||
$game_switches[SWITCH_GYM_RANDOM_EACH_BATTLE] = false
|
||||
$game_switches[SWITCH_RANDOM_GYM_PERSIST_TEAMS] = true
|
||||
$game_switches[SWITCH_LEGENDARY_MODE] = true
|
||||
|
||||
addLegendaryEggsToPC
|
||||
$PokemonSystem.hide_custom_eggs = true
|
||||
$PokemonSystem.type_icons = true
|
||||
end
|
||||
|
||||
def convert_species_to_legendary(dex_number)
|
||||
species = GameData::Species.get(dex_number).species
|
||||
dex_number = getDexNumberForSpecies(species)
|
||||
return species if isTripleFusion?(dex_number)
|
||||
isFusion = isFusion(dex_number)
|
||||
new_species = isFusion ? convert_fusion_to_legendary(species) : convert_unfused_to_legendary(species)
|
||||
echoln "#{get_readable_fusion_name(species)} -> #{get_readable_fusion_name(new_species)}"
|
||||
return new_species
|
||||
end
|
||||
|
||||
# Takes an unfused Pokemon and fuses it with a random legendary
|
||||
def convert_unfused_to_legendary(unfused_species)
|
||||
legendary_species = LEGENDARIES_LIST.sample
|
||||
pokemon_to_fuse = [unfused_species, legendary_species].shuffle
|
||||
|
||||
head_species = pokemon_to_fuse[0]
|
||||
body_species = pokemon_to_fuse[1]
|
||||
|
||||
fusion_species = getFusionSpecies(body_species, head_species)
|
||||
if customSpriteExists(body_species, head_species) # && pokemonHasCorrectType(fusion_species)
|
||||
return fusion_species.species
|
||||
else
|
||||
# Try again
|
||||
return convert_unfused_to_legendary(unfused_species)
|
||||
end
|
||||
end
|
||||
|
||||
def convert_fusion_to_legendary(species, nb_retries = 0)
|
||||
permissive_type_validation = nb_retries >= GYM_LEADER_MAX_RETRIES
|
||||
if isInGym? && !permissive_type_validation
|
||||
getNewLegendaryFusionForGymType(species, nb_retries)
|
||||
else
|
||||
getNewLegendaryFusion(species, nb_retries)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def getNewLegendaryFusion(original_species, nb_retries = 0)
|
||||
head_species = get_head_id_from_symbol(original_species)
|
||||
body_species = get_body_id_from_symbol(original_species)
|
||||
|
||||
if rand(2) == 0
|
||||
head_species = LEGENDARIES_LIST.sample
|
||||
else
|
||||
body_species = LEGENDARIES_LIST.sample
|
||||
end
|
||||
|
||||
if customSpriteExists(body_species, head_species)
|
||||
return getFusionSpecies(body_species, head_species).species
|
||||
else
|
||||
# Try again
|
||||
return getNewLegendaryFusion(original_species, nb_retries + 1)
|
||||
end
|
||||
end
|
||||
|
||||
# In gyms, the game tries to figure out which of the head and body is of the
|
||||
# gym's type and replaces the other one with a legendary.
|
||||
# If there isn't one, it will eventually go in permissive mode and
|
||||
# replace either one
|
||||
def getNewLegendaryFusionForGymType(original_species, nb_retries = 0)
|
||||
return getNewLegendaryFusion(original_species, nb_retries) if nb_retries > GYM_LEADER_MAX_RETRIES
|
||||
|
||||
head_species_id = get_head_id_from_symbol(original_species)
|
||||
body_species_id = get_body_id_from_symbol(original_species)
|
||||
|
||||
head_species = GameData::Species.get(head_species_id)
|
||||
body_species = GameData::Species.get(body_species_id)
|
||||
|
||||
gym_type = getLeaderType()
|
||||
base_pokemon_with_gym_type = [head_species, body_species].select do |species|
|
||||
GameData::Species.get(species).hasType?(gym_type)
|
||||
end
|
||||
return getNewLegendaryFusion(original_species, nb_retries) if base_pokemon_with_gym_type.empty?
|
||||
|
||||
if base_pokemon_with_gym_type.length == 2
|
||||
pokemon_to_be_kept = base_pokemon_with_gym_type.sample
|
||||
pokemon_to_be_replaced = (base_pokemon_with_gym_type - [pokemon_to_be_kept]).first
|
||||
elsif base_pokemon_with_gym_type.length == 1
|
||||
# Only one has the gym type — keep it
|
||||
pokemon_to_be_kept = base_pokemon_with_gym_type.first
|
||||
pokemon_to_be_replaced = (pokemon_to_be_kept == head_species) ? body_species : head_species
|
||||
else #Neither have the type, just pick at random
|
||||
pokemon_to_be_kept = base_pokemon_with_gym_type.sample
|
||||
pokemon_to_be_replaced = (base_pokemon_with_gym_type - [pokemon_to_be_kept]).first
|
||||
end
|
||||
|
||||
echoln "gymType: #{gym_type} - body_species: #{body_species.species} head_species: #{head_species.species}, kept: #{pokemon_to_be_kept.species}"
|
||||
|
||||
legendary_species = LEGENDARIES_LIST.sample
|
||||
|
||||
if pokemon_to_be_replaced.species == head_species.species
|
||||
head_species_id = legendary_species
|
||||
else
|
||||
body_species_id = legendary_species
|
||||
end
|
||||
echoln "picked #{head_species_id}/#{body_species_id}"
|
||||
echoln "custom sprite exists: #{customSpriteExists(body_species_id, head_species_id)}"
|
||||
if customSpriteExists(body_species_id, head_species_id)
|
||||
return getFusionSpecies(body_species_id, head_species_id).species
|
||||
else
|
||||
return getNewLegendaryFusionForGymType(original_species, nb_retries + 1)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def isInGym?()
|
||||
return $game_variables[VAR_CURRENT_GYM_TYPE] != -1 && $game_variables[VAR_CURRENT_GYM_TYPE]<= GYM_TYPES_ARRAY.length
|
||||
end
|
||||
|
||||
def pokemonHasCorrectType(species)
|
||||
return true if !isInGym? # not in a gym
|
||||
leaderType = getLeaderType()
|
||||
if leaderType == nil
|
||||
return true
|
||||
else
|
||||
return species.hasType?(leaderType)
|
||||
end
|
||||
end
|
||||
|
||||
def addLegendaryEggsToPC()
|
||||
legendaries_species = LEGENDARIES_LIST.shuffle
|
||||
legendaries_species.each do |species|
|
||||
pokemon = Pokemon.new(species, Settings::EGG_LEVEL)
|
||||
pokemon.steps_to_hatch = pokemon.species_data.hatch_steps
|
||||
pokemon.name = "Egg"
|
||||
$PokemonStorage.pbStoreCaught(pokemon)
|
||||
end
|
||||
end
|
||||
|
||||
def generate_legendary_mode_starters
|
||||
grass_option = getFusionSpecies(Settings::GRASS_STARTERS.sample,LEGENDARIES_LIST.sample)
|
||||
fire_option = getFusionSpecies(Settings::FIRE_STARTERS.sample,LEGENDARIES_LIST.sample)
|
||||
water_option = getFusionSpecies(Settings::WATER_STARTERS.sample,LEGENDARIES_LIST.sample)
|
||||
return [grass_option, fire_option, water_option]
|
||||
end
|
||||
282
Data/Scripts/052_InfiniteFusion/System/GameOptions.rb
Normal file
282
Data/Scripts/052_InfiniteFusion/System/GameOptions.rb
Normal file
@@ -0,0 +1,282 @@
|
||||
class PokemonGameOption_Scene < PokemonOption_Scene
|
||||
def pbGetOptions(inloadscreen = false)
|
||||
@current_game_mode = getTrainersDataMode
|
||||
options = []
|
||||
options << SliderOption.new(_INTL("Music Volume"), 0, 100, 5,
|
||||
proc { $PokemonSystem.bgmvolume },
|
||||
proc { |value|
|
||||
if $PokemonSystem.bgmvolume != value
|
||||
$PokemonSystem.bgmvolume = value
|
||||
if $game_system.playing_bgm != nil && !inloadscreen
|
||||
playingBGM = $game_system.getPlayingBGM
|
||||
$game_system.bgm_pause
|
||||
$game_system.bgm_resume(playingBGM)
|
||||
end
|
||||
end
|
||||
}, _INTL("Sets the volume for background music")
|
||||
)
|
||||
|
||||
options << SliderOption.new(_INTL("SE Volume"), 0, 100, 5,
|
||||
proc { $PokemonSystem.sevolume },
|
||||
proc { |value|
|
||||
if $PokemonSystem.sevolume != value
|
||||
$PokemonSystem.sevolume = value
|
||||
if $game_system.playing_bgs != nil
|
||||
$game_system.playing_bgs.volume = value
|
||||
playingBGS = $game_system.getPlayingBGS
|
||||
$game_system.bgs_pause
|
||||
$game_system.bgs_resume(playingBGS)
|
||||
end
|
||||
pbPlayCursorSE
|
||||
end
|
||||
}, _INTL("Sets the volume for sound effects")
|
||||
)
|
||||
|
||||
options << EnumOption.new(_INTL("Default Movement"), [_INTL("Walking"), _INTL("Running")],
|
||||
proc { $PokemonSystem.runstyle },
|
||||
proc { |value| $PokemonSystem.runstyle = value },
|
||||
[_INTL("Default to walking when not holding the Run key"),
|
||||
_INTL("Default to running when not holding the Run key")]
|
||||
)
|
||||
|
||||
options << EnumOption.new(_INTL("Text Speed"), [_INTL("Normal"), _INTL("Fast")],
|
||||
proc { $PokemonSystem.textspeed },
|
||||
proc { |value|
|
||||
$PokemonSystem.textspeed = value
|
||||
MessageConfig.pbSetTextSpeed(MessageConfig.pbSettingToTextSpeed(value))
|
||||
}, _INTL("Sets the speed at which the text is displayed")
|
||||
)
|
||||
if $game_switches
|
||||
options << EnumOption.new(_INTL("Difficulty"), [_INTL("Easy"), _INTL("Normal"), _INTL("Hard")],
|
||||
proc { $Trainer.selected_difficulty },
|
||||
proc { |value|
|
||||
setDifficulty(value)
|
||||
@manually_changed_difficulty = true
|
||||
}, [_INTL("All Pokémon in the team gain experience. Otherwise the same as Normal difficulty."),
|
||||
_INTL("The default experience. Levels are similar to the official games."),
|
||||
_INTL("Higher levels and smarter AI. All trainers have access to healing items.")]
|
||||
)
|
||||
end
|
||||
|
||||
if $game_switches
|
||||
options <<
|
||||
EnumOption.new(_INTL("Autosave"), [_INTL("On"), _INTL("Off")],
|
||||
proc { $game_switches[AUTOSAVE_ENABLED_SWITCH] ? 0 : 1 },
|
||||
proc { |value|
|
||||
if !$game_switches[AUTOSAVE_ENABLED_SWITCH] && value == 0
|
||||
@autosave_menu = true
|
||||
openAutosaveMenu()
|
||||
end
|
||||
$game_switches[AUTOSAVE_ENABLED_SWITCH] = value == 0
|
||||
},
|
||||
_INTL("Automatically saves when healing at Pokémon centers")
|
||||
)
|
||||
end
|
||||
|
||||
options << EnumOption.new(_INTL("Speed-up type"), [_INTL("Hold"), _INTL("Toggle")],
|
||||
proc { $PokemonSystem.speedup },
|
||||
proc { |value|
|
||||
$PokemonSystem.speedup = value
|
||||
}, _INTL("Pick how you want speed-up to be enabled")
|
||||
)
|
||||
|
||||
options << SliderOption.new(_INTL("Speed-up speed"), 1, 10, 1,
|
||||
proc { $PokemonSystem.speedup_speed },
|
||||
proc { |value|
|
||||
$PokemonSystem.speedup_speed = value
|
||||
}, _INTL("Sets by how much to speed up the game when holding the speed up button (Default: 3x)")
|
||||
)
|
||||
# if $game_switches && ($game_switches[SWITCH_NEW_GAME_PLUS] || $game_switches[SWITCH_BEAT_THE_LEAGUE]) #beat the league
|
||||
# options << EnumOption.new("Text Speed", ["Normal", "Fast", "Instant"],
|
||||
# proc { $PokemonSystem.textspeed },
|
||||
# proc { |value|
|
||||
# $PokemonSystem.textspeed = value
|
||||
# MessageConfig.pbSetTextSpeed(MessageConfig.pbSettingToTextSpeed(value))
|
||||
# }, "Sets the speed at which the text is displayed"
|
||||
# )
|
||||
# else
|
||||
# options << EnumOption.new("Text Speed", ["Normal", "Fast"],
|
||||
# proc { $PokemonSystem.textspeed },
|
||||
# proc { |value|
|
||||
# $PokemonSystem.textspeed = value
|
||||
# MessageConfig.pbSetTextSpeed(MessageConfig.pbSettingToTextSpeed(value))
|
||||
# }, "Sets the speed at which the text is displayed"
|
||||
# )
|
||||
# end
|
||||
options <<
|
||||
EnumOption.new(_INTL("Download data"), [_INTL("On"), _INTL("Off")],
|
||||
proc { $PokemonSystem.download_sprites },
|
||||
proc { |value|
|
||||
$PokemonSystem.download_sprites = value
|
||||
},
|
||||
_INTL("Automatically download missing custom sprites and Pokédex entries from the internet")
|
||||
)
|
||||
#
|
||||
generated_entries_option_selected = $PokemonSystem.use_generated_dex_entries ? 1 : 0
|
||||
options << EnumOption.new(_INTL("Autogen dex entries"), [_INTL("Off"), _INTL("On")],
|
||||
proc { generated_entries_option_selected },
|
||||
proc { |value|
|
||||
$PokemonSystem.use_generated_dex_entries = value == 1
|
||||
},
|
||||
[
|
||||
_INTL("Fusions without a custom Pokédex entry display nothing."),
|
||||
_INTL("Fusions without a custom Pokédex entry display an auto-generated placeholder.")
|
||||
|
||||
]
|
||||
)
|
||||
|
||||
generated_entries_option_selected = $PokemonSystem.include_alt_sprites_in_random ? 1 : 0
|
||||
options << EnumOption.new(_INTL("Sprite categories"), [_INTL("Normal"), _INTL("Anything")],
|
||||
proc { generated_entries_option_selected },
|
||||
proc { |value|
|
||||
$PokemonSystem.include_alt_sprites_in_random = value == 1
|
||||
},
|
||||
[
|
||||
_INTL("Auto-selected sprites follow standard Pokémon sprites rules."),
|
||||
_INTL("Auto-selected sprites can be anything, including references, memes, jokes, etc.")
|
||||
]
|
||||
) ? 1 : 0
|
||||
|
||||
custom_eggs_option_selected = $PokemonSystem.hide_custom_eggs ? 1 : 0
|
||||
options << EnumOption.new(_INTL("Custom Eggs"), [_INTL("On"), _INTL("Off")],
|
||||
proc { custom_eggs_option_selected },
|
||||
proc { |value|
|
||||
$PokemonSystem.hide_custom_eggs = value == 1
|
||||
},
|
||||
[_INTL("Eggs have different sprites for each Pokémon."),
|
||||
_INTL("Eggs all use the same sprite.")]
|
||||
)
|
||||
|
||||
if $game_switches && ($game_switches[SWITCH_NEW_GAME_PLUS] || $game_switches[SWITCH_BEAT_THE_LEAGUE]) # beat the league
|
||||
options <<
|
||||
EnumOption.new(_INTL("Battle type"), [_INTL("1v1"), _INTL("2v2"), _INTL("3v3")],
|
||||
proc { $PokemonSystem.battle_type },
|
||||
proc { |value|
|
||||
if value == 0
|
||||
$game_variables[VAR_DEFAULT_BATTLE_TYPE] = [1, 1]
|
||||
elsif value == 1
|
||||
$game_variables[VAR_DEFAULT_BATTLE_TYPE] = [2, 2]
|
||||
elsif value == 2
|
||||
$game_variables[VAR_DEFAULT_BATTLE_TYPE] = [3, 3]
|
||||
else
|
||||
$game_variables[VAR_DEFAULT_BATTLE_TYPE] = [1, 1]
|
||||
end
|
||||
$PokemonSystem.battle_type = value
|
||||
}, _INTL("Sets the number of Pokémon sent out in battles (when possible)")
|
||||
)
|
||||
end
|
||||
|
||||
options << EnumOption.new(_INTL("Battle Effects"), [_INTL("On"), _INTL("Off")],
|
||||
proc { $PokemonSystem.battlescene },
|
||||
proc { |value| $PokemonSystem.battlescene = value },
|
||||
_INTL("Display move animations in battles")
|
||||
)
|
||||
|
||||
options << EnumOption.new(_INTL("Battle Style"), [_INTL("Switch"), _INTL("Set")],
|
||||
proc { $PokemonSystem.battlestyle },
|
||||
proc { |value| $PokemonSystem.battlestyle = value },
|
||||
[_INTL("Prompts to switch Pokémon before the opponent sends out the next one"),
|
||||
_INTL("No prompt to switch Pokémon before the opponent sends the next one")]
|
||||
)
|
||||
|
||||
options << NumberOption.new(_INTL("Speech Frame"), 1, Settings::SPEECH_WINDOWSKINS.length,
|
||||
proc { $PokemonSystem.textskin },
|
||||
proc { |value|
|
||||
$PokemonSystem.textskin = value
|
||||
MessageConfig.pbSetSpeechFrame("Graphics/Windowskins/" + Settings::SPEECH_WINDOWSKINS[value])
|
||||
}
|
||||
)
|
||||
# NumberOption.new("Menu Frame",1,Settings::MENU_WINDOWSKINS.length,
|
||||
# proc { $PokemonSystem.frame },
|
||||
# proc { |value|
|
||||
# $PokemonSystem.frame = value
|
||||
# MessageConfig.pbSetSystemFrame("Graphics/Windowskins/" + Settings::MENU_WINDOWSKINS[value])
|
||||
# }
|
||||
# ),
|
||||
options << EnumOption.new(_INTL("Text Entry"), [_INTL("Cursor"), _INTL("Keyboard")],
|
||||
proc { $PokemonSystem.textinput },
|
||||
proc { |value| $PokemonSystem.textinput = value },
|
||||
[_INTL("Enter text by selecting letters on the screen"),
|
||||
_INTL("Enter text by typing on the keyboard")]
|
||||
)
|
||||
if $game_variables
|
||||
options << EnumOption.new(_INTL("Fusion Icons"), [_INTL("Combined"), _INTL("DNA")],
|
||||
proc { $game_variables[VAR_FUSION_ICON_STYLE] },
|
||||
proc { |value| $game_variables[VAR_FUSION_ICON_STYLE] = value },
|
||||
[_INTL("Combines both Pokémon's party icons"),
|
||||
_INTL("Uses the same party icon for all fusions")]
|
||||
)
|
||||
battle_type_icon_option_selected = $PokemonSystem.type_icons ? 1 : 0
|
||||
options << EnumOption.new(_INTL("Battle Type Icons"), [_INTL("Off"), _INTL("On")],
|
||||
proc { battle_type_icon_option_selected },
|
||||
proc { |value| $PokemonSystem.type_icons = value == 1 },
|
||||
_INTL("Display the enemy Pokémon type in battles.")
|
||||
)
|
||||
|
||||
end
|
||||
options << EnumOption.new(_INTL("Screen Size"), [_INTL("S"), _INTL("M"), _INTL("L"), _INTL("XL"), _INTL("Full")],
|
||||
proc { [$PokemonSystem.screensize, 4].min },
|
||||
proc { |value|
|
||||
if $PokemonSystem.screensize != value
|
||||
$PokemonSystem.screensize = value
|
||||
pbSetResizeFactor($PokemonSystem.screensize)
|
||||
echoln $PokemonSystem.screensize
|
||||
end
|
||||
}, _INTL("Sets the size of the screen")
|
||||
)
|
||||
options << EnumOption.new(_INTL("Quick Surf"), [_INTL("Off"), _INTL("On")],
|
||||
proc { $PokemonSystem.quicksurf },
|
||||
proc { |value| $PokemonSystem.quicksurf = value },
|
||||
_INTL("Start surfing automatically when interacting with water")
|
||||
)
|
||||
|
||||
options << EnumOption.new(_INTL("Level caps"), [_INTL("Off"), _INTL("On")],
|
||||
proc { $PokemonSystem.level_caps },
|
||||
proc { |value| $PokemonSystem.level_caps = value },
|
||||
_INTL("Prevents leveling above the next gym leader's highest leveled Pokemon")
|
||||
)
|
||||
|
||||
device_option_selected = $PokemonSystem.on_mobile ? 1 : 0
|
||||
options << EnumOption.new(_INTL("Device"), [_INTL("PC"), _INTL("Mobile")],
|
||||
proc { device_option_selected },
|
||||
proc { |value| $PokemonSystem.on_mobile = value == 1 },
|
||||
["The intended device on which to play the game.",
|
||||
_INTL("Disables some options that aren't supported when playing on mobile.")]
|
||||
)
|
||||
|
||||
if $game_switches && $game_switches[SWITCH_LEGENDARY_MODE]
|
||||
selected_game_mode = $game_switches[SWITCH_MODERN_MODE] ? 1 : 0
|
||||
options << EnumOption.new(_INTL("Trainers"), [_INTL("Classic"), _INTL("Remix")],
|
||||
proc { selected_game_mode },
|
||||
proc { |value|
|
||||
$game_switches[SWITCH_MODERN_MODE] = value == 1
|
||||
@manually_changed_gamemode = true
|
||||
},
|
||||
[_INTL("Use trainers from Classic Mode for Legendary Mode"),
|
||||
_INTL("Use trainers from Remix Mode for Legendary Mode")]
|
||||
)
|
||||
end
|
||||
return options
|
||||
end
|
||||
|
||||
def pbEndScene
|
||||
echoln "Selected Difficulty: #{$Trainer.selected_difficulty}, lowest difficutly: #{$Trainer.lowest_difficulty}" if $Trainer
|
||||
if $Trainer && $Trainer.selected_difficulty < $Trainer.lowest_difficulty
|
||||
$Trainer.lowest_difficulty = $Trainer.selected_difficulty
|
||||
echoln "lowered difficulty (#{$Trainer.selected_difficulty})"
|
||||
if @manually_changed_difficulty
|
||||
pbMessage(_INTL("The savefile's lowest selected difficulty was changed to #{getDisplayDifficulty()}."))
|
||||
@manually_changed_difficulty = false
|
||||
end
|
||||
end
|
||||
|
||||
if getTrainersDataMode != @current_game_mode
|
||||
pbMessage(_INTL("The game was mode changed - Reshuffling trainers."))
|
||||
Kernel.pbShuffleTrainers
|
||||
@manually_changed_gamemode = false
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
440
Data/Scripts/052_InfiniteFusion/System/HttpCalls.rb
Normal file
440
Data/Scripts/052_InfiniteFusion/System/HttpCalls.rb
Normal file
@@ -0,0 +1,440 @@
|
||||
def test_http_get
|
||||
url = "http://localhost:8080"
|
||||
response = HTTPLite.get(url)
|
||||
if response[:status] == 200
|
||||
p response[:body]
|
||||
end
|
||||
end
|
||||
|
||||
def updateHttpSettingsFile
|
||||
return if !downloadAllowed?()
|
||||
echoln "UPDATING SETTINGS"
|
||||
download_file(Settings::HTTP_CONFIGS_FILE_URL, Settings::HTTP_CONFIGS_FILE_PATH,)
|
||||
end
|
||||
|
||||
def updateCreditsFile
|
||||
return if !downloadAllowed?()
|
||||
download_file(Settings::CREDITS_FILE_URL, Settings::CREDITS_FILE_PATH,)
|
||||
end
|
||||
|
||||
def updateCustomDexFile
|
||||
return if !downloadAllowed?()
|
||||
download_file(Settings::CUSTOM_DEX_FILE_URL, Settings::CUSTOM_DEX_ENTRIES_PATH,)
|
||||
end
|
||||
|
||||
def createCustomSpriteFolders()
|
||||
if !Dir.exist?(Settings::CUSTOM_BATTLERS_FOLDER)
|
||||
Dir.mkdir(Settings::CUSTOM_BATTLERS_FOLDER)
|
||||
end
|
||||
if !Dir.exist?(Settings::CUSTOM_BATTLERS_FOLDER_INDEXED)
|
||||
Dir.mkdir(Settings::CUSTOM_BATTLERS_FOLDER_INDEXED)
|
||||
end
|
||||
end
|
||||
|
||||
def download_file(url, saveLocation)
|
||||
echoln url
|
||||
begin
|
||||
response = HTTPLite.get(url)
|
||||
if response[:status] == 200
|
||||
File.open(saveLocation, "wb") do |file|
|
||||
file.write(response[:body])
|
||||
end
|
||||
echoln _INTL("\nDownloaded file {1} to {2}", url, saveLocation)
|
||||
return saveLocation
|
||||
else
|
||||
echoln _INTL("Failed to download file {1}", url)
|
||||
end
|
||||
return nil
|
||||
rescue MKXPError, Errno::ENOENT => error
|
||||
echo error
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
#Returns:
|
||||
# A file was downloaded ->true
|
||||
# A file was not downloaded -> false
|
||||
# #
|
||||
#TODO:
|
||||
# This method bypasses the client-side rate limiting
|
||||
# MAKE SURE TO ALWAYS CHECK requestRateExceeded? BEFORE CALLING THIS METHOD
|
||||
# #
|
||||
def fetch_sprite_from_web(url, destinationPath)
|
||||
return false if !downloadAllowed?()
|
||||
begin
|
||||
|
||||
response = HTTPLite.get(url)
|
||||
if response[:status] == 200
|
||||
File.open(destinationPath, "wb") do |file|
|
||||
file.write(response[:body])
|
||||
end
|
||||
echoln "Downloaded #{url} to #{destinationPath}"
|
||||
return true
|
||||
end
|
||||
echoln "Failed to download #{url}"
|
||||
return false
|
||||
rescue MKXPError => e
|
||||
echoln "MKXPError: #{e.message}"
|
||||
return false
|
||||
rescue Errno::ENOENT => e
|
||||
echoln "File Error: #{e.message}"
|
||||
return false
|
||||
rescue Exception => e
|
||||
echoln "Error: #{e.message}"
|
||||
end
|
||||
end
|
||||
|
||||
def download_spritesheet(pif_sprite, dest)
|
||||
return nil if requestRateExceeded?(Settings::CUSTOMSPRITES_RATE_LOG_FILE,Settings::CUSTOMSPRITES_ENTRIES_RATE_TIME_WINDOW,Settings::CUSTOMSPRITES_RATE_MAX_NB_REQUESTS)
|
||||
case pif_sprite.type
|
||||
when :AUTOGEN
|
||||
return
|
||||
when :CUSTOM
|
||||
url = Settings::
|
||||
CUSTOM_FUSIONS_SPRITESHEET_TRUE_SIZE_URL + "#{pif_sprite.head_id}/#{pif_sprite.head_id}#{pif_sprite.alt_letter}.png"
|
||||
when :BASE
|
||||
url = Settings::BASE_POKEMON_SPRITESHEET_TRUE_SIZE_URL + "#{pif_sprite.head_id}.png"
|
||||
end
|
||||
folder = File.dirname(dest)
|
||||
ensure_folder_exists(folder)
|
||||
|
||||
fetchedFromWeb = fetch_sprite_from_web(url, dest)
|
||||
return fetchedFromWeb
|
||||
end
|
||||
|
||||
def ensure_folder_exists(folder)
|
||||
# Recursively create directories if they don't exist
|
||||
unless Dir.exist?(folder)
|
||||
parent = File.dirname(folder)
|
||||
ensure_folder_exists(parent) unless Dir.exist?(parent)
|
||||
Dir.mkdir(folder)
|
||||
end
|
||||
end
|
||||
|
||||
#Returns: The local path of the downloaded sprite
|
||||
# def download_sprite(base_path, head_id, body_id, saveLocation = "Graphics/temp", alt_letter = "")
|
||||
# return nil if requestRateExceeded?(Settings::CUSTOMSPRITES_RATE_LOG_FILE,Settings::CUSTOMSPRITES_ENTRIES_RATE_TIME_WINDOW,Settings::CUSTOMSPRITES_RATE_MAX_NB_REQUESTS)
|
||||
# filename = "#{head_id}.#{body_id}#{alt_letter}.png"
|
||||
# filename = "#{head_id}#{alt_letter}.png" if !body_id #unfused
|
||||
#
|
||||
# #check if it's in the Custom sprites list if it's a fusion
|
||||
# if head_id && body_id
|
||||
# return nil if !custom_exists(filename)
|
||||
# end
|
||||
#
|
||||
# begin
|
||||
# head_id = head_id.to_s
|
||||
# body_id = body_id.to_s
|
||||
#
|
||||
# downloaded_file_name = "{1}/{2}.{3}{4}.png", saveLocation, head_id, body_id, alt_letter
|
||||
# if !body_id || body_id == ""
|
||||
# downloaded_file_name = "{1}{2}{3}.png", saveLocation, head_id, alt_letter
|
||||
# end
|
||||
#
|
||||
# return downloaded_file_name if pbResolveBitmap(downloaded_file_name)
|
||||
#
|
||||
# url = base_path, head_id, body_id
|
||||
# if !body_id
|
||||
# url = base_path, head_id
|
||||
# end
|
||||
# if fetch_sprite_from_web(url,downloaded_file_name)
|
||||
# return downloaded_file_name
|
||||
# end
|
||||
# return nil
|
||||
# rescue MKXPError => e
|
||||
# echoln "MKXPError: #{e.message}"
|
||||
# return nil
|
||||
# rescue Errno::ENOENT => e
|
||||
# echoln "File Error: #{e.message}"
|
||||
# return nil
|
||||
# end
|
||||
# end
|
||||
|
||||
def custom_exists(target_file)
|
||||
file_path = Settings::CUSTOM_SPRITES_FILE_PATH
|
||||
|
||||
# Read the file and store its lines in an array, removing newlines
|
||||
file_list = File.readlines(file_path, chomp: true)
|
||||
# Perform binary search
|
||||
low = 0
|
||||
high = file_list.length - 1
|
||||
while low <= high
|
||||
mid = (low + high) / 2
|
||||
case file_list[mid] <=> target_file
|
||||
when 0
|
||||
return true # Found the target file
|
||||
when -1
|
||||
low = mid + 1 # Target is in the upper half
|
||||
when 1
|
||||
high = mid - 1 # Target is in the lower half
|
||||
end
|
||||
end
|
||||
return false # Target file not found
|
||||
end
|
||||
|
||||
#
|
||||
# Autogens are no longer downloaded from the web. Instead, the game comes with spritesheets, from which
|
||||
# it extracts the sprites and puts them in individual files (for faster loading)
|
||||
#
|
||||
def download_autogen_sprite(head_id, body_id)
|
||||
#return nil if !downloadAllowed?()
|
||||
#template_url = Settings::AUTOGEN_SPRITES_REPO_URL + "{1}/{1}.{2}.png"
|
||||
|
||||
destPath = "#{Settings::BATTLERS_FOLDER}#{head_id}"
|
||||
autogenExtracter = AutogenExtracter.new
|
||||
return autogenExtracter.extract_bitmap_to_file(PIFSprite.new(:AUTOGEN, head_id, body_id), destPath)
|
||||
|
||||
# url = template_url, head_id, body_id
|
||||
# sprite = download_sprite(url, head_id, body_id, destPath)
|
||||
# return sprite if sprite
|
||||
# return nil
|
||||
end
|
||||
|
||||
def download_custom_sprite(head_id, body_id, alt_letter = "")
|
||||
return nil unless downloadAllowed?()
|
||||
#url = getDownloadableCustomSpritesUrl() + "{1}.{2}{3}.png"
|
||||
destPath = "#{Settings::CUSTOM_BATTLERS_FOLDER_INDEXED}#{head_id}"
|
||||
spriteExtracter = CustomSpriteExtracter.new
|
||||
sprite_path = spriteExtracter.extract_bitmap_to_file(head_id, body_id, alt_letter, destPath)
|
||||
echoln sprite_path
|
||||
return sprite_path
|
||||
|
||||
# if !Dir.exist?(destPath)
|
||||
# Dir.mkdir(destPath)
|
||||
# end
|
||||
# sprite = download_sprite(url, head_id, body_id,alt_letter), head_id, body_id, destPath, alt_letter
|
||||
# return sprite if sprite
|
||||
# return nil
|
||||
end
|
||||
|
||||
# def download_custom_sprite(head_id, body_id, spriteformBody_suffix = "", spriteformHead_suffix = "", alt_letter="")
|
||||
# head_id = (head_id.to_s) + spriteformHead_suffix.to_s
|
||||
# body_id = (body_id.to_s) + spriteformBody_suffix.to_s
|
||||
# return nil if !downloadAllowed?()
|
||||
# url = getDownloadableCustomSpritesUrl() + "{1}.{2}{3}.png"
|
||||
# destPath = "{1}{2}", Settings::CUSTOM_BATTLERS_FOLDER_INDEXED, head_id
|
||||
# if !Dir.exist?(destPath)
|
||||
# Dir.mkdir(destPath)
|
||||
# end
|
||||
# sprite = download_sprite(url, head_id, body_id,alt_letter), head_id, body_id, destPath, alt_letter
|
||||
# return sprite if sprite
|
||||
# return nil
|
||||
# end
|
||||
|
||||
# def download_custom_sprite_filename(filename)
|
||||
# head_id = (head_id.to_s) + spriteformHead_suffix.to_s
|
||||
# body_id = (body_id.to_s) + spriteformBody_suffix.to_s
|
||||
# return nil if !downloadAllowed?()
|
||||
# url = getDownloadableCustomSpritesUrl() + "{1}.{2}{3}.png"
|
||||
# destPath = "{1}{2}", Settings::CUSTOM_BATTLERS_FOLDER_INDEXED, head_id
|
||||
# if !Dir.exist?(destPath)
|
||||
# Dir.mkdir(destPath)
|
||||
# end
|
||||
# sprite = download_sprite(url, head_id, body_id,alt_letter), head_id, body_id, destPath, alt_letter
|
||||
# return sprite if sprite
|
||||
# return nil
|
||||
# end
|
||||
|
||||
# #todo refactor & put custom base sprites in same folder as fusion sprites
|
||||
# def download_unfused_main_sprite(dex_num, alt_letter="")
|
||||
# base_url = alt_letter == "" ? Settings::BASE_POKEMON_SPRITES_REPO_URL : getDownloadableBaseSpritesUrl()
|
||||
# filename = "{1}{2}.png",dex_num,alt_letter
|
||||
# url = base_url + filename
|
||||
#
|
||||
# echoln url
|
||||
# destPath = Settings::CUSTOM_BASE_SPRITES_FOLDER
|
||||
# sprite = download_sprite(url, dex_num, nil, destPath,alt_letter)
|
||||
#
|
||||
# return sprite if sprite
|
||||
# return nil
|
||||
# end
|
||||
|
||||
# def download_all_unfused_alt_sprites(dex_num)
|
||||
# base_url = getDownloadableBaseSpritesUrl() + "{1}"
|
||||
# extension = ".png"
|
||||
# destPath = "{1}", Settings::CUSTOM_BASE_SPRITES_FOLDER
|
||||
# if !Dir.exist?(destPath)
|
||||
# Dir.mkdir(destPath)
|
||||
# end
|
||||
# alt_url = base_url, dex_num + extension
|
||||
# download_sprite(alt_url, dex_num, nil, destPath)
|
||||
# alphabet = ('a'..'z').to_a + ('aa'..'az').to_a
|
||||
# alphabet.each do |letter|
|
||||
# alt_url = base_url, dex_num + letter + extension
|
||||
# sprite = download_sprite(alt_url, dex_num, nil, destPath, letter)
|
||||
# return if !sprite
|
||||
# end
|
||||
# end
|
||||
|
||||
# def download_all_unfused_alt_sprites(dex_num)
|
||||
# template_url = getDownloadableBaseSpritesUrl()
|
||||
# baseUrl = template_url,dex_num
|
||||
# destDirectory = "{1}", Settings::CUSTOM_BASE_SPRITES_FOLDER
|
||||
# if !Dir.exist?(destDirectory)
|
||||
# Dir.mkdir(destDirectory)
|
||||
# end
|
||||
# sprites_alt_map = map_alt_sprite_letters_for_pokemon(dex_num.to_s)
|
||||
# # Sorting the sprite keys by their status in order of priority: "main", "temp", "alt"
|
||||
# sprite_letters_to_download = sprites_alt_map.keys.sort_by do |key|
|
||||
# case sprites_alt_map[key]
|
||||
# when "main" then 0
|
||||
# when "temp" then 1
|
||||
# when "alt" then 2
|
||||
# else 3 # Catch-all for any undefined statuses, if any
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# nb_sprites_downloaded = 0
|
||||
# sprites_processed=0
|
||||
#
|
||||
# sprite_letters_to_download.each do |letter|
|
||||
# sprites_processed+=1
|
||||
# echoln sprites_processed
|
||||
# echoln nb_sprites_downloaded
|
||||
#
|
||||
# break if nb_sprites_downloaded > Settings::MAX_NB_SPRITES_TO_DOWNLOAD_AT_ONCE
|
||||
#
|
||||
# filename = "#{dex_num}#{letter}.png"
|
||||
# url = baseUrl + filename
|
||||
# destPath = destDirectory + "/" + filename
|
||||
# next if pbResolveBitmap(destPath)
|
||||
# downloaded_new_sprite= fetch_sprite_from_web(url,destPath)
|
||||
# if downloaded_new_sprite
|
||||
# nb_sprites_downloaded += 1
|
||||
# break if requestRateExceeded?(Settings::CUSTOMSPRITES_RATE_LOG_FILE,Settings::CUSTOMSPRITES_ENTRIES_RATE_TIME_WINDOW,Settings::CUSTOMSPRITES_RATE_MAX_NB_REQUESTS)
|
||||
# end
|
||||
#
|
||||
# end
|
||||
# end
|
||||
|
||||
# def download_all_alt_sprites(head_id, body_id)
|
||||
# base_url = "#{getDownloadableCustomSpritesUrl()}{1}.{2}"
|
||||
# extension = ".png"
|
||||
# destPath = "{1}{2}", Settings::CUSTOM_BATTLERS_FOLDER_INDEXED, head_id
|
||||
# if !Dir.exist?(destPath)
|
||||
# Dir.mkdir(destPath)
|
||||
# end
|
||||
# sprite_letters_to_download = list_all_sprites_letters_head_body(head_id,body_id)
|
||||
# sprite_letters_to_download.each do |letter|
|
||||
# alt_url = base_url + letter + extension
|
||||
# download_sprite(alt_url, head_id, body_id, destPath, letter)
|
||||
# end
|
||||
# end
|
||||
|
||||
#format: [1.1.png, 1.2.png, etc.]
|
||||
# https://api.github.com/repos/infinitefusion/contents/sprites/CustomBattlers
|
||||
# repo = "Aegide/custom-fusion-sprites"
|
||||
# folder = "CustomBattlers"
|
||||
#
|
||||
|
||||
# def fetch_online_custom_sprites
|
||||
# page_start =1
|
||||
# page_end =2
|
||||
#
|
||||
# repo = "infinitefusion/sprites"
|
||||
# folder = "CustomBattlers"
|
||||
# api_url = "https://api.github.com/repos/#{repo}/contents/#{folder}"
|
||||
#
|
||||
# files = []
|
||||
# page = page_start
|
||||
#
|
||||
# File.open(Settings::CUSTOM_SPRITES_FILE_PATH, "wb") do |csv|
|
||||
# loop do
|
||||
# break if page > page_end
|
||||
# response = HTTPLite.get(api_url, {'page' => page.to_s})
|
||||
# response_files = HTTPLite::JSON.parse(response[:body])
|
||||
# break if response_files.empty?
|
||||
# response_files.each do |file|
|
||||
# csv << [file['name']].to_s
|
||||
# csv << "\n"
|
||||
# end
|
||||
# page += 1
|
||||
# end
|
||||
# end
|
||||
#
|
||||
#
|
||||
# write_custom_sprites_csv(files)
|
||||
# end
|
||||
|
||||
# Too many file to get everything without getting
|
||||
# rate limited by github, so instead we're getting the
|
||||
# files list from a csv file that will be manually updated
|
||||
# with each new spritepack
|
||||
|
||||
def updateOnlineCustomSpritesFile
|
||||
return if !downloadAllowed?()
|
||||
echoln "UPDATING CUSTOM SPRITE LISTS"
|
||||
download_file(Settings::SPRITES_FILE_URL, Settings::CUSTOM_SPRITES_FILE_PATH)
|
||||
download_file(Settings::BASE_SPRITES_FILE_URL, Settings::BASE_SPRITES_FILE_PATH)
|
||||
end
|
||||
|
||||
def list_online_custom_sprites(updateList = false)
|
||||
sprites_list = []
|
||||
File.foreach(Settings::CUSTOM_SPRITES_FILE_PATH) do |line|
|
||||
sprites_list << line
|
||||
end
|
||||
return sprites_list
|
||||
end
|
||||
|
||||
GAME_VERSION_FORMAT_REGEX = /\A\d+(\.\d+)*\z/
|
||||
|
||||
def fetch_latest_game_version
|
||||
begin
|
||||
# download_file(Settings::VERSION_FILE_URL, Settings::VERSION_FILE_PATH)
|
||||
# version_file = File.open(Settings::VERSION_FILE_PATH, "r")
|
||||
# version = version_file.first
|
||||
# version_file.close
|
||||
version = Settings::LATEST_GAME_RELEASE
|
||||
|
||||
version_format_valid = version.match(GAME_VERSION_FORMAT_REGEX)
|
||||
|
||||
return version if version_format_valid
|
||||
return nil
|
||||
rescue MKXPError, Errno::ENOENT => error
|
||||
echo error
|
||||
return nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# update_log_file: keep to true when trying to make an actual request
|
||||
# set to false if just checking
|
||||
def requestRateExceeded?(logFile, timeWindow, maxRequests, update_log_file = true)
|
||||
# Read or initialize the request log
|
||||
if File.exist?(logFile)
|
||||
log_data = File.read(logFile).split("\n")
|
||||
request_timestamps = log_data.map(&:to_i)
|
||||
else
|
||||
request_timestamps = []
|
||||
end
|
||||
|
||||
current_time = Time.now.to_i
|
||||
|
||||
# Remove old timestamps that are outside the time window
|
||||
request_timestamps.reject! { |timestamp| (current_time - timestamp) > timeWindow }
|
||||
|
||||
# Update the log with the current request
|
||||
request_timestamps << current_time
|
||||
|
||||
# Write the updated log back to the file
|
||||
if update_log_file
|
||||
File.write(logFile, request_timestamps.join("\n"))
|
||||
end
|
||||
echoln "Rate limiting: Current: #{request_timestamps.size}, Max: #{maxRequests}"
|
||||
rateLimitExceeded = request_timestamps.size > maxRequests
|
||||
return rateLimitExceeded
|
||||
end
|
||||
|
||||
# def getDownloadableCustomSpritesUrl()
|
||||
# if Settings::USE_NEW_URL_FOR_CUSTOM_SPRITES
|
||||
# return Settings::CUSTOM_SPRITES_NEW_URL
|
||||
# end
|
||||
# return Settings::CUSTOM_SPRITES_REPO_URL
|
||||
# end
|
||||
|
||||
# def getDownloadableBaseSpritesUrl()
|
||||
# if Settings::USE_NEW_URL_FOR_BASE_SPRITES
|
||||
# return Settings::BASE_POKEMON_ALT_SPRITES_NEW_URL
|
||||
# end
|
||||
# return Settings::BASE_POKEMON_ALT_SPRITES_REPO_URL
|
||||
# end
|
||||
913
Data/Scripts/052_InfiniteFusion/System/MultiSaves.rb
Normal file
913
Data/Scripts/052_InfiniteFusion/System/MultiSaves.rb
Normal file
@@ -0,0 +1,913 @@
|
||||
# Auto Multi Save by http404error
|
||||
# For Pokemon Essentials v19.1
|
||||
|
||||
|
||||
# Description:
|
||||
# Adds multiple save slots and the abliity to auto-save.
|
||||
# Included is code to autosave every 30 overworld steps. Feel free to edit or delete it (it's right at the top).
|
||||
# On the Load screen you can use the left and right buttons while "Continue" is selected to cycle through files.
|
||||
# When saving, you can quickly save to the same slot you loaded from, or pick another slot.
|
||||
# Battle Challenges are NOT supported.
|
||||
|
||||
# Customization:
|
||||
# I recommend altering your pause menu to quit to the title screen or load screen instead of exiting entirely.
|
||||
# -> For instance, just change the menu text to "Quit to Title" and change `$scene = nil` to `$scene = pbCallTitle`.
|
||||
# Call Game.auto_save whenever you want.
|
||||
# -> Autosaving during an event script will correctly resume event execution when you load the game.
|
||||
# -> I haven't investigated if it might be possible to autosave on closing the window with the X or Alt-F4 yet.
|
||||
# You can rename the slots to your liking, or change how many there are.
|
||||
# In some cases, you might want to remove the option to save to a different slot than the one you loaded from.
|
||||
|
||||
# Notes:
|
||||
# On the first Load, the old Game.rxdata will be copied to the first slot in MANUAL_SLOTS. It won't have a known save time though.
|
||||
# The interface to `Game.save` has been changed.
|
||||
# Due to the slots, alters the save backup system in the case of save corruption/crashes - backups will be named Backup000.rxdata and so on.
|
||||
# Heavily modifies the SaveData module and Save and Load screens. This may cause incompatibility with some other plugins or custom game code.
|
||||
# Not everything here has been tested extensively, only what applies to normal usage of my game. Please let me know if you run into any problems.
|
||||
|
||||
# Future development ideas:
|
||||
# There isn't currently support for unlimited slots but it wouldn't be too hard.
|
||||
# Letting the user name their slots seems cool.
|
||||
# It would be nice if there was a sliding animation for switching files on that load screen. :)
|
||||
# It would be nice if the file select arrows used nicer animated graphics, kind of like the Bag.
|
||||
# Maybe auto-save slots should act like a queue instead of cycling around.
|
||||
|
||||
# Autosave every 30 steps
|
||||
# Events.onStepTaken += proc {
|
||||
# $Trainer.autosave_steps = 0 if !$Trainer.autosave_steps
|
||||
# $Trainer.autosave_steps += 1
|
||||
# if $Trainer.autosave_steps >= 30
|
||||
# echo("Autosaving...")
|
||||
# $Trainer.autosave_steps = 0
|
||||
# Game.auto_save
|
||||
# echoln("done.")
|
||||
# end
|
||||
# }
|
||||
|
||||
def onLoadExistingGame()
|
||||
migrateOldSavesToCharacterCustomization()
|
||||
clear_all_images()
|
||||
loadDateSpecificChanges()
|
||||
end
|
||||
|
||||
def loadDateSpecificChanges()
|
||||
current_date = Time.new
|
||||
if (current_date.day == 1 && current_date.month == 4)
|
||||
$Trainer.hat2=HAT_CLOWN if $Trainer.unlocked_hats.include?(HAT_CLOWN)
|
||||
end
|
||||
end
|
||||
|
||||
def onStartingNewGame() end
|
||||
|
||||
def migrateOldSavesToCharacterCustomization()
|
||||
if !$Trainer.unlocked_clothes
|
||||
$Trainer.unlocked_clothes = [DEFAULT_OUTFIT_MALE,
|
||||
DEFAULT_OUTFIT_FEMALE,
|
||||
STARTING_OUTFIT]
|
||||
end
|
||||
if !$Trainer.unlocked_hats
|
||||
$Trainer.unlocked_hats = [DEFAULT_OUTFIT_MALE, DEFAULT_OUTFIT_FEMALE]
|
||||
end
|
||||
if !$Trainer.unlocked_hairstyles
|
||||
$Trainer.unlocked_hairstyles = [DEFAULT_OUTFIT_MALE, DEFAULT_OUTFIT_FEMALE]
|
||||
end
|
||||
|
||||
if !$Trainer.clothes || !$Trainer.hair #|| !$Trainer.hat
|
||||
setupStartingOutfit()
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module SaveData
|
||||
# You can rename these slots or change the amount of them
|
||||
# They change the actual save file names though, so it would take some extra work to use the translation system on them.
|
||||
AUTO_SLOTS = [
|
||||
'Auto 1',
|
||||
'Auto 2'
|
||||
]
|
||||
MANUAL_SLOTS = [
|
||||
'File A',
|
||||
'File B',
|
||||
'File C',
|
||||
'File D',
|
||||
'File E',
|
||||
'File F',
|
||||
'File G',
|
||||
'File H'
|
||||
]
|
||||
|
||||
# For compatibility with games saved without this plugin
|
||||
OLD_SAVE_SLOT = 'Game'
|
||||
|
||||
SAVE_DIR = if File.directory?(System.data_directory)
|
||||
System.data_directory
|
||||
else
|
||||
'.'
|
||||
end
|
||||
|
||||
def self.each_slot
|
||||
(AUTO_SLOTS + MANUAL_SLOTS).each { |f| yield f }
|
||||
end
|
||||
|
||||
def self.get_full_path(file)
|
||||
return "#{SAVE_DIR}/#{file}.rxdata"
|
||||
end
|
||||
|
||||
def self.get_backup_file_path
|
||||
backup_file = "Backup000"
|
||||
while File.file?(self.get_full_path(backup_file))
|
||||
backup_file.next!
|
||||
end
|
||||
return self.get_full_path(backup_file)
|
||||
end
|
||||
|
||||
# Given a list of save file names and a file name in it, return the next file after it which exists
|
||||
# If no other file exists, will just return the same file again
|
||||
def self.get_next_slot(file_list, file)
|
||||
old_index = file_list.find_index(file)
|
||||
ordered_list = file_list.rotate(old_index + 1)
|
||||
ordered_list.each do |f|
|
||||
return f if File.file?(self.get_full_path(f))
|
||||
end
|
||||
# should never reach here since the original file should always exist
|
||||
return file
|
||||
end
|
||||
|
||||
# See self.get_next_slot
|
||||
def self.get_prev_slot(file_list, file)
|
||||
return self.get_next_slot(file_list.reverse, file)
|
||||
end
|
||||
|
||||
# Returns nil if there are no saves
|
||||
# Returns the first save if there's a tie for newest
|
||||
# Old saves from previous version don't store their saved time, so are treated as very old
|
||||
def self.get_newest_save_slot
|
||||
newest_time = Time.at(0) # the Epoch
|
||||
newest_slot = nil
|
||||
self.each_slot do |file_slot|
|
||||
full_path = self.get_full_path(file_slot)
|
||||
next if !File.file?(full_path)
|
||||
begin
|
||||
temp_save_data = self.read_from_file(full_path)
|
||||
rescue
|
||||
next
|
||||
end
|
||||
|
||||
save_time = temp_save_data[:player].last_time_saved || Time.at(1)
|
||||
if save_time > newest_time
|
||||
newest_time = save_time
|
||||
newest_slot = file_slot
|
||||
end
|
||||
end
|
||||
# Port old save
|
||||
if newest_slot.nil? && File.file?(self.get_full_path(OLD_SAVE_SLOT))
|
||||
file_copy(self.get_full_path(OLD_SAVE_SLOT), self.get_full_path(MANUAL_SLOTS[0]))
|
||||
return MANUAL_SLOTS[0]
|
||||
end
|
||||
return newest_slot
|
||||
end
|
||||
|
||||
# @return [Boolean] whether any save file exists
|
||||
def self.exists?
|
||||
self.each_slot do |slot|
|
||||
full_path = SaveData.get_full_path(slot)
|
||||
return true if File.file?(full_path)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# This is used in a hidden function (ctrl+down+cancel on title screen) or if the save file is corrupt
|
||||
# Pass nil to delete everything, or a file path to just delete that one
|
||||
# @raise [Error::ENOENT]
|
||||
def self.delete_file(file_path = nil)
|
||||
if file_path
|
||||
File.delete(file_path) if File.file?(file_path)
|
||||
else
|
||||
self.each_slot do |slot|
|
||||
full_path = self.get_full_path(slot)
|
||||
File.delete(full_path) if File.file?(full_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Moves a save file from the old Saved Games folder to the new
|
||||
# location specified by {MANUAL_SLOTS[0]}. Does nothing if a save file
|
||||
# already exists in {MANUAL_SLOTS[0]}.
|
||||
def self.move_old_windows_save
|
||||
return if self.exists?
|
||||
game_title = System.game_title.gsub(/[^\w ]/, '_')
|
||||
home = ENV['HOME'] || ENV['HOMEPATH']
|
||||
return if home.nil?
|
||||
old_location = File.join(home, 'Saved Games', game_title)
|
||||
return unless File.directory?(old_location)
|
||||
old_file = File.join(old_location, 'Game.rxdata')
|
||||
return unless File.file?(old_file)
|
||||
File.move(old_file, MANUAL_SLOTS[0])
|
||||
end
|
||||
|
||||
# Runs all possible conversions on the given save data.
|
||||
# Saves a backup before running conversions.
|
||||
# @param save_data [Hash] save data to run conversions on
|
||||
# @return [Boolean] whether conversions were run
|
||||
def self.run_conversions(save_data)
|
||||
validate save_data => Hash
|
||||
conversions_to_run = self.get_conversions(save_data)
|
||||
return false if conversions_to_run.none?
|
||||
File.open(SaveData.get_backup_file_path, 'wb') { |f| Marshal.dump(save_data, f) }
|
||||
echoln "Backed up save to #{SaveData.get_backup_file_path}"
|
||||
echoln "Running #{conversions_to_run.length} conversions..."
|
||||
conversions_to_run.each do |conversion|
|
||||
echo "#{conversion.title}..."
|
||||
conversion.run(save_data)
|
||||
echoln ' done.'
|
||||
end
|
||||
echoln '' if conversions_to_run.length > 0
|
||||
save_data[:essentials_version] = Essentials::VERSION
|
||||
save_data[:game_version] = Settings::GAME_VERSION
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class PokemonLoad_Scene
|
||||
def pbChoose(commands, continue_idx)
|
||||
@sprites["cmdwindow"].commands = commands
|
||||
loop do
|
||||
Graphics.update
|
||||
Input.update
|
||||
pbUpdate
|
||||
if Input.trigger?(Input::USE)
|
||||
return @sprites["cmdwindow"].index
|
||||
elsif @sprites["cmdwindow"].index == continue_idx
|
||||
@sprites["leftarrow"].visible = true
|
||||
@sprites["rightarrow"].visible = true
|
||||
if Input.trigger?(Input::LEFT)
|
||||
return -3
|
||||
elsif Input.trigger?(Input::RIGHT)
|
||||
return -2
|
||||
end
|
||||
else
|
||||
@sprites["leftarrow"].visible = false
|
||||
@sprites["rightarrow"].visible = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbStartScene(commands, show_continue, trainer, frame_count, map_id)
|
||||
@commands = commands
|
||||
@sprites = {}
|
||||
@viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
|
||||
@viewport.z = 99998
|
||||
addBackgroundOrColoredPlane(@sprites, "background", "loadbg", Color.new(248, 248, 248), @viewport)
|
||||
|
||||
@sprites["leftarrow"] = AnimatedSprite.new("Graphics/Pictures/leftarrow", 8, 40, 28, 2, @viewport)
|
||||
@sprites["leftarrow"].x = 10
|
||||
@sprites["leftarrow"].y = 140
|
||||
@sprites["leftarrow"].play
|
||||
|
||||
#@sprites["leftarrow"].visible=true
|
||||
|
||||
@sprites["rightarrow"] = AnimatedSprite.new("Graphics/Pictures/rightarrow", 8, 40, 28, 2, @viewport)
|
||||
@sprites["rightarrow"].x = 460
|
||||
@sprites["rightarrow"].y = 140
|
||||
@sprites["rightarrow"].play
|
||||
#@sprites["rightarrow"].visible=true
|
||||
|
||||
y = 16 * 2
|
||||
for i in 0...commands.length
|
||||
@sprites["panel#{i}"] = PokemonLoadPanel.new(i, commands[i],
|
||||
(show_continue) ? (i == 0) : false, trainer, frame_count, map_id, @viewport)
|
||||
@sprites["panel#{i}"].x = 24 * 2
|
||||
@sprites["panel#{i}"].y = y
|
||||
@sprites["panel#{i}"].pbRefresh
|
||||
y += (show_continue && i == 0) ? 112 * 2 : 24 * 2
|
||||
end
|
||||
@sprites["cmdwindow"] = Window_CommandPokemon.new([])
|
||||
@sprites["cmdwindow"].viewport = @viewport
|
||||
@sprites["cmdwindow"].visible = false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class PokemonLoadScreen
|
||||
def initialize(scene)
|
||||
@scene = scene
|
||||
@selected_file = SaveData.get_newest_save_slot
|
||||
end
|
||||
|
||||
# @param file_path [String] file to load save data from
|
||||
# @return [Hash] save data
|
||||
def load_save_file(file_path)
|
||||
begin
|
||||
save_data = SaveData.read_from_file(file_path)
|
||||
rescue
|
||||
save_data = try_load_backup(file_path)
|
||||
end
|
||||
unless SaveData.valid?(save_data)
|
||||
save_data = try_load_backup(file_path)
|
||||
end
|
||||
return save_data
|
||||
end
|
||||
|
||||
def try_load_backup(file_path)
|
||||
file_name = File.basename(file_path, ".rxdata") # e.g. "File A"
|
||||
save_folder = File.dirname(file_path)
|
||||
backup_dir = File.join(save_folder, "backups", file_name)
|
||||
|
||||
echoln file_path
|
||||
unless Dir.exist?(backup_dir)
|
||||
self.prompt_save_deletion(file_path)
|
||||
return {}
|
||||
end
|
||||
|
||||
backups = Dir.children(backup_dir).select { |f|
|
||||
f.start_with?(file_name + "_") && f.end_with?(".rxdata")
|
||||
}
|
||||
|
||||
echoln backups
|
||||
echoln file_name + "_"
|
||||
|
||||
if backups.empty?
|
||||
self.prompt_save_deletion(file_path)
|
||||
return {}
|
||||
end
|
||||
|
||||
# Sort by numeric timestamp
|
||||
backups.sort_by! do |fname|
|
||||
timestamp = fname.sub(/^#{Regexp.escape(file_name)}_/, "").sub(/\.rxdata$/, "")
|
||||
timestamp.to_i
|
||||
end
|
||||
|
||||
latest = backups.last
|
||||
timestamp_str = latest.sub(/^#{Regexp.escape(file_name)}_/, "").sub(/\.rxdata$/, "")
|
||||
|
||||
# Convert numeric timestamp to readable date (custom formatting)
|
||||
if timestamp_str.length >= 12
|
||||
year = timestamp_str[0,4]
|
||||
month = timestamp_str[4,2]
|
||||
day = timestamp_str[6,2]
|
||||
hour = timestamp_str[8,2]
|
||||
minute = timestamp_str[10,2]
|
||||
formatted_time = "#{year}-#{month}-#{day} #{hour}:#{minute}"
|
||||
else
|
||||
formatted_time = timestamp_str
|
||||
end
|
||||
|
||||
pbMessage(_INTL(
|
||||
"The save file is corrupt. The most recent backup will be loaded instead.\n" +
|
||||
"\\C[2]{1}\\C[0]\nBackup date: \\C[3]{2}",
|
||||
latest, formatted_time
|
||||
))
|
||||
|
||||
latest_backup = File.join(backup_dir, latest)
|
||||
return load_save_file(latest_backup)
|
||||
end
|
||||
|
||||
|
||||
def formatSaveDate(str)
|
||||
year = str[0,4]
|
||||
month = str[4,2]
|
||||
day = str[6,2]
|
||||
hour = str[8,2]
|
||||
minute = str[10,2]
|
||||
return "#{year}-#{month}-#{day} #{hour}:#{minute}"
|
||||
end
|
||||
|
||||
|
||||
# Called if save file is invalid.
|
||||
# Prompts the player to delete the save files.
|
||||
def prompt_save_deletion(file_path)
|
||||
pbMessage(_INTL("A save file is corrupt, or is incompatible with this game."))
|
||||
self.delete_save_data(file_path) if pbConfirmMessageSerious(
|
||||
_INTL("No backup was found. Do you want to delete that save file? The game will exit afterwards either way.")
|
||||
)
|
||||
exit
|
||||
end
|
||||
|
||||
# nil deletes all, otherwise just the given file
|
||||
def delete_save_data(file_path = nil)
|
||||
begin
|
||||
SaveData.delete_file(file_path)
|
||||
pbMessage(_INTL("The save data was deleted."))
|
||||
rescue SystemCallError
|
||||
pbMessage(_INTL("The save data could not be deleted."))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#So that the options menu is set on the correct difficulty on older saves
|
||||
def ensureCorrectDifficulty()
|
||||
$Trainer.selected_difficulty = 1 #normal
|
||||
$Trainer.selected_difficulty = 0 if $game_switches[SWITCH_GAME_DIFFICULTY_EASY]
|
||||
$Trainer.selected_difficulty = 2 if $game_switches[SWITCH_GAME_DIFFICULTY_HARD]
|
||||
$Trainer.lowest_difficulty = $Trainer.selected_difficulty if !$Trainer.lowest_difficulty
|
||||
end
|
||||
|
||||
def setGameMode()
|
||||
$Trainer.game_mode = 0 #classic
|
||||
$Trainer.game_mode = 2 if $game_switches[SWITCH_MODERN_MODE]
|
||||
$Trainer.game_mode = 3 if $game_switches[SWITCH_EXPERT_MODE]
|
||||
$Trainer.game_mode = 4 if $game_switches[SWITCH_SINGLE_POKEMON_MODE]
|
||||
$Trainer.game_mode = 1 if $game_switches[SWITCH_RANDOMIZED_AT_LEAST_ONCE]
|
||||
$Trainer.game_mode = 5 if $game_switches[ENABLED_DEBUG_MODE_AT_LEAST_ONCE]
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pbStartLoadScreen
|
||||
updateHttpSettingsFile
|
||||
updateCustomDexFile
|
||||
newer_version = find_newer_available_version
|
||||
if newer_version
|
||||
pbMessage(_INTL("Version {1} is now available! Please use the game's installer to download the newest version. Check the Discord for more information.", newer_version))
|
||||
end
|
||||
|
||||
if Settings::STARTUP_MESSAGES != ""
|
||||
pbMessage(_INTL(Settings::STARTUP_MESSAGES))
|
||||
end
|
||||
if ($game_temp.unimportedSprites && $game_temp.unimportedSprites.size > 0)
|
||||
handleReplaceExistingSprites()
|
||||
end
|
||||
if ($game_temp.nb_imported_sprites && $game_temp.nb_imported_sprites > 0)
|
||||
pbMessage(_INTL("{1} new custom sprites were imported into the game", $game_temp.nb_imported_sprites.to_s))
|
||||
end
|
||||
checkEnableSpritesDownload
|
||||
|
||||
$game_temp.nb_imported_sprites = nil
|
||||
copyKeybindings()
|
||||
save_file_list = SaveData::AUTO_SLOTS + SaveData::MANUAL_SLOTS
|
||||
first_time = true
|
||||
loop do
|
||||
# Outer loop is used for switching save files
|
||||
if @selected_file
|
||||
@save_data = load_save_file(SaveData.get_full_path(@selected_file))
|
||||
else
|
||||
@save_data = {}
|
||||
end
|
||||
commands = []
|
||||
cmd_continue = -1
|
||||
cmd_new_game = -1
|
||||
cmd_options = -1
|
||||
cmd_language = -1
|
||||
cmd_mystery_gift = -1
|
||||
cmd_debug = -1
|
||||
cmd_quit = -1
|
||||
show_continue = !@save_data.empty?
|
||||
new_game_plus = show_continue && (@save_data[:player].new_game_plus_unlocked || $DEBUG)
|
||||
|
||||
if show_continue
|
||||
commands[cmd_continue = commands.length] = "#{@selected_file}"
|
||||
if @save_data[:player].mystery_gift_unlocked
|
||||
commands[cmd_mystery_gift = commands.length] = _INTL('Mystery Gift') # Honestly I have no idea how to make Mystery Gift work well with this.
|
||||
end
|
||||
end
|
||||
|
||||
commands[cmd_new_game = commands.length] = _INTL('New Game')
|
||||
if new_game_plus
|
||||
commands[cmd_new_game_plus = commands.length] = _INTL('New Game +')
|
||||
end
|
||||
commands[cmd_options = commands.length] = _INTL('Options')
|
||||
commands[cmd_language = commands.length] = _INTL('Language') if Settings::LANGUAGES.length >= 2
|
||||
commands[cmd_discord = commands.length] = _INTL('Discord')
|
||||
commands[cmd_wiki = commands.length] = _INTL('Wiki')
|
||||
commands[cmd_debug = commands.length] = _INTL('Debug') if $DEBUG
|
||||
commands[cmd_quit = commands.length] = _INTL('Quit Game')
|
||||
cmd_left = -3
|
||||
cmd_right = -2
|
||||
|
||||
map_id = show_continue ? @save_data[:map_factory].map.map_id : 0
|
||||
@scene.pbStartScene(commands, show_continue, @save_data[:player],
|
||||
@save_data[:frame_count] || 0, map_id)
|
||||
@scene.pbSetParty(@save_data[:player]) if show_continue
|
||||
if first_time
|
||||
@scene.pbStartScene2
|
||||
first_time = false
|
||||
else
|
||||
@scene.pbUpdate
|
||||
end
|
||||
|
||||
loop do
|
||||
# Inner loop is used for going to other menus and back and stuff (vanilla)
|
||||
command = @scene.pbChoose(commands, cmd_continue)
|
||||
pbPlayDecisionSE if command != cmd_quit
|
||||
|
||||
case command
|
||||
when cmd_continue
|
||||
@scene.pbEndScene
|
||||
Game.load(@save_data)
|
||||
$game_switches[SWITCH_V5_1] = true
|
||||
check_for_spritepack_update()
|
||||
ensureCorrectDifficulty()
|
||||
setGameMode()
|
||||
initialize_alt_sprite_substitutions()
|
||||
$PokemonGlobal.autogen_sprites_cache = {}
|
||||
preload_party(@save_data[:player])
|
||||
return
|
||||
when cmd_new_game
|
||||
@scene.pbEndScene
|
||||
Game.start_new(new_game_plus)
|
||||
initialize_alt_sprite_substitutions()
|
||||
@save_data[:player].new_game_plus_unlocked=new_game_plus if @save_data[:player]
|
||||
return
|
||||
when cmd_new_game_plus
|
||||
@scene.pbEndScene
|
||||
Game.start_new(true,@save_data[:bag], @save_data[:storage_system], @save_data[:player])
|
||||
initialize_alt_sprite_substitutions()
|
||||
@save_data[:player].new_game_plus_unlocked = true
|
||||
return
|
||||
when cmd_discord
|
||||
openUrlInBrowser(Settings::DISCORD_URL)
|
||||
when cmd_wiki
|
||||
openUrlInBrowser(Settings::WIKI_URL)
|
||||
when cmd_mystery_gift
|
||||
pbFadeOutIn { pbDownloadMysteryGift(@save_data[:player]) }
|
||||
when cmd_options
|
||||
pbFadeOutIn do
|
||||
scene = PokemonGameOption_Scene.new
|
||||
screen = PokemonOptionScreen.new(scene)
|
||||
screen.pbStartScreen(true)
|
||||
end
|
||||
when cmd_language
|
||||
@scene.pbEndScene
|
||||
$PokemonSystem.language = pbChooseLanguage
|
||||
pbLoadMessages('Data/' + Settings::LANGUAGES[$PokemonSystem.language][1])
|
||||
if show_continue
|
||||
@save_data[:pokemon_system] = $PokemonSystem
|
||||
File.open(SaveData.get_full_path(@selected_file), 'wb') { |file| Marshal.dump(@save_data, file) }
|
||||
end
|
||||
$scene = pbCallTitle
|
||||
return
|
||||
when cmd_debug
|
||||
pbFadeOutIn { pbDebugMenu(false) }
|
||||
when cmd_quit
|
||||
pbPlayCloseMenuSE
|
||||
@scene.pbEndScene
|
||||
$scene = nil
|
||||
return
|
||||
when cmd_left
|
||||
@scene.pbCloseScene
|
||||
@selected_file = SaveData.get_prev_slot(save_file_list, @selected_file)
|
||||
break # to outer loop
|
||||
when cmd_right
|
||||
@scene.pbCloseScene
|
||||
@selected_file = SaveData.get_next_slot(save_file_list, @selected_file)
|
||||
break # to outer loop
|
||||
else
|
||||
pbPlayBuzzerSE
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class PokemonSave_Scene
|
||||
def pbUpdateSlotInfo(slottext)
|
||||
pbDisposeSprite(@sprites, "slotinfo")
|
||||
@sprites["slotinfo"] = Window_AdvancedTextPokemon.new(slottext)
|
||||
@sprites["slotinfo"].viewport = @viewport
|
||||
@sprites["slotinfo"].x = 0
|
||||
@sprites["slotinfo"].y = 160
|
||||
@sprites["slotinfo"].width = 228 if @sprites["slotinfo"].width < 228
|
||||
@sprites["slotinfo"].visible = true
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
class PokemonSaveScreen
|
||||
def doSave(slot)
|
||||
if Game.save(slot)
|
||||
pbMessage(_INTL("\\se[]{1} saved the game.\\me[GUI save game]\\wtnp[30]", $Trainer.name))
|
||||
return true
|
||||
else
|
||||
pbMessage(_INTL("\\se[]Save failed.\\wtnp[30]"))
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
# Return true if pause menu should close after this is done (if the game was saved successfully)
|
||||
def pbSaveScreen
|
||||
ret = false
|
||||
@scene.pbStartScreen
|
||||
if !$Trainer.save_slot
|
||||
# New Game - must select slot
|
||||
ret = slotSelect
|
||||
else
|
||||
choices = [
|
||||
_INTL("Save to #{$Trainer.save_slot}"),
|
||||
_INTL("Save to another slot"),
|
||||
_INTL("Don't save")
|
||||
]
|
||||
opt = pbMessage(_INTL('Would you like to save the game?'), choices, 3)
|
||||
if opt == 0
|
||||
pbSEPlay('GUI save choice')
|
||||
ret = doSave($Trainer.save_slot)
|
||||
elsif opt == 1
|
||||
pbPlayDecisionSE
|
||||
ret = slotSelect
|
||||
else
|
||||
pbPlayCancelSE
|
||||
end
|
||||
end
|
||||
@scene.pbEndScreen
|
||||
return ret
|
||||
end
|
||||
|
||||
# Call this to open the slot select screen
|
||||
# Returns true if the game was saved, otherwise false
|
||||
def slotSelect
|
||||
ret = false
|
||||
choices = SaveData::MANUAL_SLOTS
|
||||
choice_info = SaveData::MANUAL_SLOTS.map { |s| getSaveInfoBoxContents(s) }
|
||||
index = slotSelectCommands(choices, choice_info)
|
||||
if index >= 0
|
||||
slot = SaveData::MANUAL_SLOTS[index]
|
||||
# Confirm if slot not empty
|
||||
if !File.file?(SaveData.get_full_path(slot)) ||
|
||||
pbConfirmMessageSerious(_INTL("Are you sure you want to overwrite the save in {1}?",slot)) # If the slot names were changed this grammar might need adjustment.
|
||||
pbSEPlay('GUI save choice')
|
||||
ret = doSave(slot)
|
||||
end
|
||||
end
|
||||
pbPlayCloseMenuSE if !ret
|
||||
return ret
|
||||
end
|
||||
|
||||
# Handles the UI for the save slot select screen. Returns the index of the chosen slot, or -1.
|
||||
# Based on pbShowCommands
|
||||
def slotSelectCommands(choices, choice_info, defaultCmd = 0)
|
||||
msgwindow = Window_AdvancedTextPokemon.new(_INTL("Which slot to save in?"))
|
||||
msgwindow.z = 99999
|
||||
msgwindow.visible = true
|
||||
msgwindow.letterbyletter = true
|
||||
msgwindow.back_opacity = MessageConfig::WINDOW_OPACITY
|
||||
pbBottomLeftLines(msgwindow, 2)
|
||||
$game_temp.message_window_showing = true if $game_temp
|
||||
msgwindow.setSkin(MessageConfig.pbGetSpeechFrame)
|
||||
|
||||
cmdwindow = Window_CommandPokemonEx.new(choices)
|
||||
cmdwindow.z = 99999
|
||||
cmdwindow.visible = true
|
||||
cmdwindow.resizeToFit(cmdwindow.commands)
|
||||
pbPositionNearMsgWindow(cmdwindow, msgwindow, :right)
|
||||
cmdwindow.index = defaultCmd
|
||||
command = 0
|
||||
loop do
|
||||
@scene.pbUpdateSlotInfo(choice_info[cmdwindow.index])
|
||||
Graphics.update
|
||||
Input.update
|
||||
cmdwindow.update
|
||||
msgwindow.update if msgwindow
|
||||
if Input.trigger?(Input::BACK)
|
||||
command = -1
|
||||
break
|
||||
end
|
||||
if Input.trigger?(Input::USE)
|
||||
command = cmdwindow.index
|
||||
break
|
||||
end
|
||||
pbUpdateSceneMap
|
||||
end
|
||||
ret = command
|
||||
cmdwindow.dispose
|
||||
msgwindow.dispose
|
||||
$game_temp.message_window_showing = false if $game_temp
|
||||
Input.update
|
||||
return ret
|
||||
end
|
||||
|
||||
# Show the player some data about their currently selected save slot for quick identification
|
||||
# This doesn't use player gender for coloring, unlike the default save window
|
||||
def getSaveInfoBoxContents(slot)
|
||||
full_path = SaveData.get_full_path(slot)
|
||||
if !File.file?(full_path)
|
||||
return _INTL("<ac><c3=3050C8,D0D0C8>(empty)</c3></ac>")
|
||||
end
|
||||
temp_save_data = SaveData.read_from_file(full_path)
|
||||
|
||||
# Last save time
|
||||
time = temp_save_data[:player].last_time_saved
|
||||
if time
|
||||
date_str = time.strftime(_INTL("%x"))
|
||||
time_str = time.strftime(_INTL("%I:%M%p"))
|
||||
datetime_str = "#{date_str}<r>#{time_str}<br>"
|
||||
else
|
||||
datetime_str = _INTL("<ac>(old save)</ac>")
|
||||
end
|
||||
|
||||
# Map name
|
||||
map_str = pbGetMapNameFromId(temp_save_data[:map_factory].map.map_id)
|
||||
|
||||
# Elapsed time
|
||||
totalsec = (temp_save_data[:frame_count] || 0) / Graphics.frame_rate
|
||||
hour = totalsec / 60 / 60
|
||||
min = totalsec / 60 % 60
|
||||
if hour > 0
|
||||
elapsed_str = _INTL("Time<r>{1}h {2}m<br>", hour, min)
|
||||
else
|
||||
elapsed_str = _INTL("Time<r>{1}m<br>", min)
|
||||
end
|
||||
|
||||
return "<c3=3050C8,D0D0C8>#{datetime_str}</c3>" + # blue
|
||||
"<ac><c3=209808,90F090>#{map_str}</c3></ac>" + # green
|
||||
"#{elapsed_str}"
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
module Game
|
||||
# Fix New Game bug (if you saved during an event script)
|
||||
# This fix is from Essentials v20.1 Hotfixes 1.0.5
|
||||
def self.start_new(ngp_unlocked=false,ngp_bag = nil, ngp_storage = nil, ngp_trainer = nil)
|
||||
if $game_map && $game_map.events
|
||||
$game_map.events.each_value { |event| event.clear_starting }
|
||||
end
|
||||
$game_temp.common_event_id = 0 if $game_temp
|
||||
$PokemonTemp.begunNewGame = true
|
||||
pbMapInterpreter&.clear
|
||||
pbMapInterpreter&.setup(nil, 0, 0)
|
||||
$scene = Scene_Map.new
|
||||
SaveData.load_new_game_values
|
||||
$MapFactory = PokemonMapFactory.new($data_system.start_map_id)
|
||||
$game_player.moveto($data_system.start_x, $data_system.start_y)
|
||||
$game_player.refresh
|
||||
$PokemonEncounters = PokemonEncounters.new
|
||||
$PokemonEncounters.setup($game_map.map_id)
|
||||
$game_map.autoplay
|
||||
$game_map.update
|
||||
#
|
||||
# if ngp_bag != nil
|
||||
# $PokemonBag = ngp_clean_item_data(ngp_bag)
|
||||
# end
|
||||
if ngp_storage != nil
|
||||
$PokemonStorage = ngp_clean_pc_data(ngp_storage, ngp_trainer.party)
|
||||
end
|
||||
if ngp_trainer
|
||||
$Trainer.unlocked_hats = ngp_trainer.unlocked_hats
|
||||
$Trainer.unlocked_clothes = ngp_trainer.unlocked_clothes
|
||||
end
|
||||
$Trainer.new_game_plus_unlocked = ngp_unlocked
|
||||
end
|
||||
|
||||
# Loads bootup data from save file (if it exists) or creates bootup data (if
|
||||
# it doesn't).
|
||||
def self.set_up_system
|
||||
SaveData.move_old_windows_save if System.platform[/Windows/]
|
||||
save_slot = SaveData.get_newest_save_slot
|
||||
if save_slot
|
||||
save_data = SaveData.read_from_file(SaveData.get_full_path(save_slot))
|
||||
else
|
||||
save_data = {}
|
||||
end
|
||||
if save_data.empty?
|
||||
SaveData.initialize_bootup_values
|
||||
else
|
||||
SaveData.load_bootup_values(save_data)
|
||||
end
|
||||
# Set resize factor
|
||||
pbSetResizeFactor([$PokemonSystem.screensize, 4].min)
|
||||
# Set language (and choose language if there is no save file)
|
||||
if Settings::LANGUAGES.length >= 2
|
||||
$PokemonSystem.language = pbChooseLanguage if save_data.empty?
|
||||
pbLoadMessages('Data/' + Settings::LANGUAGES[$PokemonSystem.language][1])
|
||||
end
|
||||
end
|
||||
|
||||
def self.backup_savefile(save_path, slot)
|
||||
begin
|
||||
backup_dir = File.join(File.dirname(save_path), "backups")
|
||||
Dir.mkdir(backup_dir) if !Dir.exist?(backup_dir)
|
||||
|
||||
backup_slot_dir = File.join(File.dirname(save_path), "backups/#{slot}")
|
||||
Dir.mkdir(backup_slot_dir) if !Dir.exist?(backup_slot_dir)
|
||||
|
||||
# Manage rolling backups
|
||||
if File.exist?(save_path)
|
||||
# Generate a timestamped backup name
|
||||
timestamp = Time.now.strftime(_INTL("%Y%m%d%H%M%S"))
|
||||
backup_file = File.join(backup_slot_dir, "#{slot}_#{timestamp}.rxdata")
|
||||
|
||||
# Copy the save file manually
|
||||
File.open(save_path, 'rb') do |source|
|
||||
File.open(backup_file, 'wb') do |dest|
|
||||
dest.write(source.read)
|
||||
end
|
||||
end
|
||||
|
||||
# Clean up old backups
|
||||
backups = Dir.get(backup_slot_dir, "*.rxdata")
|
||||
# Keep only the latest N backups
|
||||
if backups.length > Settings::SAVEFILE_NB_BACKUPS
|
||||
excess_backups = backups[0...(backups.length - Settings::SAVEFILE_NB_BACKUPS)]
|
||||
echoln excess_backups
|
||||
excess_backups.each { |old_backup| File.delete(old_backup) }
|
||||
end
|
||||
end
|
||||
rescue => e
|
||||
echoln ("There was an error while creating a backup savefile.")
|
||||
echoln("Error: #{e.message}")
|
||||
end
|
||||
end
|
||||
|
||||
# Saves the game. Returns whether the operation was successful.
|
||||
# @param save_file [String] the save file path
|
||||
# @param safe [Boolean] whether $PokemonGlobal.safesave should be set to true
|
||||
# @return [Boolean] whether the operation was successful
|
||||
# @raise [SaveData::InvalidValueError] if an invalid value is being saved
|
||||
def self.save(slot = nil, auto = false, safe: false)
|
||||
slot = $Trainer.save_slot if slot.nil?
|
||||
return false if slot.nil?
|
||||
|
||||
file_path = SaveData.get_full_path(slot)
|
||||
self.backup_savefile(file_path, slot)
|
||||
|
||||
$PokemonGlobal.safesave = safe
|
||||
$game_system.save_count += 1
|
||||
$game_system.magic_number = $data_system.magic_number
|
||||
$Trainer.save_slot = slot unless auto
|
||||
$Trainer.last_time_saved = Time.now
|
||||
begin
|
||||
SaveData.save_to_file(file_path)
|
||||
Graphics.frame_reset
|
||||
rescue IOError, SystemCallError
|
||||
$game_system.save_count -= 1
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
# Overwrites the first empty autosave slot, otherwise the oldest existing autosave
|
||||
def self.auto_save
|
||||
oldest_time = nil
|
||||
oldest_slot = nil
|
||||
SaveData::AUTO_SLOTS.each do |slot|
|
||||
full_path = SaveData.get_full_path(slot)
|
||||
if !File.file?(full_path)
|
||||
oldest_slot = slot
|
||||
break
|
||||
end
|
||||
temp_save_data = SaveData.read_from_file(full_path)
|
||||
save_time = temp_save_data[:player].last_time_saved || Time.at(1)
|
||||
if oldest_time.nil? || save_time < oldest_time
|
||||
oldest_time = save_time
|
||||
oldest_slot = slot
|
||||
end
|
||||
end
|
||||
self.save(oldest_slot, true)
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
# Lol who needs the FileUtils gem?
|
||||
# This is the implementation from the original pbEmergencySave.
|
||||
def file_copy(src, dst)
|
||||
File.open(src, 'rb') do |r|
|
||||
File.open(dst, 'wb') do |w|
|
||||
while s = r.read(4096)
|
||||
w.write s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# When I needed extra data fields in the save file I put them in Player because it seemed easier than figuring out
|
||||
# how to make a save file conversion, and I prefer to maintain backwards compatibility.
|
||||
class Player
|
||||
attr_accessor :last_time_saved
|
||||
attr_accessor :save_slot
|
||||
attr_accessor :autosave_steps
|
||||
end
|
||||
|
||||
def pbEmergencySave
|
||||
oldscene = $scene
|
||||
$scene = nil
|
||||
pbMessage(_INTL("The script is taking too long. The game will restart."))
|
||||
return if !$Trainer
|
||||
return if !$Trainer.save_slot
|
||||
current_file = SaveData.get_full_path($Trainer.save_slot)
|
||||
backup_file = SaveData.get_backup_file_path
|
||||
file_copy(current_file, backup_file)
|
||||
if Game.save
|
||||
pbMessage(_INTL("\\se[]The game was saved.\\me[GUI save game] The previous save file has been backed up.\\wtnp[30]"))
|
||||
else
|
||||
pbMessage(_INTL("\\se[]Save failed.\\wtnp[30]"))
|
||||
end
|
||||
$scene = oldscene
|
||||
end
|
||||
89
Data/Scripts/052_InfiniteFusion/System/Pathfinding.rb
Normal file
89
Data/Scripts/052_InfiniteFusion/System/Pathfinding.rb
Normal file
@@ -0,0 +1,89 @@
|
||||
|
||||
def getDirection(x_incr,y_incr)
|
||||
return DIRECTION_RIGHT if x_incr>0
|
||||
return DIRECTION_LEFT if x_incr<0
|
||||
return DIRECTION_DOWN if y_incr>0
|
||||
return DIRECTION_UP if y_incr<0
|
||||
return 0
|
||||
end
|
||||
|
||||
|
||||
def get_direction_forward_x(directionId)
|
||||
return 1 if directionId == DIRECTION_RIGHT
|
||||
return -1 if directionId == DIRECTION_LEFT
|
||||
return 0
|
||||
end
|
||||
|
||||
|
||||
def get_direction_forward_y(directionId)
|
||||
return 1 if directionId == DIRECTION_DOWN
|
||||
return -1 if directionId == DIRECTION_UP
|
||||
return 0
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
#Basic pathfinding to move an event towards a certain general direction while avoiding obstacles
|
||||
def pathFindingGetDirection(current_x,current_y,goal_direction,pathfindingRange=4)
|
||||
goal_direction_is_horizontal = goal_direction == DIRECTION_RIGHT || goal_direction == DIRECTION_LEFT
|
||||
direction_forward_x = get_direction_forward_x(goal_direction)
|
||||
direction_forward_y = get_direction_forward_y(goal_direction)
|
||||
#echoln "Goal direction :#{goal_direction}. ForwardX: #{direction_forward_x}. ForwardY: #{direction_forward_y}"
|
||||
if(eventCanPassThrough(current_x+direction_forward_x,current_y+direction_forward_y,goal_direction))
|
||||
return goal_direction
|
||||
else
|
||||
if goal_direction_is_horizontal
|
||||
alternate_direction_x=direction_forward_x
|
||||
alternate_direction_y=1
|
||||
else
|
||||
alternate_direction_x=1
|
||||
alternate_direction_y=direction_forward_y
|
||||
end
|
||||
|
||||
echoln "########### CURRENT_POSITION: #{current_x},#{current_y}"
|
||||
direction_polarities = [1,-1]
|
||||
|
||||
for i in 1..pathfindingRange
|
||||
for polarity in direction_polarities
|
||||
new_x = goal_direction_is_horizontal ? current_x+ direction_forward_x : current_x+((i*alternate_direction_x)*polarity)
|
||||
new_y = !goal_direction_is_horizontal ? current_y + direction_forward_y : current_y+((i*alternate_direction_y)*polarity)
|
||||
echoln "Checking for #{new_x}, #{new_y}"
|
||||
if eventCanPassThrough(new_x,new_y,goal_direction)
|
||||
if goal_direction_is_horizontal
|
||||
new_direction = getDirection(0,(i*alternate_direction_y)*polarity)
|
||||
echoln "found a gap! new direction x: #{0}, new direction y: #{(i*alternate_direction_y)*polarity}"
|
||||
if eventCanPassThrough(current_x,current_y+polarity,goal_direction)
|
||||
return new_direction
|
||||
else
|
||||
echoln "...but cannot go in that direction (#{current_x},#{current_y+new_direction} blocked)"
|
||||
end
|
||||
else
|
||||
new_direction = getDirection((i*alternate_direction_x)*polarity,0)
|
||||
if eventCanPassThrough(current_x+polarity,current_y,goal_direction)
|
||||
return new_direction
|
||||
else
|
||||
echoln "...but cannot go in that direction"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
def eventCanPassThrough(x, y, direction)
|
||||
if x == $game_player.x && y == $game_player.y
|
||||
echoln "cannot pass because of player"
|
||||
return false
|
||||
end
|
||||
|
||||
$PokemonTemp.dependentEvents.realEvents.each { |dependantEvent|
|
||||
if x == dependantEvent.x && y == dependantEvent.y
|
||||
echoln "cannot pass because of dependant event #{dependantEvent.name}(#{dependantEvent.x},#{dependantEvent.y})"
|
||||
return false
|
||||
end
|
||||
}
|
||||
return $game_player.passable?(x, y, direction)
|
||||
end
|
||||
217
Data/Scripts/052_InfiniteFusion/System/SpeechBubbles.rb
Normal file
217
Data/Scripts/052_InfiniteFusion/System/SpeechBubbles.rb
Normal file
@@ -0,0 +1,217 @@
|
||||
PluginManager.register({
|
||||
:name => "Carmaniac's Speech Bubbles",
|
||||
:version => "1.1",
|
||||
:credits => ["Carmaniac","Avery","Boonzeet"],
|
||||
:link => "https://reliccastle.com/resources/461/"
|
||||
})
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Carmaniac's Speech Bubbles for v18
|
||||
# Updated by Avery
|
||||
#-------------------------------------------------------------------------------
|
||||
# To use, call pbCallBub(type, eventID)
|
||||
#
|
||||
# Where type is either 1 or 2:
|
||||
# 1 - floating bubble
|
||||
# 2 - speech bubble with arrow
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Class modifiers
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
class PokemonTemp
|
||||
attr_accessor :speechbubble_bubble
|
||||
attr_accessor :speechbubble_vp
|
||||
attr_accessor :speechbubble_arrow
|
||||
attr_accessor :speechbubble_outofrange
|
||||
attr_accessor :speechbubble_talking
|
||||
attr_accessor :speechbubble_alwaysDown
|
||||
attr_accessor :speechbubble_alwaysUp
|
||||
end
|
||||
|
||||
module MessageConfig
|
||||
BUBBLETEXTBASE = Color.new(22,22,22)
|
||||
BUBBLETEXTSHADOW = Color.new(166,160,151)
|
||||
WindowOpacity = 255
|
||||
end
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Function modifiers
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
class Window_AdvancedTextPokemon
|
||||
def text=(value)
|
||||
if value != nil && value != "" && $PokemonTemp.speechbubble_bubble && $PokemonTemp.speechbubble_bubble > 0
|
||||
if $PokemonTemp.speechbubble_bubble == 1
|
||||
$PokemonTemp.speechbubble_bubble = 0
|
||||
resizeToFit2(value,400,100)
|
||||
|
||||
@x = $game_map.events[$PokemonTemp.speechbubble_talking].screen_x
|
||||
@y = $game_map.events[$PokemonTemp.speechbubble_talking].screen_y - (32 + @height)
|
||||
|
||||
if @y>(Graphics.height-@height-2)
|
||||
@y = (Graphics.height-@height)
|
||||
elsif @y<2
|
||||
@y=2
|
||||
end
|
||||
if @x>(Graphics.width-@width-2)
|
||||
@x = ($game_map.events[$PokemonTemp.speechbubble_talking].screen_x-@width)
|
||||
elsif @x<2
|
||||
@x=2
|
||||
end
|
||||
elsif $PokemonTemp.speechbubble_bubble == 3
|
||||
@x=$game_player.x+32
|
||||
@y=$game_player.y+36
|
||||
else
|
||||
$PokemonTemp.speechbubble_bubble = 0
|
||||
end
|
||||
end
|
||||
setText(value)
|
||||
end
|
||||
end
|
||||
|
||||
def pbRepositionMessageWindow(msgwindow, linecount=2)
|
||||
msgwindow.height=32*linecount+msgwindow.borderY
|
||||
msgwindow.y=(Graphics.height)-(msgwindow.height)
|
||||
if $game_temp && $game_temp.in_battle && !$scene.respond_to?("update_basic")
|
||||
msgwindow.y=0
|
||||
elsif $game_system && $game_system.respond_to?("message_position")
|
||||
case $game_system.message_position
|
||||
when 0 # up
|
||||
msgwindow.y=0
|
||||
when 1 # middle
|
||||
msgwindow.y=(Graphics.height/2)-(msgwindow.height/2)
|
||||
when 2
|
||||
if $PokemonTemp.speechbubble_bubble == 1 || $PokemonTemp.speechbubble_bubble == 3
|
||||
msgwindow.setSkin("Graphics/windowskins/frlgtextskin")
|
||||
msgwindow.height = 100
|
||||
msgwindow.width = 400
|
||||
elsif $PokemonTemp.speechbubble_bubble==2
|
||||
msgwindow.setSkin("Graphics/windowskins/frlgtextskin")
|
||||
msgwindow.height = 102
|
||||
msgwindow.width = Graphics.width
|
||||
if ($game_player.direction==8 && !$PokemonTemp.speechbubble_alwaysDown) || $PokemonTemp.speechbubble_alwaysUp
|
||||
$PokemonTemp.speechbubble_vp = Viewport.new(0, 0, Graphics.width, 280)
|
||||
msgwindow.y = 6
|
||||
else
|
||||
$PokemonTemp.speechbubble_vp = Viewport.new(0, 6 + msgwindow.height, Graphics.width, 280)
|
||||
msgwindow.y = (Graphics.height - msgwindow.height) - 6
|
||||
if $PokemonTemp.speechbubble_outofrange==true
|
||||
msgwindow.y = 6
|
||||
end
|
||||
end
|
||||
else
|
||||
msgwindow.height = 102
|
||||
msgwindow.y = Graphics.height - msgwindow.height - 6
|
||||
end
|
||||
end
|
||||
end
|
||||
if $game_system && $game_system.respond_to?("message_frame")
|
||||
if $game_system.message_frame != 0
|
||||
msgwindow.opacity = 0
|
||||
end
|
||||
end
|
||||
if $game_message
|
||||
case $game_message.background
|
||||
when 1 # dim
|
||||
msgwindow.opacity=0
|
||||
when 2 # transparent
|
||||
msgwindow.opacity=0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbCreateMessageWindow(viewport=nil,skin=nil)
|
||||
arrow = nil
|
||||
if $PokemonTemp.speechbubble_bubble==2 && $game_map.events[$PokemonTemp.speechbubble_talking] != nil # Message window set to floating bubble.
|
||||
if ($game_player.direction==DIRECTION_UP && (!$PokemonTemp.speechbubble_alwaysDown) || $PokemonTemp.speechbubble_alwaysUp)# Player facing up, message window top.
|
||||
$PokemonTemp.speechbubble_vp = Viewport.new(0, 104, Graphics.width, 280)
|
||||
$PokemonTemp.speechbubble_vp.z = 999999
|
||||
arrow = Sprite.new($PokemonTemp.speechbubble_vp)
|
||||
arrow.x = $game_map.events[$PokemonTemp.speechbubble_talking].screen_x - Graphics.width
|
||||
arrow.y = ($game_map.events[$PokemonTemp.speechbubble_talking].screen_y - Graphics.height) - 136
|
||||
arrow.z = 999999
|
||||
arrow.bitmap = RPG::Cache.load_bitmap_path("Graphics/Pictures/Arrow4")
|
||||
arrow.zoom_x = 2
|
||||
arrow.zoom_y = 2
|
||||
if arrow.x<-230
|
||||
arrow.x = $game_map.events[$PokemonTemp.speechbubble_talking].screen_x
|
||||
arrow.bitmap = RPG::Cache.load_bitmap_path("Graphics/Pictures/Arrow3")
|
||||
end
|
||||
else # Player facing left, down, right, message window bottom.
|
||||
$PokemonTemp.speechbubble_vp = Viewport.new(0, 0, Graphics.width, 280)
|
||||
$PokemonTemp.speechbubble_vp.z = 999999
|
||||
arrow = Sprite.new($PokemonTemp.speechbubble_vp)
|
||||
arrow.x = $game_map.events[$PokemonTemp.speechbubble_talking].screen_x
|
||||
arrow.y = $game_map.events[$PokemonTemp.speechbubble_talking].screen_y
|
||||
arrow.z = 999999
|
||||
arrow.bitmap = RPG::Cache.load_bitmap_path("Graphics/Pictures/Arrow1")
|
||||
if arrow.y>=Graphics.height-120 # Change arrow direction.
|
||||
$PokemonTemp.speechbubble_outofrange=true
|
||||
$PokemonTemp.speechbubble_vp.rect.y+=104
|
||||
arrow.x = $game_map.events[$PokemonTemp.speechbubble_talking].screen_x - Graphics.width
|
||||
arrow.bitmap = RPG::Cache.load_bitmap_path("Graphics/Pictures/Arrow4")
|
||||
arrow.y = ($game_map.events[$PokemonTemp.speechbubble_talking].screen_y - Graphics.height) - 136
|
||||
if arrow.x<-250
|
||||
arrow.x = $game_map.events[$PokemonTemp.speechbubble_talking].screen_x
|
||||
arrow.bitmap = RPG::Cache.load_bitmap_path("Graphics/Pictures/Arrow3")
|
||||
end
|
||||
if arrow.x>=256
|
||||
arrow.x-=15# = $game_map.events[$PokemonTemp.speechbubble_talking].screen_x-Graphics.width
|
||||
arrow.bitmap = RPG::Cache.load_bitmap_path("Graphics/Pictures/Arrow3")
|
||||
end
|
||||
else
|
||||
$PokemonTemp.speechbubble_outofrange=false
|
||||
end
|
||||
arrow.zoom_x = 2
|
||||
arrow.zoom_y = 2
|
||||
end
|
||||
end
|
||||
$PokemonTemp.speechbubble_arrow = arrow
|
||||
msgwindow=Window_AdvancedTextPokemon.new("")
|
||||
if !viewport
|
||||
msgwindow.z=99999
|
||||
else
|
||||
msgwindow.viewport=viewport
|
||||
end
|
||||
msgwindow.visible=true
|
||||
msgwindow.letterbyletter=true
|
||||
msgwindow.back_opacity=MessageConfig::WindowOpacity
|
||||
pbBottomLeftLines(msgwindow,2)
|
||||
$game_temp.message_window_showing=true if $game_temp
|
||||
$game_message.visible=true if $game_message
|
||||
skin=MessageConfig.pbGetSpeechFrame() if !skin
|
||||
msgwindow.setSkin(skin)
|
||||
return msgwindow
|
||||
end
|
||||
|
||||
def pbDisposeMessageWindow(msgwindow)
|
||||
$game_temp.message_window_showing=false if $game_temp
|
||||
$game_message.visible=false if $game_message
|
||||
msgwindow.dispose
|
||||
$PokemonTemp.speechbubble_arrow.dispose if $PokemonTemp.speechbubble_arrow
|
||||
$PokemonTemp.speechbubble_vp.dispose if $PokemonTemp.speechbubble_vp
|
||||
$PokemonTemp.speechbubble_bubble=nil
|
||||
end
|
||||
|
||||
def pbCallBubUp(status=0,value=0)
|
||||
pbCallBub(status,value,false,true)
|
||||
end
|
||||
|
||||
def pbCallBubDown(status=0,value=0)
|
||||
pbCallBub(status,value,true,false)
|
||||
end
|
||||
|
||||
#always_down, always_up is not ideal but used everywhere in game so too late to change
|
||||
def pbCallBub(status=0,value=0,always_down=false, always_up=false)
|
||||
begin
|
||||
$PokemonTemp.speechbubble_talking=get_character(value).id if status<3
|
||||
$PokemonTemp.speechbubble_bubble=status
|
||||
$PokemonTemp.speechbubble_alwaysDown=always_down
|
||||
$PokemonTemp.speechbubble_alwaysUp=always_up
|
||||
|
||||
rescue
|
||||
return #Let's not crash the game if error
|
||||
end
|
||||
end
|
||||
71
Data/Scripts/052_InfiniteFusion/System/Spped Up.rb
Normal file
71
Data/Scripts/052_InfiniteFusion/System/Spped Up.rb
Normal file
@@ -0,0 +1,71 @@
|
||||
|
||||
#==============================================================================#
|
||||
# Better Fast-forward Mode #
|
||||
# v1.0 #
|
||||
# #
|
||||
# by Marin #
|
||||
#==============================================================================#
|
||||
# Usage #
|
||||
# #
|
||||
# SPEEDUP_STAGES are the speed stages the game will pick from. If you click F, #
|
||||
# it'll choose the next number in that array. It goes back to the first number #
|
||||
# afterward. #
|
||||
# #
|
||||
# $GameSpeed is the current index in the speed up array. #
|
||||
# Should you want to change that manually, you can do, say, $GameSpeed = 0 #
|
||||
# #
|
||||
# If you don't want the user to be able to speed up at certain points, you can #
|
||||
# use "pbDisallowSpeedup" and "pbAllowSpeedup". #
|
||||
#==============================================================================#
|
||||
# Please give credit when using this. #
|
||||
#==============================================================================#
|
||||
|
||||
PluginManager.register({
|
||||
:name => "Better Fast-forward Mode",
|
||||
:version => "1.1",
|
||||
:credits => "Marin",
|
||||
:link => "https://reliccastle.com/resources/151/"
|
||||
})
|
||||
|
||||
# When the user clicks F, it'll pick the next number in this array.
|
||||
SPEEDUP_STAGES = [1,2,3]
|
||||
|
||||
|
||||
def pbAllowSpeedup
|
||||
$CanToggle = true
|
||||
end
|
||||
|
||||
def pbDisallowSpeedup
|
||||
$CanToggle = false
|
||||
end
|
||||
|
||||
# Default game speed.
|
||||
$GameSpeed = 0
|
||||
$frame = 0
|
||||
$CanToggle = true
|
||||
|
||||
module Graphics
|
||||
class << Graphics
|
||||
alias fast_forward_update update
|
||||
end
|
||||
|
||||
def self.update
|
||||
if $CanToggle && Input.trigger?(Input::AUX1)
|
||||
$GameSpeed += 1
|
||||
$GameSpeed = 0 if $GameSpeed >= SPEEDUP_STAGES.size
|
||||
end
|
||||
$frame += 1
|
||||
if $PokemonSystem && $PokemonSystem.speedup == 1
|
||||
speedStage = SPEEDUP_STAGES[$GameSpeed]
|
||||
else
|
||||
speedStage = 1
|
||||
if Input.press?(Input::AUX1) && $CanToggle
|
||||
$PokemonSystem.speedup_speed = Settings::DEFAULT_SPEED_UP_SPEED if !$PokemonSystem.speedup_speed || $PokemonSystem.speedup_speed==0
|
||||
speedStage=$PokemonSystem.speedup_speed+1
|
||||
end
|
||||
end
|
||||
return unless $frame % speedStage == 0
|
||||
fast_forward_update
|
||||
$frame = 0
|
||||
end
|
||||
end
|
||||
55
Data/Scripts/052_InfiniteFusion/System/TempEvents.rb
Normal file
55
Data/Scripts/052_InfiniteFusion/System/TempEvents.rb
Normal file
@@ -0,0 +1,55 @@
|
||||
class PokemonTemp
|
||||
attr_accessor :tempEvents
|
||||
attr_accessor :silhouetteDirection
|
||||
|
||||
def tempEvents
|
||||
@tempEvents = {} if !@tempEvents
|
||||
return @tempEvents
|
||||
end
|
||||
|
||||
def pbClearTempEvents()
|
||||
return if !@tempEvents || @tempEvents.empty?
|
||||
@tempEvents.keys.each { |map_id|
|
||||
map = $MapFactory.getMapNoAdd(map_id)
|
||||
@tempEvents[map_id].each { |event|
|
||||
$game_self_switches[[map_id, event.id, "A"]] = false
|
||||
$game_self_switches[[map_id, event.id, "B"]] = false
|
||||
$game_self_switches[[map_id, event.id, "C"]] = false
|
||||
$game_self_switches[[map_id, event.id, "D"]] = false
|
||||
|
||||
map.events[event.id].erase if map.events[event.id]
|
||||
}
|
||||
}
|
||||
@tempEvents = {}
|
||||
@silhouetteDirection = nil
|
||||
end
|
||||
|
||||
def createTempEvent(eventTemplateID, map_id, position = [0, 0],direction=nil)
|
||||
template_event = $MapFactory.getMap(MAP_TEMPLATE_EVENTS,false).events[eventTemplateID]
|
||||
key_id = ($game_map.events.keys.max || -1) + 1
|
||||
|
||||
rpgEvent= template_event.event.dup
|
||||
rpgEvent.id = key_id
|
||||
gameEvent = Game_Event.new($game_map.map_id, rpgEvent, $game_map)
|
||||
|
||||
gameEvent.moveto(position[0], position[1])
|
||||
gameEvent.direction = direction if direction
|
||||
|
||||
registerTempEvent(map_id, gameEvent)
|
||||
|
||||
$game_map.events[key_id] = gameEvent
|
||||
sprite = Sprite_Character.new(Spriteset_Map.viewport, $game_map.events[key_id])
|
||||
$scene.spritesets[$game_map.map_id] = Spriteset_Map.new($game_map) if $scene.spritesets[$game_map.map_id] == nil
|
||||
$scene.spritesets[$game_map.map_id].character_sprites.push(sprite)
|
||||
return gameEvent
|
||||
end
|
||||
|
||||
def registerTempEvent(map, event)
|
||||
@tempEvents = {} if !@tempEvents
|
||||
mapEvents = @tempEvents.has_key?(map) ? @tempEvents[map] : []
|
||||
mapEvents.push(event)
|
||||
@tempEvents[map] = mapEvents
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
293
Data/Scripts/052_InfiniteFusion/System/UnrealTime.rb
Normal file
293
Data/Scripts/052_InfiniteFusion/System/UnrealTime.rb
Normal file
@@ -0,0 +1,293 @@
|
||||
# #===============================================================================
|
||||
# # * Unreal Time System - by FL (Credits will be apreciated)
|
||||
# #===============================================================================
|
||||
# #
|
||||
# # This script is for Pokémon Essentials. It makes the time in game uses its
|
||||
# # own clock that only pass when you are in game instead of using real time
|
||||
# # (like Minecraft and Zelda: Ocarina of Time).
|
||||
# #
|
||||
# #== INSTALLATION ===============================================================
|
||||
# #
|
||||
# # To this script works, put it above main OR convert into a plugin.
|
||||
# #
|
||||
# #== HOW TO USE =================================================================
|
||||
# #
|
||||
# # This script automatic works after installed.
|
||||
# #
|
||||
# # If you wish to add/reduce time, there are 3 ways:
|
||||
# #
|
||||
# # 1. EXTRA_SECONDS/EXTRA_DAYS are variables numbers that hold time passage;
|
||||
# # The time in these variable isn't affected by PROPORTION.
|
||||
# # Example: When the player sleeps you wish to the time in game advance
|
||||
# # 8 hours, so put in EXTRA_SECONDS a game variable number and sum
|
||||
# # 28800 (60*60*8) in this variable every time that the players sleeps.
|
||||
# #
|
||||
# # 2. 'UnrealTime.add_seconds(seconds)' and 'UnrealTime.add_days(days)' does the
|
||||
# # same thing, in fact, EXTRA_SECONDS/EXTRA_DAYS call these methods.
|
||||
# #
|
||||
# # 3. 'UnrealTime.advance_to(16,17,18)' advance the time to a fixed time of day,
|
||||
# # 16:17:18 on this example.
|
||||
# #
|
||||
# #== NOTES ======================================================================
|
||||
# #
|
||||
# # If you wish to some parts still use real time like the Trainer Card start time
|
||||
# # and Pokémon Trainer Memo, just change 'pbGetTimeNow' to 'Time.now' in their
|
||||
# # scripts.
|
||||
# #
|
||||
# # This script uses the Ruby Time class. Before Essentials version 19 (who came
|
||||
# # with 64-bit ruby) it can only have 1901-2038 range.
|
||||
# #
|
||||
# # Some time methods:
|
||||
# # 'pbGetTimeNow.year', 'pbGetTimeNow.mon' (the numbers from 1-12),
|
||||
# # 'pbGetTimeNow.day','pbGetTimeNow.hour', 'pbGetTimeNow.min',
|
||||
# # 'pbGetTimeNow.sec', 'pbGetAbbrevMonthName(pbGetTimeNow.mon)',
|
||||
# # 'pbGetTimeNow.strftime("%A")' (displays weekday name),
|
||||
# # 'pbGetTimeNow.strftime("%I:%M %p")' (displays Hours:Minutes pm/am)
|
||||
# #
|
||||
# #===============================================================================
|
||||
#
|
||||
# if defined?(PluginManager) && !PluginManager.installed?("Unreal Time System")
|
||||
# PluginManager.register({
|
||||
# :name => "Unreal Time System",
|
||||
# :version => "1.1",
|
||||
# :link => "https://www.pokecommunity.com/showthread.php?t=285831",
|
||||
# :credits => "FL"
|
||||
# })
|
||||
# end
|
||||
#
|
||||
module UnrealTime
|
||||
# Set false to disable this system (returns Time.now)
|
||||
ENABLED = true
|
||||
|
||||
# Time proportion here.
|
||||
# So if it is 100, one second in real time will be 100 seconds in game.
|
||||
# If it is 60, one second in real time will be one minute in game.
|
||||
PROPORTION = 60
|
||||
|
||||
# Starting on Essentials v17, the map tone only try to refresh tone each 30
|
||||
# real time seconds.
|
||||
# If this variable number isn't -1, the game use this number instead of 30.
|
||||
# When time is changed with advance_to or add_seconds, the tone refreshes.
|
||||
TONE_CHECK_INTERVAL = 10.0
|
||||
|
||||
# Make this true to time only pass at field (Scene_Map)
|
||||
# A note to scripters: To make time pass on other scenes, put line
|
||||
# '$PokemonGlobal.addNewFrameCount' near to line 'Graphics.update'
|
||||
TIME_STOPS = true
|
||||
|
||||
# Make this true to time pass in battle, during turns and command selection.
|
||||
# This won't affect the Pokémon and Bag submenus.
|
||||
# Only works if TIME_STOPS=true.
|
||||
BATTLE_PASS = true
|
||||
|
||||
# Make this true to time pass when the Dialog box or the main menu are open.
|
||||
# This won't affect the submenus like Pokémon and Bag.
|
||||
# Only works if TIME_STOPS=true.
|
||||
TALK_PASS = true
|
||||
|
||||
# Choose switch number that when true the time won't pass (or -1 to cancel).
|
||||
# Only works if TIME_STOPS=true.
|
||||
SWITCH_STOPS = -1
|
||||
|
||||
# Choose variable(s) number(s) that can hold time passage (or -1 to cancel).
|
||||
# Look at description for more details.
|
||||
EXTRA_SECONDS = 79
|
||||
EXTRA_DAYS = -1
|
||||
|
||||
WEEK_DAY_VARIABLE = 280
|
||||
WEEK_DAYS = [:MONDAY,:TUESDAY,:WEDNESDAY,:THURSDAY,:FRIDAY,:SATURDAY,:SUNDAY]
|
||||
|
||||
# Initial date. In sequence: Year, month, day, hour and minutes.
|
||||
# Method UnrealTime.reset resets time back to this time.
|
||||
def self.initial_date
|
||||
return Time.local(2000, 1, 1, 4, 0)
|
||||
end
|
||||
|
||||
# Advance to next time. If time already passed, advance
|
||||
# into the time on the next day.
|
||||
# Hour is 0..23
|
||||
def self.advance_to(hour, min = 0, sec = 0)
|
||||
if hour < 0 || hour > 23
|
||||
raise RangeError, "hour is #{hour}, should be 0..23"
|
||||
end
|
||||
day_seconds = 60 * 60 * 24
|
||||
seconds_now = pbGetTimeNow.hour * 60 * 60 + pbGetTimeNow.min * 60 + pbGetTimeNow.sec
|
||||
target_seconds = hour * 60 * 60 + min * 60 + sec
|
||||
seconds_added = target_seconds - seconds_now
|
||||
seconds_added += day_seconds if seconds_added < 0
|
||||
$PokemonGlobal.newFrameCount += seconds_added
|
||||
PBDayNight.sheduleToneRefresh
|
||||
end
|
||||
|
||||
# Resets time to initial_date.
|
||||
def self.reset
|
||||
raise "Method doesn't work when TIME_STOPS is false!" if !TIME_STOPS
|
||||
$game_variables[EXTRA_SECONDS] = 0 if EXTRA_DAYS > 0
|
||||
$game_variables[EXTRA_DAYS] = 0 if EXTRA_DAYS > 0
|
||||
$PokemonGlobal.newFrameCount = 0
|
||||
$PokemonGlobal.extraYears = 0
|
||||
PBDayNight.sheduleToneRefresh
|
||||
end
|
||||
|
||||
# Does the same thing as EXTRA_SECONDS variable.
|
||||
def self.add_seconds(seconds)
|
||||
raise "Method doesn't work when TIME_STOPS is false!" if !TIME_STOPS
|
||||
$PokemonGlobal.newFrameCount += (seconds * Graphics.frame_rate) / PROPORTION.to_f
|
||||
PBDayNight.sheduleToneRefresh
|
||||
end
|
||||
|
||||
def self.add_days(days)
|
||||
add_seconds(60 * 60 * 24 * days)
|
||||
end
|
||||
|
||||
NEED_32_BIT_FIX = [''].pack('p').size <= 4
|
||||
end
|
||||
|
||||
# Essentials V18 and lower compatibility
|
||||
module Settings
|
||||
TIME_SHADING = defined?(ENABLESHADING) ? ENABLESHADING : ::TIME_SHADING
|
||||
end if defined?(TIME_SHADING) || defined?(ENABLESHADING)
|
||||
|
||||
module PBDayNight
|
||||
class << self
|
||||
if method_defined?(:getTone) && UnrealTime::TONE_CHECK_INTERVAL > 0
|
||||
def getTone
|
||||
@cachedTone = Tone.new(0, 0, 0) if !@cachedTone
|
||||
return @cachedTone if !Settings::TIME_SHADING
|
||||
toneNeedUpdate = (!@dayNightToneLastUpdate ||
|
||||
Graphics.frame_count - @dayNightToneLastUpdate >=
|
||||
Graphics.frame_rate * UnrealTime::TONE_CHECK_INTERVAL
|
||||
)
|
||||
if toneNeedUpdate
|
||||
getToneInternal
|
||||
@dayNightToneLastUpdate = Graphics.frame_count
|
||||
end
|
||||
return @cachedTone
|
||||
end
|
||||
end
|
||||
|
||||
# Shedule a tone refresh on the next try (probably next frame)
|
||||
def sheduleToneRefresh
|
||||
@dayNightToneLastUpdate = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def getDayOfTheWeek()
|
||||
day_of_week = (pbGetTimeNow.day % UnrealTime::WEEK_DAYS.length).to_i
|
||||
return UnrealTime::WEEK_DAYS[day_of_week]
|
||||
end
|
||||
|
||||
def isDayOfTheWeek(day)
|
||||
return day == getDayOfTheWeek()
|
||||
end
|
||||
|
||||
def pbGetTimeNow
|
||||
return Time.now if !$PokemonGlobal || !UnrealTime::ENABLED
|
||||
day_seconds = 60 * 60 * 24
|
||||
if UnrealTime::TIME_STOPS
|
||||
# Sum the extra values to newFrameCount
|
||||
if UnrealTime::EXTRA_SECONDS > 0
|
||||
UnrealTime.add_seconds(pbGet(UnrealTime::EXTRA_SECONDS))
|
||||
$game_variables[UnrealTime::EXTRA_SECONDS] = 0
|
||||
end
|
||||
if UnrealTime::EXTRA_DAYS > 0
|
||||
UnrealTime.add_seconds(day_seconds * pbGet(UnrealTime::EXTRA_DAYS))
|
||||
$game_variables[UnrealTime::EXTRA_DAYS] = 0
|
||||
end
|
||||
elsif UnrealTime::EXTRA_SECONDS > 0 && UnrealTime::EXTRA_DAYS > 0
|
||||
# Checks to regulate the max/min values at UnrealTime::EXTRA_SECONDS
|
||||
while pbGet(UnrealTime::EXTRA_SECONDS) >= day_seconds
|
||||
$game_variables[UnrealTime::EXTRA_SECONDS] -= day_seconds
|
||||
$game_variables[UnrealTime::EXTRA_DAYS] += 1
|
||||
end
|
||||
while pbGet(UnrealTime::EXTRA_SECONDS) <= -day_seconds
|
||||
$game_variables[UnrealTime::EXTRA_SECONDS] += day_seconds
|
||||
$game_variables[UnrealTime::EXTRA_DAYS] -= 1
|
||||
end
|
||||
end
|
||||
start_time = UnrealTime.initial_date
|
||||
if UnrealTime::TIME_STOPS
|
||||
time_played = $PokemonGlobal.newFrameCount
|
||||
else
|
||||
time_played = Graphics.frame_count
|
||||
end
|
||||
time_played = (time_played * UnrealTime::PROPORTION) / Graphics.frame_rate
|
||||
time_jumped = 0
|
||||
if UnrealTime::EXTRA_SECONDS > -1
|
||||
time_jumped += pbGet(UnrealTime::EXTRA_SECONDS)
|
||||
end
|
||||
if UnrealTime::EXTRA_DAYS > -1
|
||||
time_jumped += pbGet(UnrealTime::EXTRA_DAYS) * day_seconds
|
||||
end
|
||||
time_ret = 0
|
||||
# Before Essentials V19, there is a year limit. To prevent crashes due to this
|
||||
# limit, every time that you reach in year 2036 the system will subtract 6
|
||||
# years (to works with leap year) from your date and sum in
|
||||
# $PokemonGlobal.extraYears. You can sum your actual year with this extraYears
|
||||
# when displaying years.
|
||||
loop do
|
||||
time_fix = 0
|
||||
if $PokemonGlobal.extraYears != 0
|
||||
time_fix = $PokemonGlobal.extraYears * day_seconds * (365 * 6 + 1) / 6
|
||||
end
|
||||
time_ret = start_time + (time_played + time_jumped - time_fix)
|
||||
break if !UnrealTime::NEED_32_BIT_FIX || time_ret.year < 2036
|
||||
$PokemonGlobal.extraYears += 6
|
||||
end
|
||||
return time_ret
|
||||
end
|
||||
|
||||
if UnrealTime::ENABLED
|
||||
class PokemonGlobalMetadata
|
||||
attr_accessor :newFrameCount # Became float when using extra values
|
||||
attr_accessor :extraYears
|
||||
|
||||
def addNewFrameCount
|
||||
return if (UnrealTime::SWITCH_STOPS > 0 &&
|
||||
$game_switches[UnrealTime::SWITCH_STOPS])
|
||||
self.newFrameCount += 1
|
||||
end
|
||||
|
||||
def newFrameCount
|
||||
@newFrameCount = 0 if !@newFrameCount
|
||||
return @newFrameCount
|
||||
end
|
||||
|
||||
def extraYears
|
||||
@extraYears = 0 if !@extraYears
|
||||
return @extraYears
|
||||
end
|
||||
end
|
||||
|
||||
if UnrealTime::TIME_STOPS
|
||||
class Scene_Map
|
||||
alias :updateold :update
|
||||
|
||||
def update
|
||||
$PokemonGlobal.addNewFrameCount
|
||||
updateold
|
||||
end
|
||||
|
||||
if UnrealTime::TALK_PASS
|
||||
alias :miniupdateold :miniupdate
|
||||
|
||||
def miniupdate
|
||||
$PokemonGlobal.addNewFrameCount
|
||||
miniupdateold
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if UnrealTime::BATTLE_PASS
|
||||
class PokeBattle_Scene
|
||||
alias :pbGraphicsUpdateold :pbGraphicsUpdate
|
||||
|
||||
def pbGraphicsUpdate
|
||||
$PokemonGlobal.addNewFrameCount
|
||||
pbGraphicsUpdateold
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
251
Data/Scripts/052_InfiniteFusion/System/platform.rb
Normal file
251
Data/Scripts/052_InfiniteFusion/System/platform.rb
Normal file
@@ -0,0 +1,251 @@
|
||||
#
|
||||
# # ▼▲▼ XRXS50. Action-Maps XC. ▼▲▼ built 033010
|
||||
# # by 桜雅 在土
|
||||
#
|
||||
# #======================================================
|
||||
# # □ Customization points
|
||||
# #======================================================
|
||||
# class XRXS50
|
||||
# #
|
||||
# # Action-Maps - ID maps actives
|
||||
# #
|
||||
#
|
||||
# ENABLE_FULL_ACTY_MAPS = [404,547,548,549,550,217,614,615,656]
|
||||
#
|
||||
# #
|
||||
# # Slide descent (diagonal drop)
|
||||
# #
|
||||
# ENABLE_SLIDE_DESCENT = true
|
||||
# #
|
||||
# # true: Jump in the direction facing orientation: Jump
|
||||
# # false : Jump to the direction in which the key is pressed.
|
||||
# #
|
||||
# JUMP_AS_KEY = true
|
||||
# end
|
||||
# #======================================================
|
||||
# # ■ Game_Player
|
||||
# #======================================================
|
||||
# class Game_Player < Game_Character
|
||||
# #------------------------------------------------------
|
||||
# # Public Variable
|
||||
# #------------------------------------------------------
|
||||
# # Existing
|
||||
# attr_writer :direction_fix
|
||||
# attr_accessor :walk_anime
|
||||
# # New
|
||||
# attr_accessor :now_jumps
|
||||
# attr_writer :xrxs50_direction_sidefix
|
||||
# #------------------------------------------------------
|
||||
# # ○Maximum jump number
|
||||
# #------------------------------------------------------
|
||||
# def max_jumps
|
||||
# return $game_switches[890] ? 5 : 2
|
||||
# end
|
||||
# #------------------------------------------------------
|
||||
# # ● Vers la gauche
|
||||
# #------------------------------------------------------
|
||||
# alias xrxs50_turn_left turn_left
|
||||
# def turn_left
|
||||
# if @xrxs50_direction_sidefix
|
||||
# @direction = 4
|
||||
# else
|
||||
# turn_generic(4)
|
||||
#
|
||||
#
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# #------------------------------------------------------
|
||||
# # ● Vers la droite
|
||||
# #------------------------------------------------------
|
||||
# alias xrxs50_turn_right turn_right
|
||||
# def turn_right
|
||||
# if @xrxs50_direction_sidefix
|
||||
# @direction = 6
|
||||
# else
|
||||
# turn_generic(6)
|
||||
# end
|
||||
# end
|
||||
# #------------------------------------------------------
|
||||
# # ● Vers le haut et le bas
|
||||
# #------------------------------------------------------
|
||||
# alias xrxs50_turn_up turn_up
|
||||
# def turn_up
|
||||
# if @xrxs50_direction_sidefix and Input.press?(Input::UP)
|
||||
# return if $game_switches[890]
|
||||
# @direction = 8
|
||||
# xrxs50_turn_up
|
||||
# else
|
||||
# turn_generic(8)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# alias xrxs50_turn_down turn_down
|
||||
# def turn_down
|
||||
# if @xrxs50_direction_sidefix and Input.press?(Input::DOWN)
|
||||
# xrxs50_turn_right
|
||||
# else
|
||||
# turn_generic(2)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# end
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# #======================================================
|
||||
# # ■ Scene_Map
|
||||
# #======================================================
|
||||
# class Scene_Map
|
||||
# #------------------------------------------------------
|
||||
# # ● Main processing
|
||||
# #------------------------------------------------------
|
||||
# alias xrxs50_main main
|
||||
# def main
|
||||
# # Check
|
||||
# xrxs50_enable_check
|
||||
# # Recall
|
||||
# xrxs50_main
|
||||
# end
|
||||
# #------------------------------------------------------
|
||||
# # ● Frame update
|
||||
# #------------------------------------------------------
|
||||
# alias xrxs50_update update
|
||||
# def update
|
||||
# # Recall
|
||||
# xrxs50_update
|
||||
# # Frame update (coordinate system update)
|
||||
# if @xrxs50_enable
|
||||
# update_coordinates
|
||||
# end
|
||||
# end
|
||||
# #------------------------------------------------------
|
||||
# # ○ Frame update (coordinate system update)
|
||||
# #------------------------------------------------------
|
||||
# def update_coordinates
|
||||
# if $game_player.passable?($game_player.x,$game_player.y,2) #2
|
||||
# unless $game_player.moving?
|
||||
#
|
||||
# if XRXS50::ENABLE_SLIDE_DESCENT and
|
||||
# Input.press?(Input::RIGHT) and
|
||||
# $game_player.passable?($game_player.x,$game_player.y+1,6) #1,6
|
||||
# $game_player.move_lower_right
|
||||
# $game_player.turn_right
|
||||
# elsif XRXS50::ENABLE_SLIDE_DESCENT and
|
||||
# Input.press?(Input::LEFT) and
|
||||
# $game_player.passable?($game_player.x,$game_player.y+1,4)
|
||||
# $game_player.move_lower_left
|
||||
# $game_player.turn_left
|
||||
# else
|
||||
# $game_player.move_down
|
||||
# end
|
||||
# end
|
||||
# else
|
||||
# if Input.trigger?(Input::UP) && !$game_switches[890]
|
||||
# @direction =8 #8
|
||||
# end
|
||||
# $game_player.move_down
|
||||
# $game_player.walk_anime = true unless $game_player.walk_anime
|
||||
# $game_player.now_jumps = 0
|
||||
#
|
||||
#
|
||||
# end
|
||||
#
|
||||
# input = $game_switches[890] ? Input::UP : Input::X
|
||||
# if Input.trigger?(input) and $game_player.now_jumps < $game_player.max_jumps
|
||||
# if XRXS50::JUMP_AS_KEY
|
||||
# direction = $game_player.direction == 4 ? -1 : 1
|
||||
# #si pas jump as key
|
||||
# else
|
||||
# if Input.press?(Input::RIGHT)
|
||||
# direction = 1
|
||||
# elsif Input.press?(Input::LEFT)
|
||||
# direction = -1
|
||||
# else
|
||||
# direction = 0
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# #if $game_switches[31] == true
|
||||
# # @direction =8 #8# Jump Height
|
||||
# #else
|
||||
# $game_player.jump(direction, -2)# Jump Height
|
||||
# pbSEPlay("Jump",100)
|
||||
# #end
|
||||
# $game_player.now_jumps += 1 #1
|
||||
# $game_player.walk_anime = false
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# #------------------------------------------------------
|
||||
# # ● Location movement of player
|
||||
# #------------------------------------------------------
|
||||
# #alias xrxs50_transfer_player transfer_player
|
||||
# #def transfer_player(cancelVehicles=false)
|
||||
# # #Recall
|
||||
# #xrxs50_transfer_player
|
||||
# # #Check
|
||||
# #xrxs50_enable_check
|
||||
# #end
|
||||
#
|
||||
# def transfer_player(cancelVehicles=true)
|
||||
# $game_temp.player_transferring = false
|
||||
# if cancelVehicles
|
||||
# Kernel.pbCancelVehicles($game_temp.player_new_map_id)
|
||||
# end
|
||||
# autofade($game_temp.player_new_map_id)
|
||||
# pbBridgeOff
|
||||
# if $game_map.map_id != $game_temp.player_new_map_id
|
||||
# $MapFactory.setup($game_temp.player_new_map_id)
|
||||
# end
|
||||
# $game_player.moveto($game_temp.player_new_x, $game_temp.player_new_y)
|
||||
# case $game_temp.player_new_direction
|
||||
# when 2
|
||||
# $game_player.turn_down
|
||||
# when 4
|
||||
# $game_player.turn_left
|
||||
# when 6
|
||||
# $game_player.turn_right
|
||||
# when 8
|
||||
# $game_player.turn_up
|
||||
# end
|
||||
#
|
||||
# xrxs50_enable_check
|
||||
# $game_player.straighten
|
||||
# $game_map.update
|
||||
# disposeSpritesets
|
||||
# GC.start
|
||||
# createSpritesets
|
||||
# if $game_temp.transition_processing
|
||||
# $game_temp.transition_processing = false
|
||||
# Graphics.transition(20)
|
||||
# end
|
||||
# $game_map.autoplay
|
||||
# Graphics.frame_reset
|
||||
# Input.update
|
||||
# end
|
||||
#
|
||||
#
|
||||
#
|
||||
# #------------------------------------------------------
|
||||
# # ○ XRXS50 Decision whether to run
|
||||
# #------------------------------------------------------
|
||||
# def xrxs50_enable_check
|
||||
# if XRXS50::ENABLE_FULL_ACTY_MAPS.include?($game_map.map_id)
|
||||
#
|
||||
# $game_player.now_jumps = 0 if $game_player.now_jumps.nil?
|
||||
# @xrxs50_enable = true #Gravité
|
||||
# $game_player.direction_fix =true
|
||||
# $game_player.xrxs50_direction_sidefix = true
|
||||
#
|
||||
# else
|
||||
# @xrxs50_enable = false
|
||||
# $game_player.direction_fix = false
|
||||
# $game_player.xrxs50_direction_sidefix = false
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
#
|
||||
#
|
||||
Reference in New Issue
Block a user