- Fixed Bug, where end speeches wouldn't work on the player side in a simulated battle
- Fixed Bug, where recompiling the trainers pbs wouldn't updated the scripted battles
- Fixed Bug, where in simulated battles the player could still choose the next Pokemon for the player side
How to update (Clean installation only)
1. Replace your whole 14_Scripted_Battle_Compile script section with the following content
Ruby:#=============================================================================== # Compile scripted battles #=============================================================================== def pbCompileScriptedBattles(mustCompile = false) return if !$DEBUG # create a dummy trainer to prevent errors # just replace it with whatever trainer you have defined path = "PBS/battles/" name = "blueVSBrock2" files = Dir.entries(path) latestDataTime = 0 latestTextTime = 0 # Check data files and PBS files, and recompile if any PBS file was edited # more recently than the data files were last created files.each{ |f| next if !/\.(?:rb|txt)$/i.match(f) fData = f.gsub(/\.(?:rb|txt)$/i,".dat") begin File.open("Data/#{fData}") { |file| latestDataTime = [latestDataTime,file.mtime.to_i].max } rescue SystemCallError mustCompile = true end } files.each{ |f| next if !/\.(?:rb|txt)$/i.match(f) begin File.open("#{path}#{f}") { |file| latestTextTime = [latestTextTime,file.mtime.to_i].max } rescue SystemCallError end } mustCompile |= (latestTextTime>=latestDataTime) if mustCompile $Trainer = PokeBattle_Trainer.new(:RIVAL1,"Blue") files.each{ |f| next if !/\.(?:rb|txt)$/i.match(f) records = [] pbCompilerEachPreppedLine("#{path}#{f}") { |line,lineno| records.push(line) } code = "" for rec in records code += "#{rec}\r\n" end begin script = eval(code) rescue SyntaxError => e pbPrintException(e) end name = f.gsub(/\.(?:rb|txt)$/i,'') save_data(script,"Data/#{name}.dat") } $Trainer = nil end end
2. In the Compiler script section (the one from Essentials), change
toRuby:# Compile scripted battles pbCompileScriptedBattles
Ruby:# Compile scripted battles pbCompileScriptedBattles(mustCompile)
3. Replace your whole 2_PField_Simulated_Battles script section with the following content
Ruby:#=============================================================================== # Start a trainer battle #=============================================================================== def pbSimulatedTrainerBattleCore(players,opponents,fullNames=[false,false]) outcomeVar = $PokemonTemp.battleRules["outcomeVar"] || 1 canLose = $PokemonTemp.battleRules["canLose"] || false # Skip battle if the player has no able Pokémon, or if holding Ctrl in Debug mode if $Trainer.ablePokemonCount==0 || ($DEBUG && Input.press?(Input::CTRL)) pbMessage(_INTL("SKIPPING BATTLE...")) if $DEBUG pbMessage(_INTL("AFTER WINNING...")) if $DEBUG && $Trainer.ablePokemonCount>0 pbSet(outcomeVar,($Trainer.ablePokemonCount==0) ? 0 : 1) # Treat it as undecided/a win $PokemonTemp.clearBattleRules $PokemonGlobal.nextBattleBGM = nil $PokemonGlobal.nextBattleME = nil $PokemonGlobal.nextBattleCaptureME = nil $PokemonGlobal.nextBattleBack = nil return ($Trainer.ablePokemonCount==0) ? 0 : 1 # Treat it as undecided/a win end # Record information about party Pokémon to be used at the end of battle (e.g. # comparing levels for an evolution check) Events.onStartBattle.trigger(nil) # Generate trainers and their parties based on the arguments given foeTrainers = [] foeItems = [] foeEndSpeeches = [] foeParty = [] foePartyStarts = [] for opponent in opponents raise _INTL("Expected an array of trainer data, got {1}.",opponent) if !opponent.is_a?(Array) if opponent[0].is_a?(PokeBattle_Trainer) # [trainer object, party, end speech, items] foeTrainers.push(opponent[0]) foePartyStarts.push(foeParty.length) opponent[1].each { |pkmn| foeParty.push(pkmn) } foeEndSpeeches.push(opponent[2]) foeItems.push(opponent[3]) else # [trainer type, trainer name, ID, speech (optional)] trainer = pbLoadTrainer(opponent[0],opponent[1],opponent[2]) pbMissingTrainer(opponent[0],opponent[1],opponent[2]) if !trainer return 0 if !trainer Events.onTrainerPartyLoad.trigger(nil,trainer) foeTrainers.push(trainer[0]) foePartyStarts.push(foeParty.length) trainer[2].each { |pkmn| foeParty.push(pkmn) } foeEndSpeeches.push(opponent[3] || trainer[3]) foeItems.push(trainer[1]) end end # Calculate who the player trainer(s) and their party are playerTrainers = [] playerParty = [] playerPartyStarts = [] playerItems = [] playerEndSpeeches = [] for player in players raise _INTL("Expected an array of trainer data, got {1}.",player) if !player.is_a?(Array) if player[0].is_a?(PokeBattle_Trainer) # [trainer object, party, end speech, items] playerTrainers.push(player[0]) playerPartyStarts.push(playerParty.length) player[1].each { |pkmn| playerParty.push(pkmn) } playerEndSpeeches.push(player[2]) playerItems.push(player[3]) echo("Was trainer object") echo(player[2]) else # [trainer type, trainer name, ID, speech (optional)] trainer = pbLoadTrainer(player[0],player[1],player[2]) pbMissingTrainer(player[0],player[1],player[2]) if !trainer return 0 if !trainer Events.onTrainerPartyLoad.trigger(nil,trainer) playerTrainers.push(trainer[0]) playerPartyStarts.push(playerParty.length) trainer[2].each { |pkmn| playerParty.push(pkmn) } playerEndSpeeches.push(player[3] || trainer[3]) playerItems.push(trainer[1]) end end # Create the battle scene (the visual side of it) scene = pbNewBattleScene # Create the battle class (the mechanics side of it) battle = PokeBattle_SimulatedBattle.new(scene,playerParty,foeParty,playerTrainers,foeTrainers,fullNames) battle.party1starts = playerPartyStarts battle.party2starts = foePartyStarts battle.items = foeItems battle.endSpeeches = foeEndSpeeches battle.playerEndspeeches = playerEndSpeeches # Set various other properties in the battle class pbPrepareBattle(battle) $PokemonTemp.clearBattleRules # End the trainer intro music Audio.me_stop # Perform the battle itself decision = 0 pbScriptedBattleAnimation(pbGetTrainerBattleBGM(foeTrainers),(battle.singleBattle?) ? 1 : 3,foeTrainers, playerTrainers) { pbSceneStandby { decision = battle.pbStartBattle } pbAfterSimulatedBattle(decision,canLose) } Input.update # Save the result of the battle in a Game Variable (1 by default) # 0 - Undecided or aborted # 1 - Player won # 2 - Player lost # 3 - Player or wild Pokémon ran from battle, or player forfeited the match # 5 - Draw pbSet(outcomeVar,decision) return decision end #=============================================================================== # Standard methods that start a simulated trainer battle of various sizes #=============================================================================== def pbSimulatedTrainerBattle(player,opponent,size0=1,size1=1,canLose=true,outcomeVar=1,fullNames=[false,false]) # Set some battle rules setBattleRule("outcomeVar",outcomeVar) if outcomeVar!=1 setBattleRule("canLose") if canLose setBattleRule(sprintf("%dv%d",size0,size1)) # Perform the battle if player.is_a?(Array) players = [] for pl in player players.push([pl.trainerID,pl.trainerName,pl.trainerPartyID,pl.endSpeech]) end else players = [[player.trainerID,player.trainerName,player.trainerPartyID,player.endSpeech]] end if opponent.is_a?(Array) opponents = [] for op in opponent opponents.push([op.trainerID,op.trainerName,op.trainerPartyID,op.endSpeech]) end else opponents = [[opponent.trainerID,opponent.trainerName,opponent.trainerPartyID,opponent.endSpeech]] end decision = pbSimulatedTrainerBattleCore(players,opponents,fullNames) $PokemonTemp.waitingTrainer = nil # Return true if the player won the battle, and false if any other result return (decision==1) end #=============================================================================== # After battles #=============================================================================== def pbAfterSimulatedBattle(decision,canLose) if decision==2 || decision==5 # if loss or draw if canLose $Trainer.party.each { |pkmn| pkmn.heal } (Graphics.frame_rate/4).times { Graphics.update } end end Events.onEndBattle.trigger(nil,decision,canLose) end Events.onEndBattle += proc { |sender,e| decision = e[0] canLose = e[1] case decision when 1, 4 # Win, capture when 2, 5 # Lose, draw if !canLose $game_system.bgm_unpause $game_system.bgs_unpause pbStartOver end end }
4. Replace your whole 5_Simulated_Battle_Switching script section with the following content
Ruby:class PokeBattle_SimulatedBattle def pbGetOwnerName(idxBattler) owner = pbGetOwnerFromBattlerIndex(idxBattler) return pbGetNameOf(owner,opposes?(idxBattler)) end # For choosing a replacement Pokémon when prompted in the middle of other # things happening (U-turn, Baton Pass, in def pbSwitch). def pbSwitchInBetween(idxBattler,checkLaxOnly=false,canCancel=false) return @battleAI.pbDefaultChooseNewEnemy(idxBattler,pbParty(idxBattler)) end def pbOwnedByPlayer?(idxBattler) return false if opposes?(idxBattler) return pbGetOwnerIndexFromBattlerIndex(idxBattler)==0 && !@controlPlayer end end
This new version contains a permanent solution to this bug, which was caused by my script trying to access trainer data before that was compiled. With that bug fix your scripted battles will only recompile when they have changed and compiling them will always happen after compiling everything else.
How to update (Clean Installation Only)
1. Replace your whole 14_Scripted_Battle_Compile script section with the following content
Ruby:#=============================================================================== # Compile scripted battles #=============================================================================== def pbCompileScriptedBattles return if !$DEBUG # create a dummy trainer to prevent errors # just replace it with whatever trainer you have defined path = "PBS/battles/" name = "blueVSBrock2" files = Dir.entries(path) latestDataTime = 0 latestTextTime = 0 mustCompile = false # Check data files and PBS files, and recompile if any PBS file was edited # more recently than the data files were last created files.each{ |f| next if !/\.(?:rb|txt)$/i.match(f) fData = f.gsub(/\.(?:rb|txt)$/i,".dat") begin File.open("Data/#{fData}") { |file| latestDataTime = [latestDataTime,file.mtime.to_i].max } rescue SystemCallError mustCompile = true end } files.each{ |f| next if !/\.(?:rb|txt)$/i.match(f) begin File.open("#{path}#{f}") { |file| latestTextTime = [latestTextTime,file.mtime.to_i].max } rescue SystemCallError end } mustCompile |= (latestTextTime>=latestDataTime) if mustCompile $Trainer = PokeBattle_Trainer.new(:RIVAL1,"Blue") files.each{ |f| next if !/\.(?:rb|txt)$/i.match(f) records = [] pbCompilerEachPreppedLine("#{path}#{f}") { |line,lineno| records.push(line) } code = "" for rec in records code += "#{rec}\r\n" end begin script = eval(code) rescue SyntaxError => e pbPrintException(e) end name = f.gsub(/\.(?:rb|txt)$/i,'') save_data(script,"Data/#{name}.dat") } $Trainer = nil end end
2. In the Compiler script section (the one from Essentials), right after
addRuby:if !$INEDITOR && LANGUAGES.length>=2 pbLoadMessages("Data/"+LANGUAGES[$PokemonSystem.language][1]) end
Ruby:# Compile scripted battles pbCompileScriptedBattles
With this update you can now use Z-Moves, Ultra Burst, Dynamax and GMax in scripted battles. To make this work you will need the ZUD Plugin by Lucidious89 and StCooler.
Say thanks to the two people who suggested this support :)
There won't be support for Raid Battles, as that requires too much rework, for the time that I got.
For this major update, I highly recommend doing a complete new installation. Just remove the old script sections and replace them with the new ones.
With this version I added full VS Animation support. Just make sure to have all files set up (see here).
With this version there is one more file added: Shared_PField_Visuals.txt
Update Guide (Clean installation only)
If you have already installed the script and want to update you can do either of the following things. In both cases you need to add a new script section named Shared_PField_Visuals and copy over the content of the file with the same name.
Option 1:
Change pbBattleAnimation to pbScriptedBattleAnimation and add ,player after ,foe
in the following places
Line Numbers are assuming no changes were made:PField_Simulated_Battles, Line 96 PField_Scripted_Battles, Line 77 PField_Scripted_Battles, Line 219
Option 2:
Replace the whole PField_Scripted_Battles and PField_Simulated_Battles script sections with the new files
Summary
- Merged :moveMessage with :tryUseMoveMessage
- They can both be used to show a message, whenever a Pokemon tries to use a move, regardless of success
- I lost (or removed on purpose) the code that was used for :moveMessage and after investigating, decided that there is no need to differentiate between those two
- Updated docs
Changed files/sections
- Scripted_Battle_Battler_2
- Scripted_Battle_Docs
Changed methods
- def pbTryUseMove
To update your project copy the contents of the changed files/sections or replace the changed methods.
There was an oversight in the first release, that would break protect and multihit moves in normal battles. This is fixed now.
Either redownload the folder and replace everything with dirty.txt if you are using the dirty approach or replace the contents of Scripted_Battle_Moves Script Section with the content of the file.
Or just copy the new version here and replace the whole methods.
Update:class PokeBattle_Move_0C0 < PokeBattle_Move def pbNumHits(user,targets) if isConst?(@id,PBMoves,:WATERSHURIKEN) && isConst?(user.species,PBSpecies,:GRENINJA) && user.form==1 return 3 end if defined?(@battle.script) hits = user.roundParams[:multiHit] return hits if !hits.nil? end hitChances = [2,2,3,3,4,5] r = @battle.pbRandom(hitChances.length) r = hitChances.length-1 if user.hasActiveAbility?(:SKILLLINK) return hitChances[r] end end class PokeBattle_ProtectMove < PokeBattle_Move def pbMoveFailed?(user,targets) success = nil if defined?(@battle.script) success = user.roundParams[:success] return false if success end if @sidedEffect if user.pbOwnSide.effects[@effect] user.effects[PBEffects::ProtectRate] = 1 @battle.pbDisplay(_INTL("But it failed!")) return true end elsif user.effects[@effect] || (!success.nil? && success == false) user.effects[PBEffects::ProtectRate] = 1 @battle.pbDisplay(_INTL("But it failed!")) return true end if !(@sidedEffect && NEWEST_BATTLE_MECHANICS) && user.effects[PBEffects::ProtectRate]>1 && @battle.pbRandom(user.effects[PBEffects::ProtectRate])!=0 user.effects[PBEffects::ProtectRate] = 1 @battle.pbDisplay(_INTL("But it failed!")) return true end if pbMoveFailedLastInRound?(user) user.effects[PBEffects::ProtectRate] = 1 return true end return false end end