Pokémon Essentials’ battle system handles everything from damage calculation to status effects, weather, and ability triggers. Understanding these systems is essential for creating custom moves, abilities, and battle mechanics.
The fundamental class representing a Pokémon in battle:
Data/EditorScripts/031_PokeBattle_Pokemon.rb
class PokeBattle_Pokemon attr_reader(:totalhp) # Current Total HP attr_reader(:attack) # Current Attack stat attr_reader(:defense) # Current Defense stat attr_reader(:speed) # Current Speed stat attr_reader(:spatk) # Current Special Attack stat attr_reader(:spdef) # Current Special Defense stat attr_accessor(:hp) # Current HP attr_accessor(:status) # Status problem (PBStatuses) attr_accessor(:statusCount) # Sleep count/Toxic flag attr_accessor(:item) # Held item attr_accessor(:moves) # Moves (PBMove) attr_accessor(:iv) # Individual Values (6 values) attr_accessor(:ev) # Effort Values (6 values) EVLIMIT = 510 # Max total EVs EVSTATLIMIT = 252 # Max EVs that a single stat can haveend
class PBMove attr_reader(:id) # This move's ID attr_accessor(:pp) # The amount of PP remaining attr_accessor(:ppup) # The number of PP Ups used # Gets this move's type. def type movedata=PBMoveData.new(@id) return movedata.type end # Gets the maximum PP for this move. def totalpp movedata=PBMoveData.new(@id) tpp=movedata.totalpp return tpp+(tpp*@ppup/5).floor endend
Every Pokémon has base stats that determine their potential:
Data/EditorScripts/031_PokeBattle_Pokemon.rb
# Returns this Pokémon's base stats. An array of six values.def baseStats dexdata=pbOpenDexData pbDexDataOffset(dexdata,@species,10) ret=[ dexdata.fgetb, # HP dexdata.fgetb, # Attack dexdata.fgetb, # Defense dexdata.fgetb, # Speed dexdata.fgetb, # Special Attack dexdata.fgetb # Special Defense ] dexdata.close return retend
# Returns the specified stat of this Pokémon (not used for total HP).def calcStat(base,level,iv,ev,pv) return ((((base*2+iv+(ev>>2))*level/100).floor+5)*pv/100).floorend
The pv parameter is the nature modifier:
110 for boosted stats (e.g., Adamant boosts Attack)
90 for reduced stats (e.g., Adamant reduces Sp. Atk)
# Recalculates this Pokémon's stats.def calcStats nature=self.nature stats=[] pvalues=[100,100,100,100,100] nd5=(nature/5).floor nm5=(nature%5).floor if nd5!=nm5 pvalues[nd5]=110 # Boosted stat pvalues[nm5]=90 # Reduced stat end level=self.level bs=self.baseStats for i in 0..5 base=bs[i] if i==PBStats::HP stats[i]=calcHP(base,level,@iv[i],@ev[i]) else stats[i]=calcStat(base,level,@iv[i],@ev[i],pvalues[i-1]) end end @totalhp=stats[0] @attack=stats[1] @defense=stats[2] @speed=stats[3] @spatk=stats[4] @spdef=stats[5]end
# Silently learns the given move. Will erase the first known move if it has to.def pbLearnMove(move) if move.is_a?(String) || move.is_a?(Symbol) move=getID(PBMoves,move) end return if move<=0 # Check if already knows the move for i in 0...4 if @moves[i].id==move # Move to end of list if already known j=i+1; while j<4 break if @moves[j].id==0 tmp=@moves[j] @moves[j]=@moves[j-1] @moves[j-1]=tmp j+=1 end return end end # Find empty slot for i in 0...4 if @moves[i].id==0 @moves[i]=PBMove.new(move) return end end # No empty slots, replace first move @moves[0]=@moves[1] @moves[1]=@moves[2] @moves[2]=@moves[3] @moves[3]=PBMove.new(move)end
attr_accessor(:status) # Status problem (PBStatuses) attr_accessor(:statusCount) # Sleep count/Toxic flag# Heals the status problem of this Pokémon.def healStatus return if isEgg? @status=0 @statusCount=0end
# Heals all HP of this Pokémon.def healHP return if isEgg? @hp=@totalhpend# Heals all PP of this Pokémon.def healPP(index=-1) return if isEgg? if index>=0 @moves[index].pp=@moves[index].totalpp else for i in 0...4 @moves[i].pp=@moves[i].totalpp end endend# Heals all HP, PP, and status problems of this Pokémon.def heal return if isEgg? healHP healStatus healPPend
# Returns the ID of this Pokemon's ability.def ability abil=abilityIndex abils=getAbilityList ret1=0; ret2=0 for i in 0...abils.length next if !abils[i][0] || abils[i][0]<=0 return abils[i][0] if abils[i][1]==abil ret1=abils[i][0] if abils[i][1]==0 ret2=abils[i][0] if abils[i][1]==1 end abil=(@personalID&1) if abil>=2 return ret2 if abil==1 && ret2>0 return ret1end# Returns whether this Pokémon has a particular ability.def hasAbility?(value=0) if value==0 return self.ability>0 else if value.is_a?(String) || value.is_a?(Symbol) value=getID(PBAbilities,value) end return self.ability==value end return falseend
The battle challenge system for facilities like Battle Tower:
Data/EditorScripts/036_PBattle_OrgBattle.rb
def pbOrganizedBattleEx(opponent,challengedata,endspeech,endspeechwin) if !challengedata challengedata=PokemonChallengeRules.new end scene=pbNewBattleScene # Heal all Pokémon for i in 0...$Trainer.party.length $Trainer.party[i].heal end # Store original items olditems=$Trainer.party.transform{|p| p.item } # Create battle battle=challengedata.createBattle(scene,$Trainer,opponent) battle.internalbattle=false battle.endspeech=endspeech battle.endspeechwin=endspeechwin # Adjust levels oldlevels=challengedata.adjustLevels($Trainer.party,opponent.party) # Start battle pbPrepareBattle(battle) decision=0 trainerbgm=pbGetTrainerBattleBGM(opponent) pbBattleAnimation(trainerbgm) { pbSceneStandby { decision=battle.pbStartBattle } } # Restore original state challengedata.unadjustLevels($Trainer.party,opponent.party,oldlevels) for i in 0...$Trainer.party.length $Trainer.party[i].heal $Trainer.party[i].setItem(olditems[i]) end return (decision==1)end