mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-09 06:04:59 +00:00
Yet more script rearranging
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
module PokeBattle_BattleCommon
|
||||
#=============================================================================
|
||||
# Store caught Pokémon
|
||||
#=============================================================================
|
||||
def pbStorePokemon(pkmn)
|
||||
# Nickname the Pokémon (unless it's a Shadow Pokémon)
|
||||
if !pkmn.shadowPokemon?
|
||||
if pbDisplayConfirm(_INTL("Would you like to give a nickname to {1}?", pkmn.name))
|
||||
nickname = @scene.pbNameEntry(_INTL("{1}'s nickname?", pkmn.speciesName), pkmn)
|
||||
pkmn.name = nickname
|
||||
end
|
||||
end
|
||||
# Store the Pokémon
|
||||
currentBox = @peer.pbCurrentBox
|
||||
storedBox = @peer.pbStorePokemon(pbPlayer,pkmn)
|
||||
if storedBox<0
|
||||
pbDisplayPaused(_INTL("{1} has been added to your party.",pkmn.name))
|
||||
@initialItems[0][pbPlayer.party.length-1] = pkmn.item_id if @initialItems
|
||||
return
|
||||
end
|
||||
# Messages saying the Pokémon was stored in a PC box
|
||||
creator = @peer.pbGetStorageCreatorName
|
||||
curBoxName = @peer.pbBoxName(currentBox)
|
||||
boxName = @peer.pbBoxName(storedBox)
|
||||
if storedBox!=currentBox
|
||||
if creator
|
||||
pbDisplayPaused(_INTL("Box \"{1}\" on {2}'s PC was full.",curBoxName,creator))
|
||||
else
|
||||
pbDisplayPaused(_INTL("Box \"{1}\" on someone's PC was full.",curBoxName))
|
||||
end
|
||||
pbDisplayPaused(_INTL("{1} was transferred to box \"{2}\".",pkmn.name,boxName))
|
||||
else
|
||||
if creator
|
||||
pbDisplayPaused(_INTL("{1} was transferred to {2}'s PC.",pkmn.name,creator))
|
||||
else
|
||||
pbDisplayPaused(_INTL("{1} was transferred to someone's PC.",pkmn.name))
|
||||
end
|
||||
pbDisplayPaused(_INTL("It was stored in box \"{1}\".",boxName))
|
||||
end
|
||||
end
|
||||
|
||||
# Register all caught Pokémon in the Pokédex, and store them.
|
||||
def pbRecordAndStoreCaughtPokemon
|
||||
@caughtPokemon.each do |pkmn|
|
||||
pbPlayer.pokedex.register(pkmn) # In case the form changed upon leaving battle
|
||||
# Record the Pokémon's species as owned in the Pokédex
|
||||
if !pbPlayer.hasOwned?(pkmn.species)
|
||||
pbPlayer.pokedex.set_owned(pkmn.species)
|
||||
if $Trainer.has_pokedex
|
||||
pbDisplayPaused(_INTL("{1}'s data was added to the Pokédex.",pkmn.name))
|
||||
@scene.pbShowPokedex(pkmn.species)
|
||||
end
|
||||
end
|
||||
# Record a Shadow Pokémon's species as having been caught
|
||||
pbPlayer.pokedex.set_shadow_pokemon_owned(pkmn.species) if pkmn.shadowPokemon?
|
||||
# Store caught Pokémon
|
||||
pbStorePokemon(pkmn)
|
||||
end
|
||||
@caughtPokemon.clear
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Throw a Poké Ball
|
||||
#=============================================================================
|
||||
def pbThrowPokeBall(idxBattler,ball,catch_rate=nil,showPlayer=false)
|
||||
# Determine which Pokémon you're throwing the Poké Ball at
|
||||
battler = nil
|
||||
if opposes?(idxBattler)
|
||||
battler = @battlers[idxBattler]
|
||||
else
|
||||
battler = @battlers[idxBattler].pbDirectOpposing(true)
|
||||
end
|
||||
if battler.fainted?
|
||||
battler.eachAlly do |b|
|
||||
battler = b
|
||||
break
|
||||
end
|
||||
end
|
||||
# Messages
|
||||
itemName = GameData::Item.get(ball).name
|
||||
if battler.fainted?
|
||||
if itemName.starts_with_vowel?
|
||||
pbDisplay(_INTL("{1} threw an {2}!",pbPlayer.name,itemName))
|
||||
else
|
||||
pbDisplay(_INTL("{1} threw a {2}!",pbPlayer.name,itemName))
|
||||
end
|
||||
pbDisplay(_INTL("But there was no target..."))
|
||||
return
|
||||
end
|
||||
if itemName.starts_with_vowel?
|
||||
pbDisplayBrief(_INTL("{1} threw an {2}!",pbPlayer.name,itemName))
|
||||
else
|
||||
pbDisplayBrief(_INTL("{1} threw a {2}!",pbPlayer.name,itemName))
|
||||
end
|
||||
# Animation of opposing trainer blocking Poké Balls (unless it's a Snag Ball
|
||||
# at a Shadow Pokémon)
|
||||
if trainerBattle? && !(GameData::Item.get(ball).is_snag_ball? && battler.shadowPokemon?)
|
||||
@scene.pbThrowAndDeflect(ball,1)
|
||||
pbDisplay(_INTL("The Trainer blocked your Poké Ball! Don't be a thief!"))
|
||||
return
|
||||
end
|
||||
# Calculate the number of shakes (4=capture)
|
||||
pkmn = battler.pokemon
|
||||
@criticalCapture = false
|
||||
numShakes = pbCaptureCalc(pkmn,battler,catch_rate,ball)
|
||||
PBDebug.log("[Threw Poké Ball] #{itemName}, #{numShakes} shakes (4=capture)")
|
||||
# Animation of Ball throw, absorb, shake and capture/burst out
|
||||
@scene.pbThrow(ball,numShakes,@criticalCapture,battler.index,showPlayer)
|
||||
# Outcome message
|
||||
case numShakes
|
||||
when 0
|
||||
pbDisplay(_INTL("Oh no! The Pokémon broke free!"))
|
||||
BallHandlers.onFailCatch(ball,self,battler)
|
||||
when 1
|
||||
pbDisplay(_INTL("Aww! It appeared to be caught!"))
|
||||
BallHandlers.onFailCatch(ball,self,battler)
|
||||
when 2
|
||||
pbDisplay(_INTL("Aargh! Almost had it!"))
|
||||
BallHandlers.onFailCatch(ball,self,battler)
|
||||
when 3
|
||||
pbDisplay(_INTL("Gah! It was so close, too!"))
|
||||
BallHandlers.onFailCatch(ball,self,battler)
|
||||
when 4
|
||||
pbDisplayBrief(_INTL("Gotcha! {1} was caught!",pkmn.name))
|
||||
@scene.pbThrowSuccess # Play capture success jingle
|
||||
pbRemoveFromParty(battler.index,battler.pokemonIndex)
|
||||
# Gain Exp
|
||||
if Settings::GAIN_EXP_FOR_CAPTURE
|
||||
battler.captured = true
|
||||
pbGainExp
|
||||
battler.captured = false
|
||||
end
|
||||
battler.pbReset
|
||||
if pbAllFainted?(battler.index)
|
||||
@decision = (trainerBattle?) ? 1 : 4 # Battle ended by win/capture
|
||||
end
|
||||
# Modify the Pokémon's properties because of the capture
|
||||
if GameData::Item.get(ball).is_snag_ball?
|
||||
pkmn.owner = Pokemon::Owner.new_from_trainer(pbPlayer)
|
||||
end
|
||||
BallHandlers.onCatch(ball,self,pkmn)
|
||||
pkmn.poke_ball = ball
|
||||
pkmn.makeUnmega if pkmn.mega?
|
||||
pkmn.makeUnprimal
|
||||
pkmn.update_shadow_moves if pkmn.shadowPokemon?
|
||||
pkmn.record_first_moves
|
||||
# Reset form
|
||||
pkmn.forced_form = nil if MultipleForms.hasFunction?(pkmn.species,"getForm")
|
||||
@peer.pbOnLeavingBattle(self,pkmn,true,true)
|
||||
# Make the Poké Ball and data box disappear
|
||||
@scene.pbHideCaptureBall(idxBattler)
|
||||
# Save the Pokémon for storage at the end of battle
|
||||
@caughtPokemon.push(pkmn)
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Calculate how many shakes a thrown Poké Ball will make (4 = capture)
|
||||
#=============================================================================
|
||||
def pbCaptureCalc(pkmn,battler,catch_rate,ball)
|
||||
return 4 if $DEBUG && Input.press?(Input::CTRL)
|
||||
# Get a catch rate if one wasn't provided
|
||||
catch_rate = pkmn.species_data.catch_rate if !catch_rate
|
||||
# Modify catch_rate depending on the Poké Ball's effect
|
||||
ultraBeast = [:NIHILEGO, :BUZZWOLE, :PHEROMOSA, :XURKITREE, :CELESTEELA,
|
||||
:KARTANA, :GUZZLORD, :POIPOLE, :NAGANADEL, :STAKATAKA,
|
||||
:BLACEPHALON].include?(pkmn.species)
|
||||
if !ultraBeast || ball == :BEASTBALL
|
||||
catch_rate = BallHandlers.modifyCatchRate(ball,catch_rate,self,battler,ultraBeast)
|
||||
else
|
||||
catch_rate /= 10
|
||||
end
|
||||
# First half of the shakes calculation
|
||||
a = battler.totalhp
|
||||
b = battler.hp
|
||||
x = ((3*a-2*b)*catch_rate.to_f)/(3*a)
|
||||
# Calculation modifiers
|
||||
if battler.status == :SLEEP || battler.status == :FROZEN
|
||||
x *= 2.5
|
||||
elsif battler.status != :NONE
|
||||
x *= 1.5
|
||||
end
|
||||
x = x.floor
|
||||
x = 1 if x<1
|
||||
# Definite capture, no need to perform randomness checks
|
||||
return 4 if x>=255 || BallHandlers.isUnconditional?(ball,self,battler)
|
||||
# Second half of the shakes calculation
|
||||
y = ( 65536 / ((255.0/x)**0.1875) ).floor
|
||||
# Critical capture check
|
||||
if Settings::ENABLE_CRITICAL_CAPTURES
|
||||
c = 0
|
||||
numOwned = $Trainer.pokedex.owned_count
|
||||
if numOwned>600; c = x*5/12
|
||||
elsif numOwned>450; c = x*4/12
|
||||
elsif numOwned>300; c = x*3/12
|
||||
elsif numOwned>150; c = x*2/12
|
||||
elsif numOwned>30; c = x/12
|
||||
end
|
||||
# Calculate the number of shakes
|
||||
if c>0 && pbRandom(256)<c
|
||||
@criticalCapture = true
|
||||
return 4 if pbRandom(65536)<y
|
||||
return 0
|
||||
end
|
||||
end
|
||||
# Calculate the number of shakes
|
||||
numShakes = 0
|
||||
for i in 0...4
|
||||
break if numShakes<i
|
||||
numShakes += 1 if pbRandom(65536)<y
|
||||
end
|
||||
return numShakes
|
||||
end
|
||||
end
|
||||
785
Data/Scripts/011_Battle/003_Battle/002_PokeBattle_Battle.rb
Normal file
785
Data/Scripts/011_Battle/003_Battle/002_PokeBattle_Battle.rb
Normal file
@@ -0,0 +1,785 @@
|
||||
# Results of battle:
|
||||
# 0 - Undecided or aborted
|
||||
# 1 - Player won
|
||||
# 2 - Player lost
|
||||
# 3 - Player or wild Pokémon ran from battle, or player forfeited the match
|
||||
# 4 - Wild Pokémon was caught
|
||||
# 5 - Draw
|
||||
# Possible actions a battler can take in a round:
|
||||
# :None
|
||||
# :UseMove
|
||||
# :SwitchOut
|
||||
# :UseItem
|
||||
# :Call
|
||||
# :Run
|
||||
# :Shift
|
||||
# NOTE: If you want to have more than 3 Pokémon on a side at once, you will need
|
||||
# to edit some code. Mainly this is to change/add coordinates for the
|
||||
# sprites, describe the relationships between Pokémon and trainers, and to
|
||||
# change messages. The methods that will need editing are as follows:
|
||||
# class PokeBattle_Battle
|
||||
# def setBattleMode
|
||||
# def pbGetOwnerIndexFromBattlerIndex
|
||||
# def pbGetOpposingIndicesInOrder
|
||||
# def nearBattlers?
|
||||
# def pbStartBattleSendOut
|
||||
# def pbEORShiftDistantBattlers
|
||||
# def pbCanShift?
|
||||
# def pbEndOfRoundPhase
|
||||
# class TargetMenuDisplay
|
||||
# def initialize
|
||||
# class PokemonDataBox
|
||||
# def initializeDataBoxGraphic
|
||||
# module PokeBattle_SceneConstants
|
||||
# def self.pbBattlerPosition
|
||||
# def self.pbTrainerPosition
|
||||
# class PokemonTemp
|
||||
# def recordBattleRule
|
||||
# (There is no guarantee that this list is complete.)
|
||||
|
||||
class PokeBattle_Battle
|
||||
attr_reader :scene # Scene object for this battle
|
||||
attr_reader :peer
|
||||
attr_reader :field # Effects common to the whole of a battle
|
||||
attr_reader :sides # Effects common to each side of a battle
|
||||
attr_reader :positions # Effects that apply to a battler position
|
||||
attr_reader :battlers # Currently active Pokémon
|
||||
attr_reader :sideSizes # Array of number of battlers per side
|
||||
attr_accessor :backdrop # Filename fragment used for background graphics
|
||||
attr_accessor :backdropBase # Filename fragment used for base graphics
|
||||
attr_accessor :time # Time of day (0=day, 1=eve, 2=night)
|
||||
attr_accessor :environment # Battle surroundings (for mechanics purposes)
|
||||
attr_reader :turnCount
|
||||
attr_accessor :decision # Decision: 0=undecided; 1=win; 2=loss; 3=escaped; 4=caught
|
||||
attr_reader :player # Player trainer (or array of trainers)
|
||||
attr_reader :opponent # Opponent trainer (or array of trainers)
|
||||
attr_accessor :items # Items held by opponents
|
||||
attr_accessor :endSpeeches
|
||||
attr_accessor :endSpeechesWin
|
||||
attr_accessor :party1starts # Array of start indexes for each player-side trainer's party
|
||||
attr_accessor :party2starts # Array of start indexes for each opponent-side trainer's party
|
||||
attr_accessor :internalBattle # Internal battle flag
|
||||
attr_accessor :debug # Debug flag
|
||||
attr_accessor :canRun # True if player can run from battle
|
||||
attr_accessor :canLose # True if player won't black out if they lose
|
||||
attr_accessor :switchStyle # Switch/Set "battle style" option
|
||||
attr_accessor :showAnims # "Battle Effects" option
|
||||
attr_accessor :controlPlayer # Whether player's Pokémon are AI controlled
|
||||
attr_accessor :expGain # Whether Pokémon can gain Exp/EVs
|
||||
attr_accessor :moneyGain # Whether the player can gain/lose money
|
||||
attr_accessor :rules
|
||||
attr_accessor :choices # Choices made by each Pokémon this round
|
||||
attr_accessor :megaEvolution # Battle index of each trainer's Pokémon to Mega Evolve
|
||||
attr_reader :initialItems
|
||||
attr_reader :recycleItems
|
||||
attr_reader :belch
|
||||
attr_reader :battleBond
|
||||
attr_reader :usedInBattle # Whether each Pokémon was used in battle (for Burmy)
|
||||
attr_reader :successStates # Success states
|
||||
attr_accessor :lastMoveUsed # Last move used
|
||||
attr_accessor :lastMoveUser # Last move user
|
||||
attr_reader :switching # True if during the switching phase of the round
|
||||
attr_reader :futureSight # True if Future Sight is hitting
|
||||
attr_reader :endOfRound # True during the end of round
|
||||
attr_accessor :moldBreaker # True if Mold Breaker applies
|
||||
attr_reader :struggle # The Struggle move
|
||||
|
||||
include PokeBattle_BattleCommon
|
||||
|
||||
def pbRandom(x); return rand(x); end
|
||||
|
||||
#=============================================================================
|
||||
# Creating the battle class
|
||||
#=============================================================================
|
||||
def initialize(scene,p1,p2,player,opponent)
|
||||
if p1.length==0
|
||||
raise ArgumentError.new(_INTL("Party 1 has no Pokémon."))
|
||||
elsif p2.length==0
|
||||
raise ArgumentError.new(_INTL("Party 2 has no Pokémon."))
|
||||
end
|
||||
@scene = scene
|
||||
@peer = PokeBattle_BattlePeer.create
|
||||
@battleAI = PokeBattle_AI.new(self)
|
||||
@field = PokeBattle_ActiveField.new # Whole field (gravity/rooms)
|
||||
@sides = [PokeBattle_ActiveSide.new, # Player's side
|
||||
PokeBattle_ActiveSide.new] # Foe's side
|
||||
@positions = [] # Battler positions
|
||||
@battlers = []
|
||||
@sideSizes = [1,1] # Single battle, 1v1
|
||||
@backdrop = ""
|
||||
@backdropBase = nil
|
||||
@time = 0
|
||||
@environment = :None # e.g. Tall grass, cave, still water
|
||||
@turnCount = 0
|
||||
@decision = 0
|
||||
@caughtPokemon = []
|
||||
player = [player] if !player.nil? && !player.is_a?(Array)
|
||||
opponent = [opponent] if !opponent.nil? && !opponent.is_a?(Array)
|
||||
@player = player # Array of Player/NPCTrainer objects, or nil
|
||||
@opponent = opponent # Array of NPCTrainer objects, or nil
|
||||
@items = nil
|
||||
@endSpeeches = []
|
||||
@endSpeechesWin = []
|
||||
@party1 = p1
|
||||
@party2 = p2
|
||||
@party1order = Array.new(@party1.length) { |i| i }
|
||||
@party2order = Array.new(@party2.length) { |i| i }
|
||||
@party1starts = [0]
|
||||
@party2starts = [0]
|
||||
@internalBattle = true
|
||||
@debug = false
|
||||
@canRun = true
|
||||
@canLose = false
|
||||
@switchStyle = true
|
||||
@showAnims = true
|
||||
@controlPlayer = false
|
||||
@expGain = true
|
||||
@moneyGain = true
|
||||
@rules = {}
|
||||
@priority = []
|
||||
@priorityTrickRoom = false
|
||||
@choices = []
|
||||
@megaEvolution = [
|
||||
[-1] * (@player ? @player.length : 1),
|
||||
[-1] * (@opponent ? @opponent.length : 1)
|
||||
]
|
||||
@initialItems = [
|
||||
Array.new(@party1.length) { |i| (@party1[i]) ? @party1[i].item_id : nil },
|
||||
Array.new(@party2.length) { |i| (@party2[i]) ? @party2[i].item_id : nil }
|
||||
]
|
||||
@recycleItems = [Array.new(@party1.length, nil), Array.new(@party2.length, nil)]
|
||||
@belch = [Array.new(@party1.length, false), Array.new(@party2.length, false)]
|
||||
@battleBond = [Array.new(@party1.length, false), Array.new(@party2.length, false)]
|
||||
@usedInBattle = [Array.new(@party1.length, false), Array.new(@party2.length, false)]
|
||||
@successStates = []
|
||||
@lastMoveUsed = nil
|
||||
@lastMoveUser = -1
|
||||
@switching = false
|
||||
@futureSight = false
|
||||
@endOfRound = false
|
||||
@moldBreaker = false
|
||||
@runCommand = 0
|
||||
@nextPickupUse = 0
|
||||
if GameData::Move.exists?(:STRUGGLE)
|
||||
@struggle = PokeBattle_Move.from_pokemon_move(self, Pokemon::Move.new(:STRUGGLE))
|
||||
else
|
||||
@struggle = PokeBattle_Struggle.new(self, nil)
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Information about the type and size of the battle
|
||||
#=============================================================================
|
||||
def wildBattle?; return @opponent.nil?; end
|
||||
def trainerBattle?; return !@opponent.nil?; end
|
||||
|
||||
# Sets the number of battler slots on each side of the field independently.
|
||||
# For "1v2" names, the first number is for the player's side and the second
|
||||
# number is for the opposing side.
|
||||
def setBattleMode(mode)
|
||||
@sideSizes =
|
||||
case mode
|
||||
when "triple", "3v3" then [3, 3]
|
||||
when "3v2" then [3, 2]
|
||||
when "3v1" then [3, 1]
|
||||
when "2v3" then [2, 3]
|
||||
when "double", "2v2" then [2, 2]
|
||||
when "2v1" then [2, 1]
|
||||
when "1v3" then [1, 3]
|
||||
when "1v2" then [1, 2]
|
||||
else [1, 1] # Single, 1v1 (default)
|
||||
end
|
||||
end
|
||||
|
||||
def singleBattle?
|
||||
return pbSideSize(0)==1 && pbSideSize(1)==1
|
||||
end
|
||||
|
||||
def pbSideSize(index)
|
||||
return @sideSizes[index%2]
|
||||
end
|
||||
|
||||
def maxBattlerIndex
|
||||
return (pbSideSize(0)>pbSideSize(1)) ? (pbSideSize(0)-1)*2 : pbSideSize(1)*2-1
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Trainers and owner-related methods
|
||||
#=============================================================================
|
||||
def pbPlayer; return @player[0]; end
|
||||
|
||||
# Given a battler index, returns the index within @player/@opponent of the
|
||||
# trainer that controls that battler index.
|
||||
# NOTE: You shouldn't ever have more trainers on a side than there are battler
|
||||
# positions on that side. This method doesn't account for if you do.
|
||||
def pbGetOwnerIndexFromBattlerIndex(idxBattler)
|
||||
trainer = (opposes?(idxBattler)) ? @opponent : @player
|
||||
return 0 if !trainer
|
||||
case trainer.length
|
||||
when 2
|
||||
n = pbSideSize(idxBattler%2)
|
||||
return [0,0,1][idxBattler/2] if n==3
|
||||
return idxBattler/2 # Same as [0,1][idxBattler/2], i.e. 2 battler slots
|
||||
when 3
|
||||
return idxBattler/2
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
def pbGetOwnerFromBattlerIndex(idxBattler)
|
||||
idxTrainer = pbGetOwnerIndexFromBattlerIndex(idxBattler)
|
||||
return (opposes?(idxBattler)) ? @opponent[idxTrainer] : @player[idxTrainer]
|
||||
end
|
||||
|
||||
def pbGetOwnerIndexFromPartyIndex(idxBattler,idxParty)
|
||||
ret = -1
|
||||
pbPartyStarts(idxBattler).each_with_index do |start,i|
|
||||
break if start>idxParty
|
||||
ret = i
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
# Only used for the purpose of an error message when one trainer tries to
|
||||
# switch another trainer's Pokémon.
|
||||
def pbGetOwnerFromPartyIndex(idxBattler,idxParty)
|
||||
idxTrainer = pbGetOwnerIndexFromPartyIndex(idxBattler,idxParty)
|
||||
return (opposes?(idxBattler)) ? @opponent[idxTrainer] : @player[idxTrainer]
|
||||
end
|
||||
|
||||
def pbGetOwnerName(idxBattler)
|
||||
idxTrainer = pbGetOwnerIndexFromBattlerIndex(idxBattler)
|
||||
return @opponent[idxTrainer].full_name if opposes?(idxBattler) # Opponent
|
||||
return @player[idxTrainer].full_name if idxTrainer>0 # Ally trainer
|
||||
return @player[idxTrainer].name # Player
|
||||
end
|
||||
|
||||
def pbGetOwnerItems(idxBattler)
|
||||
return [] if !@items || !opposes?(idxBattler)
|
||||
return @items[pbGetOwnerIndexFromBattlerIndex(idxBattler)]
|
||||
end
|
||||
|
||||
# Returns whether the battler in position idxBattler is owned by the same
|
||||
# trainer that owns the Pokémon in party slot idxParty. This assumes that
|
||||
# both the battler position and the party slot are from the same side.
|
||||
def pbIsOwner?(idxBattler,idxParty)
|
||||
idxTrainer1 = pbGetOwnerIndexFromBattlerIndex(idxBattler)
|
||||
idxTrainer2 = pbGetOwnerIndexFromPartyIndex(idxBattler,idxParty)
|
||||
return idxTrainer1==idxTrainer2
|
||||
end
|
||||
|
||||
def pbOwnedByPlayer?(idxBattler)
|
||||
return false if opposes?(idxBattler)
|
||||
return pbGetOwnerIndexFromBattlerIndex(idxBattler)==0
|
||||
end
|
||||
|
||||
# Returns the number of Pokémon positions controlled by the given trainerIndex
|
||||
# on the given side of battle.
|
||||
def pbNumPositions(side,idxTrainer)
|
||||
ret = 0
|
||||
for i in 0...pbSideSize(side)
|
||||
t = pbGetOwnerIndexFromBattlerIndex(i*2+side)
|
||||
next if t!=idxTrainer
|
||||
ret += 1
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Get party information (counts all teams on the same side)
|
||||
#=============================================================================
|
||||
def pbParty(idxBattler)
|
||||
return (opposes?(idxBattler)) ? @party2 : @party1
|
||||
end
|
||||
|
||||
def pbOpposingParty(idxBattler)
|
||||
return (opposes?(idxBattler)) ? @party1 : @party2
|
||||
end
|
||||
|
||||
def pbPartyOrder(idxBattler)
|
||||
return (opposes?(idxBattler)) ? @party2order : @party1order
|
||||
end
|
||||
|
||||
def pbPartyStarts(idxBattler)
|
||||
return (opposes?(idxBattler)) ? @party2starts : @party1starts
|
||||
end
|
||||
|
||||
# Returns the player's team in its display order. Used when showing the party
|
||||
# screen.
|
||||
def pbPlayerDisplayParty(idxBattler=0)
|
||||
partyOrders = pbPartyOrder(idxBattler)
|
||||
idxStart, _idxEnd = pbTeamIndexRangeFromBattlerIndex(idxBattler)
|
||||
ret = []
|
||||
eachInTeamFromBattlerIndex(idxBattler) { |pkmn,i| ret[partyOrders[i]-idxStart] = pkmn }
|
||||
return ret
|
||||
end
|
||||
|
||||
def pbAbleCount(idxBattler=0)
|
||||
party = pbParty(idxBattler)
|
||||
count = 0
|
||||
party.each { |pkmn| count += 1 if pkmn && pkmn.able? }
|
||||
return count
|
||||
end
|
||||
|
||||
def pbAbleNonActiveCount(idxBattler=0)
|
||||
party = pbParty(idxBattler)
|
||||
inBattleIndices = []
|
||||
eachSameSideBattler(idxBattler) { |b| inBattleIndices.push(b.pokemonIndex) }
|
||||
count = 0
|
||||
party.each_with_index do |pkmn,idxParty|
|
||||
next if !pkmn || !pkmn.able?
|
||||
next if inBattleIndices.include?(idxParty)
|
||||
count += 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
def pbAllFainted?(idxBattler=0)
|
||||
return pbAbleCount(idxBattler)==0
|
||||
end
|
||||
|
||||
# For the given side of the field (0=player's, 1=opponent's), returns an array
|
||||
# containing the number of able Pokémon in each team.
|
||||
def pbAbleTeamCounts(side)
|
||||
party = pbParty(side)
|
||||
partyStarts = pbPartyStarts(side)
|
||||
ret = []
|
||||
idxTeam = -1
|
||||
nextStart = 0
|
||||
party.each_with_index do |pkmn,i|
|
||||
if i>=nextStart
|
||||
idxTeam += 1
|
||||
nextStart = (idxTeam<partyStarts.length-1) ? partyStarts[idxTeam+1] : party.length
|
||||
end
|
||||
next if !pkmn || !pkmn.able?
|
||||
ret[idxTeam] = 0 if !ret[idxTeam]
|
||||
ret[idxTeam] += 1
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Get team information (a team is only the Pokémon owned by a particular
|
||||
# trainer)
|
||||
#=============================================================================
|
||||
def pbTeamIndexRangeFromBattlerIndex(idxBattler)
|
||||
partyStarts = pbPartyStarts(idxBattler)
|
||||
idxTrainer = pbGetOwnerIndexFromBattlerIndex(idxBattler)
|
||||
idxPartyStart = partyStarts[idxTrainer]
|
||||
idxPartyEnd = (idxTrainer<partyStarts.length-1) ? partyStarts[idxTrainer+1] : pbParty(idxBattler).length
|
||||
return idxPartyStart, idxPartyEnd
|
||||
end
|
||||
|
||||
def pbTeamLengthFromBattlerIndex(idxBattler)
|
||||
idxPartyStart, idxPartyEnd = pbTeamIndexRangeFromBattlerIndex(idxBattler)
|
||||
return idxPartyEnd-idxPartyStart
|
||||
end
|
||||
|
||||
def eachInTeamFromBattlerIndex(idxBattler)
|
||||
party = pbParty(idxBattler)
|
||||
idxPartyStart, idxPartyEnd = pbTeamIndexRangeFromBattlerIndex(idxBattler)
|
||||
party.each_with_index { |pkmn,i| yield pkmn,i if pkmn && i>=idxPartyStart && i<idxPartyEnd }
|
||||
end
|
||||
|
||||
def eachInTeam(side,idxTrainer)
|
||||
party = pbParty(side)
|
||||
partyStarts = pbPartyStarts(side)
|
||||
idxPartyStart = partyStarts[idxTrainer]
|
||||
idxPartyEnd = (idxTrainer<partyStarts.length-1) ? partyStarts[idxTrainer+1] : party.length
|
||||
party.each_with_index { |pkmn,i| yield pkmn,i if pkmn && i>=idxPartyStart && i<idxPartyEnd }
|
||||
end
|
||||
|
||||
# Used for Illusion.
|
||||
# NOTE: This cares about the temporary rearranged order of the team. That is,
|
||||
# if you do some switching, the last Pokémon in the team could change
|
||||
# and the Illusion could be a different Pokémon.
|
||||
def pbLastInTeam(idxBattler)
|
||||
party = pbParty(idxBattler)
|
||||
partyOrders = pbPartyOrder(idxBattler)
|
||||
idxPartyStart, idxPartyEnd = pbTeamIndexRangeFromBattlerIndex(idxBattler)
|
||||
ret = -1
|
||||
party.each_with_index do |pkmn,i|
|
||||
next if i<idxPartyStart || i>=idxPartyEnd # Check the team only
|
||||
next if !pkmn || !pkmn.able? # Can't copy a non-fainted Pokémon or egg
|
||||
ret = i if partyOrders[i]>partyOrders[ret]
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
# Used to calculate money gained/lost after winning/losing a battle.
|
||||
def pbMaxLevelInTeam(side,idxTrainer)
|
||||
ret = 1
|
||||
eachInTeam(side,idxTrainer) do |pkmn,_i|
|
||||
ret = pkmn.level if pkmn.level>ret
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Iterate through battlers
|
||||
#=============================================================================
|
||||
def eachBattler
|
||||
@battlers.each { |b| yield b if b && !b.fainted? }
|
||||
end
|
||||
|
||||
def eachSameSideBattler(idxBattler=0)
|
||||
idxBattler = idxBattler.index if idxBattler.respond_to?("index")
|
||||
@battlers.each { |b| yield b if b && !b.fainted? && !b.opposes?(idxBattler) }
|
||||
end
|
||||
|
||||
def eachOtherSideBattler(idxBattler=0)
|
||||
idxBattler = idxBattler.index if idxBattler.respond_to?("index")
|
||||
@battlers.each { |b| yield b if b && !b.fainted? && b.opposes?(idxBattler) }
|
||||
end
|
||||
|
||||
def pbSideBattlerCount(idxBattler=0)
|
||||
ret = 0
|
||||
eachSameSideBattler(idxBattler) { |_b| ret += 1 }
|
||||
return ret
|
||||
end
|
||||
|
||||
def pbOpposingBattlerCount(idxBattler=0)
|
||||
ret = 0
|
||||
eachOtherSideBattler(idxBattler) { |_b| ret += 1 }
|
||||
return ret
|
||||
end
|
||||
|
||||
# This method only counts the player's Pokémon, not a partner trainer's.
|
||||
def pbPlayerBattlerCount
|
||||
ret = 0
|
||||
eachSameSideBattler { |b| ret += 1 if b.pbOwnedByPlayer? }
|
||||
return ret
|
||||
end
|
||||
|
||||
def pbCheckGlobalAbility(abil)
|
||||
eachBattler { |b| return b if b.hasActiveAbility?(abil) }
|
||||
return nil
|
||||
end
|
||||
|
||||
def pbCheckOpposingAbility(abil,idxBattler=0,nearOnly=false)
|
||||
eachOtherSideBattler(idxBattler) do |b|
|
||||
next if nearOnly && !b.near?(idxBattler)
|
||||
return b if b.hasActiveAbility?(abil)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
# Given a battler index, and using battle side sizes, returns an array of
|
||||
# battler indices from the opposing side that are in order of most "opposite".
|
||||
# Used when choosing a target and pressing up/down to move the cursor to the
|
||||
# opposite side, and also when deciding which target to select first for some
|
||||
# moves.
|
||||
def pbGetOpposingIndicesInOrder(idxBattler)
|
||||
case pbSideSize(0)
|
||||
when 1
|
||||
case pbSideSize(1)
|
||||
when 1 # 1v1 single
|
||||
return [0] if opposes?(idxBattler)
|
||||
return [1]
|
||||
when 2 # 1v2
|
||||
return [0] if opposes?(idxBattler)
|
||||
return [3,1]
|
||||
when 3 # 1v3
|
||||
return [0] if opposes?(idxBattler)
|
||||
return [3,5,1]
|
||||
end
|
||||
when 2
|
||||
case pbSideSize(1)
|
||||
when 1 # 2v1
|
||||
return [0,2] if opposes?(idxBattler)
|
||||
return [1]
|
||||
when 2 # 2v2 double
|
||||
return [[3,1],[2,0],[1,3],[0,2]][idxBattler]
|
||||
when 3 # 2v3
|
||||
return [[5,3,1],[2,0],[3,1,5]][idxBattler] if idxBattler<3
|
||||
return [0,2]
|
||||
end
|
||||
when 3
|
||||
case pbSideSize(1)
|
||||
when 1 # 3v1
|
||||
return [2,0,4] if opposes?(idxBattler)
|
||||
return [1]
|
||||
when 2 # 3v2
|
||||
return [[3,1],[2,4,0],[3,1],[2,0,4],[1,3]][idxBattler]
|
||||
when 3 # 3v3 triple
|
||||
return [[5,3,1],[4,2,0],[3,5,1],[2,0,4],[1,3,5],[0,2,4]][idxBattler]
|
||||
end
|
||||
end
|
||||
return [idxBattler]
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Comparing the positions of two battlers
|
||||
#=============================================================================
|
||||
def opposes?(idxBattler1,idxBattler2=0)
|
||||
idxBattler1 = idxBattler1.index if idxBattler1.respond_to?("index")
|
||||
idxBattler2 = idxBattler2.index if idxBattler2.respond_to?("index")
|
||||
return (idxBattler1&1)!=(idxBattler2&1)
|
||||
end
|
||||
|
||||
def nearBattlers?(idxBattler1,idxBattler2)
|
||||
return false if idxBattler1==idxBattler2
|
||||
return true if pbSideSize(0)<=2 && pbSideSize(1)<=2
|
||||
# Get all pairs of battler positions that are not close to each other
|
||||
pairsArray = [[0,4],[1,5]] # Covers 3v1 and 1v3
|
||||
case pbSideSize(0)
|
||||
when 3
|
||||
case pbSideSize(1)
|
||||
when 3 # 3v3 (triple)
|
||||
pairsArray.push([0,1])
|
||||
pairsArray.push([4,5])
|
||||
when 2 # 3v2
|
||||
pairsArray.push([0,1])
|
||||
pairsArray.push([3,4])
|
||||
end
|
||||
when 2 # 2v3
|
||||
pairsArray.push([0,1])
|
||||
pairsArray.push([2,5])
|
||||
end
|
||||
# See if any pair matches the two battlers being assessed
|
||||
pairsArray.each do |pair|
|
||||
return false if pair.include?(idxBattler1) && pair.include?(idxBattler2)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Altering a party or rearranging battlers
|
||||
#=============================================================================
|
||||
def pbRemoveFromParty(idxBattler,idxParty)
|
||||
party = pbParty(idxBattler)
|
||||
# Erase the Pokémon from the party
|
||||
party[idxParty] = nil
|
||||
# Rearrange the display order of the team to place the erased Pokémon last
|
||||
# in it (to avoid gaps)
|
||||
partyOrders = pbPartyOrder(idxBattler)
|
||||
partyStarts = pbPartyStarts(idxBattler)
|
||||
idxTrainer = pbGetOwnerIndexFromPartyIndex(idxBattler,idxParty)
|
||||
idxPartyStart = partyStarts[idxTrainer]
|
||||
idxPartyEnd = (idxTrainer<partyStarts.length-1) ? partyStarts[idxTrainer+1] : party.length
|
||||
origPartyPos = partyOrders[idxParty] # Position of erased Pokémon initially
|
||||
partyOrders[idxParty] = idxPartyEnd # Put erased Pokémon last in the team
|
||||
party.each_with_index do |_pkmn,i|
|
||||
next if i<idxPartyStart || i>=idxPartyEnd # Only check the team
|
||||
next if partyOrders[i]<origPartyPos # Appeared before erased Pokémon
|
||||
partyOrders[i] -= 1 # Appeared after erased Pokémon; bump it up by 1
|
||||
end
|
||||
end
|
||||
|
||||
def pbSwapBattlers(idxA,idxB)
|
||||
return false if !@battlers[idxA] || !@battlers[idxB]
|
||||
# Can't swap if battlers aren't owned by the same trainer
|
||||
return false if opposes?(idxA,idxB)
|
||||
return false if pbGetOwnerIndexFromBattlerIndex(idxA)!=pbGetOwnerIndexFromBattlerIndex(idxB)
|
||||
@battlers[idxA], @battlers[idxB] = @battlers[idxB], @battlers[idxA]
|
||||
@battlers[idxA].index, @battlers[idxB].index = @battlers[idxB].index, @battlers[idxA].index
|
||||
@choices[idxA], @choices[idxB] = @choices[idxB], @choices[idxA]
|
||||
@scene.pbSwapBattlerSprites(idxA,idxB)
|
||||
# Swap the target of any battlers' effects that point at either of the
|
||||
# swapped battlers, to ensure they still point at the correct target
|
||||
# NOTE: LeechSeed is not swapped, because drained HP goes to whichever
|
||||
# Pokémon is in the position that Leech Seed was used from.
|
||||
# NOTE: PerishSongUser doesn't need to change, as it's only used to
|
||||
# determine which side the Perish Song user was on, and a battler
|
||||
# can't change sides.
|
||||
effectsToSwap = [PBEffects::Attract,
|
||||
PBEffects::BideTarget,
|
||||
PBEffects::CounterTarget,
|
||||
PBEffects::LockOnPos,
|
||||
PBEffects::MeanLook,
|
||||
PBEffects::MirrorCoatTarget,
|
||||
PBEffects::SkyDrop,
|
||||
PBEffects::TrappingUser]
|
||||
eachBattler do |b|
|
||||
for i in effectsToSwap
|
||||
next if b.effects[i]!=idxA && b.effects[i]!=idxB
|
||||
b.effects[i] = (b.effects[i]==idxA) ? idxB : idxA
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#
|
||||
#=============================================================================
|
||||
# Returns the battler representing the Pokémon at index idxParty in its party,
|
||||
# on the same side as a battler with battler index of idxBattlerOther.
|
||||
def pbFindBattler(idxParty,idxBattlerOther=0)
|
||||
eachSameSideBattler(idxBattlerOther) { |b| return b if b.pokemonIndex==idxParty }
|
||||
return nil
|
||||
end
|
||||
|
||||
# Only used for Wish, as the Wishing Pokémon will no longer be in battle.
|
||||
def pbThisEx(idxBattler,idxParty)
|
||||
party = pbParty(idxBattler)
|
||||
if opposes?(idxBattler)
|
||||
return _INTL("The opposing {1}",party[idxParty].name) if trainerBattle?
|
||||
return _INTL("The wild {1}",party[idxParty].name)
|
||||
end
|
||||
return _INTL("The ally {1}",party[idxParty].name) if !pbOwnedByPlayer?(idxBattler)
|
||||
return party[idxParty].name
|
||||
end
|
||||
|
||||
def pbSetSeen(battler)
|
||||
return if !battler || !@internalBattle
|
||||
pbPlayer.pokedex.register(battler.displaySpecies,battler.displayGender,battler.displayForm)
|
||||
end
|
||||
|
||||
def nextPickupUse
|
||||
@nextPickupUse += 1
|
||||
return @nextPickupUse
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Weather and terrain
|
||||
#=============================================================================
|
||||
def defaultWeather=(value)
|
||||
@field.defaultWeather = value
|
||||
@field.weather = value
|
||||
@field.weatherDuration = -1
|
||||
end
|
||||
|
||||
# Returns the effective weather (note that weather effects can be negated)
|
||||
def pbWeather
|
||||
eachBattler { |b| return :None if b.hasActiveAbility?([:CLOUDNINE, :AIRLOCK]) }
|
||||
return @field.weather
|
||||
end
|
||||
|
||||
# Used for causing weather by a move or by an ability.
|
||||
def pbStartWeather(user,newWeather,fixedDuration=false,showAnim=true)
|
||||
return if @field.weather==newWeather
|
||||
@field.weather = newWeather
|
||||
duration = (fixedDuration) ? 5 : -1
|
||||
if duration>0 && user && user.itemActive?
|
||||
duration = BattleHandlers.triggerWeatherExtenderItem(user.item,
|
||||
@field.weather,duration,user,self)
|
||||
end
|
||||
@field.weatherDuration = duration
|
||||
weather_data = GameData::BattleWeather.try_get(@field.weather)
|
||||
pbCommonAnimation(weather_data.animation) if showAnim && weather_data
|
||||
pbHideAbilitySplash(user) if user
|
||||
case @field.weather
|
||||
when :Sun then pbDisplay(_INTL("The sunlight turned harsh!"))
|
||||
when :Rain then pbDisplay(_INTL("It started to rain!"))
|
||||
when :Sandstorm then pbDisplay(_INTL("A sandstorm brewed!"))
|
||||
when :Hail then pbDisplay(_INTL("It started to hail!"))
|
||||
when :HarshSun then pbDisplay(_INTL("The sunlight turned extremely harsh!"))
|
||||
when :HeavyRain then pbDisplay(_INTL("A heavy rain began to fall!"))
|
||||
when :StrongWinds then pbDisplay(_INTL("Mysterious strong winds are protecting Flying-type Pokémon!"))
|
||||
when :ShadowSky then pbDisplay(_INTL("A shadow sky appeared!"))
|
||||
end
|
||||
# Check for end of primordial weather, and weather-triggered form changes
|
||||
eachBattler { |b| b.pbCheckFormOnWeatherChange }
|
||||
pbEndPrimordialWeather
|
||||
end
|
||||
|
||||
def pbEndPrimordialWeather
|
||||
oldWeather = @field.weather
|
||||
# End Primordial Sea, Desolate Land, Delta Stream
|
||||
case @field.weather
|
||||
when :HarshSun
|
||||
if !pbCheckGlobalAbility(:DESOLATELAND)
|
||||
@field.weather = :None
|
||||
pbDisplay("The harsh sunlight faded!")
|
||||
end
|
||||
when :HeavyRain
|
||||
if !pbCheckGlobalAbility(:PRIMORDIALSEA)
|
||||
@field.weather = :None
|
||||
pbDisplay("The heavy rain has lifted!")
|
||||
end
|
||||
when :StrongWinds
|
||||
if !pbCheckGlobalAbility(:DELTASTREAM)
|
||||
@field.weather = :None
|
||||
pbDisplay("The mysterious air current has dissipated!")
|
||||
end
|
||||
end
|
||||
if @field.weather!=oldWeather
|
||||
# Check for form changes caused by the weather changing
|
||||
eachBattler { |b| b.pbCheckFormOnWeatherChange }
|
||||
# Start up the default weather
|
||||
pbStartWeather(nil,@field.defaultWeather) if @field.defaultWeather != :None
|
||||
end
|
||||
end
|
||||
|
||||
def defaultTerrain=(value)
|
||||
@field.defaultTerrain = value
|
||||
@field.terrain = value
|
||||
@field.terrainDuration = -1
|
||||
end
|
||||
|
||||
def pbStartTerrain(user,newTerrain,fixedDuration=true)
|
||||
return if @field.terrain==newTerrain
|
||||
@field.terrain = newTerrain
|
||||
duration = (fixedDuration) ? 5 : -1
|
||||
if duration>0 && user && user.itemActive?
|
||||
duration = BattleHandlers.triggerTerrainExtenderItem(user.item,
|
||||
newTerrain,duration,user,self)
|
||||
end
|
||||
@field.terrainDuration = duration
|
||||
terrain_data = GameData::BattleTerrain.try_get(@field.terrain)
|
||||
pbCommonAnimation(terrain_data.animation) if terrain_data
|
||||
pbHideAbilitySplash(user) if user
|
||||
case @field.terrain
|
||||
when :Electric
|
||||
pbDisplay(_INTL("An electric current runs across the battlefield!"))
|
||||
when :Grassy
|
||||
pbDisplay(_INTL("Grass grew to cover the battlefield!"))
|
||||
when :Misty
|
||||
pbDisplay(_INTL("Mist swirled about the battlefield!"))
|
||||
when :Psychic
|
||||
pbDisplay(_INTL("The battlefield got weird!"))
|
||||
end
|
||||
# Check for terrain seeds that boost stats in a terrain
|
||||
eachBattler { |b| b.pbItemTerrainStatBoostCheck }
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Messages and animations
|
||||
#=============================================================================
|
||||
def pbDisplay(msg,&block)
|
||||
@scene.pbDisplayMessage(msg,&block)
|
||||
end
|
||||
|
||||
def pbDisplayBrief(msg)
|
||||
@scene.pbDisplayMessage(msg,true)
|
||||
end
|
||||
|
||||
def pbDisplayPaused(msg,&block)
|
||||
@scene.pbDisplayPausedMessage(msg,&block)
|
||||
end
|
||||
|
||||
def pbDisplayConfirm(msg)
|
||||
return @scene.pbDisplayConfirmMessage(msg)
|
||||
end
|
||||
|
||||
def pbShowCommands(msg,commands,canCancel=true)
|
||||
@scene.pbShowCommands(msg,commands,canCancel)
|
||||
end
|
||||
|
||||
def pbAnimation(move,user,targets,hitNum=0)
|
||||
@scene.pbAnimation(move,user,targets,hitNum) if @showAnims
|
||||
end
|
||||
|
||||
def pbCommonAnimation(name,user=nil,targets=nil)
|
||||
@scene.pbCommonAnimation(name,user,targets) if @showAnims
|
||||
end
|
||||
|
||||
def pbShowAbilitySplash(battler,delay=false,logTrigger=true)
|
||||
PBDebug.log("[Ability triggered] #{battler.pbThis}'s #{battler.abilityName}") if logTrigger
|
||||
return if !PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@scene.pbShowAbilitySplash(battler)
|
||||
if delay
|
||||
Graphics.frame_rate.times { @scene.pbUpdate } # 1 second
|
||||
end
|
||||
end
|
||||
|
||||
def pbHideAbilitySplash(battler)
|
||||
return if !PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@scene.pbHideAbilitySplash(battler)
|
||||
end
|
||||
|
||||
def pbReplaceAbilitySplash(battler)
|
||||
return if !PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
@scene.pbReplaceAbilitySplash(battler)
|
||||
end
|
||||
end
|
||||
539
Data/Scripts/011_Battle/003_Battle/003_Battle_StartAndEnd.rb
Normal file
539
Data/Scripts/011_Battle/003_Battle/003_Battle_StartAndEnd.rb
Normal file
@@ -0,0 +1,539 @@
|
||||
class PokeBattle_Battle
|
||||
class BattleAbortedException < Exception; end
|
||||
|
||||
def pbAbort
|
||||
raise BattleAbortedException.new("Battle aborted")
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Makes sure all Pokémon exist that need to. Alter the type of battle if
|
||||
# necessary. Will never try to create battler positions, only delete them
|
||||
# (except for wild Pokémon whose number of positions are fixed). Reduces the
|
||||
# size of each side by 1 and tries again. If the side sizes are uneven, only
|
||||
# the larger side's size will be reduced by 1 each time, until both sides are
|
||||
# an equal size (then both sides will be reduced equally).
|
||||
#=============================================================================
|
||||
def pbEnsureParticipants
|
||||
# Prevent battles larger than 2v2 if both sides have multiple trainers
|
||||
# NOTE: This is necessary to ensure that battlers can never become unable to
|
||||
# hit each other due to being too far away. In such situations,
|
||||
# battlers will move to the centre position at the end of a round, but
|
||||
# because they cannot move into a position owned by a different
|
||||
# trainer, it's possible that battlers will be unable to move close
|
||||
# enough to hit each other if there are multiple trainers on each
|
||||
# side.
|
||||
if trainerBattle? && (@sideSizes[0]>2 || @sideSizes[1]>2) &&
|
||||
@player.length>1 && @opponent.length>1
|
||||
raise _INTL("Can't have battles larger than 2v2 where both sides have multiple trainers")
|
||||
end
|
||||
# Find out how many Pokémon each trainer has
|
||||
side1counts = pbAbleTeamCounts(0)
|
||||
side2counts = pbAbleTeamCounts(1)
|
||||
# Change the size of the battle depending on how many wild Pokémon there are
|
||||
if wildBattle? && side2counts[0]!=@sideSizes[1]
|
||||
if @sideSizes[0]==@sideSizes[1]
|
||||
# Even number of battlers per side, change both equally
|
||||
@sideSizes = [side2counts[0],side2counts[0]]
|
||||
else
|
||||
# Uneven number of battlers per side, just change wild side's size
|
||||
@sideSizes[1] = side2counts[0]
|
||||
end
|
||||
end
|
||||
# Check if battle is possible, including changing the number of battlers per
|
||||
# side if necessary
|
||||
loop do
|
||||
needsChanging = false
|
||||
for side in 0...2 # Each side in turn
|
||||
next if side==1 && wildBattle? # Wild side's size already checked above
|
||||
sideCounts = (side==0) ? side1counts : side2counts
|
||||
requireds = []
|
||||
# Find out how many Pokémon each trainer on side needs to have
|
||||
for i in 0...@sideSizes[side]
|
||||
idxTrainer = pbGetOwnerIndexFromBattlerIndex(i*2+side)
|
||||
requireds[idxTrainer] = 0 if requireds[idxTrainer].nil?
|
||||
requireds[idxTrainer] += 1
|
||||
end
|
||||
# Compare the have values with the need values
|
||||
if requireds.length>sideCounts.length
|
||||
raise _INTL("Error: def pbGetOwnerIndexFromBattlerIndex gives invalid owner index ({1} for battle type {2}v{3}, trainers {4}v{5})",
|
||||
requireds.length-1,@sideSizes[0],@sideSizes[1],side1counts.length,side2counts.length)
|
||||
end
|
||||
sideCounts.each_with_index do |_count,i|
|
||||
if !requireds[i] || requireds[i]==0
|
||||
raise _INTL("Player-side trainer {1} has no battler position for their Pokémon to go (trying {2}v{3} battle)",
|
||||
i+1,@sideSizes[0],@sideSizes[1]) if side==0
|
||||
raise _INTL("Opposing trainer {1} has no battler position for their Pokémon to go (trying {2}v{3} battle)",
|
||||
i+1,@sideSizes[0],@sideSizes[1]) if side==1
|
||||
end
|
||||
next if requireds[i]<=sideCounts[i] # Trainer has enough Pokémon to fill their positions
|
||||
if requireds[i]==1
|
||||
raise _INTL("Player-side trainer {1} has no able Pokémon",i+1) if side==0
|
||||
raise _INTL("Opposing trainer {1} has no able Pokémon",i+1) if side==1
|
||||
end
|
||||
# Not enough Pokémon, try lowering the number of battler positions
|
||||
needsChanging = true
|
||||
break
|
||||
end
|
||||
break if needsChanging
|
||||
end
|
||||
break if !needsChanging
|
||||
# Reduce one or both side's sizes by 1 and try again
|
||||
if wildBattle?
|
||||
PBDebug.log("#{@sideSizes[0]}v#{@sideSizes[1]} battle isn't possible " +
|
||||
"(#{side1counts} player-side teams versus #{side2counts[0]} wild Pokémon)")
|
||||
newSize = @sideSizes[0]-1
|
||||
else
|
||||
PBDebug.log("#{@sideSizes[0]}v#{@sideSizes[1]} battle isn't possible " +
|
||||
"(#{side1counts} player-side teams versus #{side2counts} opposing teams)")
|
||||
newSize = @sideSizes.max-1
|
||||
end
|
||||
if newSize==0
|
||||
raise _INTL("Couldn't lower either side's size any further, battle isn't possible")
|
||||
end
|
||||
for side in 0...2
|
||||
next if side==1 && wildBattle? # Wild Pokémon's side size is fixed
|
||||
next if @sideSizes[side]==1 || newSize>@sideSizes[side]
|
||||
@sideSizes[side] = newSize
|
||||
end
|
||||
PBDebug.log("Trying #{@sideSizes[0]}v#{@sideSizes[1]} battle instead")
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Set up all battlers
|
||||
#=============================================================================
|
||||
def pbCreateBattler(idxBattler,pkmn,idxParty)
|
||||
if !@battlers[idxBattler].nil?
|
||||
raise _INTL("Battler index {1} already exists",idxBattler)
|
||||
end
|
||||
@battlers[idxBattler] = PokeBattle_Battler.new(self,idxBattler)
|
||||
@positions[idxBattler] = PokeBattle_ActivePosition.new
|
||||
pbClearChoice(idxBattler)
|
||||
@successStates[idxBattler] = PokeBattle_SuccessState.new
|
||||
@battlers[idxBattler].pbInitialize(pkmn,idxParty)
|
||||
end
|
||||
|
||||
def pbSetUpSides
|
||||
ret = [[],[]]
|
||||
for side in 0...2
|
||||
# Set up wild Pokémon
|
||||
if side==1 && wildBattle?
|
||||
pbParty(1).each_with_index do |pkmn,idxPkmn|
|
||||
pbCreateBattler(2*idxPkmn+side,pkmn,idxPkmn)
|
||||
# Changes the Pokémon's form upon entering battle (if it should)
|
||||
@peer.pbOnEnteringBattle(self,pkmn,true)
|
||||
pbSetSeen(@battlers[2*idxPkmn+side])
|
||||
@usedInBattle[side][idxPkmn] = true
|
||||
end
|
||||
next
|
||||
end
|
||||
# Set up player's Pokémon and trainers' Pokémon
|
||||
trainer = (side==0) ? @player : @opponent
|
||||
requireds = []
|
||||
# Find out how many Pokémon each trainer on side needs to have
|
||||
for i in 0...@sideSizes[side]
|
||||
idxTrainer = pbGetOwnerIndexFromBattlerIndex(i*2+side)
|
||||
requireds[idxTrainer] = 0 if requireds[idxTrainer].nil?
|
||||
requireds[idxTrainer] += 1
|
||||
end
|
||||
# For each trainer in turn, find the needed number of Pokémon for them to
|
||||
# send out, and initialize them
|
||||
battlerNumber = 0
|
||||
trainer.each_with_index do |_t,idxTrainer|
|
||||
ret[side][idxTrainer] = []
|
||||
eachInTeam(side,idxTrainer) do |pkmn,idxPkmn|
|
||||
next if !pkmn.able?
|
||||
idxBattler = 2*battlerNumber+side
|
||||
pbCreateBattler(idxBattler,pkmn,idxPkmn)
|
||||
ret[side][idxTrainer].push(idxBattler)
|
||||
battlerNumber += 1
|
||||
break if ret[side][idxTrainer].length>=requireds[idxTrainer]
|
||||
end
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Send out all battlers at the start of battle
|
||||
#=============================================================================
|
||||
def pbStartBattleSendOut(sendOuts)
|
||||
# "Want to battle" messages
|
||||
if wildBattle?
|
||||
foeParty = pbParty(1)
|
||||
case foeParty.length
|
||||
when 1
|
||||
pbDisplayPaused(_INTL("Oh! A wild {1} appeared!",foeParty[0].name))
|
||||
when 2
|
||||
pbDisplayPaused(_INTL("Oh! A wild {1} and {2} appeared!",foeParty[0].name,
|
||||
foeParty[1].name))
|
||||
when 3
|
||||
pbDisplayPaused(_INTL("Oh! A wild {1}, {2} and {3} appeared!",foeParty[0].name,
|
||||
foeParty[1].name,foeParty[2].name))
|
||||
end
|
||||
else # Trainer battle
|
||||
case @opponent.length
|
||||
when 1
|
||||
pbDisplayPaused(_INTL("You are challenged by {1}!",@opponent[0].full_name))
|
||||
when 2
|
||||
pbDisplayPaused(_INTL("You are challenged by {1} and {2}!",@opponent[0].full_name,
|
||||
@opponent[1].full_name))
|
||||
when 3
|
||||
pbDisplayPaused(_INTL("You are challenged by {1}, {2} and {3}!",
|
||||
@opponent[0].full_name,@opponent[1].full_name,@opponent[2].full_name))
|
||||
end
|
||||
end
|
||||
# Send out Pokémon (opposing trainers first)
|
||||
for side in [1,0]
|
||||
next if side==1 && wildBattle?
|
||||
msg = ""
|
||||
toSendOut = []
|
||||
trainers = (side==0) ? @player : @opponent
|
||||
# Opposing trainers and partner trainers's messages about sending out Pokémon
|
||||
trainers.each_with_index do |t,i|
|
||||
next if side==0 && i==0 # The player's message is shown last
|
||||
msg += "\r\n" if msg.length>0
|
||||
sent = sendOuts[side][i]
|
||||
case sent.length
|
||||
when 1
|
||||
msg += _INTL("{1} sent out {2}!",t.full_name,@battlers[sent[0]].name)
|
||||
when 2
|
||||
msg += _INTL("{1} sent out {2} and {3}!",t.full_name,
|
||||
@battlers[sent[0]].name,@battlers[sent[1]].name)
|
||||
when 3
|
||||
msg += _INTL("{1} sent out {2}, {3} and {4}!",t.full_name,
|
||||
@battlers[sent[0]].name,@battlers[sent[1]].name,@battlers[sent[2]].name)
|
||||
end
|
||||
toSendOut.concat(sent)
|
||||
end
|
||||
# The player's message about sending out Pokémon
|
||||
if side==0
|
||||
msg += "\r\n" if msg.length>0
|
||||
sent = sendOuts[side][0]
|
||||
case sent.length
|
||||
when 1
|
||||
msg += _INTL("Go! {1}!",@battlers[sent[0]].name)
|
||||
when 2
|
||||
msg += _INTL("Go! {1} and {2}!",@battlers[sent[0]].name,@battlers[sent[1]].name)
|
||||
when 3
|
||||
msg += _INTL("Go! {1}, {2} and {3}!",@battlers[sent[0]].name,
|
||||
@battlers[sent[1]].name,@battlers[sent[2]].name)
|
||||
end
|
||||
toSendOut.concat(sent)
|
||||
end
|
||||
pbDisplayBrief(msg) if msg.length>0
|
||||
# The actual sending out of Pokémon
|
||||
animSendOuts = []
|
||||
toSendOut.each do |idxBattler|
|
||||
animSendOuts.push([idxBattler,@battlers[idxBattler].pokemon])
|
||||
end
|
||||
pbSendOut(animSendOuts,true)
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Start a battle
|
||||
#=============================================================================
|
||||
def pbStartBattle
|
||||
PBDebug.log("")
|
||||
PBDebug.log("******************************************")
|
||||
logMsg = "[Started battle] "
|
||||
if @sideSizes[0]==1 && @sideSizes[1]==1
|
||||
logMsg += "Single "
|
||||
elsif @sideSizes[0]==2 && @sideSizes[1]==2
|
||||
logMsg += "Double "
|
||||
elsif @sideSizes[0]==3 && @sideSizes[1]==3
|
||||
logMsg += "Triple "
|
||||
else
|
||||
logMsg += "#{@sideSizes[0]}v#{@sideSizes[1]} "
|
||||
end
|
||||
logMsg += "wild " if wildBattle?
|
||||
logMsg += "trainer " if trainerBattle?
|
||||
logMsg += "battle (#{@player.length} trainer(s) vs. "
|
||||
logMsg += "#{pbParty(1).length} wild Pokémon)" if wildBattle?
|
||||
logMsg += "#{@opponent.length} trainer(s))" if trainerBattle?
|
||||
PBDebug.log(logMsg)
|
||||
pbEnsureParticipants
|
||||
begin
|
||||
pbStartBattleCore
|
||||
rescue BattleAbortedException
|
||||
@decision = 0
|
||||
@scene.pbEndBattle(@decision)
|
||||
end
|
||||
return @decision
|
||||
end
|
||||
|
||||
def pbStartBattleCore
|
||||
# Set up the battlers on each side
|
||||
sendOuts = pbSetUpSides
|
||||
# Create all the sprites and play the battle intro animation
|
||||
@scene.pbStartBattle(self)
|
||||
# Show trainers on both sides sending out Pokémon
|
||||
pbStartBattleSendOut(sendOuts)
|
||||
# Weather announcement
|
||||
weather_data = GameData::BattleWeather.try_get(@field.weather)
|
||||
pbCommonAnimation(weather_data.animation) if weather_data
|
||||
case @field.weather
|
||||
when :Sun then pbDisplay(_INTL("The sunlight is strong."))
|
||||
when :Rain then pbDisplay(_INTL("It is raining."))
|
||||
when :Sandstorm then pbDisplay(_INTL("A sandstorm is raging."))
|
||||
when :Hail then pbDisplay(_INTL("Hail is falling."))
|
||||
when :HarshSun then pbDisplay(_INTL("The sunlight is extremely harsh."))
|
||||
when :HeavyRain then pbDisplay(_INTL("It is raining heavily."))
|
||||
when :StrongWinds then pbDisplay(_INTL("The wind is strong."))
|
||||
when :ShadowSky then pbDisplay(_INTL("The sky is shadowy."))
|
||||
end
|
||||
# Terrain announcement
|
||||
terrain_data = GameData::BattleTerrain.try_get(@field.terrain)
|
||||
pbCommonAnimation(terrain_data.animation) if terrain_data
|
||||
case @field.terrain
|
||||
when :Electric
|
||||
pbDisplay(_INTL("An electric current runs across the battlefield!"))
|
||||
when :Grassy
|
||||
pbDisplay(_INTL("Grass is covering the battlefield!"))
|
||||
when :Misty
|
||||
pbDisplay(_INTL("Mist swirls about the battlefield!"))
|
||||
when :Psychic
|
||||
pbDisplay(_INTL("The battlefield is weird!"))
|
||||
end
|
||||
# Abilities upon entering battle
|
||||
pbOnActiveAll
|
||||
# Main battle loop
|
||||
pbBattleLoop
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Main battle loop
|
||||
#=============================================================================
|
||||
def pbBattleLoop
|
||||
@turnCount = 0
|
||||
loop do # Now begin the battle loop
|
||||
PBDebug.log("")
|
||||
PBDebug.log("***Round #{@turnCount+1}***")
|
||||
if @debug && @turnCount>=100
|
||||
@decision = pbDecisionOnTime
|
||||
PBDebug.log("")
|
||||
PBDebug.log("***Undecided after 100 rounds, aborting***")
|
||||
pbAbort
|
||||
break
|
||||
end
|
||||
PBDebug.log("")
|
||||
# Command phase
|
||||
PBDebug.logonerr { pbCommandPhase }
|
||||
break if @decision>0
|
||||
# Attack phase
|
||||
PBDebug.logonerr { pbAttackPhase }
|
||||
break if @decision>0
|
||||
# End of round phase
|
||||
PBDebug.logonerr { pbEndOfRoundPhase }
|
||||
break if @decision>0
|
||||
@turnCount += 1
|
||||
end
|
||||
pbEndOfBattle
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# End of battle
|
||||
#=============================================================================
|
||||
def pbGainMoney
|
||||
return if !@internalBattle || !@moneyGain
|
||||
# Money rewarded from opposing trainers
|
||||
if trainerBattle?
|
||||
tMoney = 0
|
||||
@opponent.each_with_index do |t,i|
|
||||
tMoney += pbMaxLevelInTeam(1, i) * t.base_money
|
||||
end
|
||||
tMoney *= 2 if @field.effects[PBEffects::AmuletCoin]
|
||||
tMoney *= 2 if @field.effects[PBEffects::HappyHour]
|
||||
oldMoney = pbPlayer.money
|
||||
pbPlayer.money += tMoney
|
||||
moneyGained = pbPlayer.money-oldMoney
|
||||
if moneyGained>0
|
||||
pbDisplayPaused(_INTL("You got ${1} for winning!",moneyGained.to_s_formatted))
|
||||
end
|
||||
end
|
||||
# Pick up money scattered by Pay Day
|
||||
if @field.effects[PBEffects::PayDay]>0
|
||||
@field.effects[PBEffects::PayDay] *= 2 if @field.effects[PBEffects::AmuletCoin]
|
||||
@field.effects[PBEffects::PayDay] *= 2 if @field.effects[PBEffects::HappyHour]
|
||||
oldMoney = pbPlayer.money
|
||||
pbPlayer.money += @field.effects[PBEffects::PayDay]
|
||||
moneyGained = pbPlayer.money-oldMoney
|
||||
if moneyGained>0
|
||||
pbDisplayPaused(_INTL("You picked up ${1}!",moneyGained.to_s_formatted))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbLoseMoney
|
||||
return if !@internalBattle || !@moneyGain
|
||||
return if $game_switches[Settings::NO_MONEY_LOSS]
|
||||
maxLevel = pbMaxLevelInTeam(0,0) # Player's Pokémon only, not partner's
|
||||
multiplier = [8,16,24,36,48,64,80,100,120]
|
||||
idxMultiplier = [pbPlayer.badge_count, multiplier.length - 1].min
|
||||
tMoney = maxLevel*multiplier[idxMultiplier]
|
||||
tMoney = pbPlayer.money if tMoney>pbPlayer.money
|
||||
oldMoney = pbPlayer.money
|
||||
pbPlayer.money -= tMoney
|
||||
moneyLost = oldMoney-pbPlayer.money
|
||||
if moneyLost>0
|
||||
if trainerBattle?
|
||||
pbDisplayPaused(_INTL("You gave ${1} to the winner...",moneyLost.to_s_formatted))
|
||||
else
|
||||
pbDisplayPaused(_INTL("You panicked and dropped ${1}...",moneyLost.to_s_formatted))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbEndOfBattle
|
||||
oldDecision = @decision
|
||||
@decision = 4 if @decision==1 && wildBattle? && @caughtPokemon.length>0
|
||||
case oldDecision
|
||||
##### WIN #####
|
||||
when 1
|
||||
PBDebug.log("")
|
||||
PBDebug.log("***Player won***")
|
||||
if trainerBattle?
|
||||
@scene.pbTrainerBattleSuccess
|
||||
case @opponent.length
|
||||
when 1
|
||||
pbDisplayPaused(_INTL("You defeated {1}!",@opponent[0].full_name))
|
||||
when 2
|
||||
pbDisplayPaused(_INTL("You defeated {1} and {2}!",@opponent[0].full_name,
|
||||
@opponent[1].full_name))
|
||||
when 3
|
||||
pbDisplayPaused(_INTL("You defeated {1}, {2} and {3}!",@opponent[0].full_name,
|
||||
@opponent[1].full_name,@opponent[2].full_name))
|
||||
end
|
||||
@opponent.each_with_index do |_t,i|
|
||||
@scene.pbShowOpponent(i)
|
||||
msg = (@endSpeeches[i] && @endSpeeches[i]!="") ? @endSpeeches[i] : "..."
|
||||
pbDisplayPaused(msg.gsub(/\\[Pp][Nn]/,pbPlayer.name))
|
||||
end
|
||||
end
|
||||
# Gain money from winning a trainer battle, and from Pay Day
|
||||
pbGainMoney if @decision!=4
|
||||
# Hide remaining trainer
|
||||
@scene.pbShowOpponent(@opponent.length) if trainerBattle? && @caughtPokemon.length>0
|
||||
##### LOSE, DRAW #####
|
||||
when 2, 5
|
||||
PBDebug.log("")
|
||||
PBDebug.log("***Player lost***") if @decision==2
|
||||
PBDebug.log("***Player drew with opponent***") if @decision==5
|
||||
if @internalBattle
|
||||
pbDisplayPaused(_INTL("You have no more Pokémon that can fight!"))
|
||||
if trainerBattle?
|
||||
case @opponent.length
|
||||
when 1
|
||||
pbDisplayPaused(_INTL("You lost against {1}!",@opponent[0].full_name))
|
||||
when 2
|
||||
pbDisplayPaused(_INTL("You lost against {1} and {2}!",
|
||||
@opponent[0].full_name,@opponent[1].full_name))
|
||||
when 3
|
||||
pbDisplayPaused(_INTL("You lost against {1}, {2} and {3}!",
|
||||
@opponent[0].full_name,@opponent[1].full_name,@opponent[2].full_name))
|
||||
end
|
||||
end
|
||||
# Lose money from losing a battle
|
||||
pbLoseMoney
|
||||
pbDisplayPaused(_INTL("You blacked out!")) if !@canLose
|
||||
elsif @decision==2
|
||||
if @opponent
|
||||
@opponent.each_with_index do |_t,i|
|
||||
@scene.pbShowOpponent(i)
|
||||
msg = (@endSpeechesWin[i] && @endSpeechesWin[i]!="") ? @endSpeechesWin[i] : "..."
|
||||
pbDisplayPaused(msg.gsub(/\\[Pp][Nn]/,pbPlayer.name))
|
||||
end
|
||||
end
|
||||
end
|
||||
##### CAUGHT WILD POKÉMON #####
|
||||
when 4
|
||||
@scene.pbWildBattleSuccess if !Settings::GAIN_EXP_FOR_CAPTURE
|
||||
end
|
||||
# Register captured Pokémon in the Pokédex, and store them
|
||||
pbRecordAndStoreCaughtPokemon
|
||||
# Collect Pay Day money in a wild battle that ended in a capture
|
||||
pbGainMoney if @decision==4
|
||||
# Pass on Pokérus within the party
|
||||
if @internalBattle
|
||||
infected = []
|
||||
$Trainer.party.each_with_index do |pkmn,i|
|
||||
infected.push(i) if pkmn.pokerusStage==1
|
||||
end
|
||||
infected.each do |idxParty|
|
||||
strain = $Trainer.party[idxParty].pokerusStrain
|
||||
if idxParty>0 && $Trainer.party[idxParty-1].pokerusStage==0
|
||||
$Trainer.party[idxParty-1].givePokerus(strain) if rand(3)==0 # 33%
|
||||
end
|
||||
if idxParty<$Trainer.party.length-1 && $Trainer.party[idxParty+1].pokerusStage==0
|
||||
$Trainer.party[idxParty+1].givePokerus(strain) if rand(3)==0 # 33%
|
||||
end
|
||||
end
|
||||
end
|
||||
# Clean up battle stuff
|
||||
@scene.pbEndBattle(@decision)
|
||||
@battlers.each do |b|
|
||||
next if !b
|
||||
pbCancelChoice(b.index) # Restore unused items to Bag
|
||||
BattleHandlers.triggerAbilityOnSwitchOut(b.ability,b,true) if b.abilityActive?
|
||||
end
|
||||
pbParty(0).each_with_index do |pkmn,i|
|
||||
next if !pkmn
|
||||
@peer.pbOnLeavingBattle(self,pkmn,@usedInBattle[0][i],true) # Reset form
|
||||
pkmn.item = @initialItems[0][i]
|
||||
end
|
||||
return @decision
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Judging
|
||||
#=============================================================================
|
||||
def pbJudgeCheckpoint(user,move=nil); end
|
||||
|
||||
def pbDecisionOnTime
|
||||
counts = [0,0]
|
||||
hpTotals = [0,0]
|
||||
for side in 0...2
|
||||
pbParty(side).each do |pkmn|
|
||||
next if !pkmn || !pkmn.able?
|
||||
counts[side] += 1
|
||||
hpTotals[side] += pkmn.hp
|
||||
end
|
||||
end
|
||||
return 1 if counts[0]>counts[1] # Win (player has more able Pokémon)
|
||||
return 2 if counts[0]<counts[1] # Loss (foe has more able Pokémon)
|
||||
return 1 if hpTotals[0]>hpTotals[1] # Win (player has more HP in total)
|
||||
return 2 if hpTotals[0]<hpTotals[1] # Loss (foe has more HP in total)
|
||||
return 5 # Draw
|
||||
end
|
||||
|
||||
# Unused
|
||||
def pbDecisionOnTime2
|
||||
counts = [0,0]
|
||||
hpTotals = [0,0]
|
||||
for side in 0...2
|
||||
pbParty(side).each do |pkmn|
|
||||
next if !pkmn || !pkmn.able?
|
||||
counts[side] += 1
|
||||
hpTotals[side] += 100*pkmn.hp/pkmn.totalhp
|
||||
end
|
||||
hpTotals[side] /= counts[side] if counts[side]>1
|
||||
end
|
||||
return 1 if counts[0]>counts[1] # Win (player has more able Pokémon)
|
||||
return 2 if counts[0]<counts[1] # Loss (foe has more able Pokémon)
|
||||
return 1 if hpTotals[0]>hpTotals[1] # Win (player has a bigger average HP %)
|
||||
return 2 if hpTotals[0]<hpTotals[1] # Loss (foe has a bigger average HP %)
|
||||
return 5 # Draw
|
||||
end
|
||||
|
||||
def pbDecisionOnDraw; return 5; end # Draw
|
||||
|
||||
def pbJudge
|
||||
fainted1 = pbAllFainted?(0)
|
||||
fainted2 = pbAllFainted?(1)
|
||||
if fainted1 && fainted2; @decision = pbDecisionOnDraw # Draw
|
||||
elsif fainted1; @decision = 2 # Loss
|
||||
elsif fainted2; @decision = 1 # Win
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,263 @@
|
||||
class PokeBattle_Battle
|
||||
#=============================================================================
|
||||
# Gaining Experience
|
||||
#=============================================================================
|
||||
def pbGainExp
|
||||
# Play wild victory music if it's the end of the battle (has to be here)
|
||||
@scene.pbWildBattleSuccess if wildBattle? && pbAllFainted?(1) && !pbAllFainted?(0)
|
||||
return if !@internalBattle || !@expGain
|
||||
# Go through each battler in turn to find the Pokémon that participated in
|
||||
# battle against it, and award those Pokémon Exp/EVs
|
||||
expAll = (GameData::Item.exists?(:EXPALL) && $PokemonBag.pbHasItem?(:EXPALL))
|
||||
p1 = pbParty(0)
|
||||
@battlers.each do |b|
|
||||
next unless b && b.opposes? # Can only gain Exp from fainted foes
|
||||
next if b.participants.length==0
|
||||
next unless b.fainted? || b.captured
|
||||
# Count the number of participants
|
||||
numPartic = 0
|
||||
b.participants.each do |partic|
|
||||
next unless p1[partic] && p1[partic].able? && pbIsOwner?(0,partic)
|
||||
numPartic += 1
|
||||
end
|
||||
# Find which Pokémon have an Exp Share
|
||||
expShare = []
|
||||
if !expAll
|
||||
eachInTeam(0,0) do |pkmn,i|
|
||||
next if !pkmn.able?
|
||||
next if !pkmn.hasItem?(:EXPSHARE) && GameData::Item.try_get(@initialItems[0][i]) != :EXPSHARE
|
||||
expShare.push(i)
|
||||
end
|
||||
end
|
||||
# Calculate EV and Exp gains for the participants
|
||||
if numPartic>0 || expShare.length>0 || expAll
|
||||
# Gain EVs and Exp for participants
|
||||
eachInTeam(0,0) do |pkmn,i|
|
||||
next if !pkmn.able?
|
||||
next unless b.participants.include?(i) || expShare.include?(i)
|
||||
pbGainEVsOne(i,b)
|
||||
pbGainExpOne(i,b,numPartic,expShare,expAll)
|
||||
end
|
||||
# Gain EVs and Exp for all other Pokémon because of Exp All
|
||||
if expAll
|
||||
showMessage = true
|
||||
eachInTeam(0,0) do |pkmn,i|
|
||||
next if !pkmn.able?
|
||||
next if b.participants.include?(i) || expShare.include?(i)
|
||||
pbDisplayPaused(_INTL("Your party Pokémon in waiting also got Exp. Points!")) if showMessage
|
||||
showMessage = false
|
||||
pbGainEVsOne(i,b)
|
||||
pbGainExpOne(i,b,numPartic,expShare,expAll,false)
|
||||
end
|
||||
end
|
||||
end
|
||||
# Clear the participants array
|
||||
b.participants = []
|
||||
end
|
||||
end
|
||||
|
||||
def pbGainEVsOne(idxParty,defeatedBattler)
|
||||
pkmn = pbParty(0)[idxParty] # The Pokémon gaining EVs from defeatedBattler
|
||||
evYield = defeatedBattler.pokemon.evYield
|
||||
# Num of effort points pkmn already has
|
||||
evTotal = 0
|
||||
GameData::Stat.each_main { |s| evTotal += pkmn.ev[s.id] }
|
||||
# Modify EV yield based on pkmn's held item
|
||||
if !BattleHandlers.triggerEVGainModifierItem(pkmn.item,pkmn,evYield)
|
||||
BattleHandlers.triggerEVGainModifierItem(@initialItems[0][idxParty],pkmn,evYield)
|
||||
end
|
||||
# Double EV gain because of Pokérus
|
||||
if pkmn.pokerusStage>=1 # Infected or cured
|
||||
evYield.each_key { |stat| evYield[stat] *= 2 }
|
||||
end
|
||||
# Gain EVs for each stat in turn
|
||||
if pkmn.shadowPokemon? && pkmn.saved_ev
|
||||
pkmn.saved_ev.each_value { |e| evTotal += e }
|
||||
GameData::Stat.each_main do |s|
|
||||
evGain = evYield[s.id].clamp(0, Pokemon::EV_STAT_LIMIT - pkmn.ev[s.id] - pkmn.saved_ev[s.id])
|
||||
evGain = evGain.clamp(0, Pokemon::EV_LIMIT - evTotal)
|
||||
pkmn.saved_ev[s.id] += evGain
|
||||
evTotal += evGain
|
||||
end
|
||||
else
|
||||
GameData::Stat.each_main do |s|
|
||||
evGain = evYield[s.id].clamp(0, Pokemon::EV_STAT_LIMIT - pkmn.ev[s.id])
|
||||
evGain = evGain.clamp(0, Pokemon::EV_LIMIT - evTotal)
|
||||
pkmn.ev[s.id] += evGain
|
||||
evTotal += evGain
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbGainExpOne(idxParty,defeatedBattler,numPartic,expShare,expAll,showMessages=true)
|
||||
pkmn = pbParty(0)[idxParty] # The Pokémon gaining EVs from defeatedBattler
|
||||
growth_rate = pkmn.growth_rate
|
||||
# Don't bother calculating if gainer is already at max Exp
|
||||
if pkmn.exp>=growth_rate.maximum_exp
|
||||
pkmn.calc_stats # To ensure new EVs still have an effect
|
||||
return
|
||||
end
|
||||
isPartic = defeatedBattler.participants.include?(idxParty)
|
||||
hasExpShare = expShare.include?(idxParty)
|
||||
level = defeatedBattler.level
|
||||
# Main Exp calculation
|
||||
exp = 0
|
||||
a = level*defeatedBattler.pokemon.base_exp
|
||||
if expShare.length>0 && (isPartic || hasExpShare)
|
||||
if numPartic==0 # No participants, all Exp goes to Exp Share holders
|
||||
exp = a / (Settings::SPLIT_EXP_BETWEEN_GAINERS ? expShare.length : 1)
|
||||
elsif Settings::SPLIT_EXP_BETWEEN_GAINERS # Gain from participating and/or Exp Share
|
||||
exp = a/(2*numPartic) if isPartic
|
||||
exp += a/(2*expShare.length) if hasExpShare
|
||||
else # Gain from participating and/or Exp Share (Exp not split)
|
||||
exp = (isPartic) ? a : a/2
|
||||
end
|
||||
elsif isPartic # Participated in battle, no Exp Shares held by anyone
|
||||
exp = a / (Settings::SPLIT_EXP_BETWEEN_GAINERS ? numPartic : 1)
|
||||
elsif expAll # Didn't participate in battle, gaining Exp due to Exp All
|
||||
# NOTE: Exp All works like the Exp Share from Gen 6+, not like the Exp All
|
||||
# from Gen 1, i.e. Exp isn't split between all Pokémon gaining it.
|
||||
exp = a/2
|
||||
end
|
||||
return if exp<=0
|
||||
# Pokémon gain more Exp from trainer battles
|
||||
exp = (exp*1.5).floor if trainerBattle?
|
||||
# Scale the gained Exp based on the gainer's level (or not)
|
||||
if Settings::SCALED_EXP_FORMULA
|
||||
exp /= 5
|
||||
levelAdjust = (2*level+10.0)/(pkmn.level+level+10.0)
|
||||
levelAdjust = levelAdjust**5
|
||||
levelAdjust = Math.sqrt(levelAdjust)
|
||||
exp *= levelAdjust
|
||||
exp = exp.floor
|
||||
exp += 1 if isPartic || hasExpShare
|
||||
else
|
||||
exp /= 7
|
||||
end
|
||||
# Foreign Pokémon gain more Exp
|
||||
isOutsider = (pkmn.owner.id != pbPlayer.id ||
|
||||
(pkmn.owner.language != 0 && pkmn.owner.language != pbPlayer.language))
|
||||
if isOutsider
|
||||
if pkmn.owner.language != 0 && pkmn.owner.language != pbPlayer.language
|
||||
exp = (exp*1.7).floor
|
||||
else
|
||||
exp = (exp*1.5).floor
|
||||
end
|
||||
end
|
||||
# Modify Exp gain based on pkmn's held item
|
||||
i = BattleHandlers.triggerExpGainModifierItem(pkmn.item,pkmn,exp)
|
||||
if i<0
|
||||
i = BattleHandlers.triggerExpGainModifierItem(@initialItems[0][idxParty],pkmn,exp)
|
||||
end
|
||||
exp = i if i>=0
|
||||
# Make sure Exp doesn't exceed the maximum
|
||||
expFinal = growth_rate.add_exp(pkmn.exp, exp)
|
||||
expGained = expFinal-pkmn.exp
|
||||
return if expGained<=0
|
||||
# "Exp gained" message
|
||||
if showMessages
|
||||
if isOutsider
|
||||
pbDisplayPaused(_INTL("{1} got a boosted {2} Exp. Points!",pkmn.name,expGained))
|
||||
else
|
||||
pbDisplayPaused(_INTL("{1} got {2} Exp. Points!",pkmn.name,expGained))
|
||||
end
|
||||
end
|
||||
curLevel = pkmn.level
|
||||
newLevel = growth_rate.level_from_exp(expFinal)
|
||||
if newLevel<curLevel
|
||||
debugInfo = "Levels: #{curLevel}->#{newLevel} | Exp: #{pkmn.exp}->#{expFinal} | gain: #{expGained}"
|
||||
raise RuntimeError.new(
|
||||
_INTL("{1}'s new level is less than its\r\ncurrent level, which shouldn't happen.\r\n[Debug: {2}]",
|
||||
pkmn.name,debugInfo))
|
||||
end
|
||||
# Give Exp
|
||||
if pkmn.shadowPokemon?
|
||||
pkmn.exp += expGained
|
||||
return
|
||||
end
|
||||
tempExp1 = pkmn.exp
|
||||
battler = pbFindBattler(idxParty)
|
||||
loop do # For each level gained in turn...
|
||||
# EXP Bar animation
|
||||
levelMinExp = growth_rate.minimum_exp_for_level(curLevel)
|
||||
levelMaxExp = growth_rate.minimum_exp_for_level(curLevel + 1)
|
||||
tempExp2 = (levelMaxExp<expFinal) ? levelMaxExp : expFinal
|
||||
pkmn.exp = tempExp2
|
||||
@scene.pbEXPBar(battler,levelMinExp,levelMaxExp,tempExp1,tempExp2)
|
||||
tempExp1 = tempExp2
|
||||
curLevel += 1
|
||||
if curLevel>newLevel
|
||||
# Gained all the Exp now, end the animation
|
||||
pkmn.calc_stats
|
||||
battler.pbUpdate(false) if battler
|
||||
@scene.pbRefreshOne(battler.index) if battler
|
||||
break
|
||||
end
|
||||
# Levelled up
|
||||
pbCommonAnimation("LevelUp",battler) if battler
|
||||
oldTotalHP = pkmn.totalhp
|
||||
oldAttack = pkmn.attack
|
||||
oldDefense = pkmn.defense
|
||||
oldSpAtk = pkmn.spatk
|
||||
oldSpDef = pkmn.spdef
|
||||
oldSpeed = pkmn.speed
|
||||
if battler && battler.pokemon
|
||||
battler.pokemon.changeHappiness("levelup")
|
||||
end
|
||||
pkmn.calc_stats
|
||||
battler.pbUpdate(false) if battler
|
||||
@scene.pbRefreshOne(battler.index) if battler
|
||||
pbDisplayPaused(_INTL("{1} grew to Lv. {2}!",pkmn.name,curLevel))
|
||||
@scene.pbLevelUp(pkmn,battler,oldTotalHP,oldAttack,oldDefense,
|
||||
oldSpAtk,oldSpDef,oldSpeed)
|
||||
# Learn all moves learned at this level
|
||||
moveList = pkmn.getMoveList
|
||||
moveList.each { |m| pbLearnMove(idxParty,m[1]) if m[0]==curLevel }
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Learning a move
|
||||
#=============================================================================
|
||||
def pbLearnMove(idxParty,newMove)
|
||||
pkmn = pbParty(0)[idxParty]
|
||||
return if !pkmn
|
||||
pkmnName = pkmn.name
|
||||
battler = pbFindBattler(idxParty)
|
||||
moveName = GameData::Move.get(newMove).name
|
||||
# Find a space for the new move in pkmn's moveset and learn it
|
||||
for i in 0...Pokemon::MAX_MOVES
|
||||
m = pkmn.moves[i]
|
||||
return if m && m.id==newMove # Already knows the new move
|
||||
pkmn.moves[i] = Pokemon::Move.new(newMove)
|
||||
battler.moves[i] = PokeBattle_Move.from_pokemon_move(self, pkmn.moves[i]) if battler
|
||||
pbDisplay(_INTL("{1} learned {2}!",pkmnName,moveName)) { pbSEPlay("Pkmn move learnt") }
|
||||
battler.pbCheckFormOnMovesetChange if battler
|
||||
return
|
||||
end
|
||||
# pkmn already knows four moves, need to forget one to learn newMove
|
||||
loop do
|
||||
pbDisplayPaused(_INTL("{1} wants to learn {2}, but it already knows four moves.",pkmnName,moveName))
|
||||
if pbDisplayConfirm(_INTL("Forget a move to learn {1}?",moveName))
|
||||
pbDisplayPaused(_INTL("Which move should be forgotten?"))
|
||||
forgetMove = @scene.pbForgetMove(pkmn,newMove)
|
||||
if forgetMove>=0
|
||||
oldMoveName = pkmn.moves[forgetMove].name
|
||||
pkmn.moves[forgetMove] = Pokemon::Move.new(newMove) # Replaces current/total PP
|
||||
battler.moves[forgetMove] = PokeBattle_Move.from_pokemon_move(self, pkmn.moves[forgetMove]) if battler
|
||||
pbDisplayPaused(_INTL("1, 2, and... ... ... Ta-da!"))
|
||||
pbDisplayPaused(_INTL("{1} forgot how to use {2}. And...",pkmnName,oldMoveName))
|
||||
pbDisplay(_INTL("{1} learned {2}!",pkmnName,moveName)) { pbSEPlay("Pkmn move learnt") }
|
||||
battler.pbCheckFormOnMovesetChange if battler
|
||||
break
|
||||
elsif pbDisplayConfirm(_INTL("Give up on learning {1}?",moveName))
|
||||
pbDisplay(_INTL("{1} did not learn {2}.",pkmnName,moveName))
|
||||
break
|
||||
end
|
||||
elsif pbDisplayConfirm(_INTL("Give up on learning {1}?",moveName))
|
||||
pbDisplay(_INTL("{1} did not learn {2}.",pkmnName,moveName))
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,249 @@
|
||||
class PokeBattle_Battle
|
||||
#=============================================================================
|
||||
# Choosing a move/target
|
||||
#=============================================================================
|
||||
def pbCanChooseMove?(idxBattler,idxMove,showMessages,sleepTalk=false)
|
||||
battler = @battlers[idxBattler]
|
||||
move = battler.moves[idxMove]
|
||||
return false unless move
|
||||
if move.pp==0 && move.total_pp>0 && !sleepTalk
|
||||
pbDisplayPaused(_INTL("There's no PP left for this move!")) if showMessages
|
||||
return false
|
||||
end
|
||||
if battler.effects[PBEffects::Encore]>0
|
||||
idxEncoredMove = battler.pbEncoredMoveIndex
|
||||
return false if idxEncoredMove>=0 && idxMove!=idxEncoredMove
|
||||
end
|
||||
return battler.pbCanChooseMove?(move,true,showMessages,sleepTalk)
|
||||
end
|
||||
|
||||
def pbCanChooseAnyMove?(idxBattler,sleepTalk=false)
|
||||
battler = @battlers[idxBattler]
|
||||
battler.eachMoveWithIndex do |m,i|
|
||||
next if m.pp==0 && m.total_pp>0 && !sleepTalk
|
||||
if battler.effects[PBEffects::Encore]>0
|
||||
idxEncoredMove = battler.pbEncoredMoveIndex
|
||||
next if idxEncoredMove>=0 && i!=idxEncoredMove
|
||||
end
|
||||
next if !battler.pbCanChooseMove?(m,true,false,sleepTalk)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
# Called when the Pokémon is Encored, or if it can't use any of its moves.
|
||||
# Makes the Pokémon use the Encored move (if Encored), or Struggle.
|
||||
def pbAutoChooseMove(idxBattler,showMessages=true)
|
||||
battler = @battlers[idxBattler]
|
||||
if battler.fainted?
|
||||
pbClearChoice(idxBattler)
|
||||
return true
|
||||
end
|
||||
# Encore
|
||||
idxEncoredMove = battler.pbEncoredMoveIndex
|
||||
if idxEncoredMove>=0 && pbCanChooseMove?(idxBattler,idxEncoredMove,false)
|
||||
encoreMove = battler.moves[idxEncoredMove]
|
||||
@choices[idxBattler][0] = :UseMove # "Use move"
|
||||
@choices[idxBattler][1] = idxEncoredMove # Index of move to be used
|
||||
@choices[idxBattler][2] = encoreMove # PokeBattle_Move object
|
||||
@choices[idxBattler][3] = -1 # No target chosen yet
|
||||
return true if singleBattle?
|
||||
if pbOwnedByPlayer?(idxBattler)
|
||||
if showMessages
|
||||
pbDisplayPaused(_INTL("{1} has to use {2}!",battler.name,encoreMove.name))
|
||||
end
|
||||
return pbChooseTarget(battler,encoreMove)
|
||||
end
|
||||
return true
|
||||
end
|
||||
# Struggle
|
||||
if pbOwnedByPlayer?(idxBattler) && showMessages
|
||||
pbDisplayPaused(_INTL("{1} has no moves left!",battler.name))
|
||||
end
|
||||
@choices[idxBattler][0] = :UseMove # "Use move"
|
||||
@choices[idxBattler][1] = -1 # Index of move to be used
|
||||
@choices[idxBattler][2] = @struggle # Struggle PokeBattle_Move object
|
||||
@choices[idxBattler][3] = -1 # No target chosen yet
|
||||
return true
|
||||
end
|
||||
|
||||
def pbRegisterMove(idxBattler,idxMove,showMessages=true)
|
||||
battler = @battlers[idxBattler]
|
||||
move = battler.moves[idxMove]
|
||||
return false if !pbCanChooseMove?(idxBattler,idxMove,showMessages)
|
||||
@choices[idxBattler][0] = :UseMove # "Use move"
|
||||
@choices[idxBattler][1] = idxMove # Index of move to be used
|
||||
@choices[idxBattler][2] = move # PokeBattle_Move object
|
||||
@choices[idxBattler][3] = -1 # No target chosen yet
|
||||
return true
|
||||
end
|
||||
|
||||
def pbChoseMove?(idxBattler,moveID)
|
||||
return false if !@battlers[idxBattler] || @battlers[idxBattler].fainted?
|
||||
if @choices[idxBattler][0]==:UseMove && @choices[idxBattler][1]
|
||||
return @choices[idxBattler][2].id == moveID
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def pbChoseMoveFunctionCode?(idxBattler,code)
|
||||
return false if @battlers[idxBattler].fainted?
|
||||
idxMove = @choices[idxBattler][1]
|
||||
if @choices[idxBattler][0]==:UseMove && @choices[idxBattler][1]
|
||||
return @choices[idxBattler][2].function == code
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def pbRegisterTarget(idxBattler,idxTarget)
|
||||
@choices[idxBattler][3] = idxTarget # Set target of move
|
||||
end
|
||||
|
||||
# Returns whether the idxTarget will be targeted by a move with target_data
|
||||
# used by a battler in idxUser.
|
||||
def pbMoveCanTarget?(idxUser,idxTarget,target_data)
|
||||
return false if target_data.num_targets == 0
|
||||
case target_data.id
|
||||
when :NearAlly
|
||||
return false if opposes?(idxUser,idxTarget)
|
||||
return false if !nearBattlers?(idxUser,idxTarget)
|
||||
when :UserOrNearAlly
|
||||
return true if idxUser==idxTarget
|
||||
return false if opposes?(idxUser,idxTarget)
|
||||
return false if !nearBattlers?(idxUser,idxTarget)
|
||||
when :UserAndAllies
|
||||
return false if opposes?(idxUser,idxTarget)
|
||||
when :NearFoe, :RandomNearFoe, :AllNearFoes
|
||||
return false if !opposes?(idxUser,idxTarget)
|
||||
return false if !nearBattlers?(idxUser,idxTarget)
|
||||
when :Foe
|
||||
return false if !opposes?(idxUser,idxTarget)
|
||||
when :AllFoes
|
||||
return false if !opposes?(idxUser,idxTarget)
|
||||
when :NearOther, :AllNearOthers
|
||||
return false if !nearBattlers?(idxUser,idxTarget)
|
||||
when :Other
|
||||
return false if idxUser==idxTarget
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Turn order calculation (priority)
|
||||
#=============================================================================
|
||||
def pbCalculatePriority(fullCalc=false,indexArray=nil)
|
||||
needRearranging = false
|
||||
if fullCalc
|
||||
@priorityTrickRoom = (@field.effects[PBEffects::TrickRoom]>0)
|
||||
# Recalculate everything from scratch
|
||||
randomOrder = Array.new(maxBattlerIndex+1) { |i| i }
|
||||
(randomOrder.length-1).times do |i| # Can't use shuffle! here
|
||||
r = i+pbRandom(randomOrder.length-i)
|
||||
randomOrder[i], randomOrder[r] = randomOrder[r], randomOrder[i]
|
||||
end
|
||||
@priority.clear
|
||||
for i in 0..maxBattlerIndex
|
||||
b = @battlers[i]
|
||||
next if !b
|
||||
# [battler, speed, sub-priority, priority, tie-breaker order]
|
||||
bArray = [b,b.pbSpeed,0,0,randomOrder[i]]
|
||||
if @choices[b.index][0]==:UseMove || @choices[b.index][0]==:Shift
|
||||
# Calculate move's priority
|
||||
if @choices[b.index][0]==:UseMove
|
||||
move = @choices[b.index][2]
|
||||
pri = move.priority
|
||||
if b.abilityActive?
|
||||
pri = BattleHandlers.triggerPriorityChangeAbility(b.ability,b,move,pri)
|
||||
end
|
||||
bArray[3] = pri
|
||||
@choices[b.index][4] = pri
|
||||
end
|
||||
# Calculate sub-priority (first/last within priority bracket)
|
||||
# NOTE: Going fast beats going slow. A Pokémon with Stall and Quick
|
||||
# Claw will go first in its priority bracket if Quick Claw
|
||||
# triggers, regardless of Stall.
|
||||
subPri = 0
|
||||
# Abilities (Stall)
|
||||
if b.abilityActive?
|
||||
newSubPri = BattleHandlers.triggerPriorityBracketChangeAbility(b.ability,
|
||||
b,subPri,self)
|
||||
if subPri!=newSubPri
|
||||
subPri = newSubPri
|
||||
b.effects[PBEffects::PriorityAbility] = true
|
||||
b.effects[PBEffects::PriorityItem] = false
|
||||
end
|
||||
end
|
||||
# Items (Quick Claw, Custap Berry, Lagging Tail, Full Incense)
|
||||
if b.itemActive?
|
||||
newSubPri = BattleHandlers.triggerPriorityBracketChangeItem(b.item,
|
||||
b,subPri,self)
|
||||
if subPri!=newSubPri
|
||||
subPri = newSubPri
|
||||
b.effects[PBEffects::PriorityAbility] = false
|
||||
b.effects[PBEffects::PriorityItem] = true
|
||||
end
|
||||
end
|
||||
bArray[2] = subPri
|
||||
end
|
||||
@priority.push(bArray)
|
||||
end
|
||||
needRearranging = true
|
||||
else
|
||||
if (@field.effects[PBEffects::TrickRoom]>0)!=@priorityTrickRoom
|
||||
needRearranging = true
|
||||
@priorityTrickRoom = (@field.effects[PBEffects::TrickRoom]>0)
|
||||
end
|
||||
# Just recheck all battler speeds
|
||||
@priority.each do |orderArray|
|
||||
next if !orderArray
|
||||
next if indexArray && !indexArray.include?(orderArray[0].index)
|
||||
oldSpeed = orderArray[1]
|
||||
orderArray[1] = orderArray[0].pbSpeed
|
||||
needRearranging = true if orderArray[1]!=oldSpeed
|
||||
end
|
||||
end
|
||||
# Reorder the priority array
|
||||
if needRearranging
|
||||
@priority.sort! { |a,b|
|
||||
if a[3]!=b[3]
|
||||
# Sort by priority (highest value first)
|
||||
b[3]<=>a[3]
|
||||
elsif a[2]!=b[2]
|
||||
# Sort by sub-priority (highest value first)
|
||||
b[2]<=>a[2]
|
||||
elsif @priorityTrickRoom
|
||||
# Sort by speed (lowest first), and use tie-breaker if necessary
|
||||
(a[1]==b[1]) ? b[4]<=>a[4] : a[1]<=>b[1]
|
||||
else
|
||||
# Sort by speed (highest first), and use tie-breaker if necessary
|
||||
(a[1]==b[1]) ? b[4]<=>a[4] : b[1]<=>a[1]
|
||||
end
|
||||
}
|
||||
# Write the priority order to the debug log
|
||||
logMsg = (fullCalc) ? "[Round order] " : "[Round order recalculated] "
|
||||
comma = false
|
||||
@priority.each do |orderArray|
|
||||
logMsg += ", " if comma
|
||||
logMsg += "#{orderArray[0].pbThis(comma)} (#{orderArray[0].index})"
|
||||
comma = true
|
||||
end
|
||||
PBDebug.log(logMsg)
|
||||
end
|
||||
end
|
||||
|
||||
def pbPriority(onlySpeedSort=false)
|
||||
ret = []
|
||||
if onlySpeedSort
|
||||
# Sort battlers by their speed stats and tie-breaker order only.
|
||||
tempArray = []
|
||||
@priority.each { |pArray| tempArray.push([pArray[0],pArray[1],pArray[4]]) }
|
||||
tempArray.sort! { |a,b| (a[1]==b[1]) ? b[2]<=>a[2] : b[1]<=>a[1] }
|
||||
tempArray.each { |tArray| ret.push(tArray[0]) }
|
||||
else
|
||||
# Sort battlers by priority, sub-priority and their speed. Ties are
|
||||
# resolved in the same way each time this method is called in a round.
|
||||
@priority.each { |pArray| ret.push(pArray[0]) if !pArray[0].fainted? }
|
||||
end
|
||||
return ret
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,412 @@
|
||||
class PokeBattle_Battle
|
||||
#=============================================================================
|
||||
# Choosing Pokémon to switch
|
||||
#=============================================================================
|
||||
# Checks whether the replacement Pokémon (at party index idxParty) can enter
|
||||
# battle.
|
||||
# NOTE: Messages are only shown while in the party screen when choosing a
|
||||
# command for the next round.
|
||||
def pbCanSwitchLax?(idxBattler,idxParty,partyScene=nil)
|
||||
return true if idxParty<0
|
||||
party = pbParty(idxBattler)
|
||||
return false if idxParty>=party.length
|
||||
return false if !party[idxParty]
|
||||
if party[idxParty].egg?
|
||||
partyScene.pbDisplay(_INTL("An Egg can't battle!")) if partyScene
|
||||
return false
|
||||
end
|
||||
if !pbIsOwner?(idxBattler,idxParty)
|
||||
owner = pbGetOwnerFromPartyIndex(idxBattler,idxParty)
|
||||
partyScene.pbDisplay(_INTL("You can't switch {1}'s Pokémon with one of yours!",
|
||||
owner.name)) if partyScene
|
||||
return false
|
||||
end
|
||||
if party[idxParty].fainted?
|
||||
partyScene.pbDisplay(_INTL("{1} has no energy left to battle!",
|
||||
party[idxParty].name)) if partyScene
|
||||
return false
|
||||
end
|
||||
if pbFindBattler(idxParty,idxBattler)
|
||||
partyScene.pbDisplay(_INTL("{1} is already in battle!",
|
||||
party[idxParty].name)) if partyScene
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
# Check whether the currently active Pokémon (at battler index idxBattler) can
|
||||
# switch out (and that its replacement at party index idxParty can switch in).
|
||||
# NOTE: Messages are only shown while in the party screen when choosing a
|
||||
# command for the next round.
|
||||
def pbCanSwitch?(idxBattler,idxParty=-1,partyScene=nil)
|
||||
# Check whether party Pokémon can switch in
|
||||
return false if !pbCanSwitchLax?(idxBattler,idxParty,partyScene)
|
||||
# Make sure another battler isn't already choosing to switch to the party
|
||||
# Pokémon
|
||||
eachSameSideBattler(idxBattler) do |b|
|
||||
next if choices[b.index][0]!=:SwitchOut || choices[b.index][1]!=idxParty
|
||||
partyScene.pbDisplay(_INTL("{1} has already been selected.",
|
||||
pbParty(idxBattler)[idxParty].name)) if partyScene
|
||||
return false
|
||||
end
|
||||
# Check whether battler can switch out
|
||||
battler = @battlers[idxBattler]
|
||||
return true if battler.fainted?
|
||||
# Ability/item effects that allow switching no matter what
|
||||
if battler.abilityActive?
|
||||
if BattleHandlers.triggerCertainSwitchingUserAbility(battler.ability,battler,self)
|
||||
return true
|
||||
end
|
||||
end
|
||||
if battler.itemActive?
|
||||
if BattleHandlers.triggerCertainSwitchingUserItem(battler.item,battler,self)
|
||||
return true
|
||||
end
|
||||
end
|
||||
# Other certain switching effects
|
||||
return true if Settings::MORE_TYPE_EFFECTS && battler.pbHasType?(:GHOST)
|
||||
# Other certain trapping effects
|
||||
if battler.effects[PBEffects::Trapping]>0 ||
|
||||
battler.effects[PBEffects::MeanLook]>=0 ||
|
||||
battler.effects[PBEffects::Ingrain] ||
|
||||
@field.effects[PBEffects::FairyLock]>0
|
||||
partyScene.pbDisplay(_INTL("{1} can't be switched out!",battler.pbThis)) if partyScene
|
||||
return false
|
||||
end
|
||||
# Trapping abilities/items
|
||||
eachOtherSideBattler(idxBattler) do |b|
|
||||
next if !b.abilityActive?
|
||||
if BattleHandlers.triggerTrappingTargetAbility(b.ability,battler,b,self)
|
||||
partyScene.pbDisplay(_INTL("{1}'s {2} prevents switching!",
|
||||
b.pbThis,b.abilityName)) if partyScene
|
||||
return false
|
||||
end
|
||||
end
|
||||
eachOtherSideBattler(idxBattler) do |b|
|
||||
next if !b.itemActive?
|
||||
if BattleHandlers.triggerTrappingTargetItem(b.item,battler,b,self)
|
||||
partyScene.pbDisplay(_INTL("{1}'s {2} prevents switching!",
|
||||
b.pbThis,b.itemName)) if partyScene
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def pbCanChooseNonActive?(idxBattler)
|
||||
pbParty(idxBattler).each_with_index do |_pkmn,i|
|
||||
return true if pbCanSwitchLax?(idxBattler,i)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def pbRegisterSwitch(idxBattler,idxParty)
|
||||
return false if !pbCanSwitch?(idxBattler,idxParty)
|
||||
@choices[idxBattler][0] = :SwitchOut
|
||||
@choices[idxBattler][1] = idxParty # Party index of Pokémon to switch in
|
||||
@choices[idxBattler][2] = nil
|
||||
return true
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Open the party screen and potentially pick a replacement Pokémon (or AI
|
||||
# chooses replacement)
|
||||
#=============================================================================
|
||||
# Open party screen and potentially choose a Pokémon to switch with. Used in
|
||||
# all instances where the party screen is opened.
|
||||
def pbPartyScreen(idxBattler,checkLaxOnly=false,canCancel=false,shouldRegister=false)
|
||||
ret = -1
|
||||
@scene.pbPartyScreen(idxBattler,canCancel) { |idxParty,partyScene|
|
||||
if checkLaxOnly
|
||||
next false if !pbCanSwitchLax?(idxBattler,idxParty,partyScene)
|
||||
else
|
||||
next false if !pbCanSwitch?(idxBattler,idxParty,partyScene)
|
||||
end
|
||||
if shouldRegister
|
||||
next false if idxParty<0 || !pbRegisterSwitch(idxBattler,idxParty)
|
||||
end
|
||||
ret = idxParty
|
||||
next true
|
||||
}
|
||||
return ret
|
||||
end
|
||||
|
||||
# For choosing a replacement Pokémon when prompted in the middle of other
|
||||
# things happening (U-turn, Baton Pass, in def pbSwitch).
|
||||
def pbSwitchInBetween(idxBattler,checkLaxOnly=false,canCancel=false)
|
||||
return pbPartyScreen(idxBattler,checkLaxOnly,canCancel) if pbOwnedByPlayer?(idxBattler)
|
||||
return @battleAI.pbDefaultChooseNewEnemy(idxBattler,pbParty(idxBattler))
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Switching Pokémon
|
||||
#=============================================================================
|
||||
# General switching method that checks if any Pokémon need to be sent out and,
|
||||
# if so, does. Called at the end of each round.
|
||||
def pbEORSwitch(favorDraws=false)
|
||||
return if @decision>0 && !favorDraws
|
||||
return if @decision==5 && favorDraws
|
||||
pbJudge
|
||||
return if @decision>0
|
||||
# Check through each fainted battler to see if that spot can be filled.
|
||||
switched = []
|
||||
loop do
|
||||
switched.clear
|
||||
@battlers.each do |b|
|
||||
next if !b || !b.fainted?
|
||||
idxBattler = b.index
|
||||
next if !pbCanChooseNonActive?(idxBattler)
|
||||
if !pbOwnedByPlayer?(idxBattler) # Opponent/ally is switching in
|
||||
next if wildBattle? && opposes?(idxBattler) # Wild Pokémon can't switch
|
||||
idxPartyNew = pbSwitchInBetween(idxBattler)
|
||||
opponent = pbGetOwnerFromBattlerIndex(idxBattler)
|
||||
# NOTE: The player is only offered the chance to switch their own
|
||||
# Pokémon when an opponent replaces a fainted Pokémon in single
|
||||
# battles. In double battles, etc. there is no such offer.
|
||||
if @internalBattle && @switchStyle && trainerBattle? && pbSideSize(0)==1 &&
|
||||
opposes?(idxBattler) && !@battlers[0].fainted? && !switched.include?(0) &&
|
||||
pbCanChooseNonActive?(0) && @battlers[0].effects[PBEffects::Outrage]==0
|
||||
idxPartyForName = idxPartyNew
|
||||
enemyParty = pbParty(idxBattler)
|
||||
if enemyParty[idxPartyNew].ability == :ILLUSION
|
||||
new_index = pbLastInTeam(idxBattler)
|
||||
idxPartyForName = new_index if new_index >= 0
|
||||
end
|
||||
if pbDisplayConfirm(_INTL("{1} is about to send in {2}. Will you switch your Pokémon?",
|
||||
opponent.full_name, enemyParty[idxPartyForName].name))
|
||||
idxPlayerPartyNew = pbSwitchInBetween(0,false,true)
|
||||
if idxPlayerPartyNew>=0
|
||||
pbMessageOnRecall(@battlers[0])
|
||||
pbRecallAndReplace(0,idxPlayerPartyNew)
|
||||
switched.push(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
pbRecallAndReplace(idxBattler,idxPartyNew)
|
||||
switched.push(idxBattler)
|
||||
elsif trainerBattle? # Player switches in in a trainer battle
|
||||
idxPlayerPartyNew = pbGetReplacementPokemonIndex(idxBattler) # Owner chooses
|
||||
pbRecallAndReplace(idxBattler,idxPlayerPartyNew)
|
||||
switched.push(idxBattler)
|
||||
else # Player's Pokémon has fainted in a wild battle
|
||||
switch = false
|
||||
if !pbDisplayConfirm(_INTL("Use next Pokémon?"))
|
||||
switch = (pbRun(idxBattler,true)<=0)
|
||||
else
|
||||
switch = true
|
||||
end
|
||||
if switch
|
||||
idxPlayerPartyNew = pbGetReplacementPokemonIndex(idxBattler) # Owner chooses
|
||||
pbRecallAndReplace(idxBattler,idxPlayerPartyNew)
|
||||
switched.push(idxBattler)
|
||||
end
|
||||
end
|
||||
end
|
||||
break if switched.length==0
|
||||
pbPriority(true).each do |b|
|
||||
b.pbEffectsOnSwitchIn(true) if switched.include?(b.index)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbGetReplacementPokemonIndex(idxBattler,random=false)
|
||||
if random
|
||||
return -1 if !pbCanSwitch?(idxBattler) # Can battler switch out?
|
||||
choices = [] # Find all Pokémon that can switch in
|
||||
eachInTeamFromBattlerIndex(idxBattler) do |_pkmn,i|
|
||||
choices.push(i) if pbCanSwitchLax?(idxBattler,i)
|
||||
end
|
||||
return -1 if choices.length==0
|
||||
return choices[pbRandom(choices.length)]
|
||||
else
|
||||
return pbSwitchInBetween(idxBattler,true)
|
||||
end
|
||||
end
|
||||
|
||||
# Actually performs the recalling and sending out in all situations.
|
||||
def pbRecallAndReplace(idxBattler,idxParty,randomReplacement=false,batonPass=false)
|
||||
@scene.pbRecall(idxBattler) if !@battlers[idxBattler].fainted?
|
||||
@battlers[idxBattler].pbAbilitiesOnSwitchOut # Inc. primordial weather check
|
||||
@scene.pbShowPartyLineup(idxBattler&1) if pbSideSize(idxBattler)==1
|
||||
pbMessagesOnReplace(idxBattler,idxParty) if !randomReplacement
|
||||
pbReplace(idxBattler,idxParty,batonPass)
|
||||
end
|
||||
|
||||
def pbMessageOnRecall(battler)
|
||||
if battler.pbOwnedByPlayer?
|
||||
if battler.hp<=battler.totalhp/4
|
||||
pbDisplayBrief(_INTL("Good job, {1}! Come back!",battler.name))
|
||||
elsif battler.hp<=battler.totalhp/2
|
||||
pbDisplayBrief(_INTL("OK, {1}! Come back!",battler.name))
|
||||
elsif battler.turnCount>=5
|
||||
pbDisplayBrief(_INTL("{1}, that's enough! Come back!",battler.name))
|
||||
elsif battler.turnCount>=2
|
||||
pbDisplayBrief(_INTL("{1}, come back!",battler.name))
|
||||
else
|
||||
pbDisplayBrief(_INTL("{1}, switch out! Come back!",battler.name))
|
||||
end
|
||||
else
|
||||
owner = pbGetOwnerName(battler.index)
|
||||
pbDisplayBrief(_INTL("{1} withdrew {2}!",owner,battler.name))
|
||||
end
|
||||
end
|
||||
|
||||
# Only called from def pbRecallAndReplace and Battle Arena's def pbSwitch.
|
||||
def pbMessagesOnReplace(idxBattler,idxParty)
|
||||
party = pbParty(idxBattler)
|
||||
newPkmnName = party[idxParty].name
|
||||
if party[idxParty].ability == :ILLUSION
|
||||
new_index = pbLastInTeam(idxBattler)
|
||||
newPkmnName = party[new_index].name if new_index >= 0
|
||||
end
|
||||
if pbOwnedByPlayer?(idxBattler)
|
||||
opposing = @battlers[idxBattler].pbDirectOpposing
|
||||
if opposing.fainted? || opposing.hp==opposing.totalhp
|
||||
pbDisplayBrief(_INTL("You're in charge, {1}!",newPkmnName))
|
||||
elsif opposing.hp>=opposing.totalhp/2
|
||||
pbDisplayBrief(_INTL("Go for it, {1}!",newPkmnName))
|
||||
elsif opposing.hp>=opposing.totalhp/4
|
||||
pbDisplayBrief(_INTL("Just a little more! Hang in there, {1}!",newPkmnName))
|
||||
else
|
||||
pbDisplayBrief(_INTL("Your opponent's weak! Get 'em, {1}!",newPkmnName))
|
||||
end
|
||||
else
|
||||
owner = pbGetOwnerFromBattlerIndex(idxBattler)
|
||||
pbDisplayBrief(_INTL("{1} sent out {2}!",owner.full_name,newPkmnName))
|
||||
end
|
||||
end
|
||||
|
||||
# Only called from def pbRecallAndReplace above and Battle Arena's def
|
||||
# pbSwitch.
|
||||
def pbReplace(idxBattler,idxParty,batonPass=false)
|
||||
party = pbParty(idxBattler)
|
||||
idxPartyOld = @battlers[idxBattler].pokemonIndex
|
||||
# Initialise the new Pokémon
|
||||
@battlers[idxBattler].pbInitialize(party[idxParty],idxParty,batonPass)
|
||||
# Reorder the party for this battle
|
||||
partyOrder = pbPartyOrder(idxBattler)
|
||||
partyOrder[idxParty],partyOrder[idxPartyOld] = partyOrder[idxPartyOld],partyOrder[idxParty]
|
||||
# Send out the new Pokémon
|
||||
pbSendOut([[idxBattler,party[idxParty]]])
|
||||
pbCalculatePriority(false,[idxBattler]) if Settings::RECALCULATE_TURN_ORDER_AFTER_SPEED_CHANGES
|
||||
end
|
||||
|
||||
# Called from def pbReplace above and at the start of battle.
|
||||
# sendOuts is an array; each element is itself an array: [idxBattler,pkmn]
|
||||
def pbSendOut(sendOuts,startBattle=false)
|
||||
sendOuts.each { |b| @peer.pbOnEnteringBattle(self,b[1]) }
|
||||
@scene.pbSendOutBattlers(sendOuts,startBattle)
|
||||
sendOuts.each do |b|
|
||||
@scene.pbResetMoveIndex(b[0])
|
||||
pbSetSeen(@battlers[b[0]])
|
||||
@usedInBattle[b[0]&1][b[0]/2] = true
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Effects upon a Pokémon entering battle
|
||||
#=============================================================================
|
||||
# Called at the start of battle only.
|
||||
def pbOnActiveAll
|
||||
# Weather-inducing abilities, Trace, Imposter, etc.
|
||||
pbCalculatePriority(true)
|
||||
pbPriority(true).each { |b| b.pbEffectsOnSwitchIn(true) }
|
||||
pbCalculatePriority
|
||||
# Check forms are correct
|
||||
eachBattler { |b| b.pbCheckForm }
|
||||
end
|
||||
|
||||
# Called when a Pokémon switches in (entry effects, entry hazards).
|
||||
def pbOnActiveOne(battler)
|
||||
return false if battler.fainted?
|
||||
# Introduce Shadow Pokémon
|
||||
if battler.opposes? && battler.shadowPokemon?
|
||||
pbCommonAnimation("Shadow",battler)
|
||||
pbDisplay(_INTL("Oh!\nA Shadow Pokémon!"))
|
||||
end
|
||||
# Record money-doubling effect of Amulet Coin/Luck Incense
|
||||
if !battler.opposes? && [:AMULETCOIN, :LUCKINCENSE].include?(battler.item_id)
|
||||
@field.effects[PBEffects::AmuletCoin] = true
|
||||
end
|
||||
# Update battlers' participants (who will gain Exp/EVs when a battler faints)
|
||||
eachBattler { |b| b.pbUpdateParticipants }
|
||||
# Healing Wish
|
||||
if @positions[battler.index].effects[PBEffects::HealingWish]
|
||||
pbCommonAnimation("HealingWish",battler)
|
||||
pbDisplay(_INTL("The healing wish came true for {1}!",battler.pbThis(true)))
|
||||
battler.pbRecoverHP(battler.totalhp)
|
||||
battler.pbCureStatus(false)
|
||||
@positions[battler.index].effects[PBEffects::HealingWish] = false
|
||||
end
|
||||
# Lunar Dance
|
||||
if @positions[battler.index].effects[PBEffects::LunarDance]
|
||||
pbCommonAnimation("LunarDance",battler)
|
||||
pbDisplay(_INTL("{1} became cloaked in mystical moonlight!",battler.pbThis))
|
||||
battler.pbRecoverHP(battler.totalhp)
|
||||
battler.pbCureStatus(false)
|
||||
battler.eachMove { |m| m.pp = m.total_pp }
|
||||
@positions[battler.index].effects[PBEffects::LunarDance] = false
|
||||
end
|
||||
# Entry hazards
|
||||
# Stealth Rock
|
||||
if battler.pbOwnSide.effects[PBEffects::StealthRock] && battler.takesIndirectDamage? &&
|
||||
GameData::Type.exists?(:ROCK)
|
||||
bTypes = battler.pbTypes(true)
|
||||
eff = Effectiveness.calculate(:ROCK, bTypes[0], bTypes[1], bTypes[2])
|
||||
if !Effectiveness.ineffective?(eff)
|
||||
eff = eff.to_f / Effectiveness::NORMAL_EFFECTIVE
|
||||
oldHP = battler.hp
|
||||
battler.pbReduceHP(battler.totalhp*eff/8,false)
|
||||
pbDisplay(_INTL("Pointed stones dug into {1}!",battler.pbThis))
|
||||
battler.pbItemHPHealCheck
|
||||
if battler.pbAbilitiesOnDamageTaken(oldHP) # Switched out
|
||||
return pbOnActiveOne(battler) # For replacement battler
|
||||
end
|
||||
end
|
||||
end
|
||||
# Spikes
|
||||
if battler.pbOwnSide.effects[PBEffects::Spikes]>0 && battler.takesIndirectDamage? &&
|
||||
!battler.airborne?
|
||||
spikesDiv = [8,6,4][battler.pbOwnSide.effects[PBEffects::Spikes]-1]
|
||||
oldHP = battler.hp
|
||||
battler.pbReduceHP(battler.totalhp/spikesDiv,false)
|
||||
pbDisplay(_INTL("{1} is hurt by the spikes!",battler.pbThis))
|
||||
battler.pbItemHPHealCheck
|
||||
if battler.pbAbilitiesOnDamageTaken(oldHP) # Switched out
|
||||
return pbOnActiveOne(battler) # For replacement battler
|
||||
end
|
||||
end
|
||||
# Toxic Spikes
|
||||
if battler.pbOwnSide.effects[PBEffects::ToxicSpikes]>0 && !battler.fainted? &&
|
||||
!battler.airborne?
|
||||
if battler.pbHasType?(:POISON)
|
||||
battler.pbOwnSide.effects[PBEffects::ToxicSpikes] = 0
|
||||
pbDisplay(_INTL("{1} absorbed the poison spikes!",battler.pbThis))
|
||||
elsif battler.pbCanPoison?(nil,false)
|
||||
if battler.pbOwnSide.effects[PBEffects::ToxicSpikes]==2
|
||||
battler.pbPoison(nil,_INTL("{1} was badly poisoned by the poison spikes!",battler.pbThis),true)
|
||||
else
|
||||
battler.pbPoison(nil,_INTL("{1} was poisoned by the poison spikes!",battler.pbThis))
|
||||
end
|
||||
end
|
||||
end
|
||||
# Sticky Web
|
||||
if battler.pbOwnSide.effects[PBEffects::StickyWeb] && !battler.fainted? &&
|
||||
!battler.airborne?
|
||||
pbDisplay(_INTL("{1} was caught in a sticky web!",battler.pbThis))
|
||||
if battler.pbCanLowerStatStage?(:SPEED)
|
||||
battler.pbLowerStatStage(:SPEED,1,nil)
|
||||
battler.pbItemStatRestoreCheck
|
||||
end
|
||||
end
|
||||
# Battler faints if it is knocked out because of an entry hazard above
|
||||
if battler.fainted?
|
||||
battler.pbFaint
|
||||
pbGainExp
|
||||
pbJudge
|
||||
return false
|
||||
end
|
||||
battler.pbCheckForm
|
||||
return true
|
||||
end
|
||||
end
|
||||
148
Data/Scripts/011_Battle/003_Battle/007_Battle_Action_UseItem.rb
Normal file
148
Data/Scripts/011_Battle/003_Battle/007_Battle_Action_UseItem.rb
Normal file
@@ -0,0 +1,148 @@
|
||||
class PokeBattle_Battle
|
||||
#=============================================================================
|
||||
# Choosing to use an item
|
||||
#=============================================================================
|
||||
def pbCanUseItemOnPokemon?(item,pkmn,battler,scene,showMessages=true)
|
||||
if !pkmn || pkmn.egg?
|
||||
scene.pbDisplay(_INTL("It won't have any effect.")) if showMessages
|
||||
return false
|
||||
end
|
||||
# Embargo
|
||||
if battler && battler.effects[PBEffects::Embargo]>0
|
||||
scene.pbDisplay(_INTL("Embargo's effect prevents the item's use on {1}!",
|
||||
battler.pbThis(true))) if showMessages
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
# NOTE: Using a Poké Ball consumes all your actions for the round. The method
|
||||
# below is one half of making this happen; the other half is in the
|
||||
# ItemHandlers::CanUseInBattle for Poké Balls.
|
||||
def pbItemUsesAllActions?(item)
|
||||
return true if GameData::Item.get(item).is_poke_ball?
|
||||
return false
|
||||
end
|
||||
|
||||
def pbRegisterItem(idxBattler,item,idxTarget=nil,idxMove=nil)
|
||||
# Register for use of item on a Pokémon in the party
|
||||
@choices[idxBattler][0] = :UseItem
|
||||
@choices[idxBattler][1] = item # ID of item to be used
|
||||
@choices[idxBattler][2] = idxTarget # Party index of Pokémon to use item on
|
||||
@choices[idxBattler][3] = idxMove # Index of move to recharge (Ethers)
|
||||
# Delete the item from the Bag. If it turns out it will have no effect, it
|
||||
# will be re-added to the Bag later.
|
||||
pbConsumeItemInBag(item,idxBattler)
|
||||
return true
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Using an item
|
||||
#=============================================================================
|
||||
def pbConsumeItemInBag(item,idxBattler)
|
||||
return if !item
|
||||
useType = GameData::Item.get(item).battle_use
|
||||
return if useType==0 || (useType>=6 && useType<=10) # Not consumed upon use
|
||||
if pbOwnedByPlayer?(idxBattler)
|
||||
if !$PokemonBag.pbDeleteItem(item)
|
||||
raise _INTL("Tried to consume item that wasn't in the Bag somehow.")
|
||||
end
|
||||
else
|
||||
items = pbGetOwnerItems(idxBattler)
|
||||
items.each_with_index do |thisItem,i|
|
||||
next if thisItem!=item
|
||||
items[i] = nil
|
||||
break
|
||||
end
|
||||
items.compact!
|
||||
end
|
||||
end
|
||||
|
||||
def pbReturnUnusedItemToBag(item,idxBattler)
|
||||
return if item!
|
||||
useType = GameData::Item.get(item).battle_use
|
||||
return if useType==0 || (useType>=6 && useType<=10) # Not consumed upon use
|
||||
if pbOwnedByPlayer?(idxBattler)
|
||||
if $PokemonBag && $PokemonBag.pbCanStore?(item)
|
||||
$PokemonBag.pbStoreItem(item)
|
||||
else
|
||||
raise _INTL("Couldn't return unused item to Bag somehow.")
|
||||
end
|
||||
else
|
||||
items = pbGetOwnerItems(idxBattler)
|
||||
items.push(item) if items
|
||||
end
|
||||
end
|
||||
|
||||
def pbUseItemMessage(item,trainerName)
|
||||
itemName = GameData::Item.get(item).name
|
||||
if itemName.starts_with_vowel?
|
||||
pbDisplayBrief(_INTL("{1} used an {2}.",trainerName,itemName))
|
||||
else
|
||||
pbDisplayBrief(_INTL("{1} used a {2}.",trainerName,itemName))
|
||||
end
|
||||
end
|
||||
|
||||
# Uses an item on a Pokémon in the trainer's party.
|
||||
def pbUseItemOnPokemon(item,idxParty,userBattler)
|
||||
trainerName = pbGetOwnerName(userBattler.index)
|
||||
pbUseItemMessage(item,trainerName)
|
||||
pkmn = pbParty(userBattler.index)[idxParty]
|
||||
battler = pbFindBattler(idxParty,userBattler.index)
|
||||
ch = @choices[userBattler.index]
|
||||
if ItemHandlers.triggerCanUseInBattle(item,pkmn,battler,ch[3],true,self,@scene,false)
|
||||
ItemHandlers.triggerBattleUseOnPokemon(item,pkmn,battler,ch,@scene)
|
||||
ch[1] = nil # Delete item from choice
|
||||
return
|
||||
end
|
||||
pbDisplay(_INTL("But it had no effect!"))
|
||||
# Return unused item to Bag
|
||||
pbReturnUnusedItemToBag(item,userBattler.index)
|
||||
end
|
||||
|
||||
# Uses an item on a Pokémon in battle that belongs to the trainer.
|
||||
def pbUseItemOnBattler(item,idxParty,userBattler)
|
||||
trainerName = pbGetOwnerName(userBattler.index)
|
||||
pbUseItemMessage(item,trainerName)
|
||||
battler = pbFindBattler(idxParty,userBattler.index)
|
||||
ch = @choices[userBattler.index]
|
||||
if battler
|
||||
if ItemHandlers.triggerCanUseInBattle(item,battler.pokemon,battler,ch[3],true,self,@scene,false)
|
||||
ItemHandlers.triggerBattleUseOnBattler(item,battler,@scene)
|
||||
ch[1] = nil # Delete item from choice
|
||||
return
|
||||
else
|
||||
pbDisplay(_INTL("But it had no effect!"))
|
||||
end
|
||||
else
|
||||
pbDisplay(_INTL("But it's not where this item can be used!"))
|
||||
end
|
||||
# Return unused item to Bag
|
||||
pbReturnUnusedItemToBag(item,userBattler.index)
|
||||
end
|
||||
|
||||
# Uses a Poké Ball in battle directly.
|
||||
def pbUsePokeBallInBattle(item,idxBattler,userBattler)
|
||||
idxBattler = userBattler.index if idxBattler<0
|
||||
battler = @battlers[idxBattler]
|
||||
ItemHandlers.triggerUseInBattle(item,battler,self)
|
||||
@choices[userBattler.index][1] = nil # Delete item from choice
|
||||
end
|
||||
|
||||
# Uses an item in battle directly.
|
||||
def pbUseItemInBattle(item,idxBattler,userBattler)
|
||||
trainerName = pbGetOwnerName(userBattler.index)
|
||||
pbUseItemMessage(item,trainerName)
|
||||
battler = (idxBattler<0) ? userBattler : @battlers[idxBattler]
|
||||
pkmn = battler.pokemon
|
||||
ch = @choices[userBattler.index]
|
||||
if ItemHandlers.triggerCanUseInBattle(item,pkmn,battler,ch[3],true,self,@scene,false)
|
||||
ItemHandlers.triggerUseInBattle(item,battler,self)
|
||||
ch[1] = nil # Delete item from choice
|
||||
return
|
||||
end
|
||||
pbDisplay(_INTL("But it had no effect!"))
|
||||
# Return unused item to Bag
|
||||
pbReturnUnusedItemToBag(item,userBattler.index)
|
||||
end
|
||||
end
|
||||
151
Data/Scripts/011_Battle/003_Battle/008_Battle_Action_Running.rb
Normal file
151
Data/Scripts/011_Battle/003_Battle/008_Battle_Action_Running.rb
Normal file
@@ -0,0 +1,151 @@
|
||||
class PokeBattle_Battle
|
||||
#=============================================================================
|
||||
# Running from battle
|
||||
#=============================================================================
|
||||
def pbCanRun?(idxBattler)
|
||||
return false if trainerBattle?
|
||||
battler = @battlers[idxBattler]
|
||||
return false if !@canRun && !battler.opposes?
|
||||
return true if battler.pbHasType?(:GHOST) && Settings::MORE_TYPE_EFFECTS
|
||||
return true if battler.abilityActive? &&
|
||||
BattleHandlers.triggerRunFromBattleAbility(battler.ability,battler)
|
||||
return true if battler.itemActive? &&
|
||||
BattleHandlers.triggerRunFromBattleItem(battler.item,battler)
|
||||
return false if battler.effects[PBEffects::Trapping]>0 ||
|
||||
battler.effects[PBEffects::MeanLook]>=0 ||
|
||||
battler.effects[PBEffects::Ingrain] ||
|
||||
@field.effects[PBEffects::FairyLock]>0
|
||||
eachOtherSideBattler(idxBattler) do |b|
|
||||
return false if b.abilityActive? &&
|
||||
BattleHandlers.triggerTrappingTargetAbility(b.ability,battler,b,self)
|
||||
return false if b.itemActive? &&
|
||||
BattleHandlers.triggerTrappingTargetItem(b.item,battler,b,self)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
# Return values:
|
||||
# -1: Failed fleeing
|
||||
# 0: Wasn't possible to attempt fleeing, continue choosing action for the round
|
||||
# 1: Succeeded at fleeing, battle will end
|
||||
# duringBattle is true for replacing a fainted Pokémon during the End Of Round
|
||||
# phase, and false for choosing the Run command.
|
||||
def pbRun(idxBattler,duringBattle=false)
|
||||
battler = @battlers[idxBattler]
|
||||
if battler.opposes?
|
||||
return 0 if trainerBattle?
|
||||
@choices[idxBattler][0] = :Run
|
||||
@choices[idxBattler][1] = 0
|
||||
@choices[idxBattler][2] = nil
|
||||
return -1
|
||||
end
|
||||
# Fleeing from trainer battles
|
||||
if trainerBattle?
|
||||
if $DEBUG && Input.press?(Input::CTRL)
|
||||
if pbDisplayConfirm(_INTL("Treat this battle as a win?"))
|
||||
@decision = 1
|
||||
return 1
|
||||
elsif pbDisplayConfirm(_INTL("Treat this battle as a loss?"))
|
||||
@decision = 2
|
||||
return 1
|
||||
end
|
||||
elsif @internalBattle
|
||||
pbDisplayPaused(_INTL("No! There's no running from a Trainer battle!"))
|
||||
elsif pbDisplayConfirm(_INTL("Would you like to forfeit the match and quit now?"))
|
||||
pbSEPlay("Battle flee")
|
||||
pbDisplay(_INTL("{1} forfeited the match!",self.pbPlayer.name))
|
||||
@decision = 3
|
||||
return 1
|
||||
end
|
||||
return 0
|
||||
end
|
||||
# Fleeing from wild battles
|
||||
if $DEBUG && Input.press?(Input::CTRL)
|
||||
pbSEPlay("Battle flee")
|
||||
pbDisplayPaused(_INTL("You got away safely!"))
|
||||
@decision = 3
|
||||
return 1
|
||||
end
|
||||
if !@canRun
|
||||
pbDisplayPaused(_INTL("You can't escape!"))
|
||||
return 0
|
||||
end
|
||||
if !duringBattle
|
||||
if battler.pbHasType?(:GHOST) && Settings::MORE_TYPE_EFFECTS
|
||||
pbSEPlay("Battle flee")
|
||||
pbDisplayPaused(_INTL("You got away safely!"))
|
||||
@decision = 3
|
||||
return 1
|
||||
end
|
||||
# Abilities that guarantee escape
|
||||
if battler.abilityActive?
|
||||
if BattleHandlers.triggerRunFromBattleAbility(battler.ability,battler)
|
||||
pbShowAbilitySplash(battler,true)
|
||||
pbHideAbilitySplash(battler)
|
||||
pbSEPlay("Battle flee")
|
||||
pbDisplayPaused(_INTL("You got away safely!"))
|
||||
@decision = 3
|
||||
return 1
|
||||
end
|
||||
end
|
||||
# Held items that guarantee escape
|
||||
if battler.itemActive?
|
||||
if BattleHandlers.triggerRunFromBattleItem(battler.item,battler)
|
||||
pbSEPlay("Battle flee")
|
||||
pbDisplayPaused(_INTL("{1} fled using its {2}!",
|
||||
battler.pbThis,battler.itemName))
|
||||
@decision = 3
|
||||
return 1
|
||||
end
|
||||
end
|
||||
# Other certain trapping effects
|
||||
if battler.effects[PBEffects::Trapping]>0 ||
|
||||
battler.effects[PBEffects::MeanLook]>=0 ||
|
||||
battler.effects[PBEffects::Ingrain] ||
|
||||
@field.effects[PBEffects::FairyLock]>0
|
||||
pbDisplayPaused(_INTL("You can't escape!"))
|
||||
return 0
|
||||
end
|
||||
# Trapping abilities/items
|
||||
eachOtherSideBattler(idxBattler) do |b|
|
||||
next if !b.abilityActive?
|
||||
if BattleHandlers.triggerTrappingTargetAbility(b.ability,battler,b,self)
|
||||
pbDisplayPaused(_INTL("{1} prevents escape with {2}!",b.pbThis,b.abilityName))
|
||||
return 0
|
||||
end
|
||||
end
|
||||
eachOtherSideBattler(idxBattler) do |b|
|
||||
next if !b.itemActive?
|
||||
if BattleHandlers.triggerTrappingTargetItem(b.item,battler,b,self)
|
||||
pbDisplayPaused(_INTL("{1} prevents escape with {2}!",b.pbThis,b.itemName))
|
||||
return 0
|
||||
end
|
||||
end
|
||||
end
|
||||
# Fleeing calculation
|
||||
# Get the speeds of the Pokémon fleeing and the fastest opponent
|
||||
# NOTE: Not pbSpeed, because using unmodified Speed.
|
||||
@runCommand += 1 if !duringBattle # Make it easier to flee next time
|
||||
speedPlayer = @battlers[idxBattler].speed
|
||||
speedEnemy = 1
|
||||
eachOtherSideBattler(idxBattler) do |b|
|
||||
speed = b.speed
|
||||
speedEnemy = speed if speedEnemy<speed
|
||||
end
|
||||
# Compare speeds and perform fleeing calculation
|
||||
if speedPlayer>speedEnemy
|
||||
rate = 256
|
||||
else
|
||||
rate = (speedPlayer*128)/speedEnemy
|
||||
rate += @runCommand*30
|
||||
end
|
||||
if rate>=256 || @battleAI.pbAIRandom(256)<rate
|
||||
pbSEPlay("Battle flee")
|
||||
pbDisplayPaused(_INTL("You got away safely!"))
|
||||
@decision = 3
|
||||
return 1
|
||||
end
|
||||
pbDisplayPaused(_INTL("You couldn't get away!"))
|
||||
return -1
|
||||
end
|
||||
end
|
||||
189
Data/Scripts/011_Battle/003_Battle/009_Battle_Action_Other.rb
Normal file
189
Data/Scripts/011_Battle/003_Battle/009_Battle_Action_Other.rb
Normal file
@@ -0,0 +1,189 @@
|
||||
class PokeBattle_Battle
|
||||
#=============================================================================
|
||||
# Shifting a battler to another position in a battle larger than double
|
||||
#=============================================================================
|
||||
def pbCanShift?(idxBattler)
|
||||
return false if pbSideSize(0)<=2 && pbSideSize(1)<=2 # Double battle or smaller
|
||||
idxOther = -1
|
||||
case pbSideSize(idxBattler)
|
||||
when 1
|
||||
return false # Only one battler on that side
|
||||
when 2
|
||||
idxOther = (idxBattler+2)%4
|
||||
when 3
|
||||
return false if idxBattler==2 || idxBattler==3 # In middle spot already
|
||||
idxOther = ((idxBattler%2)==0) ? 2 : 3
|
||||
end
|
||||
return false if pbGetOwnerIndexFromBattlerIndex(idxBattler)!=pbGetOwnerIndexFromBattlerIndex(idxOther)
|
||||
return true
|
||||
end
|
||||
|
||||
def pbRegisterShift(idxBattler)
|
||||
@choices[idxBattler][0] = :Shift
|
||||
@choices[idxBattler][1] = 0
|
||||
@choices[idxBattler][2] = nil
|
||||
return true
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Calling at a battler
|
||||
#=============================================================================
|
||||
def pbRegisterCall(idxBattler)
|
||||
@choices[idxBattler][0] = :Call
|
||||
@choices[idxBattler][1] = 0
|
||||
@choices[idxBattler][2] = nil
|
||||
return true
|
||||
end
|
||||
|
||||
def pbCall(idxBattler)
|
||||
battler = @battlers[idxBattler]
|
||||
trainerName = pbGetOwnerName(idxBattler)
|
||||
pbDisplay(_INTL("{1} called {2}!",trainerName,battler.pbThis(true)))
|
||||
pbDisplay(_INTL("{1}!",battler.name))
|
||||
if battler.shadowPokemon?
|
||||
if battler.inHyperMode?
|
||||
battler.pokemon.hyper_mode = false
|
||||
battler.pokemon.adjustHeart(-300)
|
||||
pbDisplay(_INTL("{1} came to its senses from the Trainer's call!",battler.pbThis))
|
||||
else
|
||||
pbDisplay(_INTL("But nothing happened!"))
|
||||
end
|
||||
elsif battler.status == :SLEEP
|
||||
battler.pbCureStatus
|
||||
elsif battler.pbCanRaiseStatStage?(:ACCURACY,battler)
|
||||
battler.pbRaiseStatStage(:ACCURACY,1,battler)
|
||||
else
|
||||
pbDisplay(_INTL("But nothing happened!"))
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Choosing to Mega Evolve a battler
|
||||
#=============================================================================
|
||||
def pbHasMegaRing?(idxBattler)
|
||||
return true if !pbOwnedByPlayer?(idxBattler) # Assume AI trainer have a ring
|
||||
Settings::MEGA_RINGS.each { |item| return true if $PokemonBag.pbHasItem?(item) }
|
||||
return false
|
||||
end
|
||||
|
||||
def pbGetMegaRingName(idxBattler)
|
||||
if pbOwnedByPlayer?(idxBattler)
|
||||
Settings::MEGA_RINGS.each do |item|
|
||||
return GameData::Item.get(item).name if $PokemonBag.pbHasItem?(item)
|
||||
end
|
||||
end
|
||||
# NOTE: Add your own Mega objects for particular NPC trainers here.
|
||||
# if pbGetOwnerFromBattlerIndex(idxBattler).trainer_type == :BUGCATCHER
|
||||
# return _INTL("Mega Net")
|
||||
# end
|
||||
return _INTL("Mega Ring")
|
||||
end
|
||||
|
||||
def pbCanMegaEvolve?(idxBattler)
|
||||
return false if $game_switches[Settings::NO_MEGA_EVOLUTION]
|
||||
return false if !@battlers[idxBattler].hasMega?
|
||||
return false if wildBattle? && opposes?(idxBattler)
|
||||
return true if $DEBUG && Input.press?(Input::CTRL)
|
||||
return false if @battlers[idxBattler].effects[PBEffects::SkyDrop]>=0
|
||||
return false if !pbHasMegaRing?(idxBattler)
|
||||
side = @battlers[idxBattler].idxOwnSide
|
||||
owner = pbGetOwnerIndexFromBattlerIndex(idxBattler)
|
||||
return @megaEvolution[side][owner]==-1
|
||||
end
|
||||
|
||||
def pbRegisterMegaEvolution(idxBattler)
|
||||
side = @battlers[idxBattler].idxOwnSide
|
||||
owner = pbGetOwnerIndexFromBattlerIndex(idxBattler)
|
||||
@megaEvolution[side][owner] = idxBattler
|
||||
end
|
||||
|
||||
def pbUnregisterMegaEvolution(idxBattler)
|
||||
side = @battlers[idxBattler].idxOwnSide
|
||||
owner = pbGetOwnerIndexFromBattlerIndex(idxBattler)
|
||||
@megaEvolution[side][owner] = -1 if @megaEvolution[side][owner]==idxBattler
|
||||
end
|
||||
|
||||
def pbToggleRegisteredMegaEvolution(idxBattler)
|
||||
side = @battlers[idxBattler].idxOwnSide
|
||||
owner = pbGetOwnerIndexFromBattlerIndex(idxBattler)
|
||||
if @megaEvolution[side][owner]==idxBattler
|
||||
@megaEvolution[side][owner] = -1
|
||||
else
|
||||
@megaEvolution[side][owner] = idxBattler
|
||||
end
|
||||
end
|
||||
|
||||
def pbRegisteredMegaEvolution?(idxBattler)
|
||||
side = @battlers[idxBattler].idxOwnSide
|
||||
owner = pbGetOwnerIndexFromBattlerIndex(idxBattler)
|
||||
return @megaEvolution[side][owner]==idxBattler
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Mega Evolving a battler
|
||||
#=============================================================================
|
||||
def pbMegaEvolve(idxBattler)
|
||||
battler = @battlers[idxBattler]
|
||||
return if !battler || !battler.pokemon
|
||||
return if !battler.hasMega? || battler.mega?
|
||||
trainerName = pbGetOwnerName(idxBattler)
|
||||
# Break Illusion
|
||||
if battler.hasActiveAbility?(:ILLUSION)
|
||||
BattleHandlers.triggerTargetAbilityOnHit(battler.ability,nil,battler,nil,self)
|
||||
end
|
||||
# Mega Evolve
|
||||
case battler.pokemon.megaMessage
|
||||
when 1 # Rayquaza
|
||||
pbDisplay(_INTL("{1}'s fervent wish has reached {2}!",trainerName,battler.pbThis))
|
||||
else
|
||||
pbDisplay(_INTL("{1}'s {2} is reacting to {3}'s {4}!",
|
||||
battler.pbThis,battler.itemName,trainerName,pbGetMegaRingName(idxBattler)))
|
||||
end
|
||||
pbCommonAnimation("MegaEvolution",battler)
|
||||
battler.pokemon.makeMega
|
||||
battler.form = battler.pokemon.form
|
||||
battler.pbUpdate(true)
|
||||
@scene.pbChangePokemon(battler,battler.pokemon)
|
||||
@scene.pbRefreshOne(idxBattler)
|
||||
pbCommonAnimation("MegaEvolution2",battler)
|
||||
megaName = battler.pokemon.megaName
|
||||
if !megaName || megaName==""
|
||||
megaName = _INTL("Mega {1}", battler.pokemon.speciesName)
|
||||
end
|
||||
pbDisplay(_INTL("{1} has Mega Evolved into {2}!",battler.pbThis,megaName))
|
||||
side = battler.idxOwnSide
|
||||
owner = pbGetOwnerIndexFromBattlerIndex(idxBattler)
|
||||
@megaEvolution[side][owner] = -2
|
||||
if battler.isSpecies?(:GENGAR) && battler.mega?
|
||||
battler.effects[PBEffects::Telekinesis] = 0
|
||||
end
|
||||
pbCalculatePriority(false,[idxBattler]) if Settings::RECALCULATE_TURN_ORDER_AFTER_MEGA_EVOLUTION
|
||||
# Trigger ability
|
||||
battler.pbEffectsOnSwitchIn
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Primal Reverting a battler
|
||||
#=============================================================================
|
||||
def pbPrimalReversion(idxBattler)
|
||||
battler = @battlers[idxBattler]
|
||||
return if !battler || !battler.pokemon
|
||||
return if !battler.hasPrimal? || battler.primal?
|
||||
if battler.isSpecies?(:KYOGRE)
|
||||
pbCommonAnimation("PrimalKyogre",battler)
|
||||
elsif battler.isSpecies?(:GROUDON)
|
||||
pbCommonAnimation("PrimalGroudon",battler)
|
||||
end
|
||||
battler.pokemon.makePrimal
|
||||
battler.form = battler.pokemon.form
|
||||
battler.pbUpdate(true)
|
||||
@scene.pbChangePokemon(battler,battler.pokemon)
|
||||
@scene.pbRefreshOne(idxBattler)
|
||||
if battler.isSpecies?(:KYOGRE)
|
||||
pbCommonAnimation("PrimalKyogre2",battler)
|
||||
elsif battler.isSpecies?(:GROUDON)
|
||||
pbCommonAnimation("PrimalGroudon2",battler)
|
||||
end
|
||||
pbDisplay(_INTL("{1}'s Primal Reversion!\nIt reverted to its primal form!",battler.pbThis))
|
||||
end
|
||||
end
|
||||
250
Data/Scripts/011_Battle/003_Battle/010_Battle_Phase_Command.rb
Normal file
250
Data/Scripts/011_Battle/003_Battle/010_Battle_Phase_Command.rb
Normal file
@@ -0,0 +1,250 @@
|
||||
class PokeBattle_Battle
|
||||
#=============================================================================
|
||||
# Clear commands
|
||||
#=============================================================================
|
||||
def pbClearChoice(idxBattler)
|
||||
@choices[idxBattler] = [] if !@choices[idxBattler]
|
||||
@choices[idxBattler][0] = :None
|
||||
@choices[idxBattler][1] = 0
|
||||
@choices[idxBattler][2] = nil
|
||||
@choices[idxBattler][3] = -1
|
||||
end
|
||||
|
||||
def pbCancelChoice(idxBattler)
|
||||
# If idxBattler's choice was to use an item, return that item to the Bag
|
||||
if @choices[idxBattler][0] == :UseItem
|
||||
item = @choices[idxBattler][1]
|
||||
pbReturnUnusedItemToBag(item, idxBattler) if item
|
||||
end
|
||||
# If idxBattler chose to Mega Evolve, cancel it
|
||||
pbUnregisterMegaEvolution(idxBattler)
|
||||
# Clear idxBattler's choice
|
||||
pbClearChoice(idxBattler)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Use main command menu (Fight/Pokémon/Bag/Run)
|
||||
#=============================================================================
|
||||
def pbCommandMenu(idxBattler,firstAction)
|
||||
return @scene.pbCommandMenu(idxBattler,firstAction)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Check whether actions can be taken
|
||||
#=============================================================================
|
||||
def pbCanShowCommands?(idxBattler)
|
||||
battler = @battlers[idxBattler]
|
||||
return false if !battler || battler.fainted?
|
||||
return false if battler.usingMultiTurnAttack?
|
||||
return true
|
||||
end
|
||||
|
||||
def pbCanShowFightMenu?(idxBattler)
|
||||
battler = @battlers[idxBattler]
|
||||
# Encore
|
||||
return false if battler.effects[PBEffects::Encore]>0
|
||||
# No moves that can be chosen (will Struggle instead)
|
||||
usable = false
|
||||
battler.eachMoveWithIndex do |_m,i|
|
||||
next if !pbCanChooseMove?(idxBattler,i,false)
|
||||
usable = true
|
||||
break
|
||||
end
|
||||
return usable
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Use sub-menus to choose an action, and register it if is allowed
|
||||
#=============================================================================
|
||||
# Returns true if a choice was made, false if cancelled.
|
||||
def pbFightMenu(idxBattler)
|
||||
# Auto-use Encored move or no moves choosable, so auto-use Struggle
|
||||
return pbAutoChooseMove(idxBattler) if !pbCanShowFightMenu?(idxBattler)
|
||||
# Battle Palace only
|
||||
return true if pbAutoFightMenu(idxBattler)
|
||||
# Regular move selection
|
||||
ret = false
|
||||
@scene.pbFightMenu(idxBattler,pbCanMegaEvolve?(idxBattler)) { |cmd|
|
||||
case cmd
|
||||
when -1 # Cancel
|
||||
when -2 # Toggle Mega Evolution
|
||||
pbToggleRegisteredMegaEvolution(idxBattler)
|
||||
next false
|
||||
when -3 # Shift
|
||||
pbUnregisterMegaEvolution(idxBattler)
|
||||
pbRegisterShift(idxBattler)
|
||||
ret = true
|
||||
else # Chose a move to use
|
||||
next false if cmd<0 || !@battlers[idxBattler].moves[cmd] ||
|
||||
!@battlers[idxBattler].moves[cmd].id
|
||||
next false if !pbRegisterMove(idxBattler,cmd)
|
||||
next false if !singleBattle? &&
|
||||
!pbChooseTarget(@battlers[idxBattler],@battlers[idxBattler].moves[cmd])
|
||||
ret = true
|
||||
end
|
||||
next true
|
||||
}
|
||||
return ret
|
||||
end
|
||||
|
||||
def pbAutoFightMenu(idxBattler); return false; end
|
||||
|
||||
def pbChooseTarget(battler,move)
|
||||
target_data = move.pbTarget(battler)
|
||||
idxTarget = @scene.pbChooseTarget(battler.index,target_data)
|
||||
return false if idxTarget<0
|
||||
pbRegisterTarget(battler.index,idxTarget)
|
||||
return true
|
||||
end
|
||||
|
||||
def pbItemMenu(idxBattler,firstAction)
|
||||
if !@internalBattle
|
||||
pbDisplay(_INTL("Items can't be used here."))
|
||||
return false
|
||||
end
|
||||
ret = false
|
||||
@scene.pbItemMenu(idxBattler,firstAction) { |item,useType,idxPkmn,idxMove,itemScene|
|
||||
next false if !item
|
||||
battler = pkmn = nil
|
||||
case useType
|
||||
when 1, 2, 6, 7 # Use on Pokémon/Pokémon's move
|
||||
next false if !ItemHandlers.hasBattleUseOnPokemon(item)
|
||||
battler = pbFindBattler(idxPkmn,idxBattler)
|
||||
pkmn = pbParty(idxBattler)[idxPkmn]
|
||||
next false if !pbCanUseItemOnPokemon?(item,pkmn,battler,itemScene)
|
||||
when 3, 8 # Use on battler
|
||||
next false if !ItemHandlers.hasBattleUseOnBattler(item)
|
||||
battler = pbFindBattler(idxPkmn,idxBattler)
|
||||
pkmn = battler.pokemon if battler
|
||||
next false if !pbCanUseItemOnPokemon?(item,pkmn,battler,itemScene)
|
||||
when 4, 9 # Poké Balls
|
||||
next false if idxPkmn<0
|
||||
battler = @battlers[idxPkmn]
|
||||
pkmn = battler.pokemon if battler
|
||||
when 5, 10 # No target (Poké Doll, Guard Spec., Launcher items)
|
||||
battler = @battlers[idxBattler]
|
||||
pkmn = battler.pokemon if battler
|
||||
else
|
||||
next false
|
||||
end
|
||||
next false if !pkmn
|
||||
next false if !ItemHandlers.triggerCanUseInBattle(item,
|
||||
pkmn,battler,idxMove,firstAction,self,itemScene)
|
||||
next false if !pbRegisterItem(idxBattler,item,idxPkmn,idxMove)
|
||||
ret = true
|
||||
next true
|
||||
}
|
||||
return ret
|
||||
end
|
||||
|
||||
def pbPartyMenu(idxBattler)
|
||||
ret = -1
|
||||
if @debug
|
||||
ret = @battleAI.pbDefaultChooseNewEnemy(idxBattler,pbParty(idxBattler))
|
||||
else
|
||||
ret = pbPartyScreen(idxBattler,false,true,true)
|
||||
end
|
||||
return ret>=0
|
||||
end
|
||||
|
||||
def pbRunMenu(idxBattler)
|
||||
# Regardless of succeeding or failing to run, stop choosing actions
|
||||
return pbRun(idxBattler)!=0
|
||||
end
|
||||
|
||||
def pbCallMenu(idxBattler)
|
||||
return pbRegisterCall(idxBattler)
|
||||
end
|
||||
|
||||
def pbDebugMenu
|
||||
# NOTE: This doesn't do anything yet. Maybe you can write your own debugging
|
||||
# options!
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Command phase
|
||||
#=============================================================================
|
||||
def pbCommandPhase
|
||||
@scene.pbBeginCommandPhase
|
||||
# Reset choices if commands can be shown
|
||||
@battlers.each_with_index do |b,i|
|
||||
next if !b
|
||||
pbClearChoice(i) if pbCanShowCommands?(i)
|
||||
end
|
||||
# Reset choices to perform Mega Evolution if it wasn't done somehow
|
||||
for side in 0...2
|
||||
@megaEvolution[side].each_with_index do |megaEvo,i|
|
||||
@megaEvolution[side][i] = -1 if megaEvo>=0
|
||||
end
|
||||
end
|
||||
# Choose actions for the round (player first, then AI)
|
||||
pbCommandPhaseLoop(true) # Player chooses their actions
|
||||
return if @decision!=0 # Battle ended, stop choosing actions
|
||||
pbCommandPhaseLoop(false) # AI chooses their actions
|
||||
end
|
||||
|
||||
def pbCommandPhaseLoop(isPlayer)
|
||||
# NOTE: Doing some things (e.g. running, throwing a Poké Ball) takes up all
|
||||
# your actions in a round.
|
||||
actioned = []
|
||||
idxBattler = -1
|
||||
loop do
|
||||
break if @decision!=0 # Battle ended, stop choosing actions
|
||||
idxBattler += 1
|
||||
break if idxBattler>=@battlers.length
|
||||
next if !@battlers[idxBattler] || pbOwnedByPlayer?(idxBattler)!=isPlayer
|
||||
next if @choices[idxBattler][0]!=:None # Action is forced, can't choose one
|
||||
next if !pbCanShowCommands?(idxBattler) # Action is forced, can't choose one
|
||||
# AI controls this battler
|
||||
if @controlPlayer || !pbOwnedByPlayer?(idxBattler)
|
||||
@battleAI.pbDefaultChooseEnemyCommand(idxBattler)
|
||||
next
|
||||
end
|
||||
# Player chooses an action
|
||||
actioned.push(idxBattler)
|
||||
commandsEnd = false # Whether to cancel choosing all other actions this round
|
||||
loop do
|
||||
cmd = pbCommandMenu(idxBattler,actioned.length==1)
|
||||
# If being Sky Dropped, can't do anything except use a move
|
||||
if cmd>0 && @battlers[idxBattler].effects[PBEffects::SkyDrop]>=0
|
||||
pbDisplay(_INTL("Sky Drop won't let {1} go!",@battlers[idxBattler].pbThis(true)))
|
||||
next
|
||||
end
|
||||
case cmd
|
||||
when 0 # Fight
|
||||
break if pbFightMenu(idxBattler)
|
||||
when 1 # Bag
|
||||
if pbItemMenu(idxBattler,actioned.length==1)
|
||||
commandsEnd = true if pbItemUsesAllActions?(@choices[idxBattler][1])
|
||||
break
|
||||
end
|
||||
when 2 # Pokémon
|
||||
break if pbPartyMenu(idxBattler)
|
||||
when 3 # Run
|
||||
# NOTE: "Run" is only an available option for the first battler the
|
||||
# player chooses an action for in a round. Attempting to run
|
||||
# from battle prevents you from choosing any other actions in
|
||||
# that round.
|
||||
if pbRunMenu(idxBattler)
|
||||
commandsEnd = true
|
||||
break
|
||||
end
|
||||
when 4 # Call
|
||||
break if pbCallMenu(idxBattler)
|
||||
when -2 # Debug
|
||||
pbDebugMenu
|
||||
next
|
||||
when -1 # Go back to previous battler's action choice
|
||||
next if actioned.length<=1
|
||||
actioned.pop # Forget this battler was done
|
||||
idxBattler = actioned.last-1
|
||||
pbCancelChoice(idxBattler+1) # Clear the previous battler's choice
|
||||
actioned.pop # Forget the previous battler was done
|
||||
break
|
||||
end
|
||||
pbCancelChoice(idxBattler)
|
||||
end
|
||||
break if commandsEnd
|
||||
end
|
||||
end
|
||||
end
|
||||
190
Data/Scripts/011_Battle/003_Battle/011_Battle_Phase_Attack.rb
Normal file
190
Data/Scripts/011_Battle/003_Battle/011_Battle_Phase_Attack.rb
Normal file
@@ -0,0 +1,190 @@
|
||||
class PokeBattle_Battle
|
||||
#=============================================================================
|
||||
# Attack phase actions
|
||||
#=============================================================================
|
||||
# Quick Claw, Custap Berry's "X let it move first!" message.
|
||||
def pbAttackPhasePriorityChangeMessages
|
||||
pbPriority.each do |b|
|
||||
if b.effects[PBEffects::PriorityAbility] && b.abilityActive?
|
||||
BattleHandlers.triggerPriorityBracketUseAbility(b.ability,b,self)
|
||||
elsif b.effects[PBEffects::PriorityItem] && b.itemActive?
|
||||
BattleHandlers.triggerPriorityBracketUseItem(b.item,b,self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbAttackPhaseCall
|
||||
pbPriority.each do |b|
|
||||
next unless @choices[b.index][0]==:Call && !b.fainted?
|
||||
b.lastMoveFailed = false # Counts as a successful move for Stomping Tantrum
|
||||
pbCall(b.index)
|
||||
end
|
||||
end
|
||||
|
||||
def pbPursuit(idxSwitcher)
|
||||
@switching = true
|
||||
pbPriority.each do |b|
|
||||
next if b.fainted? || !b.opposes?(idxSwitcher) # Shouldn't hit an ally
|
||||
next if b.movedThisRound? || !pbChoseMoveFunctionCode?(b.index,"088") # Pursuit
|
||||
# Check whether Pursuit can be used
|
||||
next unless pbMoveCanTarget?(b.index,idxSwitcher,@choices[b.index][2].pbTarget(b))
|
||||
next unless pbCanChooseMove?(b.index,@choices[b.index][1],false)
|
||||
next if b.status == :SLEEP || b.status == :FROZEN
|
||||
next if b.effects[PBEffects::SkyDrop]>=0
|
||||
next if b.hasActiveAbility?(:TRUANT) && b.effects[PBEffects::Truant]
|
||||
# Mega Evolve
|
||||
if !wildBattle? || !b.opposes?
|
||||
owner = pbGetOwnerIndexFromBattlerIndex(b.index)
|
||||
pbMegaEvolve(b.index) if @megaEvolution[b.idxOwnSide][owner]==b.index
|
||||
end
|
||||
# Use Pursuit
|
||||
@choices[b.index][3] = idxSwitcher # Change Pursuit's target
|
||||
if b.pbProcessTurn(@choices[b.index],false)
|
||||
b.effects[PBEffects::Pursuit] = true
|
||||
end
|
||||
break if @decision>0 || @battlers[idxSwitcher].fainted?
|
||||
end
|
||||
@switching = false
|
||||
end
|
||||
|
||||
def pbAttackPhaseSwitch
|
||||
pbPriority.each do |b|
|
||||
next unless @choices[b.index][0]==:SwitchOut && !b.fainted?
|
||||
idxNewPkmn = @choices[b.index][1] # Party index of Pokémon to switch to
|
||||
b.lastMoveFailed = false # Counts as a successful move for Stomping Tantrum
|
||||
@lastMoveUser = b.index
|
||||
# Switching message
|
||||
pbMessageOnRecall(b)
|
||||
# Pursuit interrupts switching
|
||||
pbPursuit(b.index)
|
||||
return if @decision>0
|
||||
# Switch Pokémon
|
||||
pbRecallAndReplace(b.index,idxNewPkmn)
|
||||
b.pbEffectsOnSwitchIn(true)
|
||||
end
|
||||
end
|
||||
|
||||
def pbAttackPhaseItems
|
||||
pbPriority.each do |b|
|
||||
next unless @choices[b.index][0] == :UseItem && !b.fainted?
|
||||
b.lastMoveFailed = false # Counts as a successful move for Stomping Tantrum
|
||||
item = @choices[b.index][1]
|
||||
next if !item
|
||||
case GameData::Item.get(item).battle_use
|
||||
when 1, 2, 6, 7 # Use on Pokémon/Pokémon's move
|
||||
pbUseItemOnPokemon(item, @choices[b.index][2], b) if @choices[b.index][2] >= 0
|
||||
when 3, 8 # Use on battler
|
||||
pbUseItemOnBattler(item, @choices[b.index][2], b)
|
||||
when 4, 9 # Use Poké Ball
|
||||
pbUsePokeBallInBattle(item, @choices[b.index][2], b)
|
||||
when 5, 10 # Use directly
|
||||
pbUseItemInBattle(item, @choices[b.index][2], b)
|
||||
else
|
||||
next
|
||||
end
|
||||
return if @decision > 0
|
||||
end
|
||||
pbCalculatePriority if Settings::RECALCULATE_TURN_ORDER_AFTER_SPEED_CHANGES
|
||||
end
|
||||
|
||||
def pbAttackPhaseMegaEvolution
|
||||
pbPriority.each do |b|
|
||||
next if wildBattle? && b.opposes?
|
||||
next unless @choices[b.index][0]==:UseMove && !b.fainted?
|
||||
owner = pbGetOwnerIndexFromBattlerIndex(b.index)
|
||||
next if @megaEvolution[b.idxOwnSide][owner]!=b.index
|
||||
pbMegaEvolve(b.index)
|
||||
end
|
||||
end
|
||||
|
||||
def pbAttackPhaseMoves
|
||||
# Show charging messages (Focus Punch)
|
||||
pbPriority.each do |b|
|
||||
next unless @choices[b.index][0]==:UseMove && !b.fainted?
|
||||
next if b.movedThisRound?
|
||||
@choices[b.index][2].pbDisplayChargeMessage(b)
|
||||
end
|
||||
# Main move processing loop
|
||||
loop do
|
||||
priority = pbPriority
|
||||
# Forced to go next
|
||||
advance = false
|
||||
priority.each do |b|
|
||||
next unless b.effects[PBEffects::MoveNext] && !b.fainted?
|
||||
next unless @choices[b.index][0]==:UseMove || @choices[b.index][0]==:Shift
|
||||
next if b.movedThisRound?
|
||||
advance = b.pbProcessTurn(@choices[b.index])
|
||||
break if advance
|
||||
end
|
||||
return if @decision>0
|
||||
next if advance
|
||||
# Regular priority order
|
||||
priority.each do |b|
|
||||
next if b.effects[PBEffects::Quash]>0 || b.fainted?
|
||||
next unless @choices[b.index][0]==:UseMove || @choices[b.index][0]==:Shift
|
||||
next if b.movedThisRound?
|
||||
advance = b.pbProcessTurn(@choices[b.index])
|
||||
break if advance
|
||||
end
|
||||
return if @decision>0
|
||||
next if advance
|
||||
# Quashed
|
||||
quashLevel = 0
|
||||
loop do
|
||||
quashLevel += 1
|
||||
moreQuash = false
|
||||
priority.each do |b|
|
||||
moreQuash = true if b.effects[PBEffects::Quash]>quashLevel
|
||||
next unless b.effects[PBEffects::Quash]==quashLevel && !b.fainted?
|
||||
next unless @choices[b.index][0]==:UseMove || @choices[b.index][0]==:Shift
|
||||
next if b.movedThisRound?
|
||||
advance = b.pbProcessTurn(@choices[b.index])
|
||||
break
|
||||
end
|
||||
break if advance || !moreQuash
|
||||
end
|
||||
return if @decision>0
|
||||
next if advance
|
||||
# Check for all done
|
||||
priority.each do |b|
|
||||
if !b.fainted? && !b.movedThisRound?
|
||||
advance = true if @choices[b.index][0]==:UseMove || @choices[b.index][0]==:Shift
|
||||
end
|
||||
break if advance
|
||||
end
|
||||
next if advance
|
||||
# All Pokémon have moved; end the loop
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Attack phase
|
||||
#=============================================================================
|
||||
def pbAttackPhase
|
||||
@scene.pbBeginAttackPhase
|
||||
# Reset certain effects
|
||||
@battlers.each_with_index do |b,i|
|
||||
next if !b
|
||||
b.turnCount += 1 if !b.fainted?
|
||||
@successStates[i].clear
|
||||
if @choices[i][0]!=:UseMove && @choices[i][0]!=:Shift && @choices[i][0]!=:SwitchOut
|
||||
b.effects[PBEffects::DestinyBond] = false
|
||||
b.effects[PBEffects::Grudge] = false
|
||||
end
|
||||
b.effects[PBEffects::Rage] = false if !pbChoseMoveFunctionCode?(i,"093") # Rage
|
||||
end
|
||||
PBDebug.log("")
|
||||
# Calculate move order for this round
|
||||
pbCalculatePriority(true)
|
||||
# Perform actions
|
||||
pbAttackPhasePriorityChangeMessages
|
||||
pbAttackPhaseCall
|
||||
pbAttackPhaseSwitch
|
||||
return if @decision>0
|
||||
pbAttackPhaseItems
|
||||
return if @decision>0
|
||||
pbAttackPhaseMegaEvolution
|
||||
pbAttackPhaseMoves
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,666 @@
|
||||
class PokeBattle_Battle
|
||||
#=============================================================================
|
||||
# Decrement effect counters
|
||||
#=============================================================================
|
||||
def pbEORCountDownBattlerEffect(priority,effect)
|
||||
priority.each do |b|
|
||||
next if b.fainted? || b.effects[effect]==0
|
||||
b.effects[effect] -= 1
|
||||
yield b if block_given? && b.effects[effect]==0
|
||||
end
|
||||
end
|
||||
|
||||
def pbEORCountDownSideEffect(side,effect,msg)
|
||||
if @sides[side].effects[effect]>0
|
||||
@sides[side].effects[effect] -= 1
|
||||
pbDisplay(msg) if @sides[side].effects[effect]==0
|
||||
end
|
||||
end
|
||||
|
||||
def pbEORCountDownFieldEffect(effect,msg)
|
||||
if @field.effects[effect]>0
|
||||
@field.effects[effect] -= 1
|
||||
if @field.effects[effect]==0
|
||||
pbDisplay(msg)
|
||||
if effect==PBEffects::MagicRoom
|
||||
pbPriority(true).each { |b| b.pbItemTerrainStatBoostCheck }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# End Of Round weather
|
||||
#=============================================================================
|
||||
def pbEORWeather(priority)
|
||||
# NOTE: Primordial weather doesn't need to be checked here, because if it
|
||||
# could wear off here, it will have worn off already.
|
||||
# Count down weather duration
|
||||
@field.weatherDuration -= 1 if @field.weatherDuration>0
|
||||
# Weather wears off
|
||||
if @field.weatherDuration==0
|
||||
case @field.weather
|
||||
when :Sun then pbDisplay(_INTL("The sunlight faded."))
|
||||
when :Rain then pbDisplay(_INTL("The rain stopped."))
|
||||
when :Sandstorm then pbDisplay(_INTL("The sandstorm subsided."))
|
||||
when :Hail then pbDisplay(_INTL("The hail stopped."))
|
||||
when :ShadowSky then pbDisplay(_INTL("The shadow sky faded."))
|
||||
end
|
||||
@field.weather = :None
|
||||
# Check for form changes caused by the weather changing
|
||||
eachBattler { |b| b.pbCheckFormOnWeatherChange }
|
||||
# Start up the default weather
|
||||
pbStartWeather(nil,@field.defaultWeather) if @field.defaultWeather != :None
|
||||
return if @field.weather == :None
|
||||
end
|
||||
# Weather continues
|
||||
weather_data = GameData::BattleWeather.try_get(@field.weather)
|
||||
pbCommonAnimation(weather_data.animation) if weather_data
|
||||
case @field.weather
|
||||
# when :Sun then pbDisplay(_INTL("The sunlight is strong."))
|
||||
# when :Rain then pbDisplay(_INTL("Rain continues to fall."))
|
||||
when :Sandstorm then pbDisplay(_INTL("The sandstorm is raging."))
|
||||
when :Hail then pbDisplay(_INTL("The hail is crashing down."))
|
||||
# when :HarshSun then pbDisplay(_INTL("The sunlight is extremely harsh."))
|
||||
# when :HeavyRain then pbDisplay(_INTL("It is raining heavily."))
|
||||
# when :StrongWinds then pbDisplay(_INTL("The wind is strong."))
|
||||
when :ShadowSky then pbDisplay(_INTL("The shadow sky continues."))
|
||||
end
|
||||
# Effects due to weather
|
||||
curWeather = pbWeather
|
||||
priority.each do |b|
|
||||
# Weather-related abilities
|
||||
if b.abilityActive?
|
||||
BattleHandlers.triggerEORWeatherAbility(b.ability,curWeather,b,self)
|
||||
b.pbFaint if b.fainted?
|
||||
end
|
||||
# Weather damage
|
||||
# NOTE:
|
||||
case curWeather
|
||||
when :Sandstorm
|
||||
next if !b.takesSandstormDamage?
|
||||
pbDisplay(_INTL("{1} is buffeted by the sandstorm!",b.pbThis))
|
||||
@scene.pbDamageAnimation(b)
|
||||
b.pbReduceHP(b.totalhp/16,false)
|
||||
b.pbItemHPHealCheck
|
||||
b.pbFaint if b.fainted?
|
||||
when :Hail
|
||||
next if !b.takesHailDamage?
|
||||
pbDisplay(_INTL("{1} is buffeted by the hail!",b.pbThis))
|
||||
@scene.pbDamageAnimation(b)
|
||||
b.pbReduceHP(b.totalhp/16,false)
|
||||
b.pbItemHPHealCheck
|
||||
b.pbFaint if b.fainted?
|
||||
when :ShadowSky
|
||||
next if !b.takesShadowSkyDamage?
|
||||
pbDisplay(_INTL("{1} is hurt by the shadow sky!",b.pbThis))
|
||||
@scene.pbDamageAnimation(b)
|
||||
b.pbReduceHP(b.totalhp/16,false)
|
||||
b.pbItemHPHealCheck
|
||||
b.pbFaint if b.fainted?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# End Of Round terrain
|
||||
#=============================================================================
|
||||
def pbEORTerrain
|
||||
# Count down terrain duration
|
||||
@field.terrainDuration -= 1 if @field.terrainDuration>0
|
||||
# Terrain wears off
|
||||
if @field.terrain != :None && @field.terrainDuration == 0
|
||||
case @field.terrain
|
||||
when :Electric
|
||||
pbDisplay(_INTL("The electric current disappeared from the battlefield!"))
|
||||
when :Grassy
|
||||
pbDisplay(_INTL("The grass disappeared from the battlefield!"))
|
||||
when :Misty
|
||||
pbDisplay(_INTL("The mist disappeared from the battlefield!"))
|
||||
when :Psychic
|
||||
pbDisplay(_INTL("The weirdness disappeared from the battlefield!"))
|
||||
end
|
||||
@field.terrain = :None
|
||||
# Start up the default terrain
|
||||
pbStartTerrain(nil, @field.defaultTerrain, false) if @field.defaultTerrain != :None
|
||||
return if @field.terrain == :None
|
||||
end
|
||||
# Terrain continues
|
||||
terrain_data = GameData::BattleTerrain.try_get(@field.terrain)
|
||||
pbCommonAnimation(terrain_data.animation) if terrain_data
|
||||
case @field.terrain
|
||||
when :Electric then pbDisplay(_INTL("An electric current is running across the battlefield."))
|
||||
when :Grassy then pbDisplay(_INTL("Grass is covering the battlefield."))
|
||||
when :Misty then pbDisplay(_INTL("Mist is swirling about the battlefield."))
|
||||
when :Psychic then pbDisplay(_INTL("The battlefield is weird."))
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# End Of Round shift distant battlers to middle positions
|
||||
#=============================================================================
|
||||
def pbEORShiftDistantBattlers
|
||||
# Move battlers around if none are near to each other
|
||||
# NOTE: This code assumes each side has a maximum of 3 battlers on it, and
|
||||
# is not generalised to larger side sizes.
|
||||
if !singleBattle?
|
||||
swaps = [] # Each element is an array of two battler indices to swap
|
||||
for side in 0...2
|
||||
next if pbSideSize(side)==1 # Only battlers on sides of size 2+ need to move
|
||||
# Check if any battler on this side is near any battler on the other side
|
||||
anyNear = false
|
||||
eachSameSideBattler(side) do |b|
|
||||
eachOtherSideBattler(b) do |otherB|
|
||||
next if !nearBattlers?(otherB.index,b.index)
|
||||
anyNear = true
|
||||
break
|
||||
end
|
||||
break if anyNear
|
||||
end
|
||||
break if anyNear
|
||||
# No battlers on this side are near any battlers on the other side; try
|
||||
# to move them
|
||||
# NOTE: If we get to here (assuming both sides are of size 3 or less),
|
||||
# there is definitely only 1 able battler on this side, so we
|
||||
# don't need to worry about multiple battlers trying to move into
|
||||
# the same position. If you add support for a side of size 4+,
|
||||
# this code will need revising to account for that, as well as to
|
||||
# add more complex code to ensure battlers will end up near each
|
||||
# other.
|
||||
eachSameSideBattler(side) do |b|
|
||||
# Get the position to move to
|
||||
pos = -1
|
||||
case pbSideSize(side)
|
||||
when 2 then pos = [2,3,0,1][b.index] # The unoccupied position
|
||||
when 3 then pos = (side==0) ? 2 : 3 # The centre position
|
||||
end
|
||||
next if pos<0
|
||||
# Can't move if the same trainer doesn't control both positions
|
||||
idxOwner = pbGetOwnerIndexFromBattlerIndex(b.index)
|
||||
next if pbGetOwnerIndexFromBattlerIndex(pos)!=idxOwner
|
||||
swaps.push([b.index,pos])
|
||||
end
|
||||
end
|
||||
# Move battlers around
|
||||
swaps.each do |pair|
|
||||
next if pbSideSize(pair[0])==2 && swaps.length>1
|
||||
next if !pbSwapBattlers(pair[0],pair[1])
|
||||
case pbSideSize(side)
|
||||
when 2
|
||||
pbDisplay(_INTL("{1} moved across!",@battlers[pair[1]].pbThis))
|
||||
when 3
|
||||
pbDisplay(_INTL("{1} moved to the center!",@battlers[pair[1]].pbThis))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# End Of Round phase
|
||||
#=============================================================================
|
||||
def pbEndOfRoundPhase
|
||||
PBDebug.log("")
|
||||
PBDebug.log("[End of round]")
|
||||
@endOfRound = true
|
||||
@scene.pbBeginEndOfRoundPhase
|
||||
pbCalculatePriority # recalculate speeds
|
||||
priority = pbPriority(true) # in order of fastest -> slowest speeds only
|
||||
# Weather
|
||||
pbEORWeather(priority)
|
||||
# Future Sight/Doom Desire
|
||||
@positions.each_with_index do |pos,idxPos|
|
||||
next if !pos || pos.effects[PBEffects::FutureSightCounter]==0
|
||||
pos.effects[PBEffects::FutureSightCounter] -= 1
|
||||
next if pos.effects[PBEffects::FutureSightCounter]>0
|
||||
next if !@battlers[idxPos] || @battlers[idxPos].fainted? # No target
|
||||
moveUser = nil
|
||||
eachBattler do |b|
|
||||
next if b.opposes?(pos.effects[PBEffects::FutureSightUserIndex])
|
||||
next if b.pokemonIndex!=pos.effects[PBEffects::FutureSightUserPartyIndex]
|
||||
moveUser = b
|
||||
break
|
||||
end
|
||||
next if moveUser && moveUser.index==idxPos # Target is the user
|
||||
if !moveUser # User isn't in battle, get it from the party
|
||||
party = pbParty(pos.effects[PBEffects::FutureSightUserIndex])
|
||||
pkmn = party[pos.effects[PBEffects::FutureSightUserPartyIndex]]
|
||||
if pkmn && pkmn.able?
|
||||
moveUser = PokeBattle_Battler.new(self,pos.effects[PBEffects::FutureSightUserIndex])
|
||||
moveUser.pbInitDummyPokemon(pkmn,pos.effects[PBEffects::FutureSightUserPartyIndex])
|
||||
end
|
||||
end
|
||||
next if !moveUser # User is fainted
|
||||
move = pos.effects[PBEffects::FutureSightMove]
|
||||
pbDisplay(_INTL("{1} took the {2} attack!",@battlers[idxPos].pbThis,
|
||||
GameData::Move.get(move).name))
|
||||
# NOTE: Future Sight failing against the target here doesn't count towards
|
||||
# Stomping Tantrum.
|
||||
userLastMoveFailed = moveUser.lastMoveFailed
|
||||
@futureSight = true
|
||||
moveUser.pbUseMoveSimple(move,idxPos)
|
||||
@futureSight = false
|
||||
moveUser.lastMoveFailed = userLastMoveFailed
|
||||
@battlers[idxPos].pbFaint if @battlers[idxPos].fainted?
|
||||
pos.effects[PBEffects::FutureSightCounter] = 0
|
||||
pos.effects[PBEffects::FutureSightMove] = nil
|
||||
pos.effects[PBEffects::FutureSightUserIndex] = -1
|
||||
pos.effects[PBEffects::FutureSightUserPartyIndex] = -1
|
||||
end
|
||||
# Wish
|
||||
@positions.each_with_index do |pos,idxPos|
|
||||
next if !pos || pos.effects[PBEffects::Wish]==0
|
||||
pos.effects[PBEffects::Wish] -= 1
|
||||
next if pos.effects[PBEffects::Wish]>0
|
||||
next if !@battlers[idxPos] || !@battlers[idxPos].canHeal?
|
||||
wishMaker = pbThisEx(idxPos,pos.effects[PBEffects::WishMaker])
|
||||
@battlers[idxPos].pbRecoverHP(pos.effects[PBEffects::WishAmount])
|
||||
pbDisplay(_INTL("{1}'s wish came true!",wishMaker))
|
||||
end
|
||||
# Sea of Fire damage (Fire Pledge + Grass Pledge combination)
|
||||
curWeather = pbWeather
|
||||
for side in 0...2
|
||||
next if sides[side].effects[PBEffects::SeaOfFire]==0
|
||||
next if [:Rain, :HeavyRain].include?(curWeather)
|
||||
@battle.pbCommonAnimation("SeaOfFire") if side==0
|
||||
@battle.pbCommonAnimation("SeaOfFireOpp") if side==1
|
||||
priority.each do |b|
|
||||
next if b.opposes?(side)
|
||||
next if !b.takesIndirectDamage? || b.pbHasType?(:FIRE)
|
||||
oldHP = b.hp
|
||||
@scene.pbDamageAnimation(b)
|
||||
b.pbReduceHP(b.totalhp/8,false)
|
||||
pbDisplay(_INTL("{1} is hurt by the sea of fire!",b.pbThis))
|
||||
b.pbItemHPHealCheck
|
||||
b.pbAbilitiesOnDamageTaken(oldHP)
|
||||
b.pbFaint if b.fainted?
|
||||
end
|
||||
end
|
||||
# Status-curing effects/abilities and HP-healing items
|
||||
priority.each do |b|
|
||||
next if b.fainted?
|
||||
# Grassy Terrain (healing)
|
||||
if @field.terrain == :Grassy && b.affectedByTerrain? && b.canHeal?
|
||||
PBDebug.log("[Lingering effect] Grassy Terrain heals #{b.pbThis(true)}")
|
||||
b.pbRecoverHP(b.totalhp/16)
|
||||
pbDisplay(_INTL("{1}'s HP was restored.",b.pbThis))
|
||||
end
|
||||
# Healer, Hydration, Shed Skin
|
||||
BattleHandlers.triggerEORHealingAbility(b.ability,b,self) if b.abilityActive?
|
||||
# Black Sludge, Leftovers
|
||||
BattleHandlers.triggerEORHealingItem(b.item,b,self) if b.itemActive?
|
||||
end
|
||||
# Aqua Ring
|
||||
priority.each do |b|
|
||||
next if !b.effects[PBEffects::AquaRing]
|
||||
next if !b.canHeal?
|
||||
hpGain = b.totalhp/16
|
||||
hpGain = (hpGain*1.3).floor if b.hasActiveItem?(:BIGROOT)
|
||||
b.pbRecoverHP(hpGain)
|
||||
pbDisplay(_INTL("Aqua Ring restored {1}'s HP!",b.pbThis(true)))
|
||||
end
|
||||
# Ingrain
|
||||
priority.each do |b|
|
||||
next if !b.effects[PBEffects::Ingrain]
|
||||
next if !b.canHeal?
|
||||
hpGain = b.totalhp/16
|
||||
hpGain = (hpGain*1.3).floor if b.hasActiveItem?(:BIGROOT)
|
||||
b.pbRecoverHP(hpGain)
|
||||
pbDisplay(_INTL("{1} absorbed nutrients with its roots!",b.pbThis))
|
||||
end
|
||||
# Leech Seed
|
||||
priority.each do |b|
|
||||
next if b.effects[PBEffects::LeechSeed]<0
|
||||
next if !b.takesIndirectDamage?
|
||||
recipient = @battlers[b.effects[PBEffects::LeechSeed]]
|
||||
next if !recipient || recipient.fainted?
|
||||
oldHP = b.hp
|
||||
oldHPRecipient = recipient.hp
|
||||
pbCommonAnimation("LeechSeed",recipient,b)
|
||||
hpLoss = b.pbReduceHP(b.totalhp/8)
|
||||
recipient.pbRecoverHPFromDrain(hpLoss,b,
|
||||
_INTL("{1}'s health is sapped by Leech Seed!",b.pbThis))
|
||||
recipient.pbAbilitiesOnDamageTaken(oldHPRecipient) if recipient.hp<oldHPRecipient
|
||||
b.pbItemHPHealCheck
|
||||
b.pbAbilitiesOnDamageTaken(oldHP)
|
||||
b.pbFaint if b.fainted?
|
||||
recipient.pbFaint if recipient.fainted?
|
||||
end
|
||||
# Damage from Hyper Mode (Shadow Pokémon)
|
||||
priority.each do |b|
|
||||
next if !b.inHyperMode? || @choices[b.index][0]!=:UseMove
|
||||
hpLoss = b.totalhp/24
|
||||
@scene.pbDamageAnimation(b)
|
||||
b.pbReduceHP(hpLoss,false)
|
||||
pbDisplay(_INTL("The Hyper Mode attack hurts {1}!",b.pbThis(true)))
|
||||
b.pbFaint if b.fainted?
|
||||
end
|
||||
# Damage from poisoning
|
||||
priority.each do |b|
|
||||
next if b.fainted?
|
||||
next if b.status != :POISON
|
||||
if b.statusCount>0
|
||||
b.effects[PBEffects::Toxic] += 1
|
||||
b.effects[PBEffects::Toxic] = 15 if b.effects[PBEffects::Toxic]>15
|
||||
end
|
||||
if b.hasActiveAbility?(:POISONHEAL)
|
||||
if b.canHeal?
|
||||
anim_name = GameData::Status.get(:POISON).animation
|
||||
pbCommonAnimation(anim_name, b) if anim_name
|
||||
pbShowAbilitySplash(b)
|
||||
b.pbRecoverHP(b.totalhp/8)
|
||||
if PokeBattle_SceneConstants::USE_ABILITY_SPLASH
|
||||
pbDisplay(_INTL("{1}'s HP was restored.",b.pbThis))
|
||||
else
|
||||
pbDisplay(_INTL("{1}'s {2} restored its HP.",b.pbThis,b.abilityName))
|
||||
end
|
||||
pbHideAbilitySplash(b)
|
||||
end
|
||||
elsif b.takesIndirectDamage?
|
||||
oldHP = b.hp
|
||||
dmg = (b.statusCount==0) ? b.totalhp/8 : b.totalhp*b.effects[PBEffects::Toxic]/16
|
||||
b.pbContinueStatus { b.pbReduceHP(dmg,false) }
|
||||
b.pbItemHPHealCheck
|
||||
b.pbAbilitiesOnDamageTaken(oldHP)
|
||||
b.pbFaint if b.fainted?
|
||||
end
|
||||
end
|
||||
# Damage from burn
|
||||
priority.each do |b|
|
||||
next if b.status != :BURN || !b.takesIndirectDamage?
|
||||
oldHP = b.hp
|
||||
dmg = (Settings::MECHANICS_GENERATION >= 7) ? b.totalhp/16 : b.totalhp/8
|
||||
dmg = (dmg/2.0).round if b.hasActiveAbility?(:HEATPROOF)
|
||||
b.pbContinueStatus { b.pbReduceHP(dmg,false) }
|
||||
b.pbItemHPHealCheck
|
||||
b.pbAbilitiesOnDamageTaken(oldHP)
|
||||
b.pbFaint if b.fainted?
|
||||
end
|
||||
# Damage from sleep (Nightmare)
|
||||
priority.each do |b|
|
||||
b.effects[PBEffects::Nightmare] = false if !b.asleep?
|
||||
next if !b.effects[PBEffects::Nightmare] || !b.takesIndirectDamage?
|
||||
oldHP = b.hp
|
||||
b.pbReduceHP(b.totalhp/4)
|
||||
pbDisplay(_INTL("{1} is locked in a nightmare!",b.pbThis))
|
||||
b.pbItemHPHealCheck
|
||||
b.pbAbilitiesOnDamageTaken(oldHP)
|
||||
b.pbFaint if b.fainted?
|
||||
end
|
||||
# Curse
|
||||
priority.each do |b|
|
||||
next if !b.effects[PBEffects::Curse] || !b.takesIndirectDamage?
|
||||
oldHP = b.hp
|
||||
b.pbReduceHP(b.totalhp/4)
|
||||
pbDisplay(_INTL("{1} is afflicted by the curse!",b.pbThis))
|
||||
b.pbItemHPHealCheck
|
||||
b.pbAbilitiesOnDamageTaken(oldHP)
|
||||
b.pbFaint if b.fainted?
|
||||
end
|
||||
# Trapping attacks (Bind/Clamp/Fire Spin/Magma Storm/Sand Tomb/Whirlpool/Wrap)
|
||||
priority.each do |b|
|
||||
next if b.fainted? || b.effects[PBEffects::Trapping]==0
|
||||
b.effects[PBEffects::Trapping] -= 1
|
||||
moveName = GameData::Move.get(b.effects[PBEffects::TrappingMove]).name
|
||||
if b.effects[PBEffects::Trapping]==0
|
||||
pbDisplay(_INTL("{1} was freed from {2}!",b.pbThis,moveName))
|
||||
else
|
||||
case b.effects[PBEffects::TrappingMove]
|
||||
when :BIND then pbCommonAnimation("Bind", b)
|
||||
when :CLAMP then pbCommonAnimation("Clamp", b)
|
||||
when :FIRESPIN then pbCommonAnimation("FireSpin", b)
|
||||
when :MAGMASTORM then pbCommonAnimation("MagmaStorm", b)
|
||||
when :SANDTOMB then pbCommonAnimation("SandTomb", b)
|
||||
when :WRAP then pbCommonAnimation("Wrap", b)
|
||||
when :INFESTATION then pbCommonAnimation("Infestation", b)
|
||||
else pbCommonAnimation("Wrap", b)
|
||||
end
|
||||
if b.takesIndirectDamage?
|
||||
hpLoss = (Settings::MECHANICS_GENERATION >= 6) ? b.totalhp/8 : b.totalhp/16
|
||||
if @battlers[b.effects[PBEffects::TrappingUser]].hasActiveItem?(:BINDINGBAND)
|
||||
hpLoss = (Settings::MECHANICS_GENERATION >= 6) ? b.totalhp/6 : b.totalhp/8
|
||||
end
|
||||
@scene.pbDamageAnimation(b)
|
||||
b.pbReduceHP(hpLoss,false)
|
||||
pbDisplay(_INTL("{1} is hurt by {2}!",b.pbThis,moveName))
|
||||
b.pbItemHPHealCheck
|
||||
# NOTE: No need to call pbAbilitiesOnDamageTaken as b can't switch out.
|
||||
b.pbFaint if b.fainted?
|
||||
end
|
||||
end
|
||||
end
|
||||
# Taunt
|
||||
pbEORCountDownBattlerEffect(priority,PBEffects::Taunt) { |battler|
|
||||
pbDisplay(_INTL("{1}'s taunt wore off!",battler.pbThis))
|
||||
}
|
||||
# Encore
|
||||
priority.each do |b|
|
||||
next if b.fainted? || b.effects[PBEffects::Encore]==0
|
||||
idxEncoreMove = b.pbEncoredMoveIndex
|
||||
if idxEncoreMove>=0
|
||||
b.effects[PBEffects::Encore] -= 1
|
||||
if b.effects[PBEffects::Encore]==0 || b.moves[idxEncoreMove].pp==0
|
||||
b.effects[PBEffects::Encore] = 0
|
||||
pbDisplay(_INTL("{1}'s encore ended!",b.pbThis))
|
||||
end
|
||||
else
|
||||
PBDebug.log("[End of effect] #{b.pbThis}'s encore ended (encored move no longer known)")
|
||||
b.effects[PBEffects::Encore] = 0
|
||||
b.effects[PBEffects::EncoreMove] = nil
|
||||
end
|
||||
end
|
||||
# Disable/Cursed Body
|
||||
pbEORCountDownBattlerEffect(priority,PBEffects::Disable) { |battler|
|
||||
battler.effects[PBEffects::DisableMove] = nil
|
||||
pbDisplay(_INTL("{1} is no longer disabled!",battler.pbThis))
|
||||
}
|
||||
# Magnet Rise
|
||||
pbEORCountDownBattlerEffect(priority,PBEffects::MagnetRise) { |battler|
|
||||
pbDisplay(_INTL("{1}'s electromagnetism wore off!",battler.pbThis))
|
||||
}
|
||||
# Telekinesis
|
||||
pbEORCountDownBattlerEffect(priority,PBEffects::Telekinesis) { |battler|
|
||||
pbDisplay(_INTL("{1} was freed from the telekinesis!",battler.pbThis))
|
||||
}
|
||||
# Heal Block
|
||||
pbEORCountDownBattlerEffect(priority,PBEffects::HealBlock) { |battler|
|
||||
pbDisplay(_INTL("{1}'s Heal Block wore off!",battler.pbThis))
|
||||
}
|
||||
# Embargo
|
||||
pbEORCountDownBattlerEffect(priority,PBEffects::Embargo) { |battler|
|
||||
pbDisplay(_INTL("{1} can use items again!",battler.pbThis))
|
||||
battler.pbItemTerrainStatBoostCheck
|
||||
}
|
||||
# Yawn
|
||||
pbEORCountDownBattlerEffect(priority,PBEffects::Yawn) { |battler|
|
||||
if battler.pbCanSleepYawn?
|
||||
PBDebug.log("[Lingering effect] #{battler.pbThis} fell asleep because of Yawn")
|
||||
battler.pbSleep
|
||||
end
|
||||
}
|
||||
# Perish Song
|
||||
perishSongUsers = []
|
||||
priority.each do |b|
|
||||
next if b.fainted? || b.effects[PBEffects::PerishSong]==0
|
||||
b.effects[PBEffects::PerishSong] -= 1
|
||||
pbDisplay(_INTL("{1}'s perish count fell to {2}!",b.pbThis,b.effects[PBEffects::PerishSong]))
|
||||
if b.effects[PBEffects::PerishSong]==0
|
||||
perishSongUsers.push(b.effects[PBEffects::PerishSongUser])
|
||||
b.pbReduceHP(b.hp)
|
||||
end
|
||||
b.pbItemHPHealCheck
|
||||
b.pbFaint if b.fainted?
|
||||
end
|
||||
if perishSongUsers.length>0
|
||||
# If all remaining Pokemon fainted by a Perish Song triggered by a single side
|
||||
if (perishSongUsers.find_all { |idxBattler| opposes?(idxBattler) }.length==perishSongUsers.length) ||
|
||||
(perishSongUsers.find_all { |idxBattler| !opposes?(idxBattler) }.length==perishSongUsers.length)
|
||||
pbJudgeCheckpoint(@battlers[perishSongUsers[0]])
|
||||
end
|
||||
end
|
||||
# Check for end of battle
|
||||
if @decision>0
|
||||
pbGainExp
|
||||
return
|
||||
end
|
||||
for side in 0...2
|
||||
# Reflect
|
||||
pbEORCountDownSideEffect(side,PBEffects::Reflect,
|
||||
_INTL("{1}'s Reflect wore off!",@battlers[side].pbTeam))
|
||||
# Light Screen
|
||||
pbEORCountDownSideEffect(side,PBEffects::LightScreen,
|
||||
_INTL("{1}'s Light Screen wore off!",@battlers[side].pbTeam))
|
||||
# Safeguard
|
||||
pbEORCountDownSideEffect(side,PBEffects::Safeguard,
|
||||
_INTL("{1} is no longer protected by Safeguard!",@battlers[side].pbTeam))
|
||||
# Mist
|
||||
pbEORCountDownSideEffect(side,PBEffects::Mist,
|
||||
_INTL("{1} is no longer protected by mist!",@battlers[side].pbTeam))
|
||||
# Tailwind
|
||||
pbEORCountDownSideEffect(side,PBEffects::Tailwind,
|
||||
_INTL("{1}'s Tailwind petered out!",@battlers[side].pbTeam))
|
||||
# Lucky Chant
|
||||
pbEORCountDownSideEffect(side,PBEffects::LuckyChant,
|
||||
_INTL("{1}'s Lucky Chant wore off!",@battlers[side].pbTeam))
|
||||
# Pledge Rainbow
|
||||
pbEORCountDownSideEffect(side,PBEffects::Rainbow,
|
||||
_INTL("The rainbow on {1}'s side disappeared!",@battlers[side].pbTeam(true)))
|
||||
# Pledge Sea of Fire
|
||||
pbEORCountDownSideEffect(side,PBEffects::SeaOfFire,
|
||||
_INTL("The sea of fire around {1} disappeared!",@battlers[side].pbTeam(true)))
|
||||
# Pledge Swamp
|
||||
pbEORCountDownSideEffect(side,PBEffects::Swamp,
|
||||
_INTL("The swamp around {1} disappeared!",@battlers[side].pbTeam(true)))
|
||||
# Aurora Veil
|
||||
pbEORCountDownSideEffect(side,PBEffects::AuroraVeil,
|
||||
_INTL("{1}'s Aurora Veil wore off!",@battlers[side].pbTeam(true)))
|
||||
end
|
||||
# Trick Room
|
||||
pbEORCountDownFieldEffect(PBEffects::TrickRoom,
|
||||
_INTL("The twisted dimensions returned to normal!"))
|
||||
# Gravity
|
||||
pbEORCountDownFieldEffect(PBEffects::Gravity,
|
||||
_INTL("Gravity returned to normal!"))
|
||||
# Water Sport
|
||||
pbEORCountDownFieldEffect(PBEffects::WaterSportField,
|
||||
_INTL("The effects of Water Sport have faded."))
|
||||
# Mud Sport
|
||||
pbEORCountDownFieldEffect(PBEffects::MudSportField,
|
||||
_INTL("The effects of Mud Sport have faded."))
|
||||
# Wonder Room
|
||||
pbEORCountDownFieldEffect(PBEffects::WonderRoom,
|
||||
_INTL("Wonder Room wore off, and Defense and Sp. Def stats returned to normal!"))
|
||||
# Magic Room
|
||||
pbEORCountDownFieldEffect(PBEffects::MagicRoom,
|
||||
_INTL("Magic Room wore off, and held items' effects returned to normal!"))
|
||||
# End of terrains
|
||||
pbEORTerrain
|
||||
priority.each do |b|
|
||||
next if b.fainted?
|
||||
# Hyper Mode (Shadow Pokémon)
|
||||
if b.inHyperMode?
|
||||
if pbRandom(100)<10
|
||||
b.pokemon.hyper_mode = false
|
||||
b.pokemon.adjustHeart(-50)
|
||||
pbDisplay(_INTL("{1} came to its senses!",b.pbThis))
|
||||
else
|
||||
pbDisplay(_INTL("{1} is in Hyper Mode!",b.pbThis))
|
||||
end
|
||||
end
|
||||
# Uproar
|
||||
if b.effects[PBEffects::Uproar]>0
|
||||
b.effects[PBEffects::Uproar] -= 1
|
||||
if b.effects[PBEffects::Uproar]==0
|
||||
pbDisplay(_INTL("{1} calmed down.",b.pbThis))
|
||||
else
|
||||
pbDisplay(_INTL("{1} is making an uproar!",b.pbThis))
|
||||
end
|
||||
end
|
||||
# Slow Start's end message
|
||||
if b.effects[PBEffects::SlowStart]>0
|
||||
b.effects[PBEffects::SlowStart] -= 1
|
||||
if b.effects[PBEffects::SlowStart]==0
|
||||
pbDisplay(_INTL("{1} finally got its act together!",b.pbThis))
|
||||
end
|
||||
end
|
||||
# Bad Dreams, Moody, Speed Boost
|
||||
BattleHandlers.triggerEOREffectAbility(b.ability,b,self) if b.abilityActive?
|
||||
# Flame Orb, Sticky Barb, Toxic Orb
|
||||
BattleHandlers.triggerEOREffectItem(b.item,b,self) if b.itemActive?
|
||||
# Harvest, Pickup
|
||||
BattleHandlers.triggerEORGainItemAbility(b.ability,b,self) if b.abilityActive?
|
||||
end
|
||||
pbGainExp
|
||||
return if @decision>0
|
||||
# Form checks
|
||||
priority.each { |b| b.pbCheckForm(true) }
|
||||
# Switch Pokémon in if possible
|
||||
pbEORSwitch
|
||||
return if @decision>0
|
||||
# In battles with at least one side of size 3+, move battlers around if none
|
||||
# are near to any foes
|
||||
pbEORShiftDistantBattlers
|
||||
# Try to make Trace work, check for end of primordial weather
|
||||
priority.each { |b| b.pbContinualAbilityChecks }
|
||||
# Reset/count down battler-specific effects (no messages)
|
||||
eachBattler do |b|
|
||||
b.effects[PBEffects::BanefulBunker] = false
|
||||
b.effects[PBEffects::Charge] -= 1 if b.effects[PBEffects::Charge]>0
|
||||
b.effects[PBEffects::Counter] = -1
|
||||
b.effects[PBEffects::CounterTarget] = -1
|
||||
b.effects[PBEffects::Electrify] = false
|
||||
b.effects[PBEffects::Endure] = false
|
||||
b.effects[PBEffects::FirstPledge] = 0
|
||||
b.effects[PBEffects::Flinch] = false
|
||||
b.effects[PBEffects::FocusPunch] = false
|
||||
b.effects[PBEffects::FollowMe] = 0
|
||||
b.effects[PBEffects::HelpingHand] = false
|
||||
b.effects[PBEffects::HyperBeam] -= 1 if b.effects[PBEffects::HyperBeam]>0
|
||||
b.effects[PBEffects::KingsShield] = false
|
||||
b.effects[PBEffects::LaserFocus] -= 1 if b.effects[PBEffects::LaserFocus]>0
|
||||
if b.effects[PBEffects::LockOn]>0 # Also Mind Reader
|
||||
b.effects[PBEffects::LockOn] -= 1
|
||||
b.effects[PBEffects::LockOnPos] = -1 if b.effects[PBEffects::LockOn]==0
|
||||
end
|
||||
b.effects[PBEffects::MagicBounce] = false
|
||||
b.effects[PBEffects::MagicCoat] = false
|
||||
b.effects[PBEffects::MirrorCoat] = -1
|
||||
b.effects[PBEffects::MirrorCoatTarget] = -1
|
||||
b.effects[PBEffects::Powder] = false
|
||||
b.effects[PBEffects::Prankster] = false
|
||||
b.effects[PBEffects::PriorityAbility] = false
|
||||
b.effects[PBEffects::PriorityItem] = false
|
||||
b.effects[PBEffects::Protect] = false
|
||||
b.effects[PBEffects::RagePowder] = false
|
||||
b.effects[PBEffects::Roost] = false
|
||||
b.effects[PBEffects::Snatch] = 0
|
||||
b.effects[PBEffects::SpikyShield] = false
|
||||
b.effects[PBEffects::Spotlight] = 0
|
||||
b.effects[PBEffects::ThroatChop] -= 1 if b.effects[PBEffects::ThroatChop]>0
|
||||
b.lastHPLost = 0
|
||||
b.lastHPLostFromFoe = 0
|
||||
b.tookDamage = false
|
||||
b.tookPhysicalHit = false
|
||||
b.lastRoundMoveFailed = b.lastMoveFailed
|
||||
b.lastAttacker.clear
|
||||
b.lastFoeAttacker.clear
|
||||
end
|
||||
# Reset/count down side-specific effects (no messages)
|
||||
for side in 0...2
|
||||
@sides[side].effects[PBEffects::CraftyShield] = false
|
||||
if !@sides[side].effects[PBEffects::EchoedVoiceUsed]
|
||||
@sides[side].effects[PBEffects::EchoedVoiceCounter] = 0
|
||||
end
|
||||
@sides[side].effects[PBEffects::EchoedVoiceUsed] = false
|
||||
@sides[side].effects[PBEffects::MatBlock] = false
|
||||
@sides[side].effects[PBEffects::QuickGuard] = false
|
||||
@sides[side].effects[PBEffects::Round] = false
|
||||
@sides[side].effects[PBEffects::WideGuard] = false
|
||||
end
|
||||
# Reset/count down field-specific effects (no messages)
|
||||
@field.effects[PBEffects::IonDeluge] = false
|
||||
@field.effects[PBEffects::FairyLock] -= 1 if @field.effects[PBEffects::FairyLock]>0
|
||||
@field.effects[PBEffects::FusionBolt] = false
|
||||
@field.effects[PBEffects::FusionFlare] = false
|
||||
@endOfRound = false
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user