class PokeBattle_Battle attr_reader(:scene) # Scene object for this battle attr_accessor(:decision) # Decision: 0=undecided; 1=win; 2=loss; 3=escaped attr_reader(:battlers) # Currently active Pokemon attr_reader(:sides) # Effects common to each side of a battle attr_reader(:party1) # Player's Pokemon party attr_reader(:party2) # Foe's Pokemon party attr_accessor(:choices) # Choices made by each Pokemon this round attr_reader(:trainer) # In-game trainer, or 0 if wild battle attr_accessor(:internalbattle) # Internal battle flag attr_reader(:player) # Player trainer attr_accessor(:doublebattle) # Double battle flag attr_accessor(:weather) # Current weather, custom methods should use pbWeather instead attr_accessor(:shiftStyle) # Shift/Set "battle style" option attr_accessor(:moneygained) # Money gained in battle by using Pay Day attr_accessor(:weatherduration) # Duration of current weather, or -1 if indefinite attr_accessor(:environment) # Battle surroundings attr_reader(:switching) # True if during the switching phase of the round attr_accessor(:debug) # Debug flag def initialize(scene,p1,p2,trainerbattle,player) @scene=scene @party1=p1 @party2=p2 @player=player @environment=PBEnvironment::None # Environment for battle (ex. Tall grass, caves, still water...) @weatherduration=0 @decision=0 @battlers=[] @sides=[] @priority=[] @switching=false @internalbattle=true @usepriority=false @shiftStyle=true @struggle=PokeBattle_Move.pbFromPBMove(self,PBMove.new(PBMoves::STRUGGLE)) @struggle.pp=-1 @debug=false @debugupdate=0 @doublebattle=false @runCommand=0 @moneygained=0 @choices=[ [0,0,nil,-1],[0,0,nil,-1],[0,0,nil,-1],[0,0,nil,-1] ] if p1.length==0 raise ArgumentError.new("Party 1 has a length of 0.") return end if p2.length==0 raise ArgumentError.new("Party 2 has a length of 0.") return end if p1.length>6 raise ArgumentError.new("Party 1 has more than six Pokemon.") return end if p2.length>6 raise ArgumentError.new("Party 2 has more than six Pokemon.") return end if p2.length!=1 && !trainerbattle raise ArgumentError.new("Wild battles with more than one Pokemon are not supported.") return end sides[0]=PokeBattle_ActiveSide.new # player's side sides[1]=PokeBattle_ActiveSide.new # foe's side for i in 0..3 battlers[i]=PokeBattle_Battler.new(self,i) end @decision=0 @trainer=trainerbattle @weather=0 end def pbIsOpposing?(index) return (index%2)==1 end def pbIsDoubleBattler?(index) return (index>=2) end def pbParty(index) return pbIsOpposing?(index) ? party2 : party1 end def pbThisEx(battlerindex,pokemonindex) party=pbParty(battlerindex) if pbIsOpposing?(battlerindex) if @trainer > 0 return "Foe #{party[pokemonindex].name}" else return "Wild #{party[pokemonindex].name}" end else return "#{party[pokemonindex].name}" end end def pbStartBattle if @trainer == 0 wildpoke=@party2[0] @battlers[1].pbInitialize(wildpoke,0,false) @scene.pbStartBattle(self) pbDisplayPaused("Wild #{wildpoke.name} appeared!") playerpoke=@party1[0] pbDisplay("Go! #{playerpoke.name}!") @battlers[0].pbInitialize(playerpoke,0,false) @scene.pbSendOut(self,playerpoke) elsif @doublebattle @scene.pbStartBattle(self) pbDisplayPaused("A Trainer would like to battle!") pbDisplay("The Trainer sent out #{@party2[0].name} and #{@party2[1].name}!") @battlers[1].pbInitialize(@party2[0],0,false) @battlers[3].pbInitialize(@party2[1],1,false) @scene.pbTrainerSendOut(self,@party2[0]) @scene.pbTrainerSendOut(self,@party2[1]) pbDisplay("Go! #{@party1[0].name} and #{@party1[1].name}!") @battlers[0].pbInitialize(@party1[0],0,false) @battlers[2].pbInitialize(@party1[1],1,false) @scene.pbSendOut(self,@party1[0]) @scene.pbSendOut(self,@party1[1]) else trainerpoke=@party2[0] @scene.pbStartBattle(self) pbDisplayPaused("A Trainer would like to battle!") pbDisplay("The Trainer sent out #{trainerpoke.name}!") @battlers[1].pbInitialize(trainerpoke,0,false) @scene.pbTrainerSendOut(self,trainerpoke) playerpoke=@party1[0] pbDisplay("Go! #{playerpoke.name}!") @battlers[0].pbInitialize(playerpoke,0,false) @scene.pbSendOut(self,playerpoke) end if @weather==PBWeather::SUNNYDAY # No message elsif @weather==PBWeather::RAINDANCE pbDisplay("It is raining.") elsif @weather==PBWeather::SANDSTORM pbDisplay("A sandstorm is raging.") elsif @weather==PBWeather::HAIL # No message end # Abilities pbOnActiveAll # Now begin the battle loop turncount=0 loop do if @debug turncount+=1 if $PBDebugExceptions>=50 @decision=-1 PBDebug.log("***[Battle aborted]") raise RuntimeError.new("Battle aborted") exit break end PBDebug.log("***Round #{turncount}") end PBDebug.logonerr{ pbCommandPhase } break if @decision>0 PBDebug.logonerr{ pbAttackPhase } break if @decision>0 PBDebug.logonerr{ pbEndOfRoundPhase } break if @decision>0 end case @decision when 1 #win if @trainer>0 @scene.pbTrainerBattleSuccess pbDisplayPaused("Player defeated the Trainer!") #TODO: Get money won if @internalbattle #Player would earn money here end end if @internalbattle && @moneygained>0 pbDisplayPaused("#{@player.name} picked up $#{moneygained}!") @player.money+=moneygained @player.money=999999 if @player.money>999999 end when 2 #lose pbDisplayPaused("#{@player.name} is out of usable Pokemon!") moneylost=pbMaxLevel(@party1)*120 moneylost=@player.money if moneylost>@player.money @player.money-=moneylost if @trainer>0 pbDisplayPaused("Player lost against the Trainer!") if moneylost>0 pbDisplayPaused("#{@player.name} paid $#{moneylost} as the prize money...") pbDisplayPaused("...") end else if moneylost>0 pbDisplayPaused("#{@player.name} panicked and lost $#{moneylost}...") pbDisplayPaused("...") end end pbDisplayPaused("#{@player.name} whited out!") end @scene.pbEndBattle(@decision) return @decision end def pbMaxLevel(party) lv=0 for i in party lv=i.level if lv0 return 0 else pbDisplay("#{thispkmn.pbThis} fled!") end end if(@trainer>0) if @internalbattle pbDisplayPaused("No! There's no running from a Trainer battle!") elsif pbDisplayConfirm("Would you like to forfeit the match and quit now?") pbDisplay("#{player.name} forfeited the match!") @decision=3 return 1 end return 0 end if thispkmn.item==PBItems::SMOKEBALL if duringBattle pbDisplay("Got away safely!") else pbDisplay("#{thispkmn.pbThis} fled using its Smoke Ball!") end return 1 end if thispkmn.ability==PBAbilities::RUNAWAY if duringBattle pbDisplay("Got away safely!") else pbDisplay("#{thispkmn.pbThis} fled using Run Away!") end return 1 end if !duringBattle&&!pbCanSwitch?(idxPokemon,-1,false) # TODO: Use real messages pbDisplayPaused("Can't escape!") return 0 end # Note: not pbSpeed, because using unmodified Speed speedPlayer=@battlers[idxPokemon].speed speedEnemy=@battlers[idxPokemon].pbOppositeOpposing.speed rate=speedPlayer*128/speedEnemy rate+=@runCommand*30 rate&=0xFF ret=1 if pbRandom(256) 0 && thismove.basedamage == 0 if showMessages pbDisplayPaused("#{thispkmn.pbThis} can't use #{thismove.name} after the Taunt!") end return false end if thispkmn.effects[PBEffects::Torment] if thismove.id==thispkmn.lastMoveUsed if showMessages pbDisplayPaused("#{thispkmn.pbThis} can't use the same move in a row due to the Torment!") end return false end end if thismove.id==thispkmn.effects[PBEffects::DisableMove] if showMessages pbDisplayPaused("#{thispkmn.pbThis}'s #{thismove.name} is disabled!") end return false end if thispkmn.effects[PBEffects::Encore]>0 && idxMove!=thispkmn.effects[PBEffects::EncoreIndex] return false end return true end def pbAutoChooseMove(idxPokemon) thispkmn=@battlers[idxPokemon] if thispkmn.hp<=0 @choices[idxPokemon][0]=0 @choices[idxPokemon][1]=0 @choices[idxPokemon][2]=nil return end if thispkmn.effects[PBEffects::Encore] > 0 && pbCanChooseMove?(idxPokemon,thispkmn.effects[PBEffects::EncoreIndex],false) PBDebug.log("[Auto choosing Encore move...]") @choices[idxPokemon][0]=1 # Move @choices[idxPokemon][1]=thispkmn.effects[PBEffects::EncoreIndex] # Index of move @choices[idxPokemon][2]=@battlers[idxPokemon].moves[thispkmn.effects[PBEffects::EncoreIndex]] @choices[idxPokemon][3]=-1 else if !pbIsOpposing?(idxPokemon) pbDisplayPaused("#{thispkmn.name} has no moves left!") end @choices[idxPokemon][0]=1 # Move @choices[idxPokemon][1]=-1 # Index of move @choices[idxPokemon][2]=@struggle @choices[idxPokemon][3]=-1 end end def pbOnActiveAll for i in 0..3 # update participants in battles (unfainted participants will earn EXP even if they faint in between) if pbIsOpposing?(i) @battlers[i].pbUpdateParticipants end end @usepriority=false priority=pbPriority for i in priority if i.ability==PBAbilities::DRIZZLE && i.hp>0 @weather=PBWeather::RAINDANCE @weatherduration=-1 pbDisplay("#{i.pbThis}'s Drizzle made it rain!") end if i.ability==PBAbilities::SANDSTREAM && i.hp>0 @weather=PBWeather::SANDSTORM @weatherduration=-1 pbDisplay("#{i.pbThis}'s Sand Stream whipped up a sandstorm!") end if i.ability==PBAbilities::DROUGHT && i.hp>0 @weather=PBWeather::SUNNYDAY @weatherduration=-1 pbDisplay("#{i.pbThis}'s Drought intensified the sun's rays!") end end # Intimidate for i in 0..3 pkmn=@battlers[i] next if pkmn.hp<=0 for j in 0..3 if pkmn.ability==PBAbilities::INTIMIDATE && pkmn.pbIsOpposing?(j) @battlers[j].pbReduceAttackStatStageIntimidate(pkmn) end end end # Trace for i in 0..3 @battlers[i].pbTrace(true) end # Forecast for i in 0..3 pkmn=@battlers[i] next if pkmn.hp<=0 @battlers[i].pbForecast end end def pbOnActiveOne(pkmn) if pkmn.hp<=0 return false end for i in 0..3 # update participants in battles (unfainted participants will earn EXP even if they faint in between) if pbIsOpposing?(i) @battlers[i].pbUpdateParticipants end end if pkmn.pbOwnSide.effects[PBEffects::Spikes] > 0 if pkmn.ability!=PBAbilities::LEVITATE && !pkmn.pbHasType?(PBTypes::FLYING) spikesdiv=[0,8,6,4] pkmn.pbReduceHP(pkmn.hp/spikesdiv[pkmn.pbOwnSide.effects[PBEffects::Spikes]]) pbDisplayPaused("#{pkmn.pbThis} is hurt by Spikes!") end end if pkmn.hp<=0 pkmn.pbFaint end for i in 0..3 @battlers[i].pbAbilityCureCheck end if pkmn.hp<=0 pbGainEXP pbSwitch return false end if pkmn.ability==PBAbilities::DRIZZLE && pkmn.hp>0 @weather=PBWeather::RAINDANCE @weatherduration=-1 pbDisplay("#{pkmn.pbThis}'s Drizzle made it rain!") end if pkmn.ability==PBAbilities::SANDSTREAM && pkmn.hp>0 @weather=PBWeather::SANDSTORM @weatherduration=-1 pbDisplay("#{pkmn.pbThis}'s Sand Stream whipped up a sandstorm!") end if pkmn.ability==PBAbilities::DROUGHT && pkmn.hp>0 @weather=PBWeather::SUNNYDAY @weatherduration=-1 pbDisplay("#{pkmn.pbThis}'s Drought intensified the sun's rays!") end if pkmn.ability==PBAbilities::INTIMIDATE && pkmn.hp>0 for i in 0..3 if pkmn.pbIsOpposing?(i) @battlers[i].pbReduceAttackStatStageIntimidate(pkmn) end end end pkmn.pbTrace(true) if pkmn.ability==PBAbilities::SPEEDBOOST && pkmn.hp>0 end for i in 0..3 pkmn.pbForecast end pkmn.pbBerryCureCheck return true end def pbCanShowCommands?(idxPokemon) thispkmn=@battlers[idxPokemon] if thispkmn.hp<=0 return false end return false if thispkmn.effects[PBEffects::TwoTurnAttack]>0 return false if thispkmn.effects[PBEffects::HyperBeam]>0 return false if thispkmn.effects[PBEffects::Rollout]>0 return false if thispkmn.effects[PBEffects::Outrage]>0 return false if thispkmn.effects[PBEffects::Uproar]>0 return false if thispkmn.effects[PBEffects::Bide]>0 return true end def pbCanShowFightMenu?(idxPokemon) thispkmn=@battlers[idxPokemon] if !pbCanShowCommands?(idxPokemon) return false end # No moves that can be chosen if !pbCanChooseMove?(idxPokemon,0,false)&& !pbCanChooseMove?(idxPokemon,1,false)&& !pbCanChooseMove?(idxPokemon,2,false)&& !pbCanChooseMove?(idxPokemon,3,false) return false end # Encore encore=thispkmn.effects[PBEffects::Encore] if thispkmn.effects[PBEffects::Encore]>0 return false end return true end def pbCanSwitchLax?(idxPokemon,pkmnidxTo,showMessages) thispkmn=@battlers[idxPokemon] if pkmnidxTo>=0 party=pbParty(idxPokemon) if pkmnidxTo>=party.length return false end if party[pkmnidxTo].hp<=0 pbDisplay("#{party[pkmnidxTo].name} has no energy left to battle!") if showMessages return false end if @battlers[idxPokemon].pokemonIndex==pkmnidxTo pbDisplay("#{party[pkmnidxTo].name} is already in battle!") if showMessages return false end if @battlers[idxPokemon].pbPartner.pokemonIndex==pkmnidxTo pbDisplay("#{party[pkmnidxTo].name} is already in battle!") if showMessages return false end end return true end def pbCanSwitch?(idxPokemon,pkmnidxTo,showMessages) thispkmn=@battlers[idxPokemon] # Multi-Turn Attacks/Mean Look if !pbCanSwitchLax?(idxPokemon,pkmnidxTo,showMessages) return false end isOpposing=pbIsOpposing?(idxPokemon) party=pbParty(idxPokemon) for i in 0..3 next if isOpposing!=pbIsOpposing?(i) if choices[i][0]==2&&choices[i][1]==pkmnidxTo pbDisplay("#{party[pkmnidxTo].name} has already been selected.") if showMessages return false end end if thispkmn.effects[PBEffects::MultiTurn]>0 || thispkmn.effects[PBEffects::MeanLook]>=0 pbDisplay("#{thispkmn.pbThis} can't be switched out!") if showMessages return false end # Ingrain if thispkmn.effects[PBEffects::Ingrain] pbDisplay("#{thispkmn.pbThis} can't be switched out!") if showMessages return false end opp1=thispkmn.pbOpposing1 opp2=thispkmn.pbOpposing2 opp=nil if thispkmn.pbHasType?(PBTypes::STEEL) opp=opp1 if opp1.ability==PBAbilities::MAGNETPULL opp=opp2 if opp2.ability==PBAbilities::MAGNETPULL end if !thispkmn.pbHasType?(PBTypes::FLYING) && thispkmn.ability!=PBAbilities::LEVITATE opp=opp1 if opp1.ability==PBAbilities::ARENATRAP opp=opp2 if opp2.ability==PBAbilities::ARENATRAP end opp=opp1 if opp1.ability==PBAbilities::SHADOWTAG opp=opp2 if opp2.ability==PBAbilities::SHADOWTAG if opp pbDisplay("#{opp.pbThis}'s #{opp.ability.name} prevents switching!") if showMessages return false end return true end def pbRegisterSwitch(idxPokemon,idxOther) thispkmn=@battlers[idxPokemon] if !pbCanSwitch?(idxPokemon,idxOther,false) return false else @choices[idxPokemon][0]=2 # Pokemon @choices[idxPokemon][1]=idxOther # Pokemon to switch to @choices[idxPokemon][2]=nil return true end end def pbRegisterItem(idxPokemon,idxItem) thispkmn=@battlers[idxPokemon] thispkmn.pbUseItem(idxItem) @choices[idxPokemon][0]=3 # item @choices[idxPokemon][1]=idxItem # item used @choices[idxPokemon][2]=nil return true end def pbRegisterTarget(idxPokemon,idxTarget) thispkmn=@battlers[idxPokemon] @choices[idxPokemon][3]=idxTarget return true end def pbRandom(x) return rand(x) end def pbPriority if @usepriority # use stored priority if round isn't over yet return @priority end speeds=[] quickclaw=[] priorities=[] temp=[] @priority.clear maxpri=0 minpri=0 # Calculate each Pokemon's speed speeds[0]=@battlers[0].pbSpeed speeds[1]=@battlers[1].pbSpeed speeds[2]=@battlers[2].pbSpeed speeds[3]=@battlers[3].pbSpeed quickclaw[0]=@battlers[0].item==PBItems::QUICKCLAW quickclaw[1]=@battlers[1].item==PBItems::QUICKCLAW quickclaw[2]=@battlers[2].item==PBItems::QUICKCLAW quickclaw[3]=@battlers[3].item==PBItems::QUICKCLAW # Find the maximum and minimum priority for i in 0..3 # For this function, switching and using items # is the same as using a move with a priority of 0 pri=(@choices[i][0]!=1)?0:@choices[i][2].priority priorities[i]=pri if i==0 maxpri=pri minpri=pri else maxpri=pri if maxpripri end end # Find and order all moves with the same priority curpri=maxpri loop do temp.clear for j in 0..3 if priorities[j]==curpri temp[temp.length]=j end end # Sort by speed if temp.length==1 @priority[@priority.length]=@battlers[temp[0]] else n=temp.length usequickclaw=(pbRandom(5)==0) for m in 0..n-2 for i in m+1..n-1 if quickclaw[temp[i]] && usequickclaw cmp=(quickclaw[temp[i-1]]) ? 0 : -1 #Rank higher if without Quick Claw, or equal if with it elsif quickclaw[temp[i-1]] && usequickclaw cmp=1 # Rank lower elsif speeds[temp[i]]!=speeds[temp[i-1]] cmp=(speeds[temp[i]]>speeds[temp[i-1]]) ? -1 : 1 #Rank higher to higher-speed battler else cmp=0 end if cmp<0 # put higher-speed Pokemon first swaptmp=temp[i] temp[i]=temp[i-1] temp[i-1]=swaptmp elsif cmp==0 # swap at random if speeds are equal if pbRandom(2)==0 swaptmp=temp[i] temp[i]=temp[i-1] temp[i-1]=swaptmp end end end end #Now add the temp array to priority for i in temp @priority[@priority.length]=@battlers[i] end end curpri-=1 break unless curpri>=minpri end @usepriority=true return @priority end def pbAllFainted?(party) allfainted=true for i in party if i.hp>0 allfainted=false break end end return allfainted end def pbAbilityEffect(move,user,target) ##TODO: Complete end def pbBerryCheck ##TODO: Complete end def pbFindPlayerBattler(pkmnIndex) battler=nil for k in 0..3 if !pbIsOpposing?(k) && @battlers[k].pokemonIndex==pkmnIndex battler=@battlers[k] break end end return battler end def pbLearnMove(pkmnIndex,move) pokemon=@party1[pkmnIndex] return if !pokemon pkmnname=pokemon.name battler=pbFindPlayerBattler(pkmnIndex) movename=PokeBattle_Move.getName(move) for i in 0..3 if pokemon.moves[i].id==move return end if pokemon.moves[i].id==0 pokemon.moves[i]=PBMove.new(move) battler.moves[i]=PokeBattle_Move.pbFromPBMove(self,pokemon.moves[i]) if battler pbDisplayPaused("#{pkmnname} learned #{movename}!") return end end loop do pbDisplayPaused("#{pkmnname} wants to learn #{movename}.") #Replaces current/total PP pbDisplayPaused("But, #{pkmnname} can't learn more than four moves.") if pbDisplayConfirm("Delete a move to make room for #{movename}?") pbDisplayPaused("Which move should be forgotten?") forgetmove=@scene.pbForgetMove(pokemon) if forgetmove >=0 oldmovename=PokeBattle_Move.getName(pokemon.moves[forgetmove].id) pokemon.moves[forgetmove]=PBMove.new(move)#Replaces current/total PP battler.moves[forgetmove]=PokeBattle_Move.pbFromPBMove(self,pokemon.moves[forgetmove]) if battler pbDisplayPaused("1, 2, and... ... ...") pbDisplayPaused("Poof!") pbDisplayPaused("#{pkmnname} forgot #{oldmovename}.") pbDisplayPaused("And...") pbDisplayPaused("#{pkmnname} learned #{movename}!") return elsif pbDisplayConfirm("Should #{pkmnname} stop learning #{movename}?") pbDisplayPaused("#{pkmnname} did not learn #{movename}.") return end elsif pbDisplayConfirm("Should #{pkmnname} stop learning #{movename}?") pbDisplayPaused("#{pkmnname} did not learn #{movename}.") return end end end def pbGainEXP return if !@internalbattle successbegin=true for i in 0..3 # Not ordered by priority if !@doublebattle && pbIsDoubleBattler?(i) @battlers[i].participants=[] next end if pbIsOpposing?(i) && @battlers[i].participants.length>0 && @battlers[i].hp<=0 dexdata=File.open("PBS/dexdata.dat","rb") species=@battlers[i].species # Current species, not original species; also using R/S base EXP dexdata.pos=76*species+17 baseexp=dexdata.fgetb level=@battlers[i].level dexdata.close # First count the number of participants partic=0 expshare=0 for j in @battlers[i].participants partic+=1 if @party1[j].hp>0 end for j in 0..@party1.length-1 expshare+=1 if @party1[j].hp>0 && @party1[j].item==PBItems::EXPSHARE end # Now calculate EXP for the participants if partic>0 if @trainer==0 && successbegin @scene.pbWildBattleSuccess successbegin=false end for j in 0..@party1.length-1 thispoke=@party1[j] ispartic=0 haveexpshare=(thispoke.item==PBItems::EXPSHARE) ? 1 : 0 for k in @battlers[i].participants ispartic=1 if k==j end if thispoke.hp>0 exp=0 if expshare>0 exp=((level*baseexp/7).floor/2).floor exp=(exp/partic).floor*ispartic+(exp/expshare).floor*haveexpshare elsif ispartic==1 exp=((level*baseexp/7).floor/partic).floor end exp=(exp*1.5).floor if @trainer>0 exp=(exp*1.5).floor if thispoke.trainerID!=@player.id exp=(exp*1.5).floor if thispoke.item==PBItems::LUCKYEGG growthrate=thispoke.growthrate newexp=PBExperience.pbAddExperience(thispoke.exp,exp,growthrate) exp=newexp-thispoke.exp; if exp > 0 if thispoke.trainerID!=@player.id pbDisplay("#{thispoke.name} gained a boosted #{exp} Exp. Points!") else pbDisplay("#{thispoke.name} gained #{exp} Exp. Points!") end #Gain effort value points, using RS effort values totalev=0 for k in 0..5 totalev+=thispoke.ev[k] end dexdata=File.open("PBS/dexdata.dat") dexdata.pos=76*species+23 for k in 0..5 evgain=dexdata.fgetb if thispoke.item==PBItems::MACHOBRACE evgain*=2 end if thispoke.pokerus > 0 evgain*=2 end if evgain>0 # Can't exceed overall limit if totalev+evgain>510 evgain=totalev+evgain-510 end # Can't exceed stat limit if thispoke.ev[k]+evgain>255 evgain=thispoke.ev[k]+evgain-255 end # Add EV gain thispoke.ev[k]+=evgain totalev+=evgain end end newlevel=PBExperience.pbGetLevelFromExperience(newexp,growthrate) tempexp=0 curlevel=thispoke.level species=thispoke.species if newlevelnewlevel oldtotalhp=thispoke.hp oldattack=thispoke.attack olddefense=thispoke.defense oldspeed=thispoke.speed oldspatk=thispoke.spatk oldspdef=thispoke.spdef thispoke.level=curlevel thispoke.calcStats pbDisplay("#{thispoke.name} grew to Level #{curlevel}!") battler=nil @scene.pbLevelUp(thispoke,oldtotalhp,oldattack, olddefense,oldspeed,oldspatk,oldspdef) # Finding all moves learned at this level atkdata=File.open("PBS/attacksRS.dat","rb") offset=atkdata.getOffset(species-1) length=atkdata.getLength(species-1)>>1 atkdata.pos=offset for k in 0..length-1 level=atkdata.fgetw move=atkdata.fgetw if level==thispoke.level # Learned a new move pbLearnMove(j,move) end end atkdata.close end end end end end # Now clear the participants array @battlers[i].participants=[] end end end def pbCanChooseNonActive?(index) party=pbParty(index) for i in 0..party.length-1 return true if pbCanSwitchLax?(index,i,false) end return false end def pbSwitch priority=pbPriority return if @decision>0 if pbAllFainted?(@party1) @decision=2 return end if pbAllFainted?(@party2) @decision=1 return end for i in priority index=i.index next if !@doublebattle && pbIsDoubleBattler?(index) next if i.hp>0 next if !pbCanChooseNonActive?(index) if pbIsOpposing?(index) newenemy=@scene.pbChooseNewEnemy(index,@party2) if !@doublebattle && @battlers[0].hp>0 && @shiftStyle && @trainer > 0 && @internalbattle pbDisplayPaused("The Trainer is about to send in #{@battlers[newenemy].name}.") if pbDisplayConfirm("Will #{@player.name} change Pokemon?") newpoke=pbSwitchPlayer(0,true,true) if newpoke>=0 pbDisplay("#{@battlers[0].name}, that's enough! Come back!") @battlers[0].pbInitialize(@party1[newpoke],newpoke,false); pbDisplay("Go! #{@battlers[0].name}!") pbOnActiveOne(@battlers[0]) end end end pbDisplay("The Trainer sent out #{@party2[newenemy].name}!") @battlers[index].pbInitialize(@party2[newenemy],newenemy,false); pbOnActiveOne(@battlers[index]) elsif @trainer > 0 newpoke=pbSwitchPlayer(index,true,false) @battlers[index].pbInitialize(@party1[newpoke],newpoke,false); pbDisplay("Go! #{@battlers[index].name}!") pbOnActiveOne(@battlers[index]) else switch=false if !pbDisplayConfirm("Use next Pokemon?") switch=(pbRun(index,true)<=0) else switch=true end if switch newpoke=pbSwitchPlayer(index,true,false) @battlers[index].pbInitialize(@party1[newpoke],newpoke,false); pbDisplay("Go! #{@battlers[index].name}!") pbOnActiveOne(@battlers[index]) end end end end def pbSwitchPlayer(index,lax,cancancel) if @debug PBDebug.log("[Switching...]") return @scene.pbChooseNewEnemy(index,pbParty(index)) else return @scene.pbSwitch(index,lax,cancancel) end end def pbDebugUpdate @debugupdate+=1 if @debugupdate==30 Graphics.update @debugupdate=0 end end def pbDisplayPaused(msg) if @debug pbDebugUpdate PBDebug.log(msg) else @scene.pbDisplayPausedMessage(msg) end end def pbDisplay(msg) if @debug pbDebugUpdate PBDebug.log(msg) else @scene.pbDisplayMessage(msg) end end def pbDisplayConfirm(msg) if @debug pbDebugUpdate PBDebug.log(msg) return true else return @scene.pbDisplayConfirmMessage(msg) end end def pbCommandPhase @scene.pbBeginCommandPhase for i in 0..3 # Reset choices if commands can be shown if pbCanShowCommands?(i) choices[i][0]=0 choices[i][1]=0 choices[i][2]=nil choices[i][3]=-1 else battler=@battlers[i] PBDebug.log("[reusing commands for #{battler.pbThis}]") unless !@doublebattle && pbIsDoubleBattler?(i) end end for i in 0..3 next if !@doublebattle && pbIsDoubleBattler?(i) if pbIsOpposing?(i) || @debug if @battlers[i].hp>0 && pbCanShowCommands?(i) @scene.pbChooseEnemyCommand(i) end else commandDone=false commandEnd=false if pbCanShowCommands?(i) loop do cmd=@scene.pbCommandMenu(i) if cmd==0 # Fight if pbCanShowFightMenu?(i) loop do index=@scene.pbFightMenu(i) break if index<0 next if !pbRegisterMove(i,index) if @doublebattle thismove=@battlers[i].moves[index]; if thismove.target==0x00 # single non-user target=@scene.pbChooseTarget(i) next if target<0 pbRegisterTarget(i,target) end end commandDone=true break end else pbAutoChooseMove(i) commandDone=true end elsif cmd==1 # Pokemon pkmn=pbSwitchPlayer(i,false,true) if pkmn>=0 commandDone=true if pbRegisterSwitch(i,pkmn) end elsif cmd==2 # Bag item=@scene.pbItemMenu(i) if item>0 pbRegisterItem(i,item) commandDone=true end elsif cmd==3 # Run run=pbRun(i) if run > 0 @decision=3 # change decision to escaped commandDone=true return elsif run < 0 commandDone=true end end break if commandDone end # end command loop end # end CanShowCommands end end end def pbChoseMove?(i,move) return @choices[i][0]==1&&@choices[i][2]==move end def pbAttackPhase @scene.pbBeginAttackPhase for i in 0..3 # in order from own first, opposing first, own second, opposing second if pbChoseMove?(i,PBMoves::FOCUSPUNCH) if @battlers[i].status!=PBStatuses::SLEEP&& (@battlers[i].ability!=PBAbilities::TRUANT ||!@battlers[i].effects[PBEffects::Truant]) pbDisplay("#{@battlers[i].pbThis} is tightening its focus!"); end end end for i in 0..3 if @battlers[i].hp>0 @battlers[i].turncount+=1 end end for i in 0..3 if !pbChoseMove?(i,PBMoves::RAGE) @battlers[i].effects[PBEffects::Rage]=false end end @switching=true for i in 0..3 # in order from own first, opposing first, own second, opposing second if @choices[i][0]==2 index=@choices[i][1]# party position of Pokemon to switch to if pbIsOpposing?(i) pbDisplay("The Trainer withdrew #{battlers[i].name}!"); else pbDisplay("#{battlers[i].name}, that's enough! Come back!"); end for j in 3..0 # in order from opposing second, opposing first next if !@battlers[i].pbIsOpposing?(j) # if Pursuit and this target ("i") was chosen if pbChoseMove?(j,PBMoves::PURSUIT) && @choices[j][3]==i if @battlers[j].status!=PBStatuses::SLEEP&& @battlers[j].status!=PBStatuses::FROZEN&& (@battlers[j].ability!=PBAbilities::TRUANT ||!@battlers[j].effects[PBEffects::Truant]) @battlers[j].pbUseMove(@choices[i]) @battlers[i].effects[PBEffects::Pursuit]=true #UseMove calls pbGainEXP as appropriate @switching=false return if @decision>0 end end break if @battlers[i].hp<=0 end if pbIsOpposing?(i) pbDisplay("The Trainer sent out #{party2[index].name}!"); @battlers[i].pbInitialize(@party2[index],index,false) else pbDisplay("Go! #{party1[index].name}!"); @battlers[i].pbInitialize(@party1[index],index,false) end if !pbOnActiveOne(@battlers[i]) # If a forced switch somehow occurs here in single battles # the attack phase now end if !@doublebattle @switching=false return end end end end @switching=false # calculate priority at this time @usepriority=false # recalculate priority priority=pbPriority for i in priority i.pbProcessTurn(@choices[i.index]) return if @decision>0 end end def pbEndOfRoundPhase for i in 0..3 @battlers[i].effects[PBEffects::Protect]=false @battlers[i].effects[PBEffects::Endure]=false @battlers[i].effects[PBEffects::HyperBeam]-=1 if @battlers[i].effects[PBEffects::HyperBeam]>0 end @usepriority=false # recalculate priority priority=pbPriority #Reflect for i in 0..1 if sides[i].effects[PBEffects::Reflect] > 0 sides[i].effects[PBEffects::Reflect]-=1 if sides[i].effects[PBEffects::Reflect]==0 pbDisplay("Ally's Reflect faded!") if i==0 pbDisplay("Foe's Reflect faded!") if i==1 end end end #Light Screen for i in 0..1 if sides[i].effects[PBEffects::LightScreen] > 0 sides[i].effects[PBEffects::LightScreen]-=1 if sides[i].effects[PBEffects::LightScreen]==0 pbDisplay("Ally's Light Screen faded!") if i==0 pbDisplay("Foe's Light Screen faded!") if i==1 end end end #Mist for i in 0..1 if sides[i].effects[PBEffects::Mist] > 0 sides[i].effects[PBEffects::Mist]-=1 if sides[i].effects[PBEffects::Mist]==0 pbDisplay("Ally's Mist faded!") if i==0 pbDisplay("Foe's Mist faded!") if i==1 end end end #Safeguard for i in 0..1 if sides[i].effects[PBEffects::Safeguard] > 0 sides[i].effects[PBEffects::Safeguard]-=1 if sides[i].effects[PBEffects::Safeguard]==0 pbDisplay("Ally's party is no longer protected by Safeguard!") if i==0 pbDisplay("Foe's party is no longer protected by Safeguard!") if i==1 end end end #Wish for i in priority if i.effects[PBEffects::Wish]>0 i.effects[PBEffects::Wish]-=1 if i.effects[PBEffects::Wish]==0 && i.hp>0 wishmaker=pbThisEx(i.index,i.effects[PBEffects::WishMaker]) pbDisplay("#{wishmaker}'s Wish came true!") hpgain=i.pbRecoverHP((i.totalhp/2).floor) if hpgain==0 pbDisplay("#{i.pbThis}'s HP is full!") else pbDisplay("#{i.pbThis} regained health!") end end end end #Weather if @weather==PBWeather::RAINDANCE @weatherduration=@weatherduration-1 if @weatherduration>0 if @weatherduration==0 pbDisplay("The rain stopped.") @weather=0 else pbDisplay("Rain continues to fall."); end end if @weather==PBWeather::SANDSTORM @weatherduration=@weatherduration-1 if @weatherduration>0 if @weatherduration==0 pbDisplay("The sandstorm subsided.") @weather=0 else pbDisplay("The sandstorm rages."); if pbWeather==PBWeather::SANDSTORM for i in priority next if i.hp<=0 if i.ability!=PBAbilities::SANDVEIL && !i.pbHasType?(PBTypes::GROUND)&& !i.pbHasType?(PBTypes::ROCK)&& !i.pbHasType?(PBTypes::STEEL)&& i.effects[PBEffects::TwoTurnAttack]!=PBMoves::DIG&& i.effects[PBEffects::TwoTurnAttack]!=PBMoves::DIVE pbDisplay("#{i.pbThis} was buffeted by the sandstorm!") i.pbReduceHP(i.totalhp/16) if i.hp<=0 return if !i.pbFaint end end end end end end if @weather==PBWeather::SUNNYDAY @weatherduration=@weatherduration-1 if @weatherduration>0 if @weatherduration==0 pbDisplay("The sunlight faded.") @weather=0 else pbDisplay("The sunlight is strong."); end end if @weather==PBWeather::HAIL @weatherduration=@weatherduration-1 if @weatherduration>0 if @weatherduration==0 pbDisplay("The hail stopped.") @weather=0 else pbDisplay("Hail continues to fall."); if pbWeather==PBWeather::HAIL for i in priority next if i.hp<=0 if !i.pbHasType?(PBTypes::ICE)&& i.effects[PBEffects::TwoTurnAttack]!=PBMoves::DIG&& i.effects[PBEffects::TwoTurnAttack]!=PBMoves::DIVE pbDisplay("#{i.pbThis} was pelted by hail!") i.pbReduceHP(i.totalhp/16) if i.hp<=0 return if !i.pbFaint end end end end end end # Ingrain for i in priority # No switching during process next if i.hp<=0 if i.effects[PBEffects::Ingrain] hpgain=i.pbRecoverHP(i.totalhp/16) pbDisplay("#{i.pbThis} absorbed nutrients with its roots!") if hpgain>0 end # Rain Dish if pbWeather==PBWeather::RAINDANCE && i.ability==PBAbilities::RAINDISH hpgain=i.pbRecoverHP(i.totalhp/16) pbDisplay("#{i.pbThis}'s Rain Dish restored its HP a little!") if hpgain>0 end # Speed Boost # A Pokemon's turncount is 0 if it became active after the beginning of a round if i.turncount>0 && i.ability==PBAbilities::SPEEDBOOST if !i.pbTooHigh?(PBStats::SPEED) i.stages[PBStats::SPEED]+=1 pbDisplay("#{i.pbThis}'s Speed Boost raised its Speed!") end end # Truant if i.ability==PBAbilities::TRUANT i.effects[PBEffects::Truant]=!i.effects[PBEffects::Truant] end # Shed Skin if i.ability==PBAbilities::SHEDSKIN if pbRandom(10)<3 && i.status>0 case i.status when PBStatuses::SLEEP pbDisplay("#{i.pbThis}'s Shed Skin cured its sleep problem!") when PBStatuses::FROZEN pbDisplay("#{i.pbThis}'s Shed Skin cured its ice problem!") when PBStatuses::BURN pbDisplay("#{i.pbThis}'s Shed Skin cured its burn problem!") when PBStatuses::POISON pbDisplay("#{i.pbThis}'s Shed Skin cured its poison problem!") when PBStatuses::PARALYSIS pbDisplay("#{i.pbThis}'s Shed Skin cured its paralysis problem!") end i.status=0 i.statusCount=0 end end # Berry check pbBerryCheck # Leech Seed if i.effects[PBEffects::LeechSeed]>=0 recipient=@battlers[i.effects[PBEffects::LeechSeed]] if recipient.hp>0 hploss=i.pbReduceHP((i.totalhp/8).floor) if i.ability==PBAbilities::LIQUIDOOZE recipient.pbReduceHP(hploss) pbDisplay("It sucked up the liquid ooze!") else recipient.pbRecoverHP(hploss) pbDisplay("#{i.pbThis}'s health is sapped by Leech Seed!") end i.pbFaint if i.hp<=0 recipient.pbFaint if recipient.hp<=0 end end return if @decision>0 next if i.hp<=0 # Poison/Toxic/Burn if i.status==PBStatuses::POISON pbDisplay("#{i.pbThis} is hurt by poison!") if i.statusCount==0 i.pbReduceHP((i.totalhp/8).floor) else i.effects[PBEffects::Toxic]+=1 i.pbReduceHP((i.totalhp*i.effects[PBEffects::Toxic]/16).floor) end end if i.hp<=0 return if !i.pbFaint next end if i.status==PBStatuses::BURN pbDisplay("#{i.pbThis} is hurt by its burn!") i.pbReduceHP((i.totalhp/8).floor) end if i.hp<=0 return if !i.pbFaint next end # Nightmare if i.effects[PBEffects::Nightmare] if i.status==PBStatuses::SLEEP pbDisplay("#{i.pbThis} is locked in a nightmare!") i.pbReduceHP((i.totalhp/4).floor) else i.effects[PBEffects::Nightmare]=false end end if i.hp<=0 return if !i.pbFaint next end # Curse if i.effects[PBEffects::Curse] pbDisplay("#{i.pbThis} is afflicted by the Curse!") i.pbReduceHP((i.totalhp/4).floor) end if i.hp<=0 return if !i.pbFaint next end # Multi-turn attacks if i.effects[PBEffects::MultiTurn]>0 i.effects[PBEffects::MultiTurn]-=1 movename=PokeBattle_Move.getName(i.effects[PBEffects::MultiTurnAttack]) if i.effects[PBEffects::MultiTurn]==0 pbDisplay("#{i.pbThis} was freed from #{movename}!") else pbDisplay("#{i.pbThis} is hurt by #{movename}!") i.pbReduceHP((i.totalhp/16).floor) end end if i.hp<=0 return if !i.pbFaint next end # Uproar if i.effects[PBEffects::Uproar]>0 for j in priority if j.status==PBStatuses::SLEEP && j.ability!=PBAbilities::SOUNDPROOF pbDisplay("#{j.pbThis} woke up in the uproar!") j.effects[PBEffects::Nightmare]=false j.status=0 j.statusCount=0 end end i.effects[PBEffects::Uproar]-=1 if i.effects[PBEffects::Uproar]==0 pbDisplay("#{i.pbThis} calmed down.") else pbDisplay("#{i.pbThis} is making an uproar!") end end # Outrage if i.effects[PBEffects::Outrage]>0 i.effects[PBEffects::Outrage]-=1 if i.effects[PBEffects::Outrage]==0&&i.ability!=PBAbilities::OWNTEMPO&&i.effects[PBEffects::Confusion]<=0 i.effects[PBEffects::Confusion]=2+pbRandom(4) pbDisplay("#{i.pbThis} became confused due to fatigue!") end end # Disable if i.effects[PBEffects::Disable]>0 i.effects[PBEffects::Disable]-=1 if i.effects[PBEffects::Disable]==0 i.effects[PBEffects::DisableMove]=0 pbDisplay("#{i.pbThis} is disabled no more!") end end # Encore if i.effects[PBEffects::Encore]>0 # PBDebug.log("[Battler: #{i.pbThis}]") # PBDebug.log("[Encore=#{i.effects[PBEffects::Encore]}]") # PBDebug.log("[EncoreIndex=#{i.effects[PBEffects::EncoreIndex]}]") # PBDebug.log("[EncoreMove=#{i.effects[PBEffects::EncoreMove]}]") # PBDebug.log("[CurrentMove=#{i.moves[i.effects[PBEffects::EncoreIndex]].id}]") if i.moves[i.effects[PBEffects::EncoreIndex]].id!=i.effects[PBEffects::EncoreMove] i.effects[PBEffects::Encore]=0 i.effects[PBEffects::EncoreIndex]=0 i.effects[PBEffects::EncoreMove]=0 else i.effects[PBEffects::Encore]-=1 if i.effects[PBEffects::Encore]==0 || i.moves[i.effects[PBEffects::EncoreIndex]].pp==0 i.effects[PBEffects::Encore]=0 pbDisplay("#{i.pbThis}'s encore ended!") end end end # Taunt/Lock-on/Mind Reader if i.effects[PBEffects::LockOn]>0 i.effects[PBEffects::LockOn]-=1 if i.effects[PBEffects::LockOn]==0 i.effects[PBEffects::LockOnPos]=-1 end end i.effects[PBEffects::Taunt]-=1 if i.effects[PBEffects::Taunt]>0 i.effects[PBEffects::Charge]-=1 if i.effects[PBEffects::Charge]>0 # Yawn if i.effects[PBEffects::Yawn]>0 i.effects[PBEffects::Yawn]-=1 if i.effects[PBEffects::Yawn]==0&&i.pbCanSleepYawn? i.pbSleep pbDisplay("#{i.pbThis} fell asleep!") end end # Berry/Herb pbBerryCheck end pbGainEXP pbSwitch for i in 0..3 @battlers[i].pbTrace(false) end for i in 0..3 @battlers[i].pbForecast end #Future Sight for i in battlers # not priority if i.hp>0 && i.effects[PBEffects::FutureSight]>0 i.effects[PBEffects::FutureSight]-=1 if i.effects[PBEffects::FutureSight]==0 move=PokeBattle_Move.pbFromPBMove(self,PBMove.new(i.effects[PBEffects::FutureSightMove])) pbDisplay("#{i.pbThis} took the #{move.name} attack!") damage=((i.effects[PBEffects::FutureSightDamage]*85)/100).floor damage=1 if damage<1 move.pbReduceHPDamage(damage,nil,i) i.effects[PBEffects::FutureSight]=0 i.effects[PBEffects::FutureSightMove]=0 i.effects[PBEffects::FutureSightDamage]=0 if i.hp<=0 i.pbFaint # no return pbGainEXP pbSwitch end end end end #Perish Song for i in priority if i.hp>0 && i.effects[PBEffects::PerishSong]>0 i.effects[PBEffects::PerishSong]=i.effects[PBEffects::PerishSong]-1 pbDisplay("#{i.pbThis}'s Perish count fell to #{i.effects[PBEffects::PerishSong]}!") if i.effects[PBEffects::PerishSong]==0 i.pbReduceHP(i.hp); i.pbFaint # no return pbGainEXP pbSwitch end end end for i in 0..3 @battlers[i].effects[PBEffects::Protect]=false @battlers[i].effects[PBEffects::Endure]=false end for i in 0..3 @battlers[i].effects[PBEffects::Flinch]=false @battlers[i].effects[PBEffects::FollowMe]=false @battlers[i].effects[PBEffects::HelpingHand]=false @battlers[i].effects[PBEffects::MagicCoat]=false @battlers[i].effects[PBEffects::Snatch]=false @battlers[i].lastHPLost=0 @battlers[i].lastAttacker=-1 @battlers[i].effects[PBEffects::Counter]=-1 @battlers[i].effects[PBEffects::MirrorCoat]=-1 @battlers[i].effects[PBEffects::CounterTarget]=-1 @battlers[i].effects[PBEffects::MirrorCoatTarget]=-1 end pbSwitch # invalidate stored priority @usepriority=false end end