• Just a reminder that providing specifics on, sharing links to, or naming websites where ROMs can be accessed is against the rules. If your post has any of this information it will be removed.
  • Ever thought it'd be cool to have your art, writing, or challenge runs featured on PokéCommunity? Click here for info - we'd love to spotlight your work!
  • Our weekly protagonist poll is now up! Vote for your favorite Trading Card Game 2 protagonist in the poll by clicking here.
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

[Scripting Question] Ditto's Imposter but it targets the last Pokemon in your party - Why is my code for this Ability crashing?

  • 428
    Posts
    5
    Years
    My goal is to make an ability like Ditto's Imposter, except instead of Transforming into your opponent it targets the final Pokemon in your party like "Illusion" would and Transforms Ditto into that last Pokemon in your party.

    Code:
    Battle::AbilityEffects::OnSwitchIn.add(:DOPPELGANGERSTYLE,
      proc { |ability, battler, battle, switch_in|
        next if !switch_in || battler.effects[PBEffects::Transform]
        choice = @battle.pbLastInTeam(@index)
        #    choice = idxLastParty
        #    choice = battler.idxLastParty
        next if choice.fainted?
        next if choice.effects[PBEffects::Transform] ||
                choice.effects[PBEffects::Illusion] ||
                choice.effects[PBEffects::Substitute] > 0 ||
                choice.effects[PBEffects::SkyDrop] >= 0 ||
                choice.semiInvulnerable?
        battle.pbShowAbilitySplash(battler, true)
        battle.pbHideAbilitySplash(battler)
        battle.pbAnimation(:TRANSFORM, battler, choice)
        battle.scene.pbChangePokemon(battler, choice.pokemon)
        battler.pbTransform(choice)
      }
    )

    If you're wondering about the lines that start with "#", those are the other Choice codes I tried using for "Final Pokemon in party". They always create an error message saying my choice is an undefined method or variable.

    Code:
    [Pokémon Essentials version 20.1]
    [v20.1 Hotfixes 1.0.2]
    
    Script error in event 22 (coords 23,7), map 156 (Aaa's house)
    Exception: NoMethodError
    Message: undefined method `pbLastInTeam' for nil:NilClass
    
    ***Full script:
    TrainerBattle.start(:YOUNGSTER, "CALVIN", 0)
    Backtrace:
    215:Battle_AbilityEffects:2912:in `block in <main>'
    035:Event_Handlers:227:in `trigger'
    215:Battle_AbilityEffects:265:in `triggerOnSwitchIn'
    151:Battle_ActionSwitching:352:in `block in pbOnBattlerEnteringBattle'
    151:Battle_ActionSwitching:331:in `each'
    151:Battle_ActionSwitching:331:in `pbOnBattlerEnteringBattle'
    151:Battle_ActionSwitching:306:in `pbOnAllBattlersEnteringBattle'
    148:Battle_StartAndEnd:312:in `pbStartBattleCore'
    148:Battle_StartAndEnd:270:in `pbStartBattle'
    242:Overworld_BattleStarting:513:in `block (2 levels) in start_core'

    Here's the code I'm using under the Illusion code just in case.

    Code:
        @effects[PBEffects::Illusion]            = nil
        if hasActiveAbility?(:ILLUSION)
          idxLastParty = @battle.pbLastInTeam(@index)
          if idxLastParty >= 0 && idxLastParty != @pokemonIndex
            @effects[PBEffects::Illusion]        = @battle.pbParty(@index)[idxLastParty]
          end
        end
            if hasActiveAbility?(:DOPPELGANGERSTYLE)
          idxLastParty = @battle.pbLastInTeam(@index)
        end
        @effects[PBEffects::Imprison]            = false
     
    I did what you said, what does this new error message mean?
    Code:
    [Pokémon Essentials version 20.1]
    [v20.1 Hotfixes 1.0.2]
    
    Script error in event 22 (coords 23,7), map 156 (Aaa's house)
    Exception: NoMethodError
    Message: undefined method `index' for 0:Integer
    
    ***Full script:
    TrainerBattle.start(:YOUNGSTER, "CALVIN", 0)
    Backtrace:
    190:Scene_PlayAnimations:527:in `pbAnimationCore'
    190:Scene_PlayAnimations:505:in `block in pbAnimation'
    190:Scene_PlayAnimations:401:in `pbSaveShadows'
    190:Scene_PlayAnimations:501:in `pbAnimation'
    147:Battle:838:in `pbAnimation'
    215:Battle_AbilityEffects:2917:in `block in <main>'
    035:Event_Handlers:227:in `trigger'
    215:Battle_AbilityEffects:265:in `triggerOnSwitchIn'
    151:Battle_ActionSwitching:352:in `block in pbOnBattlerEnteringBattle'
    151:Battle_ActionSwitching:331:in `each'

    Code:
    Battle::AbilityEffects::OnSwitchIn.add(:DOPPELGANGERSTYLE,
      proc { |ability, battler, battle, switch_in|
        next if !switch_in || battler.effects[PBEffects::Transform]
        choice = battle.pbLastInTeam(@index)
        #    choice = idxLastParty
        #    choice = battler.idxLastParty
        battle.pbShowAbilitySplash(battler, true)
        battle.pbHideAbilitySplash(battler)
        battle.pbAnimation(:TRANSFORM, battler, choice)
        battle.scene.pbChangePokemon(battler, choice.pokemon)
        battler.pbTransform(choice)
      }
    )
     
    Code:
        choice = battle.pbLastInTeam(@index)

    Same kind of error; @index is undefined. What you want is the index of the battler ^^
    Code:
        choice = battle.pbLastInTeam(battler.index)
     
    That code results in this error when I send out the Ditto with the Doppelganger ability and it tries Transforming into the last Pokemon in my party.

    Code:
    [Pokémon Essentials version 20.1]
    [v20.1 Hotfixes 1.0.2]
    
    Script error in event 23 (coords 21,8), map 156 (Aaa's house)
    Exception: NoMethodError
    Message: undefined method `index' for 3:Integer
    
    ***Full script:
    TrainerBattle.start(:BUGCATCHER, "JAMES", 0)
    Backtrace:
    190:Scene_PlayAnimations:527:in `pbAnimationCore'
    190:Scene_PlayAnimations:505:in `block in pbAnimation'
    190:Scene_PlayAnimations:401:in `pbSaveShadows'
    190:Scene_PlayAnimations:501:in `pbAnimation'
    147:Battle:838:in `pbAnimation'
    215:Battle_AbilityEffects:2915:in `block in <main>'
    035:Event_Handlers:227:in `trigger'
    215:Battle_AbilityEffects:265:in `triggerOnSwitchIn'
    151:Battle_ActionSwitching:352:in `block in pbOnBattlerEnteringBattle'
    151:Battle_ActionSwitching:331:in `each'

    Or this one.

    Code:
    [Pokémon Essentials version 20.1]
    [v20.1 Hotfixes 1.0.2]
    
    Script error in event 22 (coords 23,7), map 156 (A's house)
    Exception: NoMethodError
    Message: undefined method `index' for 5:Integer
    
    ***Full script:
    TrainerBattle.start(:YOUNGSTER, "CALVIN", 0)
    Backtrace:
    190:Scene_PlayAnimations:527:in `pbAnimationCore'
    190:Scene_PlayAnimations:505:in `block in pbAnimation'
    190:Scene_PlayAnimations:401:in `pbSaveShadows'
    190:Scene_PlayAnimations:501:in `pbAnimation'
    147:Battle:838:in `pbAnimation'
    215:Battle_AbilityEffects:2915:in `block in <main>'
    035:Event_Handlers:227:in `trigger'
    215:Battle_AbilityEffects:265:in `triggerOnSwitchIn'
    151:Battle_ActionSwitching:352:in `block in pbOnBattlerEnteringBattle'
    151:Battle_ActionSwitching:331:in `each'
     
    Last edited:
    They're the same error twice :(

    Can you tell us what is line 2915 in 215:Battle_AbilityEffects?

    I suspect this is because you use an integer instead of a battler, but I can't see it if I don't have the code.
     
    Line 2915 is " battle.pbAnimation(:TRANSFORM, battler, choice)"

    This is everything from line 2909 to 2919

    Code:
    Battle::AbilityEffects::OnSwitchIn.add(:DOPPELGANGER,
      proc { |ability, battler, battle, switch_in|
        next if !switch_in || battler.effects[PBEffects::Transform]
    choice = battle.pbLastInTeam(battler.index)
        battle.pbShowAbilitySplash(battler, true)
        battle.pbHideAbilitySplash(battler)
        battle.pbAnimation(:TRANSFORM, battler, choice)
        battle.scene.pbChangePokemon(battler, choice.pokemon)
        battler.pbTransform(choice)
      }
    )
     
    I suspect this is a bug in Essentials.
    Can you post the code around line 527 in 190:Scene_PlayAnimations: `pbAnimationCore'?
    Also, I see in your code, you should put the line:
    Code:
        battle.pbHideAbilitySplash(battler)
    at the end, otherwise the ability spalsh will appear and disappear right after.
     
    Here you go.
    Code:
      def pbAnimationCore(animation, user, target, oppMove = false)
        return if !animation
        @briefMessage = false
        userSprite   = (user) ? @sprites["pokemon_#{user.index}"] : nil
        targetSprite = (target) ? @sprites["pokemon_#{target.index}"] : nil
        # Remember the original positions of Pokémon sprites
        oldUserX = (userSprite) ? userSprite.x : 0
        oldUserY = (userSprite) ? userSprite.y : 0
        oldTargetX = (targetSprite) ? targetSprite.x : oldUserX
        oldTargetY = (targetSprite) ? targetSprite.y : oldUserY
        # Create the animation player
        animPlayer = PBAnimationPlayerX.new(animation, user, target, self, oppMove)
        # Apply a transformation to the animation based on where the user and target
        # actually are. Get the centres of each sprite.
        userHeight = (userSprite&.bitmap && !userSprite.bitmap.disposed?) ? userSprite.bitmap.height : 128
        if targetSprite
          targetHeight = (targetSprite.bitmap && !targetSprite.bitmap.disposed?) ? targetSprite.bitmap.height : 128
        else
          targetHeight = userHeight
        end
        animPlayer.setLineTransform(
          FOCUSUSER_X, FOCUSUSER_Y, FOCUSTARGET_X, FOCUSTARGET_Y,
          oldUserX, oldUserY - (userHeight / 2), oldTargetX, oldTargetY - (targetHeight / 2)
        )
        # Play the animation
        animPlayer.start
        loop do
          animPlayer.update
          pbUpdate
          break if animPlayer.animDone?
        end
        animPlayer.dispose
        # Return Pokémon sprites to their original positions
        if userSprite
          userSprite.x = oldUserX
          userSprite.y = oldUserY
          userSprite.pbSetOrigin
        end
        if targetSprite
          targetSprite.x = oldTargetX
          targetSprite.y = oldTargetY
          targetSprite.pbSetOrigin
        end
      end

    Also, did I put the ability-hiding code in the right place?

    Code:
    Battle::AbilityEffects::OnSwitchIn.add(:DOPPELGANGER,
      proc { |ability, battler, battle, switch_in|
        next if !switch_in || battler.effects[PBEffects::Transform]
    choice = battle.pbLastInTeam(battler.index)
        battle.pbShowAbilitySplash(battler, true)
        battle.pbHideAbilitySplash(battler)
        battle.pbAnimation(:TRANSFORM, battler, choice)
        battle.scene.pbChangePokemon(battler, choice.pokemon)
        battler.pbTransform(choice)
            battle.pbHideAbilitySplash(battler)
      }
    )
     
    Here you go.
    Ok I know what the error is.
    *Play generic anime revelation soundtrack*
    The line:
    Code:
    choice = battle.pbLastInTeam(battler.index)
    gives an integer. It gives the index of the last Pokémon in your team. Thus, it is a number, and not a Pokémon; it is neither a PokeBattle_Pokemon (a Pokémon in your team) nor a PokeBattle_Battler (a Pokémon in battle).

    However, the line:
    Code:
        battle.pbAnimation(:TRANSFORM, battler, choice)
    requires that the third parameter (here, "choice") should be a Pokémon in battle, and it cannot do anything with integers.
    This is because :TRANSFORM is a move animation that requires a user Pokémon and a target Pokémon in battle. This function doesn't let you to transform a Pokémon into another.

    So, what can you do to have an animation? I suggest you take a look at how Mega-Evolutions work; you have two animations, one for the beginning of the animation, and one for the "flash" at the end of the mega-evolution. The animation doesn't actually "transforms" a Pokémon to its Mega-Evolution, it hides the fact that the sprites are swapped by a script.
    I don't know what the animation of Transform is but, I know how animations work in Essentials, and I assume that this animation doesn't transform, it probably juste hides the fact that the sprites are swapped, just like Mega-Evolutions. So, the animation for Transform is probably just and self-targetted animation.
    You can try to replace with this line:
    Code:
        battle.pbAnimation(:TRANSFORM, battler, battler)
    and it should do the job.

    Now I want to anticipate the next bug that you will have:
    Code:
        battle.scene.pbChangePokemon(battler, choice.pokemon)
        battler.pbTransform(choice)
    Again, "choice" here is a number, and those lines expect a Pokémon in battle (a PokeBattle_Battler).
    The first line is the actual transformation of the Pokémon from Ditto to the last Pokémon in the same team as the Ditto. You can access the last Pokémon with:
    Code:
    battle.pbParty(battler.index)[choice]
    What you want is this line:
    Code:
        battle.scene.pbChangePokemon(battler, battle.pbParty(battler.index)[choice])

    Also, I'm looking at Mega-Evolutions, because it's a functioning code that also changes a Pokémon.
    In the function "pbMegaEvolve", I see this:
    Code:
        battler.pbUpdate(true)
        @scene.pbChangePokemon(battler,battler.pokemon)
        @scene.pbRefreshOne(idxBattler)
    which can convert to:
    Code:
        battler.pbUpdate(true)
        battle.scene.pbChangePokemon(battler,battle.pbParty(battler.index)[choice])
        battle.scene.pbRefreshOne(battler.index)
    Now I don't have v20 so I cannot ensure this is the exact code but I think you can fix yourself with the right functions.

    As for the line:
    Code:
        battler.pbTransform(choice)
    actually it would take the stat changes and a few other effects in battle, but it expects "choice" to be a Pokémon in battle.

    I think you will need to make a new function that works a bit like pbTransform, but that can take a Pokémon from the team, instead of a Pokémon in battle. (Yes, both are not the same "kind of objects" in the code).
    Paste this close to the code for your ability:
    Spoiler:

    If you look at the original code of pbTransform, you will see that I removed the lines that don't make sense for a Pokémon that is not in battle (because it also takes the stat changes and a few other things).

    Then you need to use this function in your code:
    Code:
        battler.pbTransform2(battle.pbParty(battler.index)[choice])

    And now the complete code looks like this:
    Spoiler:


    Also, did I put the ability-hiding code in the right place?
    You should delete the first ability-hiding line too ^^

    NB: try to "align" the lines; add space before:
    Code:
    choice = battle.pbLastInTeam(battler.index)
    and remove some space before:
    [CODE]
            battle.pbHideAbilitySplash(battler)
    it makes it more readable for devs ^^
     
    Thank you for the new code. What does this new error mean?

    Code:
    [Pokémon Essentials version 20.1]
    [v20.1 Hotfixes 1.0.2]
    
    Script error in event 22 (coords 23,7), map 156 (Aaa's house)
    Exception: ArgumentError
    Message: Invalid argument passed to method.
    Expected #<Pokemon STARMIE Lv.50> to be one of [Symbol, GameData::Type, String], but got Pokemon.
    
    ***Full script:
    TrainerBattle.start(:YOUNGSTER, "CALVIN", 0)
    Backtrace:
    015:Validation:29:in `validate'
    103:GameData:92:in `get'
    162:Battler_ChangeSelf:137:in `pbChangeTypes'
    162:Battler_ChangeSelf:349:in `pbTransform2'
    215:Battle_AbilityEffects:2917:in `block in <main>'
    035:Event_Handlers:227:in `trigger'
    215:Battle_AbilityEffects:265:in `triggerOnSwitchIn'
    151:Battle_ActionSwitching:352:in `block in pbOnBattlerEnteringBattle'
    151:Battle_ActionSwitching:331:in `each'
    151:Battle_ActionSwitching:331:in `pbOnBattlerEnteringBattle'

    I got an error when I tried putting the Transform2 code under the Doppelganger ability so I tried putting that Transform2 code in Battler_ChangeSelf under the original Transform code, above "def pbHyperMode; end". Now the Transform code can run, but it crashes because it doesn't seem to understand what it tries turning into. Starmie lv50 is the 6th Pokemon in my party. But I have experimented with other Pokemon in my 6th party slot. They all cause the same error.
     
    Last edited:
    Ah it's my bad...

    If you check the code of pbChangeTypes:
    Spoiler:


    it takes either a Pokémon in battle, or the new type directly, but not the Pokémon.

    We can change that:

    Spoiler:
     
    I changed the new type code to match yours, what does this error message mean?

    Code:
    [Pokémon Essentials version 20.1]
    [v20.1 Hotfixes 1.0.2]
    
    Script error in event 22 (coords 23,7), map 156 (A's house)
    Exception: NoMethodError
    Message: undefined method `effects' for #<Pokemon LOPUNNY Lv.50>
    
    ***Full script:
    TrainerBattle.start(:YOUNGSTER, "CALVIN", 0)
    Backtrace:
    162:Battler_ChangeSelf:365:in `pbTransform2'
    215:Battle_AbilityEffects:2917:in `block in <main>'
    035:Event_Handlers:227:in `trigger'
    215:Battle_AbilityEffects:265:in `triggerOnSwitchIn'
    151:Battle_ActionSwitching:352:in `block in pbOnBattlerEnteringBattle'
    151:Battle_ActionSwitching:331:in `each'
    151:Battle_ActionSwitching:331:in `pbOnBattlerEnteringBattle'
    151:Battle_ActionSwitching:306:in `pbOnAllBattlersEnteringBattle'
    148:Battle_StartAndEnd:312:in `pbStartBattleCore'
    148:Battle_StartAndEnd:270:in `pbStartBattle'
     
    Line 365 is this:
    Code:
        @effects[PBEffects::WeightChange] = poke.effects[PBEffects::WeightChange]

    From this:
    Code:
      def pbTransform2(poke) # Note the "2" here
        oldAbil = @ability_id
        @effects[PBEffects::Transform]        = true
        @effects[PBEffects::TransformSpecies] = poke.species
        pbChangeTypes(poke)
        self.ability = poke.ability
        @attack  = poke.attack
        @defense = poke.defense
        @spatk   = poke.spatk
        @spdef   = poke.spdef
        @speed   = poke.speed
        @moves.clear
        poke.moves.each_with_index do |m, i|
          @moves[i] = Battle::Move.from_pokemon_move(@battle, Pokemon::Move.new(m.id))
          @moves[i].pp       = 5
          @moves[i].total_pp = 5
        end
        @effects[PBEffects::WeightChange] = poke.effects[PBEffects::WeightChange]
        @battle.scene.pbRefreshOne(@index)
        @battle.pbDisplay(_INTL("{1} transformed into {2}!", pbThis, poke.name))
        pbOnLosingAbility(oldAbil)
      end
    end
     
    Remove that line, it should be ok.
     
    It worked!

    The game still pauses on ability activation for the time it would take for an animation of Ditto transforming to play, but Ditto doesn't transform. But this is fine, at least he transforms properly now.
     
    Back
    Top