• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • 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] Battle AI Problems

3
Posts
8
Years
    • Seen Jul 3, 2020
    Hello to everyone.

    I've been trying to improve pokemon essentials AI on my own. While doing so, I've run into the folowing problem:

    Spoiler:


    What I'm trying to do with this is that the NPC trainer changes his pokemon when he doesn't have a super effective or neutral attack against the pokemon you have on the field. The thing is that after laying entry hazards (the first lines of the script do that, ensure that the pokemon controled by the AI always lays entry hazards before changing) the NPC starts swapping pokemon over and over again, never attacking when he should. As an example, if you (the player) have a Golbat and the NPC (the opponent) has a Joltik, Joltik should use an electric type move but the NPC changes Joltik instead of attacking.

    I'm pretty certain that the error is in one of those lines so I'd like for someone to tell me what I've done wrong with the script. I'd also like to keep the script as it is so please tell me how to fix it, not an entirely new one.

    Also, on a slightly different note, how can I make a reference to the other pokemon on my team (and on the opponent's team as well)? I mean the ones that are not currently in battle.

    Thanks in advance.
     
    Last edited:

    Telemetius

    Tele*
    267
    Posts
    9
    Years
  • Just a guess, maybe it's due to this spelling mistake:
    Code:
    @battlers[index].moves[0].type!=(:PSYQUIC) &&

    Code:
    @battlers[index].moves[0].type!=(:PSYCHIC) &&
     
    3
    Posts
    8
    Years
    • Seen Jul 3, 2020
    Just fixed that. It wasn't the problem. In fact, in the example I posted (Golbat vs Joltik) the psychic type doesn't matter at all. The mistake must be somewhere else, because the script isn't working at all.

    Thanks for noting the misspell, btw.
     

    Maruno

    Lead Dev of Pokémon Essentials
    5,286
    Posts
    16
    Years
    • Seen May 3, 2024
    Code:
    if (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::StickyWeb]) && @battlers[index].moves[0].function==0x153) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::StickyWeb]) && @battlers[index].moves[1].function==0x153) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::StickyWeb]) && @battlers[index].moves[2].function==0x153) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::StickyWeb]) && @battlers[index].moves[3].function==0x153) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::StealthRock]) && @battlers[index].moves[0].function==0x105) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::StealthRock]) && @battlers[index].moves[1].function==0x105) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::StealthRock]) && @battlers[index].moves[2].function==0x105) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::StealthRock]) && @battlers[index].moves[3].function==0x105) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::Spikes]) && @battlers[index].moves[0].function==0x103) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::Spikes]) && @battlers[index].moves[1].function==0x103) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::Spikes]) && @battlers[index].moves[2].function==0x103) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::Spikes]) && @battlers[index].moves[3].function==0x103) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::ToxicSpikes]) && @battlers[index].moves[0].function==0x104) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::ToxicSpikes]) && @battlers[index].moves[1].function==0x104) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::ToxicSpikes]) && @battlers[index].moves[2].function==0x104) ||
       (!(@battlers[index].pbOppositeOpposing.pbOwnSide.effects[PBEffects::ToxicSpikes]) && @battlers[index].moves[3].function==0x104)
      shouldswitch=false
    Part one of your code. That's a veritable wall of text. Note that the effects values for Spikes and Toxic Spikes are NOT booleans, they are numbers, so sticking a ! in front of it is meaningless at best and error-causing at worst.

    Let's remember that the battler script section contains a method called pbHasMoveFunction?(code), which lets us immediately reduce the code to a quarter of its size. Let us also turn the long code @battlers[index].pbOppositeOpposing.pbOwnSide into something shorter and easier to use:

    Code:
    oppside = @battlers[index].pbOppositeOpposing.pbOwnSide
    if (oppside.effects[PBEffects::StickyWeb]==false && @battlers[index].pbHasMoveFunction?(0x153)) ||
       (oppside.effects[PBEffects::StealthRock]==false && @battlers[index].pbHasMoveFunction?(0x105)) ||
       (oppside.effects[PBEffects::Spikes]==0 && @battlers[index].pbHasMoveFunction?(0x103)) ||
       (oppside.effects[PBEffects::StickyWeb]==0 && @battlers[index].pbHasMoveFunction?(0x104))
      shouldswitch = false
    Looks nicer, yes?

    Code:
    elsif ((@battlers[index].pbOppositeOpposing.pbHasType?(:POISON) && 
       @battlers[index].pbOppositeOpposing.pbHasType?(:FLYING) && 
       @battlers[index].moves[0].type!=(:STEEL) &&   
       @battlers[index].moves[0].type!=(:GHOST) && 
       @battlers[index].moves[0].type!=(:WATER) &&  
       @battlers[index].moves[0].type!=(:DRAGON) &&
       @battlers[index].moves[0].type!=(:ELECTRIC) && 
       @battlers[index].moves[0].type!=(:FIRE) &&
       @battlers[index].moves[0].type!=(:ICE) &&
       @battlers[index].moves[0].type!=(:PSYQUIC) &&
       @battlers[index].moves[0].type!=(:NORMAL) &&
       @battlers[index].moves[0].type!=(:DARK) &&
       @battlers[index].moves[0].type!=(:FLYING) &&
       @battlers[index].moves[0].type!=(:ROCK) && 
       @battlers[index].moves[1].type!=(:STEEL) &&   
       @battlers[index].moves[1].type!=(:GHOST) && 
       @battlers[index].moves[1].type!=(:WATER) &&  
       @battlers[index].moves[1].type!=(:DRAGON) &&
       @battlers[index].moves[1].type!=(:ELECTRIC) && 
       @battlers[index].moves[1].type!=(:FIRE) &&
       @battlers[index].moves[1].type!=(:ICE) &&
       @battlers[index].moves[1].type!=(:PSYQUIC) &&
       @battlers[index].moves[1].type!=(:NORMAL) &&
       @battlers[index].moves[1].type!=(:DARK) &&
       @battlers[index].moves[1].type!=(:FLYING) &&
       @battlers[index].moves[1].type!=(:ROCK) &&   
       @battlers[index].moves[2].type!=(:STEEL) &&   
       @battlers[index].moves[2].type!=(:GHOST) && 
       @battlers[index].moves[2].type!=(:WATER) &&  
       @battlers[index].moves[2].type!=(:DRAGON) &&
       @battlers[index].moves[2].type!=(:ELECTRIC) && 
       @battlers[index].moves[2].type!=(:FIRE) &&
       @battlers[index].moves[2].type!=(:ICE) &&
       @battlers[index].moves[2].type!=(:PSYQUIC) &&
       @battlers[index].moves[2].type!=(:NORMAL) &&
       @battlers[index].moves[2].type!=(:DARK) &&
       @battlers[index].moves[2].type!=(:FLYING) &&
       @battlers[index].moves[2].type!=(:ROCK) && 
       @battlers[index].moves[3].type!=(:STEEL) &&   
       @battlers[index].moves[3].type!=(:GHOST) && 
       @battlers[index].moves[3].type!=(:WATER) &&  
       @battlers[index].moves[3].type!=(:DRAGON) &&
       @battlers[index].moves[3].type!=(:ELECTRIC) && 
       @battlers[index].moves[3].type!=(:FIRE) &&
       @battlers[index].moves[3].type!=(:ICE) &&
       @battlers[index].moves[3].type!=(:PSYQUIC) &&
       @battlers[index].moves[3].type!=(:NORMAL) &&
       @battlers[index].moves[3].type!=(:DARK) &&
       @battlers[index].moves[3].type!=(:FLYING) &&
       @battlers[index].moves[3].type!=(:ROCK)))
      shouldswitch=true
    Part two. Blimey. There's a simpler way of checking the type effectiveness. Also, you should probably be checking effectivenesses against both opposing Pokémon (only ones that are not fainted, mind), because if you aren't that good against one opposing Pokémon in a double battle but you can deal out a bunch of damage to the other opponent, why switch out? Furthermore, what's the point of checking the effectiveness of a status move?

    The error being talked about above is because you're comparing a number (the move's type) to a symbol (:PSYCHIC or whatever). To correctly compare them, use code like isConst?(move.type,PBTypes,:PSYCHIC). However, I won't be doing this, because as I said, there's a better way to check effectivenesses.

    I'm going to ignore the part of your code which checks whether the opposing Pokémon is a Poison/Flying type, because from what you've said, that just sounds like a test, rather than what you actually want.

    Code:
    else
      opp1 = @battlers[index].pbOpposing1
      opp2 = @battlers[index].pbOpposing2
      haseffectivemove = false
      for i in @battlers[index].moves
        next if i.pbIsStatus?
        if (!opp1.isFainted? &&
           PBTypes.getCombinedEffectiveness(i.type,opp1.type1,opp1.type2,opp1.effects[PBEffects::Type3])>=8) ||
           (!opp2.isFainted? &&
           PBTypes.getCombinedEffectiveness(i.type,opp2.type1,opp2.type2,opp2.effects[PBEffects::Type3])>=8)
          haseffectivemove = true; break
        end
      end
      shouldswitch = true if !haseffectivemove
    end
    Normal effectiveness is 8, so >=8 is normal effectiveness or better.

    Code:
    elsif (@battlers[index].pbOppositeOpposing.pbHasType?(:POISON) &&
       @battlers[index].moves[0].type!=(:STEEL) &&
       @battlers[index].moves[0].type!=(:WATER) &&
       @battlers[index].moves[0].type!=(:DRAGON) &&
       @battlers[index].moves[0].type!=(:GHOST) &&
       @battlers[index].moves[0].type!=(:ELECTRIC) &&
       @battlers[index].moves[0].type!=(:FIRE) &&
       @battlers[index].moves[0].type!=(:ICE) && 
       @battlers[index].moves[0].type!=(:NORMAL) &&
       @battlers[index].moves[0].type!=(:ROCK) &&
       @battlers[index].moves[0].type!=(:PSYQUIC) &&
       @battlers[index].moves[0].type!=(:DARK) &&
       @battlers[index].moves[0].type!=(:EARTH) &&
       @battlers[index].moves[0].type!=(:FLYING) && 
       @battlers[index].moves[1].type!=(:STEEL) &&
       @battlers[index].moves[1].type!=(:WATER) &&
       @battlers[index].moves[1].type!=(:DRAGON) &&
       @battlers[index].moves[1].type!=(:GHOST) &&
       @battlers[index].moves[1].type!=(:ELECTRIC) &&
       @battlers[index].moves[1].type!=(:FIRE) &&
       @battlers[index].moves[1].type!=(:ICE) && 
       @battlers[index].moves[1].type!=(:NORMAL) &&
       @battlers[index].moves[1].type!=(:ROCK) &&
       @battlers[index].moves[1].type!=(:PSYQUIC) &&
       @battlers[index].moves[1].type!=(:DARK) &&
       @battlers[index].moves[1].type!=(:EARTH) &&
       @battlers[index].moves[1].type!=(:FLYING) && 
       @battlers[index].moves[2].type!=(:STEEL) &&
       @battlers[index].moves[2].type!=(:WATER) &&
       @battlers[index].moves[2].type!=(:DRAGON) &&
       @battlers[index].moves[2].type!=(:GHOST) &&
       @battlers[index].moves[2].type!=(:ELECTRIC) &&
       @battlers[index].moves[2].type!=(:FIRE) &&
       @battlers[index].moves[2].type!=(:ICE) && 
       @battlers[index].moves[2].type!=(:NORMAL) &&
       @battlers[index].moves[2].type!=(:ROCK) &&
       @battlers[index].moves[2].type!=(:PSYQUIC) &&
       @battlers[index].moves[2].type!=(:DARK) &&
       @battlers[index].moves[2].type!=(:EARTH) &&
       @battlers[index].moves[2].type!=(:FLYING) && 
       @battlers[index].moves[3].type!=(:STEEL) &&
       @battlers[index].moves[3].type!=(:WATER) &&
       @battlers[index].moves[3].type!=(:DRAGON) &&
       @battlers[index].moves[3].type!=(:GHOST) &&
       @battlers[index].moves[3].type!=(:ELECTRIC) &&
       @battlers[index].moves[3].type!=(:FIRE) &&
       @battlers[index].moves[3].type!=(:ICE) && 
       @battlers[index].moves[3].type!=(:NORMAL) &&
       @battlers[index].moves[3].type!=(:ROCK) &&
       @battlers[index].moves[3].type!=(:PSYQUIC) &&
       @battlers[index].moves[3].type!=(:DARK) &&
       @battlers[index].moves[3].type!=(:EARTH) &&
       @battlers[index].moves[3].type!=(:FLYING))
      shouldswitch=true     
    end
    Third part. More effectiveness checking here. But really, if we ignore the "is the opponent Poison-type?" part, this is already covered by my modifications to the second part. So we can scrap this part entirely.

    I ended up turning all your code into this:

    Code:
    oppside = @battlers[index].pbOppositeOpposing.pbOwnSide
    if (oppside.effects[PBEffects::StickyWeb]==false && @battlers[index].pbHasMoveFunction?(0x153)) ||
       (oppside.effects[PBEffects::StealthRock]==false && @battlers[index].pbHasMoveFunction?(0x105)) ||
       (oppside.effects[PBEffects::Spikes]==0 && @battlers[index].pbHasMoveFunction?(0x103)) ||
       (oppside.effects[PBEffects::StickyWeb]==0 && @battlers[index].pbHasMoveFunction?(0x104))
      shouldswitch = false
    else
      opp1 = @battlers[index].pbOpposing1
      opp2 = @battlers[index].pbOpposing2
      haseffectivemove = false
      for i in @battlers[index].moves
        next if i.pbIsStatus?
        if (!opp1.isFainted? &&
           PBTypes.getCombinedEffectiveness(i.type,opp1.type1,opp1.type2,opp1.effects[PBEffects::Type3])>=8) ||
           (!opp2.isFainted? &&
           PBTypes.getCombinedEffectiveness(i.type,opp2.type1,opp2.type2,opp2.effects[PBEffects::Type3])>=8)
          haseffectivemove = true; break
        end
      end
      shouldswitch = true if !haseffectivemove
    end
    Note that I've been using
    Code:
    [/COLOR] tags in my post, not [COLOR="Green"][spoiler][/COLOR] tags. Code goes in [COLOR="Green"][code][/COLOR] tags.
     
    Back
    Top