#=============================================================================== # SOS Battles - By Vendily [v17] #=============================================================================== # This script adds in SOS Battles, the added mechanic from Alola, where # Pokémon have a chance of calling for aid while in battle. # This version of the script does not implement special weather based encounters # but does have a method that can be edited to do so. # The script also defines the manually used effect of the Adrenaline Orb item. #=============================================================================== # To use it, you must add species that are able to SOS call in the SOS_CALL_RATES # hash. The key is the species symbol, and the value is the rate in percentage # the mon will call at. # AKA. :BULBASAUR=>100 is a valid entry # # Optionally, you may add species to SOS_CALL_MONS, the species that # the mon will call for. Add more entries of the same species to make them more # likely. The Key is the species symbol, and the value is an array of species. # AKA. :BULBASAUR=>[:BULBASAUR,:BULBASAUR,:BULBASAUR,:IVYSAUR,:IVYSAUR,:VENUSAUR] # is a valid entry. # If you don't have an entry for a calling species, it will call another mon of # the same species as itself. # # To implement the doubled EV points in an SOS battle, there is an additional # edit to "def pbGainExpOne" in PokeBattle_Battle # under: # evgain*=2 if thispoke.pokerusStage>=1 # Infected or cured # put: # evgain*=2 if @sosbattle # # If you wish to implement special called allies, edit the array returned by # pbSpecialSOSMons. By default, it just passes through the regular array used. # The method also takes the calling battler, if you wish to check its properties. #=============================================================================== # * Hash containing base species call rates # * Hash containing species called allies # * Switch id to enable/disable SOS battles. Set to <1 to not check. #=============================================================================== SOS_CALL_RATES={} SOS_CALL_MONS={} NO_SOS_BATTLES = -1 class PokeBattle_Battle attr_accessor :adrenalineorb attr_accessor :lastturncalled attr_accessor :lastturnanswered attr_accessor :soschain attr_accessor :sosbattle attr_accessor :wasdoublebattle def soschain return @soschain || 0 end def pbSpecialSOSMons(caller,mons) return mons end def pbCallForHelp(index,caller) cspecies=getConstantName(PBSpecies,caller.species).to_sym rate=SOS_CALL_RATES[cspecies] || 0 return if rate==0 # should never trigger anyways but you never know. pbDisplay(_INTL("{1} called for help!", caller.pbThis)) rate*=4 # base rate rate=rate.to_f # don't want to lose decimal points pbattler=@battlers[0] if pbattler.hasWorkingAbility(:INTIMIDATE) || pbattler.hasWorkingAbility(:UNNERVE) || pbattler.hasWorkingAbility(:PRESSURE) rate*=1.2 end if @lastturncalled==@turncount-1 rate*=1.5 end if !@lastturnanswered rate*=3.0 end rate=rate.round # rounding it off. pbDisplayBrief(_INTL("... ... ...")) if pbRandom(100)>1),false) @wasdoublebattle=@doublebattle if @wasdoublebattle.nil? @doublebattle=true if !@doublebattle @sosbattle=true @scene.pbSOSJoin(index,ally) pbDisplayBrief(_INTL("{1} appeared!",@battlers[index].pbThis)) caller.pbPartner.effects[PBEffects::SkipTurn]=true caller.effects[PBEffects::SkipTurn]=true @party2.push(ally) else @lastturnanswered=false pbDisplay(_INTL("Its help didn't appear!")) end end def pbGenerateSOSPokemon(species,level) genwildpoke = PokeBattle_Pokemon.new(species,level,$Trainer) items = genwildpoke.wildHoldItems firstpoke = @battlers[0] chances = [50,5,1] chances = [60,20,5] if firstpoke.hasWorkingAbility(:COMPOUNDEYES) itemrnd = rand(100) if itemrnd0 for i in 0...shinychain break if genwildpoke.isShiny? genwildpoke.personalID = rand(65536)|(rand(65536)<<16) end end ivchain=(chain/10) ivchain+=1 if chain>=5 ivs=(0..5).to_a ivs.shuffle! if ivchain>0 for i in 0...ivchain break if ivs.length==0 iv=ivs.shift genwildpoke.ivs[iv]=31 end end hachain=(chain/10) if hachain>0 genwildpoke.setAbility(2) if pbRandom(100)0 else return if @decision==5 end pbJudge() return if @decision>0 firstbattlerhp=@battlers[0].hp switched=[] for index in 0...4 next if !@doublebattle && pbIsDoubleBattler?(index) next if @battlers[index] && !@battlers[index].fainted? next if !pbCanChooseNonActive?(index) if !pbOwnedByPlayer?(index) if !pbIsOpposing?(index) || (@opponent && pbIsOpposing?(index)) newenemy=pbSwitchInBetween(index,false,false) newenemyname=newenemy if newenemy>=0 && isConst?(pbParty(index)[newenemy].ability,PBAbilities,:ILLUSION) newenemyname=pbGetLastPokeInTeam(index) end opponent=pbGetOwner(index) if !@doublebattle && firstbattlerhp>0 && @shiftStyle && @opponent && @internalbattle && pbCanChooseNonActive?(0) && pbIsOpposing?(index) && @battlers[0].effects[PBEffects::Outrage]==0 pbDisplayPaused(_INTL("{1} is about to send in {2}.",opponent.fullname,pbParty(index)[newenemyname].name)) if pbDisplayConfirm(_INTL("Will {1} change Pokémon?",self.pbPlayer.name)) newpoke=pbSwitchPlayer(0,true,true) if newpoke>=0 newpokename=newpoke if isConst?(@party1[newpoke].ability,PBAbilities,:ILLUSION) newpokename=pbGetLastPokeInTeam(0) end pbDisplayBrief(_INTL("{1}, that's enough! Come back!",@battlers[0].name)) pbRecallAndReplace(0,newpoke,newpokename) switched.push(0) end end end pbRecallAndReplace(index,newenemy,newenemyname,false,false) switched.push(index) end elsif @opponent newpoke=pbSwitchInBetween(index,true,false) newpokename=newpoke if isConst?(@party1[newpoke].ability,PBAbilities,:ILLUSION) newpokename=pbGetLastPokeInTeam(index) end pbRecallAndReplace(index,newpoke,newpokename) switched.push(index) else next if @sosbattle && !@wasdoublebattle switch=false if !pbDisplayConfirm(_INTL("Use next Pokémon?")) switch=(pbRun(index,true)<=0) else switch=true end if switch newpoke=pbSwitchInBetween(index,true,false) newpokename=newpoke if isConst?(@party1[newpoke].ability,PBAbilities,:ILLUSION) newpokename=pbGetLastPokeInTeam(index) end pbRecallAndReplace(index,newpoke,newpokename) switched.push(index) end end end if switched.length>0 priority=pbPriority for i in priority i.pbAbilitiesOnSwitchIn(true) if switched.include?(i.index) end end end end class PokeBattle_Battler def pbCanCall? return false if NO_SOS_BATTLES>0 && $game_switches[NO_SOS_BATTLES] # only wild battles return false if @opponent # only wild mons return false if !@battle.pbIsOpposing?(self.index) # can't call if partner already in return false if !self.pbPartner.fainted? # just to be safe return false if self.fainted? # no call if status return false if self.status!=0 # no call if multiturn attack return false if self.effects[PBEffects::TwoTurnAttack]>0 return false if self.effects[PBEffects::HyperBeam]>0 return false if self.effects[PBEffects::Rollout]>0 return false if self.effects[PBEffects::Outrage]>0 return false if self.effects[PBEffects::Uproar]>0 return false if self.effects[PBEffects::Bide]>0 species=getConstantName(PBSpecies,self.species).to_sym rate=SOS_CALL_RATES[species] || 0 # not a species that calls return false if rate==0 rate*=3 if self.hp>(self.totalhp/4) && self.hp<=(self.totalhp/2) rate*=5 if self.hp<=(self.totalhp/4) rate*=2 if @battle.adrenalineorb return @battle.pbRandom(100)=0 @sprites["battlebox#{partnerindex}"].appear end end if frame>=6 sendout.update end pbGraphicsUpdate pbInputUpdate pbFrameUpdate break if sendout.animdone? && !@sprites["battlebox#{battlerindex}"].appearing end if @battle.battlers[battlerindex].isShiny? && @battle.battlescene pbCommonAnimation("Shiny",@battle.battlers[battlerindex],nil) end sendout.dispose pbRefresh end end class SOSJoinAnimation def initialize(sprite,spritehash,pkmn,doublebattle,battle) @disposed=false @PokemonBattlerSprite=sprite @PokemonBattlerSprite.visible=false @PokemonBattlerSprite.src_rect.height=@PokemonBattlerSprite.bitmap.height @PokemonBattlerSprite.oy=0 @PokemonBattlerSprite.tone=Tone.new(0,0,0,248) if doublebattle @spritex=PokeBattle_SceneConstants::FOEBATTLERD1_X if pkmn.index==1 @spritex=PokeBattle_SceneConstants::FOEBATTLERD2_X if pkmn.index==3 else @spritex=PokeBattle_SceneConstants::FOEBATTLER_X end @spritey=adjustBattleSpriteY(sprite,pkmn.species,pkmn.index) if doublebattle @spritey+=PokeBattle_SceneConstants::FOEBATTLERD1_Y if pkmn.index==1 @spritey+=PokeBattle_SceneConstants::FOEBATTLERD2_Y if pkmn.index==3 else @spritey+=PokeBattle_SceneConstants::FOEBATTLER_Y end @spritehash=spritehash @pkmn=pkmn @shadowX=@spritex @shadowY=@spritey/2 if @spritehash["shadow#{@pkmn.index}"] && @spritehash["shadow#{@pkmn.index}"].bitmap!=nil @shadowX-=@spritehash["shadow#{@pkmn.index}"].bitmap.width/2 @shadowY-=@spritehash["shadow#{@pkmn.index}"].bitmap.height/2 end if @spritehash["pokemon#{@pkmn.pbPartner.index}"] pindex=@pkmn.pbPartner.index pmon=battle.battlers[pindex] case pindex when 1 @spritehash["pokemon#{pindex}"].x=PokeBattle_SceneConstants::FOEBATTLERD1_X @spritehash["pokemon#{pindex}"].y=PokeBattle_SceneConstants::FOEBATTLERD1_Y when 3 @spritehash["pokemon#{pindex}"].x=PokeBattle_SceneConstants::FOEBATTLERD2_X @spritehash["pokemon#{pindex}"].y=PokeBattle_SceneConstants::FOEBATTLERD2_Y end @spritehash["pokemon#{pindex}"].x-=@spritehash["pokemon#{pindex}"].bitmap.width/2 @spritehash["pokemon#{pindex}"].y+=adjustBattleSpriteY(@spritehash["pokemon#{pindex}"],pmon.species,pmon.index) if @spritehash["shadow#{@pkmn.index}"] && @spritehash["shadow#{@pkmn.index}"].bitmap!=nil @spritehash["shadow#{@pkmn.index}"].x=@spritehash["pokemon#{pindex}"].x @spritehash["shadow#{@pkmn.index}"].x-=@spritehash["shadow#{@pkmn.index}"].bitmap.width/2 @spritehash["shadow#{@pkmn.index}"].y=@spritehash["pokemon#{pindex}"].y/2 @spritehash["shadow#{@pkmn.index}"].y-=@spritehash["shadow#{@pkmn.index}"].bitmap.height/2 end end @shadowVisible=showShadow?(pkmn.species) @animdone=false @frame=0 end def disposed? return @disposed end def animdone? return @animdone end def dispose return if disposed? @disposed=true end def update return if disposed? @frame+=1 if @frame==4 if @spritehash["shadow#{@pkmn.index}"] @spritehash["shadow#{@pkmn.index}"].x=@shadowX @spritehash["shadow#{@pkmn.index}"].y=@shadowY @spritehash["shadow#{@pkmn.index}"].visible=@shadowVisible end @PokemonBattlerSprite.visible=true pbSpriteSetCenter(@PokemonBattlerSprite,@spritex,@spritey) @PokemonBattlerSprite.y=@spritey if @pkmn.pokemon pbPlayCry(@pkmn.pokemon) else pbPlayCrySpecies(@pkmn.species,@pkmn.form) end end if @frame>8 && @frame<=24 tone=(16-@frame)*32 @PokemonBattlerSprite.tone=Tone.new(0,0,0,tone) end if @PokemonBattlerSprite.tone.gray<=0 @animdone=true end end end ItemHandlers::BattleUseOnBattler.add(:ADRENALINEORB,proc{|item,battler,scene| battle=battler.battle if battle.adrenalineorb scene.pbDisplay(_INTL("Already used that.")) return false end playername=battle.pbPlayer.name scene.pbDisplay(_INTL("{1} used the {2}.",playername,PBItems.getName(item))) return true }) ItemHandlers::UseInBattle.add(:ADRENALINEORB,proc{|item,battler,battle| battle.adrenalineorb=true battle.pbDisplayPaused(_INTL("The {1} makes the wild Pokémon nervous!",PBItems.getName(item))) })