class PokeBattle_Battler attr_reader :battle attr_reader :totalhp attr_reader :pokemon attr_reader :name attr_reader :index attr_reader :fainted attr_reader :pokemonIndex attr_reader :usingsubmove attr_accessor :lastAttacker attr_accessor :turncount attr_accessor :effects attr_accessor :type1 attr_accessor :type2 attr_accessor :ability attr_accessor :level attr_accessor :species attr_accessor :attack attr_accessor :defense attr_accessor :speed attr_accessor :spatk attr_accessor :iv attr_accessor :spdef attr_accessor :participants attr_accessor :happiness attr_accessor :stages attr_accessor :moves attr_accessor :lastHPLost attr_accessor :lastMoveUsed attr_accessor :lastMoveUsedSketch attr_accessor :lastMoveCalled attr_accessor :currentMove attr_accessor :damagestate ### -- complex accessors def gender return @pokemon.gender if @pokemon return 2 end attr_reader :level def level=(value) @level=value @pokemon.level=value if @pokemon end attr_reader :status def status=(value) @status=value @pokemon.status=value if @pokemon if value!=PBStatuses::POISON @effects[PBEffects::Toxic]=0 end if value!=PBStatuses::POISON && value!=PBStatuses::SLEEP @statusCount=0 @pokemon.statusCount=0 if @pokemon end end attr_reader :statusCount def statusCount=(value) @statusCount=value @pokemon.statusCount=value if @pokemon end attr_reader :hp def hp=(value) @hp=value @pokemon.hp=value if @pokemon end attr_reader :item def item=(value) @item=value @pokemon.item=value if @pokemon end def hpzone return 2 if hp<=(totalhp/4).floor # red [31,11,7],[21,8,9] (bottom,top) return 1 if hp<=(totalhp/2).floor # orange [31,28,7],[25,21,1] return 0 # green [14,31,21],[11,26,16] end ### -- end complex accessors def initialize(btl,index) @battle=btl @hp=0 @fainted=true @usingsubmove=false @totalhp=0 @index=index @effects=[] @stages=[] @damagestate=PokeBattle_DamageState.new pbInitBlank pbInitEffects(false) pbInitPermanentEffects end def pbHasType?(type) if type1==type||type2==type return true end return false end def pbInitPokemon(pkmn,pkmnIndex) @name=pkmn.name @hp=pkmn.hp @pokemonIndex=pkmnIndex @type1=pkmn.type1 @type2=pkmn.type2 @totalhp=pkmn.totalhp @item=pkmn.item @ability=pkmn.ability @level=pkmn.level @species=pkmn.species @attack=pkmn.attack @defense=pkmn.defense @speed=pkmn.speed @iv=[] @iv[0]=pkmn.iv[0] @iv[1]=pkmn.iv[1] @iv[2]=pkmn.iv[2] @iv[3]=pkmn.iv[3] @iv[4]=pkmn.iv[4] @iv[5]=pkmn.iv[5] @spatk=pkmn.spatk @spdef=pkmn.spdef @happiness=pkmn.happiness @status=pkmn.status @statusCount=pkmn.statusCount @pokemon=pkmn @participants=[] # participants will earn Exp. Points if this battler is defeated @moves=[ PokeBattle_Move.pbFromPBMove(@battle,pkmn.moves[0]), PokeBattle_Move.pbFromPBMove(@battle,pkmn.moves[1]), PokeBattle_Move.pbFromPBMove(@battle,pkmn.moves[2]), PokeBattle_Move.pbFromPBMove(@battle,pkmn.moves[3]) ] end def pbInitBlank @name="" @hp=0 @type1=0 @type2=0 @totalhp=0 @item=0 @ability=0 @level=0 @species=0 @attack=0 @defense=0 @speed=0 @spatk=0 @spdef=0 @happiness=0 @status=0 @statusCount=0 @pokemon=nil @pokemonIndex=-1 @participants=[] @moves=[nil,nil,nil,nil] @iv=[0,0,0,0,0,0] end def pbInitPermanentEffects # These effects are retained even if a Pokemon is replaced @effects[PBEffects::Wish]=0 @effects[PBEffects::WishMaker]=-1 @effects[PBEffects::RecycleItem]=0 @effects[PBEffects::FutureSight]=0 @effects[PBEffects::FutureSightMove]=0 @effects[PBEffects::FutureSightDamage]=0 end def pbInitEffects(batonpass) if !batonpass # These effects are retained if Baton Pass is used @stages[PBStats::ATTACK]=0 @stages[PBStats::DEFENSE]=0 @stages[PBStats::SPEED]=0 @stages[PBStats::SPATK]=0 @stages[PBStats::SPDEF]=0 @stages[PBStats::EVASION]=0 @stages[PBStats::ACCURACY]=0 @effects[PBEffects::Confusion]=0 @effects[PBEffects::Substitute]=0 @effects[PBEffects::FocusEnergy]=false @effects[PBEffects::Curse]=false @effects[PBEffects::LockOnPos]=-1 @effects[PBEffects::LockOn]=0 for i in 0..3 next if !@battle.battlers[i] if @battle.battlers[i].effects[PBEffects::LockOnPos]==@index && @battle.battlers[i].effects[PBEffects::LockOn]>0 @battle.battlers[i].effects[PBEffects::LockOn]=0 @battle.battlers[i].effects[PBEffects::LockOnPos]=-1 end end @effects[PBEffects::Ingrain]=false @effects[PBEffects::PerishSong]=0 @effects[PBEffects::LeechSeed]=-1 @effects[PBEffects::WaterSport]=false @effects[PBEffects::MudSport]=false @effects[PBEffects::MeanLook]=-1 for i in 0..3 next if !@battle.battlers[i] if @battle.battlers[i].effects[PBEffects::MeanLook]==@index @battle.battlers[i].effects[PBEffects::MeanLook]=-1 end end else if @effects[PBEffects::LockOn] && @effects[PBEffects::LockOn]>0 @effects[PBEffects::LockOn]=2 else @effects[PBEffects::LockOn]=0 end end @fainted=false @damagestate.reset @turncount=0 @lastAttacker=-1 @effects[PBEffects::Trace]=false @effects[PBEffects::MirrorMove]=0 pbOpposing1.effects[PBEffects::MirrorMove]=0 if pbOpposing1 pbOpposing2.effects[PBEffects::MirrorMove]=0 if pbOpposing2 @effects[PBEffects::Conversion2Move]=0 @effects[PBEffects::Conversion2Type]=0 @effects[PBEffects::Toxic]=0 @effects[PBEffects::Encore]=0 @effects[PBEffects::EncoreMove]=0 @effects[PBEffects::EncoreIndex]=0 @effects[PBEffects::Attract]=-1 @effects[PBEffects::MultiTurnUser]=-1 for i in 0..3 next if !@battle.battlers[i] if @battle.battlers[i].effects[PBEffects::Attract]==@index @battle.battlers[i].effects[PBEffects::Attract]=-1 end end @effects[PBEffects::MultiTurn]=0 @effects[PBEffects::MultiTurnUser]=-1 for i in 0..3 next if !@battle.battlers[i] if @battle.battlers[i].effects[PBEffects::MultiTurnUser]==@index @battle.battlers[i].effects[PBEffects::MultiTurn]=0 @battle.battlers[i].effects[PBEffects::MultiTurnUser]=-1 end end @effects[PBEffects::Transform]=false @effects[PBEffects::MultiTurn]=0 @effects[PBEffects::Yawn]=0 @effects[PBEffects::MultiTurnAttack]=0 @effects[PBEffects::Outrage]=0 @effects[PBEffects::Foresight]=false @effects[PBEffects::HyperBeam]=0 @effects[PBEffects::DestinyBond]=false @effects[PBEffects::Grudge]=false @effects[PBEffects::Truant]=false @effects[PBEffects::Flinch]=false @effects[PBEffects::Taunt]=0 @effects[PBEffects::Transform]=false @lastMoveUsed=0 @lastMoveUsedSketch=0 @lastMoveCalled=0 @effects[PBEffects::Pursuit]=false @effects[PBEffects::WaterSport]=0 @effects[PBEffects::MudSport]=0 @effects[PBEffects::Revenge]=0 @effects[PBEffects::Bide]=0 @effects[PBEffects::BideDamage]=0 @effects[PBEffects::Stockpile]=0 @effects[PBEffects::Protect]=false @effects[PBEffects::ProtectRate]=0 @effects[PBEffects::Endure]=false @effects[PBEffects::HelpingHand]=false @effects[PBEffects::Charge]=0 @lastHPLost=0 @lastAttacker=-1 @effects[PBEffects::Counter]=-1 @effects[PBEffects::MirrorCoat]=-1 @effects[PBEffects::CounterTarget]=-1 @effects[PBEffects::MirrorCoatTarget]=-1 @effects[PBEffects::TwoTurnAttack]=0 @effects[PBEffects::Rollout]=0 @effects[PBEffects::DefenseCurl]=false @effects[PBEffects::MagicCoat]=false @effects[PBEffects::Snatch]=false @effects[PBEffects::FollowMe]=false @effects[PBEffects::Rage]=false @effects[PBEffects::Minimize]=false @effects[PBEffects::FuryCutter]=0 @effects[PBEffects::Imprison]=false @effects[PBEffects::ChoiceBand]=0 @effects[PBEffects::Uproar]=0 @effects[PBEffects::Torment]=false @effects[PBEffects::Disable]=0 @effects[PBEffects::DisableMove]=0 end def pbInitialize(pkmn,index,batonpass) pbInitPokemon(pkmn,index) pbInitEffects(batonpass) end def pbThis if @battle.pbIsOpposing?(@index) if @battle.trainer > 0 return "Foe #{@name}" else return "Wild #{@name}" end else return "#{@name}" end end def pbSpeed stagemul=[10,10,10,10,10,10,10,15,20,25,30,35,40] stagediv=[40,35,30,25,20,15,10,10,10,10,10,10,10] speed=@speed stage=@stages[PBStats::SPEED]+6 speed=(speed*stagemul[stage]/stagediv[stage]).floor if @battle.pbWeather==PBWeather::RAINDANCE && @ability==PBAbilities::SWIFTSWIM speed=speed*2 end if @battle.pbWeather==PBWeather::SUNNYDAY && @ability==PBAbilities::CHLOROPHYLL speed=speed*2 end if @item==PBItems::MACHOBRACE speed=(speed/2).floor end if self.status==PBStatuses::PARALYSIS speed=(speed/4).floor end # Dynamo Badge (index 2, internal battles only) if @battle.internalbattle if @battle.player.badges[2] && !@battle.pbIsOpposing(@index) speed=(speed*1.1).floor end end return speed end def pbReduceHP(amt) if amt>=self.hp amt=self.hp elsif amt<=0 amt=1 end oldhp=self.hp self.hp-=amt @battle.scene.pbHPChanged(self,oldhp) if amt>0 return amt end def pbRecoverHP(amt) if self.hp+amt>@totalhp amt=@totalhp-self.hp elsif amt<=0 amt=1 end oldhp=self.hp self.hp+=amt @battle.scene.pbHPChanged(self,oldhp) if amt>0 return amt end # Returns the data structure for this battler's side def pbOwnSide return @battle.sides[index&1] # Player: 0 and 2; Foe: 1 and 3 end # Returns the data structure for the opposing Pokemon's side def pbOpposingSide return @battle.sides[(index&1)^1] # Player: 1 and 3; Foe: 0 and 2 end # Returns whether the position belongs to the opposing Pokemon's side def pbIsOpposing?(i) return (@index&1)!=(i&1) end # Returns the battler's partner def pbPartner return @battle.battlers[(@index&1)|((@index&2)^2)] end # Returns the battler's first opposing Pokemon def pbOpposing1 return @battle.battlers[((@index&1)^1)] end # Returns the battler's second opposing Pokemon def pbOpposing2 return @battle.battlers[((@index&1)^1)+2] end def pbOppositeOpposing return @battle.battlers[(@index^1)] end # Update Pokemon who will gain EXP if this battler is defeated def pbUpdateParticipants return if hp<=0 # can't update if already fainted if @battle.pbIsOpposing?(@index) found1=false found2=false for i in @participants found1=true if i==pbOpposing1.pokemonIndex found2=true if i==pbOpposing2.pokemonIndex end if !found1&& pbOpposing1.hp>0 @participants[@participants.length]=pbOpposing1.pokemonIndex end if !found2&& pbOpposing2.hp>0 @participants[@participants.length]=pbOpposing2.pokemonIndex end end end def pbFaint if self.hp>0 PBDebug.log("!!!***Can't faint with HP greater than 0") return true end if @fainted # PBDebug.log("!!!***Can't faint if already fainted") return true end @battle.scene.pbFainted(self) pbInitEffects(false) # reset status self.status=0 self.statusCount=0 @fainted=true # reset choice @battle.choices[@index]=[0,0,nil,-1] @battle.pbDisplay("#{pbThis} fainted!") if @battle.pbAllFainted?(@battle.party1) @battle.decision=2 return false end return true end def pbUseItem(item) ###TODO: Complete @battle.pbDisplay("Items can't be used now.") end def pbTrace(onactive) if ability==PBAbilities::TRACE && hp>0 return if hp<=0 return if !@effects[PBEffects::Trace] && !onactive choices=[] for i in 0..3 if pbIsOpposing?(i) choices[choices.length]=i if @battle.battlers[i].ability>0 end end if choices==0 @effects[PBEffects::Trace]=true else choice=choices[@battle.pbRandom(choices.length)] battlername=@battle.battlers[choice].pbThis battlerability=@battle.battlers[choice].ability @ability=battlerability @battle.pbDisplay("#{pbThis} Traced #{battlername}'s ???!") @effects[PBEffects::Trace]=false end end end def pbForecast if ability==PBAbilities::FORECAST && species==PBSpecies::CASTFORM && hp>0 && !@battle.pbCheckGlobalAbility(PBAbilities::CLOUDNINE) && !@battle.pbCheckGlobalAbility(PBAbilities::AIRLOCK) weather=@battle.pbWeather if weather==PBWeather::SUNNYDAY && !pbHasType?(PBTypes::FIRE) @type1=PBTypes::FIRE @type2=PBTypes::FIRE @battle.pbDisplay("#{pbThis} transformed!") elsif weather==PBWeather::RAINDANCE && !pbHasType?(PBTypes::WATER) @type1=PBTypes::WATER @type2=PBTypes::WATER @battle.pbDisplay("#{pbThis} transformed!") elsif weather==PBWeather::HAIL && !pbHasType?(PBTypes::ICE) @type1=PBTypes::ICE @type2=PBTypes::ICE @battle.pbDisplay("#{pbThis} transformed!") elsif (weather==0 || weather==PBWeather::SANDSTORM) && !pbHasType?(PBTypes::NORMAL) @type1=PBTypes::NORMAL @type2=PBTypes::NORMAL @battle.pbDisplay("#{pbThis} transformed!") end end end def pbAbilityCureCheck return if hp<=0 while @ability==PBAbilities::LIMBER && self.status==PBStatuses::PARALYSIS @battle.pbDisplay("#{pbThis}'s Limber cured its paralysis problem!") self.status=0 end while @ability==PBAbilities::OBLIVIOUS && @effects[PBEffects::Attract]>=0 @battle.pbDisplay("#{pbThis}'s Oblivious cured its love problem!") @effects[PBEffects::Attract]=-1 end while @ability==PBAbilities::VITALSPIRIT &&self.status==PBStatuses::SLEEP @battle.pbDisplay("#{pbThis}'s Vital Spirit cured its sleep problem!") self.status=0 end while @ability==PBAbilities::INSOMNIA && self.status==PBStatuses::SLEEP @battle.pbDisplay("#{pbThis}'s Insomnia cured its sleep problem!") self.status=0 end while @ability==PBAbilities::IMMUNITY && self.status==PBStatuses::POISON @battle.pbDisplay("#{pbThis}'s Immunity cured its poison problem!") self.status=0 end while @ability==PBAbilities::OWNTEMPO && @effects[PBEffects::Confusion]>0 @battle.pbDisplay("#{pbThis}'s Own Tempo cured its confusion problem!") @effects[PBEffects::Confusion]=0 end while @ability==PBAbilities::MAGMAARMOR && self.status==PBStatuses::FROZEN @battle.pbDisplay("#{pbThis}'s Magma Armor cured its ice problem!") self.status=0 end while @ability==PBAbilities::WATERVEIL && self.status==PBStatuses::BURN @battle.pbDisplay("#{pbThis}'s Water Veil cured its burn problem!") self.status=0 end end def pbBerryCureCheck return if hp<=0 while self.item==PBItems::CHERIBERRY && status==PBStatuses::PARALYSIS @battle.pbDisplay("#{pbThis}'s Cheri Berry cured its paralysis problem!") self.status=0 @effects[PBEffects::RecycleItem]=self.item self.item=0 end while self.item==PBItems::CHESTOBERRY && status==PBStatuses::SLEEP @battle.pbDisplay("#{pbThis}'s Chesto Berry cured its sleep problem!") self.status=0 @effects[PBEffects::RecycleItem]=self.item self.item=0 end while self.item==PBItems::PECHABERRY && status==PBStatuses::POISON @battle.pbDisplay("#{pbThis}'s Pecha Berry cured its poison problem!") self.status=0 @effects[PBEffects::RecycleItem]=self.item self.item=0 end while self.item==PBItems::RAWSTBERRY && status==PBStatuses::BURN @battle.pbDisplay("#{pbThis}'s Rawst Berry cured its burn problem!") self.status=0 @effects[PBEffects::RecycleItem]=self.item self.item=0 end while self.item==PBItems::ASPEARBERRY && status==PBStatuses::FROZEN @battle.pbDisplay("#{pbThis}'s Aspear Berry cured its ice problem!") self.status=0 @effects[PBEffects::RecycleItem]=self.item self.item=0 end while self.item==PBItems::PERSIMBERRY && @effects[PBEffects::Confusion]>0 @battle.pbDisplay("#{pbThis}'s Persim Berry cured its confusion problem!") @effects[PBEffects::Confusion]=0 @effects[PBEffects::RecycleItem]=self.item self.item=0 end while self.item==PBItems::LUMBERRY && (status>0||@effects[PBEffects::Confusion]>0) if @effects[PBEffects::Confusion]>0 @battle.pbDisplay("#{pbThis}'s Lum Berry cured its confusion problem!") else case status when PBStatuses::PARALYSIS @battle.pbDisplay("#{pbThis}'s Lum Berry cured its paralysis problem!") when PBStatuses::SLEEP @battle.pbDisplay("#{pbThis}'s Lum Berry cured its sleep problem!") when PBStatuses::POISON @battle.pbDisplay("#{pbThis}'s Lum Berry cured its poison problem!") when PBStatuses::BURN @battle.pbDisplay("#{pbThis}'s Lum Berry cured its burn problem!") when PBStatuses::FROZEN @battle.pbDisplay("#{pbThis}'s Lum Berry cured its frozen problem!") end end self.status=0 @effects[PBEffects::Confusion]=0 @effects[PBEffects::RecycleItem]=self.item self.item=0 end if self.item==PBItems::WHITEHERB while true reducedstats=0 for i in 0..6 reducedstats+=1 if @stages[i]<0 end break if reducedstats==0 for i in 0..6 @stages[i]=0 if @stages[i]<0 end @battle.pbDisplay("#{pbThis}'s White Herb restored its status!") self.status=0 end end while self.item==PBItems::MENTALHERB && @effects[PBEffects::Attract]>=0 @battle.pbDisplay("#{pbThis}'s Mental Herb cured its love problem!") @effects[PBEffects::Attract]=-1 @effects[PBEffects::RecycleItem]=self.item self.item=0 end end def pbAddTarget(targets,target) if target.hp>0 targets[targets.length]=target return true end return false end def pbRandomTarget(targets) choices=[] pbAddTarget(choices,pbOpposing1) pbAddTarget(choices,pbOpposing2) if choices.length>0 pbAddTarget(targets,choices[@battle.pbRandom(choices.length)]) end end def pbConfusionDamage confmove=PokeBattle_Confusion.new(@battle,nil) confmove.pbEffect(self,self) pbFaint if self.hp<=0 end def pbSetPP(move,pp) move.pp=pp #Not effects[PBEffects::Mimic], since Mimic can't copy Mimic if move.id==move.thismove.id && @effects[PBEffects::Transform] move.thismove.pp=pp end end def pbReducePP(move) #TODO: Pressure if @effects[PBEffects::TwoTurnAttack]>0 || @effects[PBEffects::Bide]>0 || @effects[PBEffects::Outrage]>0 || @effects[PBEffects::Rollout]>0 || @effects[PBEffects::HyperBeam]>0 || @effects[PBEffects::Uproar]>0 # No need to reduce PP if two-turn attack return true end if move.pp<0 # No need to reduce PP for special calls of moves return true end if move.pp==0 return false end if move.pp>0 pbSetPP(move,move.pp-1) end return true end def pbReducePPOther(move) #TODO: Pressure # Somehow used during switches if move.pp>0 pbSetPP(move,move.pp-1) end end # HP Bar: Orange: 1/2, Red: 1/6 def pbFindUser(choice,targets) priority=@battle.pbPriority move=choice[2] target=choice[3] #Normally, the user is self user=self #Targets in normal cases if move.target==0x00 if target>=0 targetBattler=@battle.battlers[target] if !pbIsOpposing?(targetBattler.index) if !pbAddTarget(targets,targetBattler) pbAddTarget(targets,pbOpposing2) if !pbAddTarget(targets,pbOpposing1) end else pbAddTarget(targets,targetBattler.pbPartner) if !pbAddTarget(targets,targetBattler) end else pbRandomTarget(targets) end elsif move.target==0x04 pbRandomTarget(targets) elsif move.target==0x08 # Just pbOpposing1 because partner is determined late pbAddTarget(targets,pbOpposing2) if !pbAddTarget(targets,pbOpposing1) elsif move.target==0x20 for i in 0..3 # not ordered by priority if i!=@index pbAddTarget(targets,@battle.battlers[i]) end end else move.pbAddTarget(targets,self) end return user end def pbChangeUser(thismove,user) priority=@battle.pbPriority # Change user to user of Snatch if (thismove.flags&0x08)!=0 # flag d: Snatch for i in priority if i.effects[PBEffects::Snatch] @battle.pbDisplay("#{i.pbThis} Snatched #{user.pbThis}'s move!") i.effects[PBEffects::Snatch]=false target=user user=i # Snatch's PP is reduced if old user has Pressure userchoice=@battle.choices[user.index][1] if target.ability==PBAbilities::PRESSURE && userchoice>=0 pressuremove=user.moves[userchoice] pbSetPP(pressuremove,pressuremove.pp-1) if pressuremove.pp>0 end end end end return user end def pbChangeTarget(thismove,userandtarget,targets) priority=@battle.pbPriority changeeffect=0 user=userandtarget[0] target=userandtarget[1] # LightningRod here, considers Hidden Power as Normal if thismove.type==PBTypes::ELECTRIC && targets.length>0 && target.ability!=PBAbilities::LIGHTNINGROD # all damaging Electric attacks have a target of "single non-user" for i in priority # use Pokemon earliest in priority next if !pbIsOpposing?(i.index) if i.ability==PBAbilities::LIGHTNINGROD target=i# X's LightningRod took the attack! changeeffect=1 break end end end # Change target to user of Follow Me (overrides Magic Coat # because check for Magic Coat below uses this target) if thismove.target==0 # target is a single non-user for i in priority # use Pokemon latest in priority next if !pbIsOpposing?(i.index) if i.effects[PBEffects::FollowMe] #change target to this target=i end end end # TODO: Pressure here is incorrect if Magic Coat redirects target if target.ability==PBAbilities::PRESSURE pbReducePP(thismove) # Reduce PP end # Change user to user of Snatch if (thismove.flags&0x08)!=0 # flag d: Snatch for i in priority if i.effects[PBEffects::Snatch] @battle.pbDisplay("#{i.pbThis} Snatched #{user.pbThis}'s move!") i.effects[PBEffects::Snatch]=false target=user user=i # Snatch's PP is reduced if old user has Pressure userchoice=@battle.choices[user.index][1] if target.ability==PBAbilities::PRESSURE && userchoice>=0 pressuremove=user.moves[userchoice] pbSetPP(pressuremove,pressuremove.pp-1) if pressuremove.pp>0 end end end end userandtarget[0]=user userandtarget[1]=target if target.ability==PBAbilities::SOUNDPROOF && #Heal Bell/Perish Song handled elsewhere (thismove.id==PBMoves::GROWL|| thismove.id==PBMoves::HYPERVOICE|| thismove.id==PBMoves::SUPERSONIC|| thismove.id==PBMoves::ROAR|| thismove.id==PBMoves::GRASSWHISTLE|| thismove.id==PBMoves::METALSOUND|| thismove.id==PBMoves::SING|| thismove.id==PBMoves::SCREECH|| thismove.id==PBMoves::UPROAR|| thismove.id==PBMoves::SNORE) @battle.pbDisplay("#{target.pbThis}'s Soundproof blocks #{thismove.name}!") return false end if (thismove.flags&0x04)!=0 && target.effects[PBEffects::MagicCoat] # flag c: Magic Coat # switch user and target changeeffect=2 target.effects[PBEffects::MagicCoat]=false tmp=user user=target target=tmp # Magic Coat's PP is reduced if old user has Pressure userchoice=@battle.choices[user.index][1] if target.ability==PBAbilities::PRESSURE && userchoice>=0 pressuremove=user.moves[userchoice] pbSetPP(pressuremove,pressuremove.pp-1) if pressuremove.pp>0 end end if changeeffect==1 @battle.pbDisplay("#{target.pbThis}'s LightningRod took the move!") elsif changeeffect==2 # Target refers to the move's old user @battle.pbDisplay("#{target.pbThis}'s #{thismove.name} was bounced back by Magic Coat!") end userandtarget[0]=user userandtarget[1]=target return true end def pbObedienceCheck?(choice) if choice[0]!=1 return true end if !@battle.pbIsOpposing?(@index) && @battle.internalbattle badgelevel=10 badgelevel=30 if @battle.player.badges[1] badgelevel=50 if @battle.player.badges[3] badgelevel=70 if @battle.player.badges[5] badgelevel=100 if @battle.player.badges[7] move=choice if (@pokemon.trainerID!=@battle.player.id || @pokemon.ot!=@battle.player.name) && @level>badgelevel a=((@level+badgelevel)*@battle.pbRandom(256)/255).floor return true if a0 newchoice=othermoves[@battle.pbRandom(othermoves.length)] choice[1]=newchoice choice[2]=@moves[newchoice] choice[3]=-1 return false else return true end else c=@level-b r=@battle.pbRandom(256) if r0 PBDebug.log("[Using two-turn attack]") return true end # TODO: "Before Protect" applies to Counter/Mirror Coat if (target.status!=PBStatuses::SLEEP || target.effects[PBEffects::Substitute]>0) && thismove.id==PBMoves::DREAMEATER @battle.pbDisplay("#{target.pbThis} wasn't affected!") return false end if thismove.id==PBMoves::MEMENTO if target.pbTooLow?(PBStats::ATTACK) && target.pbTooLow?(PBStats::SPATK) @battle.pbDisplay("But it failed!") return false end user.hp=0 end if thismove.id==PBMoves::SPITUP && user.effects[PBEffects::Stockpile]==0 @battle.pbDisplay("But it failed to spit up a thing!") return false end if target.effects[PBEffects::Protect] && (thismove.flags & 0x02) # flag b: Protect/Detect @battle.pbDisplay("#{target.pbThis} protected itself!") return false end if thismove.id==PBMoves::RAGE @effects[PBEffects::Rage]=true end # TODO: Mind Reader/Lock-On # --Sketch/FutureSight/PsychUp work even on Fly/Bounce/Dive/Dig if thismove.pbMoveFailed(user,target) #TODO:Applies to Snore/Fake Out @battle.pbDisplay("But it failed!") return false end if thismove.basedamage>0 && thismove.id!=PBMoves::BEATUP && thismove.id!=PBMoves::STRUGGLE && thismove.id!=PBMoves::FUTURESIGHT && thismove.id!=PBMoves::DOOMDESIRE type=thismove.pbType(thismove.type,user,target) typemod=thismove.pbTypeModifier(type,target) if target.ability==PBAbilities::LEVITATE && type==PBTypes::GROUND @battle.pbDisplay("#{target.pbThis} makes Ground moves miss with Levitate!"); return false end if target.ability==PBAbilities::WONDERGUARD && typemod<=4 @battle.pbDisplay("#{target.pbThis} avoided damage with Wonder Guard!"); return false end if typemod==0 @battle.pbDisplay("It doesn't affect #{target.pbThis}..."); return false end end if accuracy if target.effects[PBEffects::LockOn]>0 && target.effects[PBEffects::LockOnPos]==user.index return true end if !thismove.pbAccuracyCheck(user,target)#Includes Counter/Mirror Coat if thismove.target==0x08||thismove.target==0x20 # All opposing Pokemon or all non-users @battle.pbDisplay("#{target.pbThis} avoided the attack!") elsif thismove.id==PBMoves::LEECHSEED @battle.pbDisplay("#{target.pbThis} evaded the attack!") else @battle.pbDisplay("#{user.pbThis}'s attack missed!") end return false end end return true end def pbProcessBeatUp(thismove,user,target) #TODO: Actually ignores Wonder Guard effect unless it really misses numhits=0 if !pbSuccessCheck(thismove,user,target,true) return end party=@battle.pbParty(@index) for i in 0...party.length if party[i].hp>0 && party[i].status!=0 thisname=@battle.pbThisEx(@index,i) @battle.pbDisplay("#{thisname}'s attack!"); thismove.pbSetThisPkmn(party[i]) pbProcessNonMultiHitMove(thismove,user,target,true) numhits+=1 end end if numhits==0 @battle.pbDisplay("But it failed!"); return end end def pbUpdateTargetedMove(thismove,user) # TODO: Snatch, moves that use other moves if (thismove.target==0x00||thismove.target==0x01|| thismove.target==0x04||thismove.target==0x02) && thismove.flags&0x10 && !user.usingsubmove @effects[PBEffects::MirrorMove]=thismove.id end # TODO: All targeting cases # Two-turn attacks, Magic Coat, Future Sight, Counter/MirrorCoat/Bide handled @effects[PBEffects::Conversion2Move]=thismove.id @effects[PBEffects::Conversion2Type]=thismove.pbType(thismove.type,user,self) end def pbProcessNonMultiHitMove(thismove,user,target,nocheck=false) if !nocheck && !pbSuccessCheck(thismove,user,target,true) if thismove.id==PBMoves::JUMPKICK||thismove.id==PBMoves::HIJUMPKICK #TODO: Not shown if message is "It doesn't affect XXX..." @battle.pbDisplay("#{user.pbThis} kept going and crashed!") damage=thismove.pbCalcDamage(user,target) if damage>0 if target.effects[PBEffects::Substitute]>0 if target.effects[PBEffects::Endure] || target.damagestate.focusband damage=target.hp-1 if damage>=target.hp end end damage=(damage/2).floor user.pbReduceHP(damage) end user.pbFaint if user.hp<=0 end user.effects[PBEffects::Rollout]=0 if thismove.id==PBMoves::ROLLOUT || thismove.id==PBMoves::ICEBALL user.effects[PBEffects::FuryCutter]=0 if thismove.id==PBMoves::FURYCUTTER user.effects[PBEffects::Stockpile]=0 if thismove.id==PBMoves::SPITUP target.effects[PBEffects::Conversion2Move]=-1 target.effects[PBEffects::Conversion2Type]=0 return else if thismove.id==PBMoves::ROLLOUT || thismove.id==PBMoves::ICEBALL user.effects[PBEffects::Rollout]=5 if user.effects[PBEffects::Rollout]==0 user.effects[PBEffects::Rollout]-=1 user.currentMove=thismove.id end if thismove.id==PBMoves::FURYCUTTER user.effects[PBEffects::FuryCutter]+=1 if user.effects[PBEffects::FuryCutter]<5 end end damage=thismove.pbEffect(user,target)# Recoil/drain, etc. are applied here if user.hp<=0 && thismove.id!=PBMoves::EXPLOSION && thismove.id!=PBMoves::SELFDESTRUCT user.pbFaint#no return end # Additional effect if target.damagestate.calcdamage>0 && target.ability!=PBAbilities::SHIELDDUST addleffect=thismove.addlEffect if user.ability==PBAbilities::SERENEGRACE addleffect*=2 end if @battle.pbRandom(100)0 && target.effects[PBEffects::Rage] && target.pbIsOpposing?(user.index) && damage>0 # TODO: Apparently triggers if opposing Pokemon uses Future Sight after a Future Sight attack if !target.pbTooHigh?(PBStats::ATTACK) target.stages[PBStats::ATTACK]+=1 @battle.pbDisplay("#{target.pbThis}'s Rage is building!") end end # Grudge if target.effects[PBEffects::Grudge] && target.hp<=0 && user.hp>0 @battle.pbDisplay("#{target.pbThis}'s #{thismove.name} lost all PP due to the Grudge!") thismove.pp=0 end # Destiny Bond if thismove!=PBMoves::BEATUP && target.effects[PBEffects::DestinyBond] && target.hp<=0 && user.hp>0 @battle.pbDisplay("#{target.pbThis} took #{user.pbThis} with it!") user.pbReduceHP(user.hp) user.pbFaint#no return end # Opponent faints if 0 HP if target.hp<=0 target.pbFaint#no return end # Ability effects @battle.pbAbilityEffect(thismove,user,target) for j in 0..3 @battle.battlers[j].pbBerryCureCheck end # Shell Bell if user.item==PBItems::SHELLBELL && damage > 0 && user.hp>0 hpgain=user.pbRecoverHP((damage/8).float) if hpgain>0 @battle.pbDisplay("#{user.pbThis}'s Shell Bell restored its HP a little!") end end target.pbUpdateTargetedMove(thismove,user) end def pbProcessMultiHitMove(thismove,user,target,numhits) # Includes Triple Kick realnumhits=0 for i in 0...numhits if !pbSuccessCheck(thismove,user,target,i==0||thismove.id==PBMoves::TRIPLEKICK) target.effects[PBEffects::Conversion2Move]=-1 target.effects[PBEffects::Conversion2Type]=0 return end realnumhits+=1 damage=thismove.pbEffect(user,target)# Recoil/drain, etc. are applied here return if target.damagestate.calcdamage<=0 # Critical hit message if target.damagestate.critical @battle.pbDisplay("A critical hit!") end # Rage if target.hp>0 && target.effects[PBEffects::Rage] && target.pbIsOpposing?(user.index) && damage>0 if !target.pbTooHigh?(PBStats::ATTACK) target.stages[PBStats::ATTACK]+=1 @battle.pbDisplay("#{target.pbThis}'s Rage is building!") end end # Ability effects @battle.pbAbilityEffect(thismove,user,target) # Berry check (maybe just called by ability effect, since only necessary Berries are checked) for j in 0..3 @battle.battlers[j].pbBerryCureCheck end # Shell Bell if user.item==PBItems::SHELLBELL && damage > 0 && user.hp>0 hpgain=user.pbRecoverHP((damage/8).float) if hpgain>0 @battle.pbDisplay("#{user.pbThis}'s Shell Bell restored its HP a little!") end end #Endure if target.damagestate.endured @battle.pbDisplay("#{target.pbThis} endured the hit!") break end target.pbUpdateTargetedMove(thismove,user) break if target.hp<=0 end # Focus Band if target.damagestate.focusbandused @battle.pbDisplay("#{target.pbThis} hung on using its Focus Band!") break end # Type effectiveness # Number of hits @battle.pbDisplay("Hit #{realnumhits} time(s)!") # Opponent faints if 0 HP if target.hp<=0 target.pbFaint#no return end # Additional effect if target.ability!=PBAbilities::SHIELDDUST addleffect=thismove.addlEffect if user.ability==PBAbilities::SERENEGRACE addleffect*=2 end if @battle.pbRandom(100)=0 @battle.choices[@index][1]=index end @usingsubmove=true ret=pbUseMove(choice) @usingsubmove=false return ret end def pbUseMove(choice) if choice[0]!=1# if move was not chosen return false end thismove=choice[2] if !pbReducePP(thismove) @battle.pbDisplay("#{pbThis} used #{thismove.name}!") @battle.pbDisplay("But there was no PP left for the move!") self.lastMoveUsedSketch=thismove.id return false end if thismove.pbTwoTurnAttack(self) # Beginning use of two-turn attack @effects[PBEffects::TwoTurnAttack]=thismove.id @currentMove=thismove.id self.lastMoveUsed=thismove.id self.lastMoveCalled=thismove.id else @effects[PBEffects::TwoTurnAttack]=0 # Cancel use of two-turn attack self.lastMoveUsedSketch=thismove.id self.lastMoveUsed=thismove.id self.lastMoveCalled=thismove.id case thismove.pbDisplayUseMessage(self) when 1 return true when -1 return false end end targets=[] user=pbFindUser(choice,targets) selffaint=thismove.id==PBMoves::EXPLOSION|| thismove.id==PBMoves::SELFDESTRUCT if selffaint bearer=@battle.pbCheckGlobalAbility(PBAbilities::DAMP) if bearer @battle.pbDisplay("#{bearer.pbThis}'s Damp prevents #{pbThis} from using #{thismove.name}!") return false else user.hp=0 end end if !thismove.pbOnStartUse(user) # Used by Magnitude to precalculate base damage return false end if targets.length==0 user=pbChangeUser(thismove,user) PBDebug.logonerr{ thismove.pbEffect(user,nil) } else i=0; loop do break if i>=targets.length userandtarget=[user,targets[i]] success=pbChangeTarget(thismove,userandtarget,targets) user=userandtarget[0] target=userandtarget[1] if i==0 && thismove.target==0x08 # Add partner to list of targets pbAddTarget(targets,target.pbPartner) end if !success i+=1 next end numhits=thismove.pbNumHits target.damagestate.reset if target.item==PBItems::FOCUSBAND && @battle.pbRandom(10)==0 #Works even if it's a Future Sight attack target.damagestate.focusband=true end if thismove.id==PBMoves::BEATUP pbProcessBeatUp(thismove,user,target) elsif thismove.pbIsMultiHit pbProcessMultiHitMove(thismove,user,target,numhits) else pbProcessNonMultiHitMove(thismove,user,target) end i+=1 end end if thismove.id==PBMoves::MIMIC||thismove.id==PBMoves::SKETCH||thismove.id==PBMoves::TRANSFORM user.lastMoveUsedSketch=-1 user.lastMoveUsed=-1 else user.lastMoveUsedSketch=thismove.id user.lastMoveUsed=thismove.id end if selffaint user.hp=0 user.pbFaint#no return end @battle.pbGainEXP return true end def pbBeginTurn(choice) @effects[PBEffects::DestinyBond]=false @effects[PBEffects::Grudge]=false if @effects[PBEffects::Encore]>0 && @moves[@effects[PBEffects::EncoreIndex]].id!=@effects[PBEffects::EncoreMove] PBDebug.log("[Resetting Encore effect]") @effects[PBEffects::Encore]=0 @effects[PBEffects::EncoreIndex]=0 @effects[PBEffects::EncoreMove]=0 end if @ability!=PBAbilities::SOUNDPROOF for i in 0..3 if @battle.battlers[i].effects[PBEffects::Uproar]>0 self.effects[PBEffects::Nightmare]=false @battle.pbDisplay("#{pbThis} woke up in the uproar!") self.status=0 end end end end def pbEndTurn(choice) @effects[PBEffects::Conversion2Move]=0 @effects[PBEffects::Conversion2Type]=0 for i in 0..3 @battle.battlers[i].pbAbilityCureCheck end for i in 0..3 @battle.battlers[i].pbBerryCureCheck end for i in 0..3 @battle.battlers[i].pbTrace(false) end for i in 0..3 @battle.battlers[i].pbForecast end for i in 0..3 @battle.battlers[i].pbBerryCureCheck end end def pbTryUseMove(choice) if choice[0]!=1# if move was not chosen return false end if @effects[PBEffects::Pursuit] # turn is skipped @effects[PBEffects::Pursuit]=false return false end if @effects[PBEffects::TwoTurnAttack]>0 || @effects[PBEffects::Outrage]>0|| @effects[PBEffects::HyperBeam]>0|| @effects[PBEffects::Bide]>0|| @effects[PBEffects::Rollout]>0|| @effects[PBEffects::Uproar]>0 choice[2]=PokeBattle_Move.pbFromPBMove(@battle,PBMove.new(@currentMove)) elsif @effects[PBEffects::Encore]>0 if @battle.pbCanShowCommands?(@index)&& @battle.pbCanChooseMove?(@index,@effects[PBEffects::EncoreIndex],false) PBDebug.log("[Using Encore move]") choice[1]=@effects[PBEffects::EncoreIndex] choice[2]=@moves[@effects[PBEffects::EncoreIndex]] end end thismove=choice[2] pbBeginTurn(choice) self.lastMoveUsed=-1 self.lastMoveCalled=-1 if !pbObedienceCheck?(choice) return false end if self.status==PBStatuses::SLEEP if @ability==PBAbilities::EARLYBIRD self.statusCount-=2 else self.statusCount-=1 end if self.statusCount<=0 self.effects[PBEffects::Nightmare]=false @battle.pbDisplay("#{pbThis} woke up!") self.status=0 else @battle.pbDisplay("#{pbThis} is fast asleep.") if thismove.id!=PBMoves::SNORE && thismove.id!=PBMoves::SLEEPTALK return false end end end if self.status==PBStatuses::FROZEN && thismove.id!=PBMoves::FLAMEWHEEL && thismove.id!=PBMoves::SACREDFIRE if @battle.pbRandom(10)==0 @battle.pbDisplay("#{pbThis} was defrosted!") self.status=0 else @battle.pbDisplay("#{pbThis} is frozen solid!") return false end end if @effects[PBEffects::HyperBeam]>0 @battle.pbDisplay("#{pbThis} must recharge!") return false end if @ability==PBAbilities::TRUANT && @effects[PBEffects::Truant] @battle.pbDisplay("#{pbThis} is loafing around!") return false end if @effects[PBEffects::Flinch] # No Inner Focus check here @battle.pbDisplay("#{pbThis} flinched!") @effects[PBEffects::Flinch]=false return false end if thismove.id==@effects[PBEffects::DisableMove] @battle.pbDisplayPaused("#{pbThis}'s #{thismove.name} is disabled!") return false end if @effects[PBEffects::Taunt] > 0 && thismove.basedamage == 0 @battle.pbDisplayPaused("#{pbThis} can't use #{thismove.name} after the Taunt!") return false end if pbOpposing1.effects[PBEffects::Imprison] if thismove.id==pbOpposing1.moves[0].id || thismove.id==pbOpposing1.moves[1].id || thismove.id==pbOpposing1.moves[2].id || thismove.id==pbOpposing1.moves[3].id @battle.pbDisplayPaused("#{pbThis} can't use the sealed #{thismove.name}!") PBDebug.log("[#{pbOpposing1.pbThis} has: #{pbOpposing1.moves[0].id}, #{pbOpposing1.moves[1].id},#{pbOpposing1.moves[2].id} #{pbOpposing1.moves[3].id}]") return false end end if pbOpposing2.effects[PBEffects::Imprison] if thismove.id==pbOpposing2.moves[0].id || thismove.id==pbOpposing2.moves[1].id || thismove.id==pbOpposing2.moves[2].id || thismove.id==pbOpposing2.moves[3].id @battle.pbDisplayPaused("#{pbThis} can't use the sealed #{thismove.name}!") PBDebug.log("[#{pbOpposing2.pbThis} has: #{pbOpposing2.moves[0].id}, #{pbOpposing2.moves[1].id},#{pbOpposing2.moves[2].id} #{pbOpposing2.moves[3].id}]") return false end end if @effects[PBEffects::Confusion] > 0 @effects[PBEffects::Confusion]=@effects[PBEffects::Confusion]-1 if @effects[PBEffects::Confusion]==0 @battle.pbDisplay("#{pbThis} snapped out of confusion!") else @battle.pbDisplay("#{pbThis} is confused!") if @battle.pbRandom(2) == 0 @battle.pbDisplay("It hurt itself from its confusion!") pbConfusionDamage return false end end end if @effects[PBEffects::Status]==PBStatuses::PARALYSIS if @battle.pbRandom(4) == 0 @battle.pbDisplay("#{pbThis} is paralyzed! It can't move!") return false end end if @effects[PBEffects::Attract]>=0 other=@battle.battlers[@effects[PBEffects::Attract]] @battle.pbDisplay("#{pbThis} is in love with #{other.pbThis}!") if @battle.pbRandom(2) == 0 @battle.pbDisplay("#{pbThis} is immobilized by love!") return false end end if status==PBStatuses::FROZEN && (thismove.id==PBMoves::FLAMEWHEEL || thismove.id==PBMoves::SACREDFIRE) @battle.pbDisplay("#{pbThis} was defrosted by #{thismove.name}!") status=0 end return true end def pbCancelMoves # Cancel two-turn attack @effects[PBEffects::TwoTurnAttack]=0 if @effects[PBEffects::TwoTurnAttack]>0 # Cancel current move (for Thrash, etc.) @currentMove=0 @effects[PBEffects::Bide]=0 @effects[PBEffects::Outrage]=0 @effects[PBEffects::Uproar]=0 @effects[PBEffects::Rollout]=0 @effects[PBEffects::FuryCutter]=0 end def pbProcessTurn(choice) if choice[0]!=1 # Clean up effects that end at battler's turn pbBeginTurn(choice) pbEndTurn(choice) return end ret=pbTryUseMove(choice) if !ret pbCancelMoves pbEndTurn(choice) @battle.pbSwitch return false end ret=0 # @battle.pbDisplayPaused("Before: [#{@lastMoveUsedSketch},#{@lastMoveUsed},#{@lastMoveCalled}]") PBDebug.logonerr{ ret=pbUseMove(choice) } # @battle.pbDisplayPaused("After: [#{@lastMoveUsedSketch},#{@lastMoveUsed},#{@lastMoveCalled}]") pbEndTurn(choice) @battle.pbSwitch return ret end end