v18 Wild double battles: 1v2 does not become 2v2 if Revive if used

This thread pertains to v18 of Pokémon Essentials.

darthmohawk1

Rookie
Member
Joined
Mar 18, 2021
Posts
2
Age
30
Short version: If I force a wild double battle while the player has only 1 non-fainted Pokemon, and then use the first turn of the battle to revive a second one, the game does not give a prompt to add the newly-revived Pokemon to the battle at the end of the turn.

Detailed version:
I downloaded a fresh copy of Essentials 18.1 to test a script to make all wild encounters into double battles.
I made two edits. The first: in the section "PField_Field", I removed the clause "$Trainer.ablePokemonCount>1" (around line 389), so that the game would initialize a double battle even if the player has 1 able Pokemon in their team:
Code:
  if $PokemonEncounters.pbCanEncounter?(encounter,repel)
    if !$PokemonTemp.forceSingleBattle && !pbInSafari? && ($PokemonGlobal.partner ||
       (PBTerrain.isDoubleWildBattle?(pbGetTerrainTag)))

Second, I went into the "PBTerrain" script section and added terrain types to the definition of "isDoubleWildBattle?" (starting on line 90), so that double encounters occur not just in tall grass, but in any grass:
Code:
  def self.isDoubleWildBattle?(tag)
    return tag==PBTerrain::Grass ||
           tag==PBTerrain::TallGrass
  end

Somewhat to my surprise, this change does not cause Essentials to crash when entering a battle with only 1 active Pokemon in the party (as per this resource). (I'm guessing v18 reorganized the battle system to fix that.)
However, the problem is, Essentials then loads the battle as a 1v2 fight, rather than as a 2v2 with only 1 Pokemon on the player's side. Thus, if the player uses the first turn of the fight to revive a second Pokemon, the game does not give a prompt to add the newly-revived Pokemon to the battle at the end of the turn.
How do I fix this behavior to work properly?
Thanks to any who offer help or solutions.
 

NettoHikari

Cooltrainer
Member
Joined
Jan 4, 2019
Posts
198
It seems like a really difficult task to try to change the side sizes mid-battle. It's true that v18 made it easier to define side sizes before the battle starts, but once the battle's initialized all the variables associated with each side, I think you would need to take all of those into account to try to modify the side sizes during battle.

That said, I remember that Vendily made an SOS battle script for v18: https://reliccastle.com/resources/444/. You can see here that this script manages to add an extra foe to the enemy's side during battle, so in your case, you could potentially take inspiration from the script to make it add an extra partner to the player's side.
 

darthmohawk1

Rookie
Member
Joined
Mar 18, 2021
Posts
2
Age
30
So I tried a few things this week. Some worked, some didn't.
I feel like I'm most of the way there (or at least above half?) but would appreciate a little extra guidance from someone who knows the code better than I do after only a week of investigation.

EDIT 3/21/21: I got something to work more properly. I'll post the code later; feel free to remind me if i don't post it this week.

I figured the easiest way to tackle the problem of fixing a 1v2 into a pseudo-2v2, followed by a "normal" 2v2, would be to edit the battle parameters immediately after the battle setup is done, but before the first turn starts. So I added a couple more code segments. First, under "Battle_StartAndEnd", starting on line 32 immediately after the line defining "side2counts":
Code:
    side1recounts = pbTotalTeamCounts(0)
   
    # Increase a 1v2 battle to a 2v2 battle if player's party is 2+
    if side1counts[0]==1 && side2counts[0]>=2 && side1recounts[0]>=2
      side1counts[0] = 2
    end
This code adds an extra "slot" to the player's team if it only has 1.

Naturally we have to define "side1recounts" - this is basically just a clone of "side1counts" but modified slightly to also count fainted Pokemon. That code is under "PokeBattle_Battle"; I put it on line 361, just after the block for "pbAbleTeamCounts":
Code:
  # For the given side of the field (0=player's, 1=opponent's), returns an array
  # containing the total number of Pokémon in each team.
  def pbTotalTeamCounts(side)
    party = pbParty(side)
    partyStarts = pbPartyStarts(side)
    ret = []
    idxTeam = -1
    nextStart = 0
    party.each_with_index do |pkmn,i|
      if i>=nextStart
        idxTeam += 1
        nextStart = (idxTeam<partyStarts.length-1) ? partyStarts[idxTeam+1] : party.length
      end
      next if !pkmn
      ret[idxTeam] = 0 if !ret[idxTeam]
      ret[idxTeam] += 1
    end
    return ret
  end

Then I added one more segment in "Battle_StartAndEnd" - the objective is to add one of the player's fainted Pokemon to "fill" the second "slot" created by the first code block earlier in the starting procedure, so that when the player revives one of his other 'Mons, the game will trigger a "Use next Pokemon?" prompt as per normal when it runs pbEORSwitch and, hopefully, add the revived Pokemon to the battle without me having to do any real heavy lifting:
Code:
    # If the battle has been set up as a 1v2 but there are fainted Pokemon
    # in the party, increase the size to 2v2, then set one of the
    # fainted Pokemon into the new slot
    side1origcount = pbAbleTeamCounts(0)
    side1recount = pbTotalTeamCounts(0)
    if side1origcount[0]==1 && @sideSizes[0]=2>=2 && side1recount[0]>=2
      @sideSizes[0]=2 # this line is redundant but it's OK to include as a reminder
     
      # For each trainer in turn, find the needed number of Pokémon for them to
      # send out, and initialize them
      ret = [[],[]]
      trainer = @player
      battlerNumber = 1
      requireds = []
      # Find out how many Pokémon each trainer on side needs to have
      for i in 0...@sideSizes[0]
        idxTrainer = pbGetOwnerIndexFromBattlerIndex(i*2+0)
        requireds[idxTrainer] = 0 if requireds[idxTrainer].nil?
        requireds[idxTrainer] += 1
      end
      trainer.each_with_index do |_t,idxTrainer|
        ret[0][idxTrainer] = []
        count = 0
        eachInTeam(0,idxTrainer) do |pkmn,idxPkmn|
          count += 1
          next if pkmn.able? || count==1
          idxBattler = 2
          pbCreateBattler(idxBattler,pkmn,idxPkmn)
          ret[0][idxTrainer].push(idxBattler)
          battlerNumber += 1
          break # if ret[0][idxTrainer].length>=requireds[idxTrainer]
        end
      end
    end
There's probably an easier way to write this, but I'm shooting for function before I try to make this mish-mash of copypasta "look nice".

What actually happens when the code is run?
Well, if the player enters some tall grass with exactly 1 able Pokemon and at least 1 fainted Pokemon and gets a double battle, the game will put that lone able Pokemon into the left slot of a double-battle team, leaving the right slot empty. So far so good.
Then we can use our Pokemon's turn to use a Max Revive. The wild Pokemon use their moves as normal, and at the end of the turn, the game gives us a "Use next Pokemon?" prompt. Also good. But when we select the revived Pokemon to toss out into battle, we get this error:
Code:
[Pokémon Essentials version 18.1]
Exception: NoMethodError
Message: undefined method `setPokemonBitmap' for nil:NilClass

Backtrace:
PokeBattle_Scene:323:in `pbChangePokemon'
Scene_Animations:100:in `pbSendOutBattlers'
Scene_Animations:98:in `each_with_index'
Scene_Animations:98:in `each'
Scene_Animations:98:in `each_with_index'
Scene_Animations:98:in `pbSendOutBattlers'
Battle_Action_Switching:296:in `pbSendOut'
Battle_Action_Switching:288:in `pbReplace'
Battle_Action_Switching:231:in `pbRecallAndReplace'
Battle_Action_Switching:199:in `pbEORSwitch'
...and while this doesn't crash the game outright, a host of bad things follow the initial error.

Based on the error message I'm getting back, I'm betting there's something wrong with the initial definition of the "blank" slot that's supposed to be "filled" with one of the player's fainted Pokemon. I'm not sure what the exact problem is yet, though. Another pair of eyes on it would be helpful - thanks in advance!
 
Last edited:

NettoHikari

Cooltrainer
Member
Joined
Jan 4, 2019
Posts
198
Just from first glance, I think the error you're getting is from not setting up the PokeBattle_Battler object in addition to setting up the new "slot", even though that PokeBattle_Battler object would just be empty (have default values) to start with. But yeah, post your new code since it seems like you have a better version.
 
Top