mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-09 22:24:58 +00:00
Renamed all battle-related classes and modules
This commit is contained in:
413
Data/Scripts/011_Battle/004_Scene/001_Battle_Scene.rb
Normal file
413
Data/Scripts/011_Battle/004_Scene/001_Battle_Scene.rb
Normal file
@@ -0,0 +1,413 @@
|
||||
# Battle scene (the visuals of the battle)
|
||||
class Battle::Scene
|
||||
attr_accessor :abortable # For non-interactive battles, can quit immediately
|
||||
attr_reader :viewport
|
||||
attr_reader :sprites
|
||||
|
||||
USE_ABILITY_SPLASH = (Settings::MECHANICS_GENERATION >= 5)
|
||||
MESSAGE_PAUSE_TIME = 1.0 # In seconds
|
||||
# Text colors
|
||||
MESSAGE_BASE_COLOR = Color.new(80, 80, 88)
|
||||
MESSAGE_SHADOW_COLOR = Color.new(160, 160, 168)
|
||||
# The number of party balls to show in each side's lineup.
|
||||
NUM_BALLS = Settings::MAX_PARTY_SIZE
|
||||
# Centre bottom of the player's side base graphic
|
||||
PLAYER_BASE_X = 128
|
||||
PLAYER_BASE_Y = Settings::SCREEN_HEIGHT - 80
|
||||
# Centre middle of the foe's side base graphic
|
||||
FOE_BASE_X = Settings::SCREEN_WIDTH - 128
|
||||
FOE_BASE_Y = (Settings::SCREEN_HEIGHT * 3 / 4) - 112
|
||||
# Default focal points of user and target in animations - do not change!
|
||||
# Is the centre middle of each sprite
|
||||
FOCUSUSER_X = 128
|
||||
FOCUSUSER_Y = 224
|
||||
FOCUSTARGET_X = 384
|
||||
FOCUSTARGET_Y = 96
|
||||
# Menu types
|
||||
BLANK = 0
|
||||
MESSAGE_BOX = 1
|
||||
COMMAND_BOX = 2
|
||||
FIGHT_BOX = 3
|
||||
TARGET_BOX = 4
|
||||
|
||||
# Returns where the centre bottom of a battler's sprite should be, given its
|
||||
# index and the number of battlers on its side, assuming the battler has
|
||||
# metrics of 0 (those are added later).
|
||||
def self.pbBattlerPosition(index, sideSize = 1)
|
||||
# Start at the centre of the base for the appropriate side
|
||||
if (index & 1) == 0
|
||||
ret = [PLAYER_BASE_X, PLAYER_BASE_Y]
|
||||
else
|
||||
ret = [FOE_BASE_X, FOE_BASE_Y]
|
||||
end
|
||||
# Shift depending on index (no shifting needed for sideSize of 1)
|
||||
case sideSize
|
||||
when 2
|
||||
ret[0] += [-48, 48, 32, -32][index]
|
||||
ret[1] += [ 0, 0, 16, -16][index]
|
||||
when 3
|
||||
ret[0] += [-80, 80, 0, 0, 80, -80][index]
|
||||
ret[1] += [ 0, 0, 8, -8, 16, -16][index]
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
# Returns where the centre bottom of a trainer's sprite should be, given its
|
||||
# side (0/1), index and the number of trainers on its side.
|
||||
def self.pbTrainerPosition(side, index = 0, sideSize = 1)
|
||||
# Start at the centre of the base for the appropriate side
|
||||
if side == 0
|
||||
ret = [PLAYER_BASE_X, PLAYER_BASE_Y - 16]
|
||||
else
|
||||
ret = [FOE_BASE_X, FOE_BASE_Y + 6]
|
||||
end
|
||||
# Shift depending on index (no shifting needed for sideSize of 1)
|
||||
case sideSize
|
||||
when 2
|
||||
ret[0] += [-48, 48, 32, -32][2 * index + side]
|
||||
ret[1] += [ 0, 0, 0, -16][2 * index + side]
|
||||
when 3
|
||||
ret[0] += [-80, 80, 0, 0, 80, -80][2 * index + side]
|
||||
ret[1] += [ 0, 0, 0, -8, 0, -16][2 * index + side]
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Updating and refreshing
|
||||
#=============================================================================
|
||||
def pbUpdate(cw=nil)
|
||||
pbGraphicsUpdate
|
||||
pbInputUpdate
|
||||
pbFrameUpdate(cw)
|
||||
end
|
||||
|
||||
def pbGraphicsUpdate
|
||||
# Update lineup animations
|
||||
if @animations.length>0
|
||||
shouldCompact = false
|
||||
@animations.each_with_index do |a,i|
|
||||
a.update
|
||||
if a.animDone?
|
||||
a.dispose
|
||||
@animations[i] = nil
|
||||
shouldCompact = true
|
||||
end
|
||||
end
|
||||
@animations.compact! if shouldCompact
|
||||
end
|
||||
# Update other graphics
|
||||
@sprites["battle_bg"].update if @sprites["battle_bg"].respond_to?("update")
|
||||
Graphics.update
|
||||
@frameCounter += 1
|
||||
@frameCounter = @frameCounter%(Graphics.frame_rate*12/20)
|
||||
end
|
||||
|
||||
def pbInputUpdate
|
||||
Input.update
|
||||
if Input.trigger?(Input::BACK) && @abortable && !@aborted
|
||||
@aborted = true
|
||||
@battle.pbAbort
|
||||
end
|
||||
end
|
||||
|
||||
def pbFrameUpdate(cw=nil)
|
||||
cw.update if cw
|
||||
@battle.battlers.each_with_index do |b,i|
|
||||
next if !b
|
||||
@sprites["dataBox_#{i}"].update(@frameCounter) if @sprites["dataBox_#{i}"]
|
||||
@sprites["pokemon_#{i}"].update(@frameCounter) if @sprites["pokemon_#{i}"]
|
||||
@sprites["shadow_#{i}"].update(@frameCounter) if @sprites["shadow_#{i}"]
|
||||
end
|
||||
end
|
||||
|
||||
def pbRefresh
|
||||
@battle.battlers.each_with_index do |b,i|
|
||||
next if !b
|
||||
@sprites["dataBox_#{i}"].refresh if @sprites["dataBox_#{i}"]
|
||||
end
|
||||
end
|
||||
|
||||
def pbRefreshOne(idxBattler)
|
||||
@sprites["dataBox_#{idxBattler}"].refresh if @sprites["dataBox_#{idxBattler}"]
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Party lineup
|
||||
#=============================================================================
|
||||
# Returns whether the party line-ups are currently coming on-screen
|
||||
def inPartyAnimation?
|
||||
return @animations.length>0
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Window displays
|
||||
#=============================================================================
|
||||
def pbShowWindow(windowType)
|
||||
# NOTE: If you are not using fancy graphics for the command/fight menus, you
|
||||
# will need to make "messageBox" also visible if the windowtype if
|
||||
# COMMAND_BOX/FIGHT_BOX respectively.
|
||||
@sprites["messageBox"].visible = (windowType==MESSAGE_BOX)
|
||||
@sprites["messageWindow"].visible = (windowType==MESSAGE_BOX)
|
||||
@sprites["commandWindow"].visible = (windowType==COMMAND_BOX)
|
||||
@sprites["fightWindow"].visible = (windowType==FIGHT_BOX)
|
||||
@sprites["targetWindow"].visible = (windowType==TARGET_BOX)
|
||||
end
|
||||
|
||||
# This is for the end of brief messages, which have been lingering on-screen
|
||||
# while other things happened. This is only called when another message wants
|
||||
# to be shown, and makes the brief message linger for one more second first.
|
||||
# Some animations skip this extra second by setting @briefMessage to false
|
||||
# despite not having any other messages to show.
|
||||
def pbWaitMessage
|
||||
return if !@briefMessage
|
||||
pbShowWindow(MESSAGE_BOX)
|
||||
cw = @sprites["messageWindow"]
|
||||
timer = 0.0
|
||||
while timer < MESSAGE_PAUSE_TIME
|
||||
pbUpdate(cw)
|
||||
timer += Graphics.delta_s
|
||||
end
|
||||
cw.text = ""
|
||||
cw.visible = false
|
||||
@briefMessage = false
|
||||
end
|
||||
|
||||
# NOTE: A regular message is displayed for 1 second after it fully appears (or
|
||||
# less if Back/Use is pressed). Disappears automatically after that time.
|
||||
def pbDisplayMessage(msg,brief=false)
|
||||
pbWaitMessage
|
||||
pbShowWindow(MESSAGE_BOX)
|
||||
cw = @sprites["messageWindow"]
|
||||
cw.setText(msg)
|
||||
PBDebug.log(msg)
|
||||
yielded = false
|
||||
timer = 0.0
|
||||
loop do
|
||||
pbUpdate(cw)
|
||||
if !cw.busy?
|
||||
if !yielded
|
||||
yield if block_given? # For playing SE as soon as the message is all shown
|
||||
yielded = true
|
||||
end
|
||||
if brief
|
||||
# NOTE: A brief message lingers on-screen while other things happen. A
|
||||
# regular message has to end before the game can continue.
|
||||
@briefMessage = true
|
||||
break
|
||||
end
|
||||
if timer >= MESSAGE_PAUSE_TIME # Autoclose after 1 second
|
||||
cw.text = ""
|
||||
cw.visible = false
|
||||
break
|
||||
end
|
||||
timer += Graphics.delta_s
|
||||
end
|
||||
if Input.trigger?(Input::BACK) || Input.trigger?(Input::USE) || @abortable
|
||||
if cw.busy?
|
||||
pbPlayDecisionSE if cw.pausing? && !@abortable
|
||||
cw.skipAhead
|
||||
elsif !@abortable
|
||||
cw.text = ""
|
||||
cw.visible = false
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
alias pbDisplay pbDisplayMessage
|
||||
|
||||
# NOTE: A paused message has the arrow in the bottom corner indicating there
|
||||
# is another message immediately afterward. It is displayed for 3
|
||||
# seconds after it fully appears (or less if B/C is pressed) and
|
||||
# disappears automatically after that time, except at the end of battle.
|
||||
def pbDisplayPausedMessage(msg)
|
||||
pbWaitMessage
|
||||
pbShowWindow(MESSAGE_BOX)
|
||||
cw = @sprites["messageWindow"]
|
||||
cw.text = _INTL("{1}\1",msg)
|
||||
PBDebug.log(msg)
|
||||
yielded = false
|
||||
timer = 0.0
|
||||
loop do
|
||||
pbUpdate(cw)
|
||||
if !cw.busy?
|
||||
if !yielded
|
||||
yield if block_given? # For playing SE as soon as the message is all shown
|
||||
yielded = true
|
||||
end
|
||||
if !@battleEnd
|
||||
if timer >= MESSAGE_PAUSE_TIME * 3 # Autoclose after 3 seconds
|
||||
cw.text = ""
|
||||
cw.visible = false
|
||||
break
|
||||
end
|
||||
timer += Graphics.delta_s
|
||||
end
|
||||
end
|
||||
if Input.trigger?(Input::BACK) || Input.trigger?(Input::USE) || @abortable
|
||||
if cw.busy?
|
||||
pbPlayDecisionSE if cw.pausing? && !@abortable
|
||||
cw.skipAhead
|
||||
elsif !@abortable
|
||||
cw.text = ""
|
||||
pbPlayDecisionSE
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbDisplayConfirmMessage(msg)
|
||||
return pbShowCommands(msg,[_INTL("Yes"),_INTL("No")],1)==0
|
||||
end
|
||||
|
||||
def pbShowCommands(msg,commands,defaultValue)
|
||||
pbWaitMessage
|
||||
pbShowWindow(MESSAGE_BOX)
|
||||
dw = @sprites["messageWindow"]
|
||||
dw.text = msg
|
||||
cw = Window_CommandPokemon.new(commands)
|
||||
cw.height = Graphics.height - dw.height if cw.height > Graphics.height - dw.height
|
||||
cw.x = Graphics.width-cw.width
|
||||
cw.y = Graphics.height-cw.height-dw.height
|
||||
cw.z = dw.z+1
|
||||
cw.index = 0
|
||||
cw.viewport = @viewport
|
||||
PBDebug.log(msg)
|
||||
loop do
|
||||
cw.visible = (!dw.busy?)
|
||||
pbUpdate(cw)
|
||||
dw.update
|
||||
if Input.trigger?(Input::BACK) && defaultValue>=0
|
||||
if dw.busy?
|
||||
pbPlayDecisionSE if dw.pausing?
|
||||
dw.resume
|
||||
else
|
||||
cw.dispose
|
||||
dw.text = ""
|
||||
return defaultValue
|
||||
end
|
||||
elsif Input.trigger?(Input::USE)
|
||||
if dw.busy?
|
||||
pbPlayDecisionSE if dw.pausing?
|
||||
dw.resume
|
||||
else
|
||||
cw.dispose
|
||||
dw.text = ""
|
||||
return cw.index
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Sprites
|
||||
#=============================================================================
|
||||
def pbAddSprite(id,x,y,filename,viewport)
|
||||
sprite = IconSprite.new(x,y,viewport)
|
||||
if filename
|
||||
sprite.setBitmap(filename) rescue nil
|
||||
end
|
||||
@sprites[id] = sprite
|
||||
return sprite
|
||||
end
|
||||
|
||||
def pbAddPlane(id,filename,viewport)
|
||||
sprite = AnimatedPlane.new(viewport)
|
||||
if filename
|
||||
sprite.setBitmap(filename)
|
||||
end
|
||||
@sprites[id] = sprite
|
||||
return sprite
|
||||
end
|
||||
|
||||
def pbDisposeSprites
|
||||
pbDisposeSpriteHash(@sprites)
|
||||
end
|
||||
|
||||
# Used by Ally Switch.
|
||||
def pbSwapBattlerSprites(idxA,idxB)
|
||||
@sprites["pokemon_#{idxA}"], @sprites["pokemon_#{idxB}"] = @sprites["pokemon_#{idxB}"], @sprites["pokemon_#{idxA}"]
|
||||
@sprites["shadow_#{idxA}"], @sprites["shadow_#{idxB}"] = @sprites["shadow_#{idxB}"], @sprites["shadow_#{idxA}"]
|
||||
@lastCmd[idxA], @lastCmd[idxB] = @lastCmd[idxB], @lastCmd[idxA]
|
||||
@lastMove[idxA], @lastMove[idxB] = @lastMove[idxB], @lastMove[idxA]
|
||||
[idxA,idxB].each do |i|
|
||||
@sprites["pokemon_#{i}"].index = i
|
||||
@sprites["pokemon_#{i}"].pbSetPosition
|
||||
@sprites["shadow_#{i}"].index = i
|
||||
@sprites["shadow_#{i}"].pbSetPosition
|
||||
@sprites["dataBox_#{i}"].battler = @battle.battlers[i]
|
||||
end
|
||||
pbRefresh
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Phases
|
||||
#=============================================================================
|
||||
def pbBeginCommandPhase
|
||||
@sprites["messageWindow"].text = ""
|
||||
end
|
||||
|
||||
def pbBeginAttackPhase
|
||||
pbSelectBattler(-1)
|
||||
pbShowWindow(MESSAGE_BOX)
|
||||
end
|
||||
|
||||
def pbBeginEndOfRoundPhase
|
||||
end
|
||||
|
||||
def pbEndBattle(_result)
|
||||
@abortable = false
|
||||
pbShowWindow(BLANK)
|
||||
# Fade out all sprites
|
||||
pbBGMFade(1.0)
|
||||
pbFadeOutAndHide(@sprites)
|
||||
pbDisposeSprites
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#
|
||||
#=============================================================================
|
||||
def pbSelectBattler(idxBattler,selectMode=1)
|
||||
numWindows = @battle.sideSizes.max*2
|
||||
for i in 0...numWindows
|
||||
sel = (idxBattler.is_a?(Array)) ? !idxBattler[i].nil? : i==idxBattler
|
||||
selVal = (sel) ? selectMode : 0
|
||||
@sprites["dataBox_#{i}"].selected = selVal if @sprites["dataBox_#{i}"]
|
||||
@sprites["pokemon_#{i}"].selected = selVal if @sprites["pokemon_#{i}"]
|
||||
end
|
||||
end
|
||||
|
||||
def pbChangePokemon(idxBattler,pkmn)
|
||||
idxBattler = idxBattler.index if idxBattler.respond_to?("index")
|
||||
pkmnSprite = @sprites["pokemon_#{idxBattler}"]
|
||||
shadowSprite = @sprites["shadow_#{idxBattler}"]
|
||||
back = !@battle.opposes?(idxBattler)
|
||||
pkmnSprite.setPokemonBitmap(pkmn,back)
|
||||
shadowSprite.setPokemonBitmap(pkmn)
|
||||
# Set visibility of battler's shadow
|
||||
shadowSprite.visible = pkmn.species_data.shows_shadow? if shadowSprite && !back
|
||||
end
|
||||
|
||||
def pbResetMoveIndex(idxBattler)
|
||||
@lastMove[idxBattler] = 0
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
#
|
||||
#=============================================================================
|
||||
# This method is called when the player wins a wild Pokémon battle.
|
||||
# This method can change the battle's music for example.
|
||||
def pbWildBattleSuccess
|
||||
@battleEnd = true
|
||||
pbBGMPlay(pbGetWildVictoryME)
|
||||
end
|
||||
|
||||
# This method is called when the player wins a trainer battle.
|
||||
# This method can change the battle's music for example.
|
||||
def pbTrainerBattleSuccess
|
||||
@battleEnd = true
|
||||
pbBGMPlay(pbGetTrainerVictoryME(@battle.opponent))
|
||||
end
|
||||
end
|
||||
191
Data/Scripts/011_Battle/004_Scene/002_Scene_Initialize.rb
Normal file
191
Data/Scripts/011_Battle/004_Scene/002_Scene_Initialize.rb
Normal file
@@ -0,0 +1,191 @@
|
||||
class Battle::Scene
|
||||
#=============================================================================
|
||||
# Create the battle scene and its elements
|
||||
#=============================================================================
|
||||
def initialize
|
||||
@battle = nil
|
||||
@abortable = false
|
||||
@aborted = false
|
||||
@battleEnd = false
|
||||
@animations = []
|
||||
@frameCounter = 0
|
||||
end
|
||||
|
||||
# Called whenever the battle begins.
|
||||
def pbStartBattle(battle)
|
||||
@battle = battle
|
||||
@viewport = Viewport.new(0,0,Graphics.width,Graphics.height)
|
||||
@viewport.z = 99999
|
||||
@lastCmd = Array.new(@battle.battlers.length,0)
|
||||
@lastMove = Array.new(@battle.battlers.length,0)
|
||||
pbInitSprites
|
||||
pbBattleIntroAnimation
|
||||
end
|
||||
|
||||
def pbInitSprites
|
||||
@sprites = {}
|
||||
# The background image and each side's base graphic
|
||||
pbCreateBackdropSprites
|
||||
# Create message box graphic
|
||||
messageBox = pbAddSprite("messageBox",0,Graphics.height-96,
|
||||
"Graphics/Pictures/Battle/overlay_message",@viewport)
|
||||
messageBox.z = 195
|
||||
# Create message window (displays the message)
|
||||
msgWindow = Window_AdvancedTextPokemon.newWithSize("",
|
||||
16,Graphics.height-96+2,Graphics.width-32,96,@viewport)
|
||||
msgWindow.z = 200
|
||||
msgWindow.opacity = 0
|
||||
msgWindow.baseColor = MESSAGE_BASE_COLOR
|
||||
msgWindow.shadowColor = MESSAGE_SHADOW_COLOR
|
||||
msgWindow.letterbyletter = true
|
||||
@sprites["messageWindow"] = msgWindow
|
||||
# Create command window
|
||||
@sprites["commandWindow"] = CommandMenu.new(@viewport,200)
|
||||
# Create fight window
|
||||
@sprites["fightWindow"] = FightMenu.new(@viewport,200)
|
||||
# Create targeting window
|
||||
@sprites["targetWindow"] = TargetMenu.new(@viewport,200,@battle.sideSizes)
|
||||
pbShowWindow(MESSAGE_BOX)
|
||||
# The party lineup graphics (bar and balls) for both sides
|
||||
for side in 0...2
|
||||
partyBar = pbAddSprite("partyBar_#{side}",0,0,
|
||||
"Graphics/Pictures/Battle/overlay_lineup",@viewport)
|
||||
partyBar.z = 120
|
||||
partyBar.mirror = true if side==0 # Player's lineup bar only
|
||||
partyBar.visible = false
|
||||
for i in 0...NUM_BALLS
|
||||
ball = pbAddSprite("partyBall_#{side}_#{i}",0,0,nil,@viewport)
|
||||
ball.z = 121
|
||||
ball.visible = false
|
||||
end
|
||||
# Ability splash bars
|
||||
if USE_ABILITY_SPLASH
|
||||
@sprites["abilityBar_#{side}"] = AbilitySplashBar.new(side,@viewport)
|
||||
end
|
||||
end
|
||||
# Player's and partner trainer's back sprite
|
||||
@battle.player.each_with_index do |p,i|
|
||||
pbCreateTrainerBackSprite(i,p.trainer_type,@battle.player.length)
|
||||
end
|
||||
# Opposing trainer(s) sprites
|
||||
if @battle.trainerBattle?
|
||||
@battle.opponent.each_with_index do |p,i|
|
||||
pbCreateTrainerFrontSprite(i,p.trainer_type,@battle.opponent.length)
|
||||
end
|
||||
end
|
||||
# Data boxes and Pokémon sprites
|
||||
@battle.battlers.each_with_index do |b,i|
|
||||
next if !b
|
||||
@sprites["dataBox_#{i}"] = PokemonDataBox.new(b,@battle.pbSideSize(i),@viewport)
|
||||
pbCreatePokemonSprite(i)
|
||||
end
|
||||
# Wild battle, so set up the Pokémon sprite(s) accordingly
|
||||
if @battle.wildBattle?
|
||||
@battle.pbParty(1).each_with_index do |pkmn,i|
|
||||
index = i*2+1
|
||||
pbChangePokemon(index,pkmn)
|
||||
pkmnSprite = @sprites["pokemon_#{index}"]
|
||||
pkmnSprite.tone = Tone.new(-80,-80,-80)
|
||||
pkmnSprite.visible = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def pbCreateBackdropSprites
|
||||
case @battle.time
|
||||
when 1 then time = "eve"
|
||||
when 2 then time = "night"
|
||||
end
|
||||
# Put everything together into backdrop, bases and message bar filenames
|
||||
backdropFilename = @battle.backdrop
|
||||
baseFilename = @battle.backdrop
|
||||
baseFilename = sprintf("%s_%s",baseFilename,@battle.backdropBase) if @battle.backdropBase
|
||||
messageFilename = @battle.backdrop
|
||||
if time
|
||||
trialName = sprintf("%s_%s",backdropFilename,time)
|
||||
if pbResolveBitmap(sprintf("Graphics/Battlebacks/"+trialName+"_bg"))
|
||||
backdropFilename = trialName
|
||||
end
|
||||
trialName = sprintf("%s_%s",baseFilename,time)
|
||||
if pbResolveBitmap(sprintf("Graphics/Battlebacks/"+trialName+"_base0"))
|
||||
baseFilename = trialName
|
||||
end
|
||||
trialName = sprintf("%s_%s",messageFilename,time)
|
||||
if pbResolveBitmap(sprintf("Graphics/Battlebacks/"+trialName+"_message"))
|
||||
messageFilename = trialName
|
||||
end
|
||||
end
|
||||
if !pbResolveBitmap(sprintf("Graphics/Battlebacks/"+baseFilename+"_base0")) &&
|
||||
@battle.backdropBase
|
||||
baseFilename = @battle.backdropBase
|
||||
if time
|
||||
trialName = sprintf("%s_%s",baseFilename,time)
|
||||
if pbResolveBitmap(sprintf("Graphics/Battlebacks/"+trialName+"_base0"))
|
||||
baseFilename = trialName
|
||||
end
|
||||
end
|
||||
end
|
||||
# Finalise filenames
|
||||
battleBG = "Graphics/Battlebacks/"+backdropFilename+"_bg"
|
||||
playerBase = "Graphics/Battlebacks/"+baseFilename+"_base0"
|
||||
enemyBase = "Graphics/Battlebacks/"+baseFilename+"_base1"
|
||||
messageBG = "Graphics/Battlebacks/"+messageFilename+"_message"
|
||||
# Apply graphics
|
||||
bg = pbAddSprite("battle_bg",0,0,battleBG,@viewport)
|
||||
bg.z = 0
|
||||
bg = pbAddSprite("battle_bg2",-Graphics.width,0,battleBG,@viewport)
|
||||
bg.z = 0
|
||||
bg.mirror = true
|
||||
for side in 0...2
|
||||
baseX, baseY = Battle::Scene.pbBattlerPosition(side)
|
||||
base = pbAddSprite("base_#{side}",baseX,baseY,
|
||||
(side==0) ? playerBase : enemyBase,@viewport)
|
||||
base.z = 1
|
||||
if base.bitmap
|
||||
base.ox = base.bitmap.width/2
|
||||
base.oy = (side==0) ? base.bitmap.height : base.bitmap.height/2
|
||||
end
|
||||
end
|
||||
cmdBarBG = pbAddSprite("cmdBar_bg",0,Graphics.height-96,messageBG,@viewport)
|
||||
cmdBarBG.z = 180
|
||||
end
|
||||
|
||||
def pbCreateTrainerBackSprite(idxTrainer,trainerType,numTrainers=1)
|
||||
if idxTrainer==0 # Player's sprite
|
||||
trainerFile = GameData::TrainerType.player_back_sprite_filename(trainerType)
|
||||
else # Partner trainer's sprite
|
||||
trainerFile = GameData::TrainerType.back_sprite_filename(trainerType)
|
||||
end
|
||||
spriteX, spriteY = Battle::Scene.pbTrainerPosition(0,idxTrainer,numTrainers)
|
||||
trainer = pbAddSprite("player_#{idxTrainer+1}",spriteX,spriteY,trainerFile,@viewport)
|
||||
return if !trainer.bitmap
|
||||
# Alter position of sprite
|
||||
trainer.z = 80+idxTrainer
|
||||
if trainer.bitmap.width>trainer.bitmap.height*2
|
||||
trainer.src_rect.x = 0
|
||||
trainer.src_rect.width = trainer.bitmap.width/5
|
||||
end
|
||||
trainer.ox = trainer.src_rect.width/2
|
||||
trainer.oy = trainer.bitmap.height
|
||||
end
|
||||
|
||||
def pbCreateTrainerFrontSprite(idxTrainer,trainerType,numTrainers=1)
|
||||
trainerFile = GameData::TrainerType.front_sprite_filename(trainerType)
|
||||
spriteX, spriteY = Battle::Scene.pbTrainerPosition(1,idxTrainer,numTrainers)
|
||||
trainer = pbAddSprite("trainer_#{idxTrainer+1}",spriteX,spriteY,trainerFile,@viewport)
|
||||
return if !trainer.bitmap
|
||||
# Alter position of sprite
|
||||
trainer.z = 7+idxTrainer
|
||||
trainer.ox = trainer.src_rect.width/2
|
||||
trainer.oy = trainer.bitmap.height
|
||||
end
|
||||
|
||||
def pbCreatePokemonSprite(idxBattler)
|
||||
sideSize = @battle.pbSideSize(idxBattler)
|
||||
batSprite = BattlerSprite.new(@viewport,sideSize,idxBattler,@animations)
|
||||
@sprites["pokemon_#{idxBattler}"] = batSprite
|
||||
shaSprite = BattlerShadowSprite.new(@viewport,sideSize,idxBattler)
|
||||
shaSprite.visible = false
|
||||
@sprites["shadow_#{idxBattler}"] = shaSprite
|
||||
end
|
||||
end
|
||||
465
Data/Scripts/011_Battle/004_Scene/003_Scene_ChooseCommands.rb
Normal file
465
Data/Scripts/011_Battle/004_Scene/003_Scene_ChooseCommands.rb
Normal file
@@ -0,0 +1,465 @@
|
||||
class Battle::Scene
|
||||
#=============================================================================
|
||||
# The player chooses a main command for a Pokémon
|
||||
# Return values: -1=Cancel, 0=Fight, 1=Bag, 2=Pokémon, 3=Run, 4=Call
|
||||
#=============================================================================
|
||||
def pbCommandMenu(idxBattler,firstAction)
|
||||
shadowTrainer = (GameData::Type.exists?(:SHADOW) && @battle.trainerBattle?)
|
||||
cmds = [
|
||||
_INTL("What will\n{1} do?",@battle.battlers[idxBattler].name),
|
||||
_INTL("Fight"),
|
||||
_INTL("Bag"),
|
||||
_INTL("Pokémon"),
|
||||
(shadowTrainer) ? _INTL("Call") : (firstAction) ? _INTL("Run") : _INTL("Cancel")
|
||||
]
|
||||
ret = pbCommandMenuEx(idxBattler,cmds,(shadowTrainer) ? 2 : (firstAction) ? 0 : 1)
|
||||
ret = 4 if ret==3 && shadowTrainer # Convert "Run" to "Call"
|
||||
ret = -1 if ret==3 && !firstAction # Convert "Run" to "Cancel"
|
||||
return ret
|
||||
end
|
||||
|
||||
# Mode: 0 = regular battle with "Run" (first choosable action in the round only)
|
||||
# 1 = regular battle with "Cancel"
|
||||
# 2 = regular battle with "Call" (for Shadow Pokémon battles)
|
||||
# 3 = Safari Zone
|
||||
# 4 = Bug Catching Contest
|
||||
def pbCommandMenuEx(idxBattler,texts,mode=0)
|
||||
pbShowWindow(COMMAND_BOX)
|
||||
cw = @sprites["commandWindow"]
|
||||
cw.setTexts(texts)
|
||||
cw.setIndexAndMode(@lastCmd[idxBattler],mode)
|
||||
pbSelectBattler(idxBattler)
|
||||
ret = -1
|
||||
loop do
|
||||
oldIndex = cw.index
|
||||
pbUpdate(cw)
|
||||
# Update selected command
|
||||
if Input.trigger?(Input::LEFT)
|
||||
cw.index -= 1 if (cw.index&1)==1
|
||||
elsif Input.trigger?(Input::RIGHT)
|
||||
cw.index += 1 if (cw.index&1)==0
|
||||
elsif Input.trigger?(Input::UP)
|
||||
cw.index -= 2 if (cw.index&2)==2
|
||||
elsif Input.trigger?(Input::DOWN)
|
||||
cw.index += 2 if (cw.index&2)==0
|
||||
end
|
||||
pbPlayCursorSE if cw.index!=oldIndex
|
||||
# Actions
|
||||
if Input.trigger?(Input::USE) # Confirm choice
|
||||
pbPlayDecisionSE
|
||||
ret = cw.index
|
||||
@lastCmd[idxBattler] = ret
|
||||
break
|
||||
elsif Input.trigger?(Input::BACK) && mode==1 # Cancel
|
||||
pbPlayCancelSE
|
||||
break
|
||||
elsif Input.trigger?(Input::F9) && $DEBUG # Debug menu
|
||||
pbPlayDecisionSE
|
||||
ret = -2
|
||||
break
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# The player chooses a move for a Pokémon to use
|
||||
#=============================================================================
|
||||
def pbFightMenu(idxBattler,megaEvoPossible=false)
|
||||
battler = @battle.battlers[idxBattler]
|
||||
cw = @sprites["fightWindow"]
|
||||
cw.battler = battler
|
||||
moveIndex = 0
|
||||
if battler.moves[@lastMove[idxBattler]] && battler.moves[@lastMove[idxBattler]].id
|
||||
moveIndex = @lastMove[idxBattler]
|
||||
end
|
||||
cw.shiftMode = (@battle.pbCanShift?(idxBattler)) ? 1 : 0
|
||||
cw.setIndexAndMode(moveIndex,(megaEvoPossible) ? 1 : 0)
|
||||
needFullRefresh = true
|
||||
needRefresh = false
|
||||
loop do
|
||||
# Refresh view if necessary
|
||||
if needFullRefresh
|
||||
pbShowWindow(FIGHT_BOX)
|
||||
pbSelectBattler(idxBattler)
|
||||
needFullRefresh = false
|
||||
end
|
||||
if needRefresh
|
||||
if megaEvoPossible
|
||||
newMode = (@battle.pbRegisteredMegaEvolution?(idxBattler)) ? 2 : 1
|
||||
cw.mode = newMode if newMode!=cw.mode
|
||||
end
|
||||
needRefresh = false
|
||||
end
|
||||
oldIndex = cw.index
|
||||
# General update
|
||||
pbUpdate(cw)
|
||||
# Update selected command
|
||||
if Input.trigger?(Input::LEFT)
|
||||
cw.index -= 1 if (cw.index&1)==1
|
||||
elsif Input.trigger?(Input::RIGHT)
|
||||
if battler.moves[cw.index+1] && battler.moves[cw.index+1].id
|
||||
cw.index += 1 if (cw.index&1)==0
|
||||
end
|
||||
elsif Input.trigger?(Input::UP)
|
||||
cw.index -= 2 if (cw.index&2)==2
|
||||
elsif Input.trigger?(Input::DOWN)
|
||||
if battler.moves[cw.index+2] && battler.moves[cw.index+2].id
|
||||
cw.index += 2 if (cw.index&2)==0
|
||||
end
|
||||
end
|
||||
pbPlayCursorSE if cw.index!=oldIndex
|
||||
# Actions
|
||||
if Input.trigger?(Input::USE) # Confirm choice
|
||||
pbPlayDecisionSE
|
||||
break if yield cw.index
|
||||
needFullRefresh = true
|
||||
needRefresh = true
|
||||
elsif Input.trigger?(Input::BACK) # Cancel fight menu
|
||||
pbPlayCancelSE
|
||||
break if yield -1
|
||||
needRefresh = true
|
||||
elsif Input.trigger?(Input::ACTION) # Toggle Mega Evolution
|
||||
if megaEvoPossible
|
||||
pbPlayDecisionSE
|
||||
break if yield -2
|
||||
needRefresh = true
|
||||
end
|
||||
elsif Input.trigger?(Input::SPECIAL) # Shift
|
||||
if cw.shiftMode>0
|
||||
pbPlayDecisionSE
|
||||
break if yield -3
|
||||
needRefresh = true
|
||||
end
|
||||
end
|
||||
end
|
||||
@lastMove[idxBattler] = cw.index
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Opens the party screen to choose a Pokémon to switch in (or just view its
|
||||
# summary screens)
|
||||
#=============================================================================
|
||||
def pbPartyScreen(idxBattler,canCancel=false)
|
||||
# Fade out and hide all sprites
|
||||
visibleSprites = pbFadeOutAndHide(@sprites)
|
||||
# Get player's party
|
||||
partyPos = @battle.pbPartyOrder(idxBattler)
|
||||
partyStart, _partyEnd = @battle.pbTeamIndexRangeFromBattlerIndex(idxBattler)
|
||||
modParty = @battle.pbPlayerDisplayParty(idxBattler)
|
||||
# Start party screen
|
||||
scene = PokemonParty_Scene.new
|
||||
switchScreen = PokemonPartyScreen.new(scene,modParty)
|
||||
switchScreen.pbStartScene(_INTL("Choose a Pokémon."),@battle.pbNumPositions(0,0))
|
||||
# Loop while in party screen
|
||||
loop do
|
||||
# Select a Pokémon
|
||||
scene.pbSetHelpText(_INTL("Choose a Pokémon."))
|
||||
idxParty = switchScreen.pbChoosePokemon
|
||||
if idxParty<0
|
||||
next if !canCancel
|
||||
break
|
||||
end
|
||||
# Choose a command for the selected Pokémon
|
||||
cmdSwitch = -1
|
||||
cmdSummary = -1
|
||||
commands = []
|
||||
commands[cmdSwitch = commands.length] = _INTL("Switch In") if modParty[idxParty].able?
|
||||
commands[cmdSummary = commands.length] = _INTL("Summary")
|
||||
commands[commands.length] = _INTL("Cancel")
|
||||
command = scene.pbShowCommands(_INTL("Do what with {1}?",modParty[idxParty].name),commands)
|
||||
if cmdSwitch>=0 && command==cmdSwitch # Switch In
|
||||
idxPartyRet = -1
|
||||
partyPos.each_with_index do |pos,i|
|
||||
next if pos!=idxParty+partyStart
|
||||
idxPartyRet = i
|
||||
break
|
||||
end
|
||||
break if yield idxPartyRet, switchScreen
|
||||
elsif cmdSummary>=0 && command==cmdSummary # Summary
|
||||
scene.pbSummary(idxParty,true)
|
||||
end
|
||||
end
|
||||
# Close party screen
|
||||
switchScreen.pbEndScene
|
||||
# Fade back into battle screen
|
||||
pbFadeInAndShow(@sprites,visibleSprites)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Opens the Bag screen and chooses an item to use
|
||||
#=============================================================================
|
||||
def pbItemMenu(idxBattler,_firstAction)
|
||||
# Fade out and hide all sprites
|
||||
visibleSprites = pbFadeOutAndHide(@sprites)
|
||||
# Set Bag starting positions
|
||||
oldLastPocket = $bag.last_viewed_pocket
|
||||
oldChoices = $bag.last_pocket_selections.clone
|
||||
$bag.last_viewed_pocket = @bagLastPocket if @bagLastPocket != nil
|
||||
$bag.last_pocket_selections = @bagChoices if @bagChoices != nil
|
||||
# Start Bag screen
|
||||
itemScene = PokemonBag_Scene.new
|
||||
itemScene.pbStartScene($bag, true, Proc.new { |item|
|
||||
useType = GameData::Item.get(item).battle_use
|
||||
next useType && useType>0
|
||||
},false)
|
||||
# Loop while in Bag screen
|
||||
wasTargeting = false
|
||||
loop do
|
||||
# Select an item
|
||||
item = itemScene.pbChooseItem
|
||||
break if !item
|
||||
# Choose a command for the selected item
|
||||
item = GameData::Item.get(item)
|
||||
itemName = item.name
|
||||
useType = item.battle_use
|
||||
cmdUse = -1
|
||||
commands = []
|
||||
commands[cmdUse = commands.length] = _INTL("Use") if useType && useType!=0
|
||||
commands[commands.length] = _INTL("Cancel")
|
||||
command = itemScene.pbShowCommands(_INTL("{1} is selected.",itemName),commands)
|
||||
next unless cmdUse>=0 && command==cmdUse # Use
|
||||
# Use types:
|
||||
# 0 = not usable in battle
|
||||
# 1 = use on Pokémon (lots of items, Blue Flute)
|
||||
# 2 = use on Pokémon's move (Ethers)
|
||||
# 3 = use on battler (X items, Persim Berry, Red/Yellow Flutes)
|
||||
# 4 = use on opposing battler (Poké Balls)
|
||||
# 5 = use no target (Poké Doll, Guard Spec., Poké Flute, Launcher items)
|
||||
case useType
|
||||
when 1, 2, 3 # Use on Pokémon/Pokémon's move/battler
|
||||
# Auto-choose the Pokémon/battler whose action is being decided if they
|
||||
# are the only available Pokémon/battler to use the item on
|
||||
case useType
|
||||
when 1 # Use on Pokémon
|
||||
if @battle.pbTeamLengthFromBattlerIndex(idxBattler)==1
|
||||
break if yield item.id, useType, @battle.battlers[idxBattler].pokemonIndex, -1, itemScene
|
||||
end
|
||||
when 3 # Use on battler
|
||||
if @battle.pbPlayerBattlerCount==1
|
||||
break if yield item.id, useType, @battle.battlers[idxBattler].pokemonIndex, -1, itemScene
|
||||
end
|
||||
end
|
||||
# Fade out and hide Bag screen
|
||||
itemScene.pbFadeOutScene
|
||||
# Get player's party
|
||||
party = @battle.pbParty(idxBattler)
|
||||
partyPos = @battle.pbPartyOrder(idxBattler)
|
||||
partyStart, _partyEnd = @battle.pbTeamIndexRangeFromBattlerIndex(idxBattler)
|
||||
modParty = @battle.pbPlayerDisplayParty(idxBattler)
|
||||
# Start party screen
|
||||
pkmnScene = PokemonParty_Scene.new
|
||||
pkmnScreen = PokemonPartyScreen.new(pkmnScene,modParty)
|
||||
pkmnScreen.pbStartScene(_INTL("Use on which Pokémon?"),@battle.pbNumPositions(0,0))
|
||||
idxParty = -1
|
||||
# Loop while in party screen
|
||||
loop do
|
||||
# Select a Pokémon
|
||||
pkmnScene.pbSetHelpText(_INTL("Use on which Pokémon?"))
|
||||
idxParty = pkmnScreen.pbChoosePokemon
|
||||
break if idxParty<0
|
||||
idxPartyRet = -1
|
||||
partyPos.each_with_index do |pos,i|
|
||||
next if pos!=idxParty+partyStart
|
||||
idxPartyRet = i
|
||||
break
|
||||
end
|
||||
next if idxPartyRet<0
|
||||
pkmn = party[idxPartyRet]
|
||||
next if !pkmn || pkmn.egg?
|
||||
idxMove = -1
|
||||
if useType==2 # Use on Pokémon's move
|
||||
idxMove = pkmnScreen.pbChooseMove(pkmn,_INTL("Restore which move?"))
|
||||
next if idxMove<0
|
||||
end
|
||||
break if yield item.id, useType, idxPartyRet, idxMove, pkmnScene
|
||||
end
|
||||
pkmnScene.pbEndScene
|
||||
break if idxParty>=0
|
||||
# Cancelled choosing a Pokémon; show the Bag screen again
|
||||
itemScene.pbFadeInScene
|
||||
when 4 # Use on opposing battler (Poké Balls)
|
||||
idxTarget = -1
|
||||
if @battle.pbOpposingBattlerCount(idxBattler)==1
|
||||
@battle.allOtherSideBattlers(idxBattler).each { |b| idxTarget = b.index }
|
||||
break if yield item.id, useType, idxTarget, -1, itemScene
|
||||
else
|
||||
wasTargeting = true
|
||||
# Fade out and hide Bag screen
|
||||
itemScene.pbFadeOutScene
|
||||
# Fade in and show the battle screen, choosing a target
|
||||
tempVisibleSprites = visibleSprites.clone
|
||||
tempVisibleSprites["commandWindow"] = false
|
||||
tempVisibleSprites["targetWindow"] = true
|
||||
idxTarget = pbChooseTarget(idxBattler,GameData::Target.get(:Foe),tempVisibleSprites)
|
||||
if idxTarget>=0
|
||||
break if yield item.id, useType, idxTarget, -1, self
|
||||
end
|
||||
# Target invalid/cancelled choosing a target; show the Bag screen again
|
||||
wasTargeting = false
|
||||
pbFadeOutAndHide(@sprites)
|
||||
itemScene.pbFadeInScene
|
||||
end
|
||||
when 5 # Use with no target
|
||||
break if yield item.id, useType, idxBattler, -1, itemScene
|
||||
end
|
||||
end
|
||||
@bagLastPocket = $bag.last_viewed_pocket
|
||||
@bagChoices = $bag.last_pocket_selections.clone
|
||||
$bag.last_viewed_pocket = oldLastPocket
|
||||
$bag.last_pocket_selections = oldChoices
|
||||
# Close Bag screen
|
||||
itemScene.pbEndScene
|
||||
# Fade back into battle screen (if not already showing it)
|
||||
pbFadeInAndShow(@sprites,visibleSprites) if !wasTargeting
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# The player chooses a target battler for a move/item (non-single battles only)
|
||||
#=============================================================================
|
||||
# Returns an array containing battler names to display when choosing a move's
|
||||
# target.
|
||||
# nil means can't select that position, "" means can select that position but
|
||||
# there is no battler there, otherwise is a battler's name.
|
||||
def pbCreateTargetTexts(idxBattler,target_data)
|
||||
texts = Array.new(@battle.battlers.length) do |i|
|
||||
next nil if !@battle.battlers[i]
|
||||
showName = false
|
||||
# NOTE: Targets listed here are ones with num_targets of 0, plus
|
||||
# RandomNearFoe which should look like it targets the user. All
|
||||
# other targets are handled by the "else" part.
|
||||
case target_data.id
|
||||
when :None, :User, :RandomNearFoe
|
||||
showName = (i==idxBattler)
|
||||
when :UserSide
|
||||
showName = !@battle.opposes?(i,idxBattler)
|
||||
when :FoeSide
|
||||
showName = @battle.opposes?(i,idxBattler)
|
||||
when :BothSides
|
||||
showName = true
|
||||
else
|
||||
showName = @battle.pbMoveCanTarget?(i,idxBattler,target_data)
|
||||
end
|
||||
next nil if !showName
|
||||
next (@battle.battlers[i].fainted?) ? "" : @battle.battlers[i].name
|
||||
end
|
||||
return texts
|
||||
end
|
||||
|
||||
# Returns the initial position of the cursor when choosing a target for a move
|
||||
# in a non-single battle.
|
||||
def pbFirstTarget(idxBattler,target_data)
|
||||
case target_data.id
|
||||
when :NearAlly
|
||||
@battle.allSameSideBattlers(idxBattler).each do |b|
|
||||
next if b.index==idxBattler || !@battle.nearBattlers?(b,idxBattler)
|
||||
next if b.fainted?
|
||||
return b.index
|
||||
end
|
||||
@battle.allSameSideBattlers(idxBattler).each do |b|
|
||||
next if b.index==idxBattler || !@battle.nearBattlers?(b,idxBattler)
|
||||
return b.index
|
||||
end
|
||||
when :NearFoe, :NearOther
|
||||
indices = @battle.pbGetOpposingIndicesInOrder(idxBattler)
|
||||
indices.each { |i| return i if @battle.nearBattlers?(i,idxBattler) && !@battle.battlers[i].fainted? }
|
||||
indices.each { |i| return i if @battle.nearBattlers?(i,idxBattler) }
|
||||
when :Foe, :Other
|
||||
indices = @battle.pbGetOpposingIndicesInOrder(idxBattler)
|
||||
indices.each { |i| return i if !@battle.battlers[i].fainted? }
|
||||
indices.each { |i| return i }
|
||||
end
|
||||
return idxBattler # Target the user initially
|
||||
end
|
||||
|
||||
def pbChooseTarget(idxBattler,target_data,visibleSprites=nil)
|
||||
pbShowWindow(TARGET_BOX)
|
||||
cw = @sprites["targetWindow"]
|
||||
# Create an array of battler names (only valid targets are named)
|
||||
texts = pbCreateTargetTexts(idxBattler,target_data)
|
||||
# Determine mode based on target_data
|
||||
mode = (target_data.num_targets == 1) ? 0 : 1
|
||||
cw.setDetails(texts,mode)
|
||||
cw.index = pbFirstTarget(idxBattler,target_data)
|
||||
pbSelectBattler((mode==0) ? cw.index : texts,2) # Select initial battler/data box
|
||||
pbFadeInAndShow(@sprites,visibleSprites) if visibleSprites
|
||||
ret = -1
|
||||
loop do
|
||||
oldIndex = cw.index
|
||||
pbUpdate(cw)
|
||||
# Update selected command
|
||||
if mode==0 # Choosing just one target, can change index
|
||||
if Input.trigger?(Input::LEFT) || Input.trigger?(Input::RIGHT)
|
||||
inc = ((cw.index%2)==0) ? -2 : 2
|
||||
inc *= -1 if Input.trigger?(Input::RIGHT)
|
||||
indexLength = @battle.sideSizes[cw.index%2]*2
|
||||
newIndex = cw.index
|
||||
loop do
|
||||
newIndex += inc
|
||||
break if newIndex<0 || newIndex>=indexLength
|
||||
next if texts[newIndex].nil?
|
||||
cw.index = newIndex
|
||||
break
|
||||
end
|
||||
elsif (Input.trigger?(Input::UP) && (cw.index%2)==0) ||
|
||||
(Input.trigger?(Input::DOWN) && (cw.index%2)==1)
|
||||
tryIndex = @battle.pbGetOpposingIndicesInOrder(cw.index)
|
||||
tryIndex.each do |idxBattlerTry|
|
||||
next if texts[idxBattlerTry].nil?
|
||||
cw.index = idxBattlerTry
|
||||
break
|
||||
end
|
||||
end
|
||||
if cw.index!=oldIndex
|
||||
pbPlayCursorSE
|
||||
pbSelectBattler(cw.index,2) # Select the new battler/data box
|
||||
end
|
||||
end
|
||||
if Input.trigger?(Input::USE) # Confirm
|
||||
ret = cw.index
|
||||
pbPlayDecisionSE
|
||||
break
|
||||
elsif Input.trigger?(Input::BACK) # Cancel
|
||||
ret = -1
|
||||
pbPlayCancelSE
|
||||
break
|
||||
end
|
||||
end
|
||||
pbSelectBattler(-1) # Deselect all battlers/data boxes
|
||||
return ret
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Opens a Pokémon's summary screen to try to learn a new move
|
||||
#=============================================================================
|
||||
# Called whenever a Pokémon should forget a move. It should return -1 if the
|
||||
# selection is canceled, or 0 to 3 to indicate the move to forget. It should
|
||||
# not allow HM moves to be forgotten.
|
||||
def pbForgetMove(pkmn,moveToLearn)
|
||||
ret = -1
|
||||
pbFadeOutIn {
|
||||
scene = PokemonSummary_Scene.new
|
||||
screen = PokemonSummaryScreen.new(scene)
|
||||
ret = screen.pbStartForgetScreen([pkmn],0,moveToLearn)
|
||||
}
|
||||
return ret
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Opens the nicknaming screen for a newly caught Pokémon
|
||||
#=============================================================================
|
||||
def pbNameEntry(helpText,pkmn)
|
||||
return pbEnterPokemonName(helpText, 0, Pokemon::MAX_NAME_SIZE, "", pkmn)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Shows the Pokédex entry screen for a newly caught Pokémon
|
||||
#=============================================================================
|
||||
def pbShowPokedex(species)
|
||||
pbFadeOutIn {
|
||||
scene = PokemonPokedexInfo_Scene.new
|
||||
screen = PokemonPokedexInfoScreen.new(scene)
|
||||
screen.pbDexEntry(species)
|
||||
}
|
||||
end
|
||||
end
|
||||
558
Data/Scripts/011_Battle/004_Scene/004_Scene_PlayAnimations.rb
Normal file
558
Data/Scripts/011_Battle/004_Scene/004_Scene_PlayAnimations.rb
Normal file
@@ -0,0 +1,558 @@
|
||||
class Battle::Scene
|
||||
#=============================================================================
|
||||
# Animates the battle intro
|
||||
#=============================================================================
|
||||
def pbBattleIntroAnimation
|
||||
# Make everything appear
|
||||
introAnim = Animation::Intro.new(@sprites,@viewport,@battle)
|
||||
loop do
|
||||
introAnim.update
|
||||
pbUpdate
|
||||
break if introAnim.animDone?
|
||||
end
|
||||
introAnim.dispose
|
||||
# Post-appearance activities
|
||||
# Trainer battle: get ready to show the party lineups (they are brought
|
||||
# on-screen by a separate animation)
|
||||
if @battle.trainerBattle?
|
||||
# NOTE: Here is where you'd make trainer sprites animate if they had an
|
||||
# entrance animation. Be sure to set it up like a Pokémon entrance
|
||||
# animation, i.e. add them to @animations so that they can play out
|
||||
# while party lineups appear and messages show.
|
||||
pbShowPartyLineup(0,true)
|
||||
pbShowPartyLineup(1,true)
|
||||
return
|
||||
end
|
||||
# Wild battle: play wild Pokémon's intro animations (including cry), show
|
||||
# data box(es), return the wild Pokémon's sprite(s) to normal colour, show
|
||||
# shiny animation(s)
|
||||
# Set up data box animation
|
||||
for i in 0...@battle.sideSizes[1]
|
||||
idxBattler = 2*i+1
|
||||
next if !@battle.battlers[idxBattler]
|
||||
dataBoxAnim = Animation::DataBoxAppear.new(@sprites,@viewport,idxBattler)
|
||||
@animations.push(dataBoxAnim)
|
||||
end
|
||||
# Set up wild Pokémon returning to normal colour and playing intro
|
||||
# animations (including cry)
|
||||
@animations.push(Animation::Intro2.new(@sprites,@viewport,@battle.sideSizes[1]))
|
||||
# Play all the animations
|
||||
while inPartyAnimation?
|
||||
pbUpdate
|
||||
end
|
||||
# Show shiny animation for wild Pokémon
|
||||
if @battle.showAnims
|
||||
for i in 0...@battle.sideSizes[1]
|
||||
idxBattler = 2*i+1
|
||||
next if !@battle.battlers[idxBattler] || !@battle.battlers[idxBattler].shiny?
|
||||
if Settings::SUPER_SHINY && @battle.battlers[idxBattler].super_shiny?
|
||||
pbCommonAnimation("SuperShiny", @battle.battlers[idxBattler])
|
||||
else
|
||||
pbCommonAnimation("Shiny", @battle.battlers[idxBattler])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Animates a party lineup appearing for the given side
|
||||
#=============================================================================
|
||||
def pbShowPartyLineup(side,fullAnim=false)
|
||||
@animations.push(Animation::LineupAppear.new(@sprites,@viewport,
|
||||
side,@battle.pbParty(side),@battle.pbPartyStarts(side),fullAnim))
|
||||
if !fullAnim
|
||||
while inPartyAnimation?
|
||||
pbUpdate
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Animates an opposing trainer sliding in from off-screen. Will animate a
|
||||
# previous trainer that is already on-screen slide off first. Used at the end
|
||||
# of battle.
|
||||
#=============================================================================
|
||||
def pbShowOpponent(idxTrainer)
|
||||
# Set up trainer appearing animation
|
||||
appearAnim = Animation::TrainerAppear.new(@sprites,@viewport,idxTrainer)
|
||||
@animations.push(appearAnim)
|
||||
# Play the animation
|
||||
while inPartyAnimation?
|
||||
pbUpdate
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Animates a trainer's sprite and party lineup hiding (if they are visible).
|
||||
# Animates a Pokémon being sent out into battle, then plays the shiny
|
||||
# animation for it if relevant.
|
||||
# sendOuts is an array; each element is itself an array: [idxBattler,pkmn]
|
||||
#=============================================================================
|
||||
def pbSendOutBattlers(sendOuts,startBattle=false)
|
||||
return if sendOuts.length==0
|
||||
# If party balls are still appearing, wait for them to finish showing up, as
|
||||
# the FadeAnimation will make them disappear.
|
||||
while inPartyAnimation?
|
||||
pbUpdate
|
||||
end
|
||||
@briefMessage = false
|
||||
# Make all trainers and party lineups disappear (player-side trainers may
|
||||
# animate throwing a Poké Ball)
|
||||
if @battle.opposes?(sendOuts[0][0])
|
||||
fadeAnim = Animation::TrainerFade.new(@sprites,@viewport,startBattle)
|
||||
else
|
||||
fadeAnim = Animation::PlayerFade.new(@sprites,@viewport,startBattle)
|
||||
end
|
||||
# For each battler being sent out, set the battler's sprite and create two
|
||||
# animations (the Poké Ball moving and battler appearing from it, and its
|
||||
# data box appearing)
|
||||
sendOutAnims = []
|
||||
sendOuts.each_with_index do |b,i|
|
||||
pkmn = @battle.battlers[b[0]].effects[PBEffects::Illusion] || b[1]
|
||||
pbChangePokemon(b[0],pkmn)
|
||||
pbRefresh
|
||||
if @battle.opposes?(b[0])
|
||||
sendOutAnim = Animation::PokeballTrainerSendOut.new(@sprites,@viewport,
|
||||
@battle.pbGetOwnerIndexFromBattlerIndex(b[0])+1,
|
||||
@battle.battlers[b[0]],startBattle,i)
|
||||
else
|
||||
sendOutAnim = Animation::PokeballPlayerSendOut.new(@sprites,@viewport,
|
||||
@battle.pbGetOwnerIndexFromBattlerIndex(b[0])+1,
|
||||
@battle.battlers[b[0]],startBattle,i)
|
||||
end
|
||||
dataBoxAnim = Animation::DataBoxAppear.new(@sprites,@viewport,b[0])
|
||||
sendOutAnims.push([sendOutAnim,dataBoxAnim,false])
|
||||
end
|
||||
# Play all animations
|
||||
loop do
|
||||
fadeAnim.update
|
||||
sendOutAnims.each do |a|
|
||||
next if a[2]
|
||||
a[0].update
|
||||
a[1].update if a[0].animDone?
|
||||
a[2] = true if a[1].animDone?
|
||||
end
|
||||
pbUpdate
|
||||
if !inPartyAnimation?
|
||||
break if !sendOutAnims.any? { |a| !a[2] }
|
||||
end
|
||||
end
|
||||
fadeAnim.dispose
|
||||
sendOutAnims.each do |a|
|
||||
a[0].dispose
|
||||
a[1].dispose
|
||||
end
|
||||
# Play shininess animations for shiny Pokémon
|
||||
sendOuts.each do |b|
|
||||
next if !@battle.showAnims || !@battle.battlers[b[0]].shiny?
|
||||
if Settings::SUPER_SHINY && @battle.battlers[b[0]].super_shiny?
|
||||
pbCommonAnimation("SuperShiny", @battle.battlers[b[0]])
|
||||
else
|
||||
pbCommonAnimation("Shiny", @battle.battlers[b[0]])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Animates a Pokémon being recalled into its Poké Ball and its data box hiding
|
||||
#=============================================================================
|
||||
def pbRecall(idxBattler)
|
||||
@briefMessage = false
|
||||
# Recall animation
|
||||
recallAnim = Animation::BattlerRecall.new(@sprites,@viewport,idxBattler)
|
||||
loop do
|
||||
recallAnim.update if recallAnim
|
||||
pbUpdate
|
||||
break if recallAnim.animDone?
|
||||
end
|
||||
recallAnim.dispose
|
||||
# Data box disappear animation
|
||||
dataBoxAnim = Animation::DataBoxDisappear.new(@sprites,@viewport,idxBattler)
|
||||
loop do
|
||||
dataBoxAnim.update
|
||||
pbUpdate
|
||||
break if dataBoxAnim.animDone?
|
||||
end
|
||||
dataBoxAnim.dispose
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Ability splash bar animations
|
||||
#=============================================================================
|
||||
def pbShowAbilitySplash(battler)
|
||||
return if !USE_ABILITY_SPLASH
|
||||
side = battler.index%2
|
||||
pbHideAbilitySplash(battler) if @sprites["abilityBar_#{side}"].visible
|
||||
@sprites["abilityBar_#{side}"].battler = battler
|
||||
abilitySplashAnim = Animation::AbilitySplashAppear.new(@sprites,@viewport,side)
|
||||
loop do
|
||||
abilitySplashAnim.update
|
||||
pbUpdate
|
||||
break if abilitySplashAnim.animDone?
|
||||
end
|
||||
abilitySplashAnim.dispose
|
||||
end
|
||||
|
||||
def pbHideAbilitySplash(battler)
|
||||
return if !USE_ABILITY_SPLASH
|
||||
side = battler.index%2
|
||||
return if !@sprites["abilityBar_#{side}"].visible
|
||||
abilitySplashAnim = Animation::AbilitySplashDisappear.new(@sprites,@viewport,side)
|
||||
loop do
|
||||
abilitySplashAnim.update
|
||||
pbUpdate
|
||||
break if abilitySplashAnim.animDone?
|
||||
end
|
||||
abilitySplashAnim.dispose
|
||||
end
|
||||
|
||||
def pbReplaceAbilitySplash(battler)
|
||||
return if !USE_ABILITY_SPLASH
|
||||
pbShowAbilitySplash(battler)
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# HP change animations
|
||||
#=============================================================================
|
||||
# Shows a HP-changing common animation and animates a data box's HP bar.
|
||||
# Called by def pbReduceHP, def pbRecoverHP.
|
||||
def pbHPChanged(battler,oldHP,showAnim=false)
|
||||
@briefMessage = false
|
||||
if battler.hp>oldHP
|
||||
pbCommonAnimation("HealthUp",battler) if showAnim && @battle.showAnims
|
||||
elsif battler.hp<oldHP
|
||||
pbCommonAnimation("HealthDown",battler) if showAnim && @battle.showAnims
|
||||
end
|
||||
@sprites["dataBox_#{battler.index}"].animateHP(oldHP,battler.hp,battler.totalhp)
|
||||
while @sprites["dataBox_#{battler.index}"].animatingHP
|
||||
pbUpdate
|
||||
end
|
||||
end
|
||||
|
||||
def pbDamageAnimation(battler,effectiveness=0)
|
||||
@briefMessage = false
|
||||
# Damage animation
|
||||
damageAnim = Animation::BattlerDamage.new(@sprites,@viewport,battler.index,effectiveness)
|
||||
loop do
|
||||
damageAnim.update
|
||||
pbUpdate
|
||||
break if damageAnim.animDone?
|
||||
end
|
||||
damageAnim.dispose
|
||||
end
|
||||
|
||||
# Animates battlers flashing and data boxes' HP bars because of damage taken
|
||||
# by an attack. targets is an array, which are all animated simultaneously.
|
||||
# Each element in targets is also an array: [battler, old HP, effectiveness]
|
||||
def pbHitAndHPLossAnimation(targets)
|
||||
@briefMessage = false
|
||||
# Set up animations
|
||||
damageAnims = []
|
||||
targets.each do |t|
|
||||
anim = Animation::BattlerDamage.new(@sprites,@viewport,t[0].index,t[2])
|
||||
damageAnims.push(anim)
|
||||
@sprites["dataBox_#{t[0].index}"].animateHP(t[1],t[0].hp,t[0].totalhp)
|
||||
end
|
||||
# Update loop
|
||||
loop do
|
||||
damageAnims.each { |a| a.update }
|
||||
pbUpdate
|
||||
allDone = true
|
||||
targets.each do |t|
|
||||
next if !@sprites["dataBox_#{t[0].index}"].animatingHP
|
||||
allDone = false
|
||||
break
|
||||
end
|
||||
next if !allDone
|
||||
damageAnims.each do |a|
|
||||
next if a.animDone?
|
||||
allDone = false
|
||||
break
|
||||
end
|
||||
next if !allDone
|
||||
break
|
||||
end
|
||||
damageAnims.each { |a| a.dispose }
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Animates a data box's Exp bar
|
||||
#=============================================================================
|
||||
def pbEXPBar(battler,startExp,endExp,tempExp1,tempExp2)
|
||||
return if !battler || endExp == startExp
|
||||
startExpLevel = tempExp1-startExp
|
||||
endExpLevel = tempExp2-startExp
|
||||
expRange = endExp-startExp
|
||||
dataBox = @sprites["dataBox_#{battler.index}"]
|
||||
dataBox.animateExp(startExpLevel,endExpLevel,expRange)
|
||||
while dataBox.animatingExp
|
||||
pbUpdate
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Shows stats windows upon a Pokémon levelling up
|
||||
#=============================================================================
|
||||
def pbLevelUp(pkmn,_battler,oldTotalHP,oldAttack,oldDefense,oldSpAtk,oldSpDef,oldSpeed)
|
||||
pbTopRightWindow(
|
||||
_INTL("Max. HP<r>+{1}\r\nAttack<r>+{2}\r\nDefense<r>+{3}\r\nSp. Atk<r>+{4}\r\nSp. Def<r>+{5}\r\nSpeed<r>+{6}",
|
||||
pkmn.totalhp-oldTotalHP,pkmn.attack-oldAttack,pkmn.defense-oldDefense,
|
||||
pkmn.spatk-oldSpAtk,pkmn.spdef-oldSpDef,pkmn.speed-oldSpeed))
|
||||
pbTopRightWindow(
|
||||
_INTL("Max. HP<r>{1}\r\nAttack<r>{2}\r\nDefense<r>{3}\r\nSp. Atk<r>{4}\r\nSp. Def<r>{5}\r\nSpeed<r>{6}",
|
||||
pkmn.totalhp,pkmn.attack,pkmn.defense,pkmn.spatk,pkmn.spdef,pkmn.speed))
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Animates a Pokémon fainting
|
||||
#=============================================================================
|
||||
def pbFaintBattler(battler)
|
||||
@briefMessage = false
|
||||
# Pokémon plays cry and drops down, data box disappears
|
||||
faintAnim = Animation::BattlerFaint.new(@sprites,@viewport,battler.index,@battle)
|
||||
dataBoxAnim = Animation::DataBoxDisappear.new(@sprites,@viewport,battler.index)
|
||||
loop do
|
||||
faintAnim.update
|
||||
dataBoxAnim.update
|
||||
pbUpdate
|
||||
break if faintAnim.animDone? && dataBoxAnim.animDone?
|
||||
end
|
||||
faintAnim.dispose
|
||||
dataBoxAnim.dispose
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Animates throwing a Poké Ball at a Pokémon in an attempt to catch it
|
||||
#=============================================================================
|
||||
def pbThrow(ball,shakes,critical,targetBattler,showPlayer=false)
|
||||
@briefMessage = false
|
||||
captureAnim = Animation::PokeballThrowCapture.new(@sprites,@viewport,
|
||||
ball,shakes,critical,@battle.battlers[targetBattler],showPlayer)
|
||||
loop do
|
||||
captureAnim.update
|
||||
pbUpdate
|
||||
break if captureAnim.animDone? && !inPartyAnimation?
|
||||
end
|
||||
captureAnim.dispose
|
||||
end
|
||||
|
||||
def pbThrowSuccess
|
||||
return if @battle.opponent
|
||||
@briefMessage = false
|
||||
pbMEPlay(pbGetWildCaptureME)
|
||||
i = 0
|
||||
loop do
|
||||
pbUpdate
|
||||
break if i>=Graphics.frame_rate*3.5 # 3.5 seconds
|
||||
i += 1
|
||||
end
|
||||
pbMEStop
|
||||
end
|
||||
|
||||
def pbHideCaptureBall(idxBattler)
|
||||
# NOTE: It's not really worth writing a whole Battle::Scene::Animation class
|
||||
# for making the capture ball fade out.
|
||||
ball = @sprites["captureBall"]
|
||||
return if !ball
|
||||
# Data box disappear animation
|
||||
dataBoxAnim = Animation::DataBoxDisappear.new(@sprites,@viewport,idxBattler)
|
||||
loop do
|
||||
dataBoxAnim.update
|
||||
ball.opacity -= 12*20/Graphics.frame_rate if ball.opacity>0
|
||||
pbUpdate
|
||||
break if dataBoxAnim.animDone? && ball.opacity<=0
|
||||
end
|
||||
dataBoxAnim.dispose
|
||||
end
|
||||
|
||||
def pbThrowAndDeflect(ball,idxBattler)
|
||||
@briefMessage = false
|
||||
throwAnim = Animation::PokeballThrowDeflect.new(@sprites,@viewport,
|
||||
ball,@battle.battlers[idxBattler])
|
||||
loop do
|
||||
throwAnim.update
|
||||
pbUpdate
|
||||
break if throwAnim.animDone?
|
||||
end
|
||||
throwAnim.dispose
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Hides all battler shadows before yielding to a move animation, and then
|
||||
# restores the shadows afterwards
|
||||
#=============================================================================
|
||||
def pbSaveShadows
|
||||
# Remember which shadows were visible
|
||||
shadows = Array.new(@battle.battlers.length) do |i|
|
||||
shadow = @sprites["shadow_#{i}"]
|
||||
ret = (shadow) ? shadow.visible : false
|
||||
shadow.visible = false if shadow
|
||||
next ret
|
||||
end
|
||||
# Yield to other code, i.e. playing an animation
|
||||
yield
|
||||
# Restore shadow visibility
|
||||
for i in 0...@battle.battlers.length
|
||||
shadow = @sprites["shadow_#{i}"]
|
||||
shadow.visible = shadows[i] if shadow
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Loads a move/common animation
|
||||
#=============================================================================
|
||||
# Returns the animation ID to use for a given move/user. Returns nil if that
|
||||
# move has no animations defined for it.
|
||||
def pbFindMoveAnimDetails(move2anim,moveID,idxUser,hitNum=0)
|
||||
real_move_id = GameData::Move.get(moveID).id
|
||||
noFlip = false
|
||||
if (idxUser&1)==0 # On player's side
|
||||
anim = move2anim[0][real_move_id]
|
||||
else # On opposing side
|
||||
anim = move2anim[1][real_move_id]
|
||||
noFlip = true if anim
|
||||
anim = move2anim[0][real_move_id] if !anim
|
||||
end
|
||||
return [anim+hitNum,noFlip] if anim
|
||||
return nil
|
||||
end
|
||||
|
||||
# Returns the animation ID to use for a given move. If the move has no
|
||||
# animations, tries to use a default move animation depending on the move's
|
||||
# type. If that default move animation doesn't exist, trues to use Tackle's
|
||||
# move animation. Returns nil if it can't find any of these animations to use.
|
||||
def pbFindMoveAnimation(moveID, idxUser, hitNum)
|
||||
begin
|
||||
move2anim = pbLoadMoveToAnim
|
||||
# Find actual animation requested (an opponent using the animation first
|
||||
# looks for an OppMove version then a Move version)
|
||||
anim = pbFindMoveAnimDetails(move2anim, moveID, idxUser, hitNum)
|
||||
return anim if anim
|
||||
# Actual animation not found, get the default animation for the move's type
|
||||
moveData = GameData::Move.get(moveID)
|
||||
target_data = GameData::Target.get(moveData.target)
|
||||
moveType = moveData.type
|
||||
moveKind = moveData.category
|
||||
moveKind += 3 if target_data.num_targets > 1 || target_data.affects_foe_side
|
||||
moveKind += 3 if moveKind == 2 && target_data.num_targets > 0
|
||||
# [one target physical, one target special, user status,
|
||||
# multiple targets physical, multiple targets special, non-user status]
|
||||
typeDefaultAnim = {
|
||||
:NORMAL => [:TACKLE, :SONICBOOM, :DEFENSECURL, :EXPLOSION, :SWIFT, :TAILWHIP],
|
||||
:FIGHTING => [:MACHPUNCH, :AURASPHERE, :DETECT, nil, nil, nil],
|
||||
:FLYING => [:WINGATTACK, :GUST, :ROOST, nil, :AIRCUTTER, :FEATHERDANCE],
|
||||
:POISON => [:POISONSTING, :SLUDGE, :ACIDARMOR, nil, :ACID, :POISONPOWDER],
|
||||
:GROUND => [:SANDTOMB, :MUDSLAP, nil, :EARTHQUAKE, :EARTHPOWER, :MUDSPORT],
|
||||
:ROCK => [:ROCKTHROW, :POWERGEM, :ROCKPOLISH, :ROCKSLIDE, nil, :SANDSTORM],
|
||||
:BUG => [:TWINEEDLE, :BUGBUZZ, :QUIVERDANCE, nil, :STRUGGLEBUG, :STRINGSHOT],
|
||||
:GHOST => [:LICK, :SHADOWBALL, :GRUDGE, nil, nil, :CONFUSERAY],
|
||||
:STEEL => [:IRONHEAD, :MIRRORSHOT, :IRONDEFENSE, nil, nil, :METALSOUND],
|
||||
:FIRE => [:FIREPUNCH, :EMBER, :SUNNYDAY, nil, :INCINERATE, :WILLOWISP],
|
||||
:WATER => [:CRABHAMMER, :WATERGUN, :AQUARING, nil, :SURF, :WATERSPORT],
|
||||
:GRASS => [:VINEWHIP, :MEGADRAIN, :COTTONGUARD, :RAZORLEAF, nil, :SPORE],
|
||||
:ELECTRIC => [:THUNDERPUNCH, :THUNDERSHOCK, :CHARGE, nil, :DISCHARGE, :THUNDERWAVE],
|
||||
:PSYCHIC => [:ZENHEADBUTT, :CONFUSION, :CALMMIND, nil, :SYNCHRONOISE, :MIRACLEEYE],
|
||||
:ICE => [:ICEPUNCH, :ICEBEAM, :MIST, nil, :POWDERSNOW, :HAIL],
|
||||
:DRAGON => [:DRAGONCLAW, :DRAGONRAGE, :DRAGONDANCE, nil, :TWISTER, nil],
|
||||
:DARK => [:PURSUIT, :DARKPULSE, :HONECLAWS, nil, :SNARL, :EMBARGO],
|
||||
:FAIRY => [:TACKLE, :FAIRYWIND, :MOONLIGHT, nil, :SWIFT, :SWEETKISS]
|
||||
}
|
||||
if typeDefaultAnim[moveType]
|
||||
anims = typeDefaultAnim[moveType]
|
||||
if GameData::Move.exists?(anims[moveKind])
|
||||
anim = pbFindMoveAnimDetails(move2anim, anims[moveKind], idxUser)
|
||||
end
|
||||
if !anim && moveKind >= 3 && GameData::Move.exists?(anims[moveKind - 3])
|
||||
anim = pbFindMoveAnimDetails(move2anim, anims[moveKind - 3], idxUser)
|
||||
end
|
||||
if !anim && GameData::Move.exists?(anims[2])
|
||||
anim = pbFindMoveAnimDetails(move2anim, anims[2], idxUser)
|
||||
end
|
||||
end
|
||||
return anim if anim
|
||||
# Default animation for the move's type not found, use Tackle's animation
|
||||
if GameData::Move.exists?(:TACKLE)
|
||||
return pbFindMoveAnimDetails(move2anim, :TACKLE, idxUser)
|
||||
end
|
||||
rescue
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Plays a move/common animation
|
||||
#=============================================================================
|
||||
# Plays a move animation.
|
||||
def pbAnimation(moveID,user,targets,hitNum=0)
|
||||
animID = pbFindMoveAnimation(moveID,user.index,hitNum)
|
||||
return if !animID
|
||||
anim = animID[0]
|
||||
target = (targets && targets.is_a?(Array)) ? targets[0] : targets
|
||||
animations = pbLoadBattleAnimations
|
||||
return if !animations
|
||||
pbSaveShadows {
|
||||
if animID[1] # On opposing side and using OppMove animation
|
||||
pbAnimationCore(animations[anim],target,user,true)
|
||||
else # On player's side, and/or using Move animation
|
||||
pbAnimationCore(animations[anim],user,target)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
# Plays a common animation.
|
||||
def pbCommonAnimation(animName,user=nil,target=nil)
|
||||
return if nil_or_empty?(animName)
|
||||
target = target[0] if target && target.is_a?(Array)
|
||||
animations = pbLoadBattleAnimations
|
||||
return if !animations
|
||||
animations.each do |a|
|
||||
next if !a || a.name!="Common:"+animName
|
||||
pbAnimationCore(a,user,(target!=nil) ? target : user)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
def pbAnimationCore(animation,user,target,oppMove=false)
|
||||
return if !animation
|
||||
@briefMessage = false
|
||||
userSprite = (user) ? @sprites["pokemon_#{user.index}"] : nil
|
||||
targetSprite = (target) ? @sprites["pokemon_#{target.index}"] : nil
|
||||
# Remember the original positions of Pokémon sprites
|
||||
oldUserX = (userSprite) ? userSprite.x : 0
|
||||
oldUserY = (userSprite) ? userSprite.y : 0
|
||||
oldTargetX = (targetSprite) ? targetSprite.x : oldUserX
|
||||
oldTargetY = (targetSprite) ? targetSprite.y : oldUserY
|
||||
# Create the animation player
|
||||
animPlayer = PBAnimationPlayerX.new(animation,user,target,self,oppMove)
|
||||
# Apply a transformation to the animation based on where the user and target
|
||||
# actually are. Get the centres of each sprite.
|
||||
userHeight = (userSprite && userSprite.bitmap && !userSprite.bitmap.disposed?) ? userSprite.bitmap.height : 128
|
||||
if targetSprite
|
||||
targetHeight = (targetSprite.bitmap && !targetSprite.bitmap.disposed?) ? targetSprite.bitmap.height : 128
|
||||
else
|
||||
targetHeight = userHeight
|
||||
end
|
||||
animPlayer.setLineTransform(
|
||||
FOCUSUSER_X, FOCUSUSER_Y, FOCUSTARGET_X, FOCUSTARGET_Y,
|
||||
oldUserX, oldUserY - userHeight / 2, oldTargetX, oldTargetY - targetHeight / 2)
|
||||
# Play the animation
|
||||
animPlayer.start
|
||||
loop do
|
||||
animPlayer.update
|
||||
pbUpdate
|
||||
break if animPlayer.animDone?
|
||||
end
|
||||
animPlayer.dispose
|
||||
# Return Pokémon sprites to their original positions
|
||||
if userSprite
|
||||
userSprite.x = oldUserX
|
||||
userSprite.y = oldUserY
|
||||
userSprite.pbSetOrigin
|
||||
end
|
||||
if targetSprite
|
||||
targetSprite.x = oldTargetX
|
||||
targetSprite.y = oldTargetY
|
||||
targetSprite.pbSetOrigin
|
||||
end
|
||||
end
|
||||
end
|
||||
552
Data/Scripts/011_Battle/004_Scene/005_Battle_Scene_Menus.rb
Normal file
552
Data/Scripts/011_Battle/004_Scene/005_Battle_Scene_Menus.rb
Normal file
@@ -0,0 +1,552 @@
|
||||
#===============================================================================
|
||||
# Base class for all three menu classes below
|
||||
#===============================================================================
|
||||
class Battle::Scene::MenuBase
|
||||
attr_accessor :x
|
||||
attr_accessor :y
|
||||
attr_reader :z
|
||||
attr_reader :visible
|
||||
attr_reader :color
|
||||
attr_reader :index
|
||||
attr_reader :mode
|
||||
# NOTE: Button width is half the width of the graphic containing them all.
|
||||
BUTTON_HEIGHT = 46
|
||||
TEXT_BASE_COLOR = Battle::Scene::MESSAGE_BASE_COLOR
|
||||
TEXT_SHADOW_COLOR = Battle::Scene::MESSAGE_SHADOW_COLOR
|
||||
|
||||
def initialize(viewport=nil)
|
||||
@x = 0
|
||||
@y = 0
|
||||
@z = 0
|
||||
@visible = false
|
||||
@color = Color.new(0,0,0,0)
|
||||
@index = 0
|
||||
@mode = 0
|
||||
@disposed = false
|
||||
@sprites = {}
|
||||
@visibility = {}
|
||||
end
|
||||
|
||||
def dispose
|
||||
return if disposed?
|
||||
pbDisposeSpriteHash(@sprites)
|
||||
@disposed = true
|
||||
end
|
||||
|
||||
def disposed?; return @disposed; end
|
||||
|
||||
def z=(value)
|
||||
@z = value
|
||||
for i in @sprites
|
||||
i[1].z = value if !i[1].disposed?
|
||||
end
|
||||
end
|
||||
|
||||
def visible=(value)
|
||||
@visible = value
|
||||
for i in @sprites
|
||||
i[1].visible = (value && @visibility[i[0]]) if !i[1].disposed?
|
||||
end
|
||||
end
|
||||
|
||||
def color=(value)
|
||||
@color = value
|
||||
for i in @sprites
|
||||
i[1].color = value if !i[1].disposed?
|
||||
end
|
||||
end
|
||||
|
||||
def index=(value)
|
||||
oldValue = @index
|
||||
@index = value
|
||||
@cmdWindow.index = @index if @cmdWindow
|
||||
refresh if @index!=oldValue
|
||||
end
|
||||
|
||||
def mode=(value)
|
||||
oldValue = @mode
|
||||
@mode = value
|
||||
refresh if @mode!=oldValue
|
||||
end
|
||||
|
||||
def addSprite(key,sprite)
|
||||
@sprites[key] = sprite
|
||||
@visibility[key] = true
|
||||
end
|
||||
|
||||
def setIndexAndMode(index,mode)
|
||||
oldIndex = @index
|
||||
oldMode = @mode
|
||||
@index = index
|
||||
@mode = mode
|
||||
@cmdWindow.index = @index if @cmdWindow
|
||||
refresh if @index!=oldIndex || @mode!=oldMode
|
||||
end
|
||||
|
||||
def refresh; end
|
||||
|
||||
def update
|
||||
pbUpdateSpriteHash(@sprites)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Command menu (Fight/Pokémon/Bag/Run)
|
||||
#===============================================================================
|
||||
class Battle::Scene::CommandMenu < Battle::Scene::MenuBase
|
||||
# If true, displays graphics from Graphics/Pictures/Battle/overlay_command.png
|
||||
# and Graphics/Pictures/Battle/cursor_command.png.
|
||||
# If false, just displays text and the command window over the graphic
|
||||
# Graphics/Pictures/Battle/overlay_message.png. You will need to edit def
|
||||
# pbShowWindow to make the graphic appear while the command menu is being
|
||||
# displayed.
|
||||
USE_GRAPHICS = true
|
||||
# Lists of which button graphics to use in different situations/types of battle.
|
||||
MODES = [
|
||||
[0,2,1,3], # 0 = Regular battle
|
||||
[0,2,1,9], # 1 = Regular battle with "Cancel" instead of "Run"
|
||||
[0,2,1,4], # 2 = Regular battle with "Call" instead of "Run"
|
||||
[5,7,6,3], # 3 = Safari Zone
|
||||
[0,8,1,3] # 4 = Bug Catching Contest
|
||||
]
|
||||
|
||||
def initialize(viewport,z)
|
||||
super(viewport)
|
||||
self.x = 0
|
||||
self.y = Graphics.height-96
|
||||
# Create message box (shows "What will X do?")
|
||||
@msgBox = Window_UnformattedTextPokemon.newWithSize("",
|
||||
self.x+16,self.y+2,220,Graphics.height-self.y,viewport)
|
||||
@msgBox.baseColor = TEXT_BASE_COLOR
|
||||
@msgBox.shadowColor = TEXT_SHADOW_COLOR
|
||||
@msgBox.windowskin = nil
|
||||
addSprite("msgBox",@msgBox)
|
||||
if USE_GRAPHICS
|
||||
# Create background graphic
|
||||
background = IconSprite.new(self.x,self.y,viewport)
|
||||
background.setBitmap("Graphics/Pictures/Battle/overlay_command")
|
||||
addSprite("background",background)
|
||||
# Create bitmaps
|
||||
@buttonBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/Battle/cursor_command"))
|
||||
# Create action buttons
|
||||
@buttons = Array.new(4) do |i| # 4 command options, therefore 4 buttons
|
||||
button = SpriteWrapper.new(viewport)
|
||||
button.bitmap = @buttonBitmap.bitmap
|
||||
button.x = self.x+Graphics.width-260
|
||||
button.x += (((i%2)==0) ? 0 : @buttonBitmap.width/2-4)
|
||||
button.y = self.y+6
|
||||
button.y += (((i/2)==0) ? 0 : BUTTON_HEIGHT-4)
|
||||
button.src_rect.width = @buttonBitmap.width/2
|
||||
button.src_rect.height = BUTTON_HEIGHT
|
||||
addSprite("button_#{i}",button)
|
||||
next button
|
||||
end
|
||||
else
|
||||
# Create command window (shows Fight/Bag/Pokémon/Run)
|
||||
@cmdWindow = Window_CommandPokemon.newWithSize([],
|
||||
self.x+Graphics.width-240,self.y,240,Graphics.height-self.y,viewport)
|
||||
@cmdWindow.columns = 2
|
||||
@cmdWindow.columnSpacing = 4
|
||||
@cmdWindow.ignore_input = true
|
||||
addSprite("cmdWindow",@cmdWindow)
|
||||
end
|
||||
self.z = z
|
||||
refresh
|
||||
end
|
||||
|
||||
def dispose
|
||||
super
|
||||
@buttonBitmap.dispose if @buttonBitmap
|
||||
end
|
||||
|
||||
def z=(value)
|
||||
super
|
||||
@msgBox.z += 1
|
||||
@cmdWindow.z += 1 if @cmdWindow
|
||||
end
|
||||
|
||||
def setTexts(value)
|
||||
@msgBox.text = value[0]
|
||||
return if USE_GRAPHICS
|
||||
commands = []
|
||||
for i in 1..4
|
||||
commands.push(value[i]) if value[i] && value[i]!=nil
|
||||
end
|
||||
@cmdWindow.commands = commands
|
||||
end
|
||||
|
||||
def refreshButtons
|
||||
return if !USE_GRAPHICS
|
||||
for i in 0...@buttons.length
|
||||
button = @buttons[i]
|
||||
button.src_rect.x = (i==@index) ? @buttonBitmap.width/2 : 0
|
||||
button.src_rect.y = MODES[@mode][i]*BUTTON_HEIGHT
|
||||
button.z = self.z + ((i==@index) ? 3 : 2)
|
||||
end
|
||||
end
|
||||
|
||||
def refresh
|
||||
@msgBox.refresh
|
||||
@cmdWindow.refresh if @cmdWindow
|
||||
refreshButtons
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Fight menu (choose a move)
|
||||
#===============================================================================
|
||||
class Battle::Scene::FightMenu < Battle::Scene::MenuBase
|
||||
attr_reader :battler
|
||||
attr_reader :shiftMode
|
||||
|
||||
# If true, displays graphics from Graphics/Pictures/Battle/overlay_fight.png
|
||||
# and Graphics/Pictures/Battle/cursor_fight.png.
|
||||
# If false, just displays text and the command window over the graphic
|
||||
# Graphics/Pictures/Battle/overlay_message.png. You will need to edit def
|
||||
# pbShowWindow to make the graphic appear while the command menu is being
|
||||
# displayed.
|
||||
USE_GRAPHICS = true
|
||||
TYPE_ICON_HEIGHT = 28
|
||||
# Text colours of PP of selected move
|
||||
PP_COLORS = [
|
||||
Color.new(248,72,72),Color.new(136,48,48), # Red, zero PP
|
||||
Color.new(248,136,32),Color.new(144,72,24), # Orange, 1/4 of total PP or less
|
||||
Color.new(248,192,0),Color.new(144,104,0), # Yellow, 1/2 of total PP or less
|
||||
TEXT_BASE_COLOR,TEXT_SHADOW_COLOR # Black, more than 1/2 of total PP
|
||||
]
|
||||
|
||||
def initialize(viewport,z)
|
||||
super(viewport)
|
||||
self.x = 0
|
||||
self.y = Graphics.height-96
|
||||
@battler = nil
|
||||
@shiftMode = 0
|
||||
# NOTE: @mode is for the display of the Mega Evolution button.
|
||||
# 0=don't show, 1=show unpressed, 2=show pressed
|
||||
if USE_GRAPHICS
|
||||
# Create bitmaps
|
||||
@buttonBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/Battle/cursor_fight"))
|
||||
@typeBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/types"))
|
||||
@megaEvoBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/Battle/cursor_mega"))
|
||||
@shiftBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/Battle/cursor_shift"))
|
||||
# Create background graphic
|
||||
background = IconSprite.new(0,Graphics.height-96,viewport)
|
||||
background.setBitmap("Graphics/Pictures/Battle/overlay_fight")
|
||||
addSprite("background",background)
|
||||
# Create move buttons
|
||||
@buttons = Array.new(Pokemon::MAX_MOVES) do |i|
|
||||
button = SpriteWrapper.new(viewport)
|
||||
button.bitmap = @buttonBitmap.bitmap
|
||||
button.x = self.x+4
|
||||
button.x += (((i%2)==0) ? 0 : @buttonBitmap.width/2-4)
|
||||
button.y = self.y+6
|
||||
button.y += (((i/2)==0) ? 0 : BUTTON_HEIGHT-4)
|
||||
button.src_rect.width = @buttonBitmap.width/2
|
||||
button.src_rect.height = BUTTON_HEIGHT
|
||||
addSprite("button_#{i}",button)
|
||||
next button
|
||||
end
|
||||
# Create overlay for buttons (shows move names)
|
||||
@overlay = BitmapSprite.new(Graphics.width,Graphics.height-self.y,viewport)
|
||||
@overlay.x = self.x
|
||||
@overlay.y = self.y
|
||||
pbSetNarrowFont(@overlay.bitmap)
|
||||
addSprite("overlay",@overlay)
|
||||
# Create overlay for selected move's info (shows move's PP)
|
||||
@infoOverlay = BitmapSprite.new(Graphics.width,Graphics.height-self.y,viewport)
|
||||
@infoOverlay.x = self.x
|
||||
@infoOverlay.y = self.y
|
||||
pbSetNarrowFont(@infoOverlay.bitmap)
|
||||
addSprite("infoOverlay",@infoOverlay)
|
||||
# Create type icon
|
||||
@typeIcon = SpriteWrapper.new(viewport)
|
||||
@typeIcon.bitmap = @typeBitmap.bitmap
|
||||
@typeIcon.x = self.x+416
|
||||
@typeIcon.y = self.y+20
|
||||
@typeIcon.src_rect.height = TYPE_ICON_HEIGHT
|
||||
addSprite("typeIcon",@typeIcon)
|
||||
# Create Mega Evolution button
|
||||
@megaButton = SpriteWrapper.new(viewport)
|
||||
@megaButton.bitmap = @megaEvoBitmap.bitmap
|
||||
@megaButton.x = self.x+120
|
||||
@megaButton.y = self.y-@megaEvoBitmap.height/2
|
||||
@megaButton.src_rect.height = @megaEvoBitmap.height/2
|
||||
addSprite("megaButton",@megaButton)
|
||||
# Create Shift button
|
||||
@shiftButton = SpriteWrapper.new(viewport)
|
||||
@shiftButton.bitmap = @shiftBitmap.bitmap
|
||||
@shiftButton.x = self.x+4
|
||||
@shiftButton.y = self.y-@shiftBitmap.height
|
||||
addSprite("shiftButton",@shiftButton)
|
||||
else
|
||||
# Create message box (shows type and PP of selected move)
|
||||
@msgBox = Window_AdvancedTextPokemon.newWithSize("",
|
||||
self.x+320,self.y,Graphics.width-320,Graphics.height-self.y,viewport)
|
||||
@msgBox.baseColor = TEXT_BASE_COLOR
|
||||
@msgBox.shadowColor = TEXT_SHADOW_COLOR
|
||||
pbSetNarrowFont(@msgBox.contents)
|
||||
addSprite("msgBox",@msgBox)
|
||||
# Create command window (shows moves)
|
||||
@cmdWindow = Window_CommandPokemon.newWithSize([],
|
||||
self.x,self.y,320,Graphics.height-self.y,viewport)
|
||||
@cmdWindow.columns = 2
|
||||
@cmdWindow.columnSpacing = 4
|
||||
@cmdWindow.ignore_input = true
|
||||
pbSetNarrowFont(@cmdWindow.contents)
|
||||
addSprite("cmdWindow",@cmdWindow)
|
||||
end
|
||||
self.z = z
|
||||
end
|
||||
|
||||
def dispose
|
||||
super
|
||||
@buttonBitmap.dispose if @buttonBitmap
|
||||
@typeBitmap.dispose if @typeBitmap
|
||||
@megaEvoBitmap.dispose if @megaEvoBitmap
|
||||
@shiftBitmap.dispose if @shiftBitmap
|
||||
end
|
||||
|
||||
def z=(value)
|
||||
super
|
||||
@msgBox.z += 1 if @msgBox
|
||||
@cmdWindow.z += 2 if @cmdWindow
|
||||
@overlay.z += 5 if @overlay
|
||||
@infoOverlay.z += 6 if @infoOverlay
|
||||
@typeIcon.z += 1 if @typeIcon
|
||||
end
|
||||
|
||||
def battler=(value)
|
||||
@battler = value
|
||||
refresh
|
||||
refreshButtonNames
|
||||
end
|
||||
|
||||
def shiftMode=(value)
|
||||
oldValue = @shiftMode
|
||||
@shiftMode = value
|
||||
refreshShiftButton if @shiftMode!=oldValue
|
||||
end
|
||||
|
||||
def refreshButtonNames
|
||||
moves = (@battler) ? @battler.moves : []
|
||||
if !USE_GRAPHICS
|
||||
# Fill in command window
|
||||
commands = []
|
||||
for i in 0...[4, moves.length].max
|
||||
commands.push((moves[i]) ? moves[i].name : "-")
|
||||
end
|
||||
@cmdWindow.commands = commands
|
||||
return
|
||||
end
|
||||
# Draw move names onto overlay
|
||||
@overlay.bitmap.clear
|
||||
textPos = []
|
||||
@buttons.each_with_index do |button,i|
|
||||
next if !@visibility["button_#{i}"]
|
||||
x = button.x-self.x+button.src_rect.width/2
|
||||
y = button.y-self.y+2
|
||||
moveNameBase = TEXT_BASE_COLOR
|
||||
if moves[i].type
|
||||
# NOTE: This takes a colour from a particular pixel in the button
|
||||
# graphic and makes the move name's base colour that same colour.
|
||||
# The pixel is at coordinates 10,34 in the button box. If you
|
||||
# change the graphic, you may want to change/remove the below line
|
||||
# of code to ensure the font is an appropriate colour.
|
||||
moveNameBase = button.bitmap.get_pixel(10,button.src_rect.y+34)
|
||||
end
|
||||
textPos.push([moves[i].name,x,y,2,moveNameBase,TEXT_SHADOW_COLOR])
|
||||
end
|
||||
pbDrawTextPositions(@overlay.bitmap,textPos)
|
||||
end
|
||||
|
||||
def refreshSelection
|
||||
moves = (@battler) ? @battler.moves : []
|
||||
if USE_GRAPHICS
|
||||
# Choose appropriate button graphics and z positions
|
||||
@buttons.each_with_index do |button,i|
|
||||
if !moves[i]
|
||||
@visibility["button_#{i}"] = false
|
||||
next
|
||||
end
|
||||
@visibility["button_#{i}"] = true
|
||||
button.src_rect.x = (i==@index) ? @buttonBitmap.width/2 : 0
|
||||
button.src_rect.y = GameData::Type.get(moves[i].type).icon_position * BUTTON_HEIGHT
|
||||
button.z = self.z + ((i==@index) ? 4 : 3)
|
||||
end
|
||||
end
|
||||
refreshMoveData(moves[@index])
|
||||
end
|
||||
|
||||
def refreshMoveData(move)
|
||||
# Write PP and type of the selected move
|
||||
if !USE_GRAPHICS
|
||||
moveType = GameData::Type.get(move.type).name
|
||||
if move.total_pp<=0
|
||||
@msgBox.text = _INTL("PP: ---<br>TYPE/{1}",moveType)
|
||||
else
|
||||
@msgBox.text = _ISPRINTF("PP: {1: 2d}/{2: 2d}<br>TYPE/{3:s}",
|
||||
move.pp,move.total_pp,moveType)
|
||||
end
|
||||
return
|
||||
end
|
||||
@infoOverlay.bitmap.clear
|
||||
if !move
|
||||
@visibility["typeIcon"] = false
|
||||
return
|
||||
end
|
||||
@visibility["typeIcon"] = true
|
||||
# Type icon
|
||||
type_number = GameData::Type.get(move.type).icon_position
|
||||
@typeIcon.src_rect.y = type_number * TYPE_ICON_HEIGHT
|
||||
# PP text
|
||||
if move.total_pp>0
|
||||
ppFraction = [(4.0*move.pp/move.total_pp).ceil,3].min
|
||||
textPos = []
|
||||
textPos.push([_INTL("PP: {1}/{2}",move.pp,move.total_pp),
|
||||
448,44,2,PP_COLORS[ppFraction*2],PP_COLORS[ppFraction*2+1]])
|
||||
pbDrawTextPositions(@infoOverlay.bitmap,textPos)
|
||||
end
|
||||
end
|
||||
|
||||
def refreshMegaEvolutionButton
|
||||
return if !USE_GRAPHICS
|
||||
@megaButton.src_rect.y = (@mode - 1) * @megaEvoBitmap.height / 2
|
||||
@megaButton.x = self.x + ((@shiftMode > 0) ? 204 : 120)
|
||||
@megaButton.z = self.z - 1
|
||||
@visibility["megaButton"] = (@mode > 0)
|
||||
end
|
||||
|
||||
def refreshShiftButton
|
||||
return if !USE_GRAPHICS
|
||||
@shiftButton.src_rect.y = (@shiftMode - 1) * @shiftBitmap.height
|
||||
@shiftButton.z = self.z - 1
|
||||
@visibility["shiftButton"] = (@shiftMode > 0)
|
||||
end
|
||||
|
||||
def refresh
|
||||
return if !@battler
|
||||
refreshSelection
|
||||
refreshMegaEvolutionButton
|
||||
refreshShiftButton
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Target menu (choose a move's target)
|
||||
# NOTE: Unlike the command and fight menus, this one doesn't have a textbox-only
|
||||
# version.
|
||||
#===============================================================================
|
||||
class Battle::Scene::TargetMenu < Battle::Scene::MenuBase
|
||||
attr_accessor :mode
|
||||
|
||||
# Lists of which button graphics to use in different situations/types of battle.
|
||||
MODES = [
|
||||
[0,2,1,3], # 0 = Regular battle
|
||||
[0,2,1,9], # 1 = Regular battle with "Cancel" instead of "Run"
|
||||
[0,2,1,4], # 2 = Regular battle with "Call" instead of "Run"
|
||||
[5,7,6,3], # 3 = Safari Zone
|
||||
[0,8,1,3] # 4 = Bug Catching Contest
|
||||
]
|
||||
CMD_BUTTON_WIDTH_SMALL = 170
|
||||
TEXT_BASE_COLOR = Color.new(240,248,224)
|
||||
TEXT_SHADOW_COLOR = Color.new(64,64,64)
|
||||
|
||||
def initialize(viewport,z,sideSizes)
|
||||
super(viewport)
|
||||
@sideSizes = sideSizes
|
||||
maxIndex = (@sideSizes[0]>@sideSizes[1]) ? (@sideSizes[0]-1)*2 : @sideSizes[1]*2-1
|
||||
@smallButtons = (@sideSizes.max>2)
|
||||
self.x = 0
|
||||
self.y = Graphics.height-96
|
||||
@texts = []
|
||||
# NOTE: @mode is for which buttons are shown as selected.
|
||||
# 0=select 1 button (@index), 1=select all buttons with text
|
||||
# Create bitmaps
|
||||
@buttonBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/Battle/cursor_target"))
|
||||
# Create target buttons
|
||||
@buttons = Array.new(maxIndex+1) do |i|
|
||||
numButtons = @sideSizes[i%2]
|
||||
next if numButtons<=i/2
|
||||
# NOTE: Battler indexes go from left to right from the perspective of
|
||||
# that side's trainer, so inc is different for each side for the
|
||||
# same value of i/2.
|
||||
inc = ((i%2)==0) ? i/2 : numButtons-1-i/2
|
||||
button = SpriteWrapper.new(viewport)
|
||||
button.bitmap = @buttonBitmap.bitmap
|
||||
button.src_rect.width = (@smallButtons) ? CMD_BUTTON_WIDTH_SMALL : @buttonBitmap.width/2
|
||||
button.src_rect.height = BUTTON_HEIGHT
|
||||
if @smallButtons
|
||||
button.x = self.x+170-[0,82,166][numButtons-1]
|
||||
else
|
||||
button.x = self.x+138-[0,116][numButtons-1]
|
||||
end
|
||||
button.x += (button.src_rect.width-4)*inc
|
||||
button.y = self.y+6
|
||||
button.y += (BUTTON_HEIGHT-4)*((i+1)%2)
|
||||
addSprite("button_#{i}",button)
|
||||
next button
|
||||
end
|
||||
# Create overlay (shows target names)
|
||||
@overlay = BitmapSprite.new(Graphics.width,Graphics.height-self.y,viewport)
|
||||
@overlay.x = self.x
|
||||
@overlay.y = self.y
|
||||
pbSetNarrowFont(@overlay.bitmap)
|
||||
addSprite("overlay",@overlay)
|
||||
self.z = z
|
||||
refresh
|
||||
end
|
||||
|
||||
def dispose
|
||||
super
|
||||
@buttonBitmap.dispose if @buttonBitmap
|
||||
end
|
||||
|
||||
def z=(value)
|
||||
super
|
||||
@overlay.z += 5 if @overlay
|
||||
end
|
||||
|
||||
def setDetails(texts,mode)
|
||||
@texts = texts
|
||||
@mode = mode
|
||||
refresh
|
||||
end
|
||||
|
||||
def refreshButtons
|
||||
# Choose appropriate button graphics and z positions
|
||||
@buttons.each_with_index do |button,i|
|
||||
next if !button
|
||||
sel = false
|
||||
buttonType = 0
|
||||
if @texts[i]
|
||||
sel ||= (@mode==0 && i==@index)
|
||||
sel ||= (@mode==1)
|
||||
buttonType = ((i%2)==0) ? 1 : 2
|
||||
end
|
||||
buttonType = 2*buttonType + ((@smallButtons) ? 1 : 0)
|
||||
button.src_rect.x = (sel) ? @buttonBitmap.width/2 : 0
|
||||
button.src_rect.y = buttonType*BUTTON_HEIGHT
|
||||
button.z = self.z + ((sel) ? 3 : 2)
|
||||
end
|
||||
# Draw target names onto overlay
|
||||
@overlay.bitmap.clear
|
||||
textpos = []
|
||||
@buttons.each_with_index do |button,i|
|
||||
next if !button || nil_or_empty?(@texts[i])
|
||||
x = button.x-self.x+button.src_rect.width/2
|
||||
y = button.y-self.y+2
|
||||
textpos.push([@texts[i],x,y,2,TEXT_BASE_COLOR,TEXT_SHADOW_COLOR])
|
||||
end
|
||||
pbDrawTextPositions(@overlay.bitmap,textpos)
|
||||
end
|
||||
|
||||
def refresh
|
||||
refreshButtons
|
||||
end
|
||||
end
|
||||
661
Data/Scripts/011_Battle/004_Scene/006_Battle_Scene_Objects.rb
Normal file
661
Data/Scripts/011_Battle/004_Scene/006_Battle_Scene_Objects.rb
Normal file
@@ -0,0 +1,661 @@
|
||||
#===============================================================================
|
||||
# Data box for regular battles
|
||||
#===============================================================================
|
||||
class Battle::Scene::PokemonDataBox < SpriteWrapper
|
||||
attr_reader :battler
|
||||
attr_accessor :selected
|
||||
attr_reader :animatingHP
|
||||
attr_reader :animatingExp
|
||||
|
||||
# Time in seconds to fully fill the Exp bar (from empty).
|
||||
EXP_BAR_FILL_TIME = 1.75
|
||||
# Maximum time in seconds to make a change to the HP bar.
|
||||
HP_BAR_CHANGE_TIME = 1.0
|
||||
STATUS_ICON_HEIGHT = 16
|
||||
NAME_BASE_COLOR = Color.new(72,72,72)
|
||||
NAME_SHADOW_COLOR = Color.new(184,184,184)
|
||||
MALE_BASE_COLOR = Color.new(48,96,216)
|
||||
MALE_SHADOW_COLOR = NAME_SHADOW_COLOR
|
||||
FEMALE_BASE_COLOR = Color.new(248,88,40)
|
||||
FEMALE_SHADOW_COLOR = NAME_SHADOW_COLOR
|
||||
|
||||
def initialize(battler,sideSize,viewport=nil)
|
||||
super(viewport)
|
||||
@battler = battler
|
||||
@sprites = {}
|
||||
@spriteX = 0
|
||||
@spriteY = 0
|
||||
@spriteBaseX = 0
|
||||
@selected = 0
|
||||
@frame = 0
|
||||
@showHP = false # Specifically, show the HP numbers
|
||||
@animatingHP = false
|
||||
@showExp = false # Specifically, show the Exp bar
|
||||
@animatingExp = false
|
||||
@expFlash = 0
|
||||
initializeDataBoxGraphic(sideSize)
|
||||
initializeOtherGraphics(viewport)
|
||||
refresh
|
||||
end
|
||||
|
||||
def initializeDataBoxGraphic(sideSize)
|
||||
onPlayerSide = ((@battler.index%2)==0)
|
||||
# Get the data box graphic and set whether the HP numbers/Exp bar are shown
|
||||
if sideSize==1 # One Pokémon on side, use the regular dara box BG
|
||||
bgFilename = ["Graphics/Pictures/Battle/databox_normal",
|
||||
"Graphics/Pictures/Battle/databox_normal_foe"][@battler.index%2]
|
||||
if onPlayerSide
|
||||
@showHP = true
|
||||
@showExp = true
|
||||
end
|
||||
else # Multiple Pokémon on side, use the thin dara box BG
|
||||
bgFilename = ["Graphics/Pictures/Battle/databox_thin",
|
||||
"Graphics/Pictures/Battle/databox_thin_foe"][@battler.index%2]
|
||||
end
|
||||
@databoxBitmap = AnimatedBitmap.new(bgFilename)
|
||||
# Determine the co-ordinates of the data box and the left edge padding width
|
||||
if onPlayerSide
|
||||
@spriteX = Graphics.width - 244
|
||||
@spriteY = Graphics.height - 192
|
||||
@spriteBaseX = 34
|
||||
else
|
||||
@spriteX = -16
|
||||
@spriteY = 36
|
||||
@spriteBaseX = 16
|
||||
end
|
||||
case sideSize
|
||||
when 2
|
||||
@spriteX += [-12, 12, 0, 0][@battler.index]
|
||||
@spriteY += [-20, -34, 34, 20][@battler.index]
|
||||
when 3
|
||||
@spriteX += [-12, 12, -6, 6, 0, 0][@battler.index]
|
||||
@spriteY += [-42, -46, 4, 0, 50, 46][@battler.index]
|
||||
end
|
||||
end
|
||||
|
||||
def initializeOtherGraphics(viewport)
|
||||
# Create other bitmaps
|
||||
@numbersBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/Battle/icon_numbers"))
|
||||
@hpBarBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/Battle/overlay_hp"))
|
||||
@expBarBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/Battle/overlay_exp"))
|
||||
# Create sprite to draw HP numbers on
|
||||
@hpNumbers = BitmapSprite.new(124,16,viewport)
|
||||
pbSetSmallFont(@hpNumbers.bitmap)
|
||||
@sprites["hpNumbers"] = @hpNumbers
|
||||
# Create sprite wrapper that displays HP bar
|
||||
@hpBar = SpriteWrapper.new(viewport)
|
||||
@hpBar.bitmap = @hpBarBitmap.bitmap
|
||||
@hpBar.src_rect.height = @hpBarBitmap.height/3
|
||||
@sprites["hpBar"] = @hpBar
|
||||
# Create sprite wrapper that displays Exp bar
|
||||
@expBar = SpriteWrapper.new(viewport)
|
||||
@expBar.bitmap = @expBarBitmap.bitmap
|
||||
@sprites["expBar"] = @expBar
|
||||
# Create sprite wrapper that displays everything except the above
|
||||
@contents = BitmapWrapper.new(@databoxBitmap.width,@databoxBitmap.height)
|
||||
self.bitmap = @contents
|
||||
self.visible = false
|
||||
self.z = 150+((@battler.index)/2)*5
|
||||
pbSetSystemFont(self.bitmap)
|
||||
end
|
||||
|
||||
def dispose
|
||||
pbDisposeSpriteHash(@sprites)
|
||||
@databoxBitmap.dispose
|
||||
@numbersBitmap.dispose
|
||||
@hpBarBitmap.dispose
|
||||
@expBarBitmap.dispose
|
||||
@contents.dispose
|
||||
super
|
||||
end
|
||||
|
||||
def x=(value)
|
||||
super
|
||||
@hpBar.x = value+@spriteBaseX+102
|
||||
@expBar.x = value+@spriteBaseX+6
|
||||
@hpNumbers.x = value+@spriteBaseX+80
|
||||
end
|
||||
|
||||
def y=(value)
|
||||
super
|
||||
@hpBar.y = value+40
|
||||
@expBar.y = value+74
|
||||
@hpNumbers.y = value+52
|
||||
end
|
||||
|
||||
def z=(value)
|
||||
super
|
||||
@hpBar.z = value+1
|
||||
@expBar.z = value+1
|
||||
@hpNumbers.z = value+2
|
||||
end
|
||||
|
||||
def opacity=(value)
|
||||
super
|
||||
for i in @sprites
|
||||
i[1].opacity = value if !i[1].disposed?
|
||||
end
|
||||
end
|
||||
|
||||
def visible=(value)
|
||||
super
|
||||
for i in @sprites
|
||||
i[1].visible = value if !i[1].disposed?
|
||||
end
|
||||
@expBar.visible = (value && @showExp)
|
||||
end
|
||||
|
||||
def color=(value)
|
||||
super
|
||||
for i in @sprites
|
||||
i[1].color = value if !i[1].disposed?
|
||||
end
|
||||
end
|
||||
|
||||
def battler=(b)
|
||||
@battler = b
|
||||
self.visible = (@battler && !@battler.fainted?)
|
||||
end
|
||||
|
||||
def hp
|
||||
return (@animatingHP) ? @currentHP : @battler.hp
|
||||
end
|
||||
|
||||
def exp_fraction
|
||||
return 0.0 if @rangeExp == 0
|
||||
return (@animatingExp) ? @currentExp.to_f/@rangeExp : @battler.pokemon.exp_fraction
|
||||
end
|
||||
|
||||
def animateHP(oldHP,newHP,rangeHP)
|
||||
@currentHP = oldHP
|
||||
@endHP = newHP
|
||||
@rangeHP = rangeHP
|
||||
# NOTE: A change in HP takes the same amount of time to animate, no matter
|
||||
# how big a change it is.
|
||||
@hpIncPerFrame = (newHP-oldHP).abs/(HP_BAR_CHANGE_TIME*Graphics.frame_rate)
|
||||
# minInc is the smallest amount that HP is allowed to change per frame.
|
||||
# This avoids a tiny change in HP still taking HP_BAR_CHANGE_TIME seconds.
|
||||
minInc = (rangeHP*4)/(@hpBarBitmap.width*HP_BAR_CHANGE_TIME*Graphics.frame_rate)
|
||||
@hpIncPerFrame = minInc if @hpIncPerFrame<minInc
|
||||
@animatingHP = true
|
||||
end
|
||||
|
||||
def animateExp(oldExp,newExp,rangeExp)
|
||||
return if rangeExp == 0
|
||||
@currentExp = oldExp
|
||||
@endExp = newExp
|
||||
@rangeExp = rangeExp
|
||||
# NOTE: Filling the Exp bar from empty to full takes EXP_BAR_FILL_TIME
|
||||
# seconds no matter what. Filling half of it takes half as long, etc.
|
||||
@expIncPerFrame = rangeExp/(EXP_BAR_FILL_TIME*Graphics.frame_rate)
|
||||
@animatingExp = true
|
||||
pbSEPlay("Pkmn exp gain") if @showExp
|
||||
end
|
||||
|
||||
def pbDrawNumber(number,btmp,startX,startY,align=0)
|
||||
# -1 means draw the / character
|
||||
n = (number == -1) ? [10] : number.to_i.digits.reverse
|
||||
charWidth = @numbersBitmap.width/11
|
||||
charHeight = @numbersBitmap.height
|
||||
startX -= charWidth*n.length if align==1
|
||||
n.each do |i|
|
||||
btmp.blt(startX,startY,@numbersBitmap.bitmap,Rect.new(i*charWidth,0,charWidth,charHeight))
|
||||
startX += charWidth
|
||||
end
|
||||
end
|
||||
|
||||
def refresh
|
||||
self.bitmap.clear
|
||||
return if !@battler.pokemon
|
||||
textPos = []
|
||||
imagePos = []
|
||||
# Draw background panel
|
||||
self.bitmap.blt(0,0,@databoxBitmap.bitmap,Rect.new(0,0,@databoxBitmap.width,@databoxBitmap.height))
|
||||
# Draw Pokémon's name
|
||||
nameWidth = self.bitmap.text_size(@battler.name).width
|
||||
nameOffset = 0
|
||||
nameOffset = nameWidth-116 if nameWidth>116
|
||||
textPos.push([@battler.name,@spriteBaseX+8-nameOffset,0,false,NAME_BASE_COLOR,NAME_SHADOW_COLOR])
|
||||
# Draw Pokémon's gender symbol
|
||||
case @battler.displayGender
|
||||
when 0 # Male
|
||||
textPos.push([_INTL("♂"),@spriteBaseX+126,0,false,MALE_BASE_COLOR,MALE_SHADOW_COLOR])
|
||||
when 1 # Female
|
||||
textPos.push([_INTL("♀"),@spriteBaseX+126,0,false,FEMALE_BASE_COLOR,FEMALE_SHADOW_COLOR])
|
||||
end
|
||||
pbDrawTextPositions(self.bitmap,textPos)
|
||||
# Draw Pokémon's level
|
||||
imagePos.push(["Graphics/Pictures/Battle/overlay_lv",@spriteBaseX+140,16])
|
||||
pbDrawNumber(@battler.level,self.bitmap,@spriteBaseX+162,16)
|
||||
# Draw shiny icon
|
||||
if @battler.shiny?
|
||||
shinyX = (@battler.opposes?(0)) ? 206 : -6 # Foe's/player's
|
||||
imagePos.push(["Graphics/Pictures/shiny",@spriteBaseX+shinyX,36])
|
||||
end
|
||||
# Draw Mega Evolution/Primal Reversion icon
|
||||
if @battler.mega?
|
||||
imagePos.push(["Graphics/Pictures/Battle/icon_mega",@spriteBaseX+8,34])
|
||||
elsif @battler.primal?
|
||||
primalX = (@battler.opposes?) ? 208 : -28 # Foe's/player's
|
||||
if @battler.isSpecies?(:KYOGRE)
|
||||
imagePos.push(["Graphics/Pictures/Battle/icon_primal_Kyogre",@spriteBaseX+primalX,4])
|
||||
elsif @battler.isSpecies?(:GROUDON)
|
||||
imagePos.push(["Graphics/Pictures/Battle/icon_primal_Groudon",@spriteBaseX+primalX,4])
|
||||
end
|
||||
end
|
||||
# Draw owned icon (foe Pokémon only)
|
||||
if @battler.owned? && @battler.opposes?(0)
|
||||
imagePos.push(["Graphics/Pictures/Battle/icon_own",@spriteBaseX+8,36])
|
||||
end
|
||||
# Draw status icon
|
||||
if @battler.status != :NONE
|
||||
if @battler.status == :POISON && @battler.statusCount > 0 # Badly poisoned
|
||||
s = GameData::Status.count
|
||||
else
|
||||
s = GameData::Status.get(@battler.status).icon_position
|
||||
end
|
||||
imagePos.push(["Graphics/Pictures/Battle/icon_statuses",@spriteBaseX+24,36,
|
||||
0, s * STATUS_ICON_HEIGHT, -1, STATUS_ICON_HEIGHT]) if s >= 0
|
||||
end
|
||||
pbDrawImagePositions(self.bitmap,imagePos)
|
||||
refreshHP
|
||||
refreshExp
|
||||
end
|
||||
|
||||
def refreshHP
|
||||
@hpNumbers.bitmap.clear
|
||||
return if !@battler.pokemon
|
||||
# Show HP numbers
|
||||
if @showHP
|
||||
pbDrawNumber(self.hp,@hpNumbers.bitmap,54,2,1)
|
||||
pbDrawNumber(-1,@hpNumbers.bitmap,54,2) # / char
|
||||
pbDrawNumber(@battler.totalhp,@hpNumbers.bitmap,70,2)
|
||||
end
|
||||
# Resize HP bar
|
||||
w = 0
|
||||
if self.hp>0
|
||||
w = @hpBarBitmap.width.to_f*self.hp/@battler.totalhp
|
||||
w = 1 if w<1
|
||||
# NOTE: The line below snaps the bar's width to the nearest 2 pixels, to
|
||||
# fit in with the rest of the graphics which are doubled in size.
|
||||
w = ((w/2.0).round)*2
|
||||
end
|
||||
@hpBar.src_rect.width = w
|
||||
hpColor = 0 # Green bar
|
||||
hpColor = 1 if self.hp<=@battler.totalhp/2 # Yellow bar
|
||||
hpColor = 2 if self.hp<=@battler.totalhp/4 # Red bar
|
||||
@hpBar.src_rect.y = hpColor*@hpBarBitmap.height/3
|
||||
end
|
||||
|
||||
def refreshExp
|
||||
return if !@showExp
|
||||
w = exp_fraction * @expBarBitmap.width
|
||||
# NOTE: The line below snaps the bar's width to the nearest 2 pixels, to
|
||||
# fit in with the rest of the graphics which are doubled in size.
|
||||
w = ((w/2).round)*2
|
||||
@expBar.src_rect.width = w
|
||||
end
|
||||
|
||||
def updateHPAnimation
|
||||
return if !@animatingHP
|
||||
if @currentHP<@endHP # Gaining HP
|
||||
@currentHP += @hpIncPerFrame
|
||||
@currentHP = @endHP if @currentHP>=@endHP
|
||||
elsif @currentHP>@endHP # Losing HP
|
||||
@currentHP -= @hpIncPerFrame
|
||||
@currentHP = @endHP if @currentHP<=@endHP
|
||||
end
|
||||
# Refresh the HP bar/numbers
|
||||
refreshHP
|
||||
@animatingHP = false if @currentHP==@endHP
|
||||
end
|
||||
|
||||
def updateExpAnimation
|
||||
return if !@animatingExp
|
||||
if !@showExp # Not showing the Exp bar, no need to waste time animating it
|
||||
@currentExp = @endExp
|
||||
@animatingExp = false
|
||||
return
|
||||
end
|
||||
if @currentExp<@endExp # Gaining Exp
|
||||
@currentExp += @expIncPerFrame
|
||||
@currentExp = @endExp if @currentExp>=@endExp
|
||||
elsif @currentExp>@endExp # Losing Exp
|
||||
@currentExp -= @expIncPerFrame
|
||||
@currentExp = @endExp if @currentExp<=@endExp
|
||||
end
|
||||
# Refresh the Exp bar
|
||||
refreshExp
|
||||
return if @currentExp!=@endExp # Exp bar still has more to animate
|
||||
# Exp bar is completely filled, level up with a flash and sound effect
|
||||
if @currentExp>=@rangeExp
|
||||
if @expFlash==0
|
||||
pbSEStop
|
||||
@expFlash = Graphics.frame_rate/5
|
||||
pbSEPlay("Pkmn exp full")
|
||||
self.flash(Color.new(64,200,248,192),@expFlash)
|
||||
for i in @sprites
|
||||
i[1].flash(Color.new(64,200,248,192),@expFlash) if !i[1].disposed?
|
||||
end
|
||||
else
|
||||
@expFlash -= 1
|
||||
@animatingExp = false if @expFlash==0
|
||||
end
|
||||
else
|
||||
pbSEStop
|
||||
# Exp bar has finished filling, end animation
|
||||
@animatingExp = false
|
||||
end
|
||||
end
|
||||
|
||||
QUARTER_ANIM_PERIOD = Graphics.frame_rate*3/20
|
||||
|
||||
def updatePositions(frameCounter)
|
||||
self.x = @spriteX
|
||||
self.y = @spriteY
|
||||
# Data box bobbing while Pokémon is selected
|
||||
if @selected==1 || @selected==2 # Choosing commands/targeted or damaged
|
||||
case (frameCounter/QUARTER_ANIM_PERIOD).floor
|
||||
when 1 then self.y = @spriteY-2
|
||||
when 3 then self.y = @spriteY+2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update(frameCounter=0)
|
||||
super()
|
||||
# Animate HP bar
|
||||
updateHPAnimation
|
||||
# Animate Exp bar
|
||||
updateExpAnimation
|
||||
# Update coordinates of the data box
|
||||
updatePositions(frameCounter)
|
||||
pbUpdateSpriteHash(@sprites)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Splash bar to announce a triggered ability
|
||||
#===============================================================================
|
||||
class Battle::Scene::AbilitySplashBar < SpriteWrapper
|
||||
attr_reader :battler
|
||||
|
||||
TEXT_BASE_COLOR = Color.new(0,0,0)
|
||||
TEXT_SHADOW_COLOR = Color.new(248,248,248)
|
||||
|
||||
def initialize(side,viewport=nil)
|
||||
super(viewport)
|
||||
@side = side
|
||||
@battler = nil
|
||||
# Create sprite wrapper that displays background graphic
|
||||
@bgBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/Battle/ability_bar"))
|
||||
@bgSprite = SpriteWrapper.new(viewport)
|
||||
@bgSprite.bitmap = @bgBitmap.bitmap
|
||||
@bgSprite.src_rect.y = (side==0) ? 0 : @bgBitmap.height/2
|
||||
@bgSprite.src_rect.height = @bgBitmap.height/2
|
||||
# Create bitmap that displays the text
|
||||
@contents = BitmapWrapper.new(@bgBitmap.width,@bgBitmap.height/2)
|
||||
self.bitmap = @contents
|
||||
pbSetSystemFont(self.bitmap)
|
||||
# Position the bar
|
||||
self.x = (side==0) ? -Graphics.width/2 : Graphics.width
|
||||
self.y = (side==0) ? 180 : 80
|
||||
self.z = 120
|
||||
self.visible = false
|
||||
end
|
||||
|
||||
def dispose
|
||||
@bgSprite.dispose
|
||||
@bgBitmap.dispose
|
||||
@contents.dispose
|
||||
super
|
||||
end
|
||||
|
||||
def x=(value)
|
||||
super
|
||||
@bgSprite.x = value
|
||||
end
|
||||
|
||||
def y=(value)
|
||||
super
|
||||
@bgSprite.y = value
|
||||
end
|
||||
|
||||
def z=(value)
|
||||
super
|
||||
@bgSprite.z = value-1
|
||||
end
|
||||
|
||||
def opacity=(value)
|
||||
super
|
||||
@bgSprite.opacity = value
|
||||
end
|
||||
|
||||
def visible=(value)
|
||||
super
|
||||
@bgSprite.visible = value
|
||||
end
|
||||
|
||||
def color=(value)
|
||||
super
|
||||
@bgSprite.color = value
|
||||
end
|
||||
|
||||
def battler=(value)
|
||||
@battler = value
|
||||
refresh
|
||||
end
|
||||
|
||||
def refresh
|
||||
self.bitmap.clear
|
||||
return if !@battler
|
||||
textPos = []
|
||||
textX = (@side==0) ? 10 : self.bitmap.width-8
|
||||
# Draw Pokémon's name
|
||||
textPos.push([_INTL("{1}'s",@battler.name),textX,-4,@side==1,
|
||||
TEXT_BASE_COLOR,TEXT_SHADOW_COLOR,true])
|
||||
# Draw Pokémon's ability
|
||||
textPos.push([@battler.abilityName,textX,26,@side==1,
|
||||
TEXT_BASE_COLOR,TEXT_SHADOW_COLOR,true])
|
||||
pbDrawTextPositions(self.bitmap,textPos)
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
@bgSprite.update
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Pokémon sprite (used in battle)
|
||||
#===============================================================================
|
||||
class Battle::Scene::BattlerSprite < RPG::Sprite
|
||||
attr_reader :pkmn
|
||||
attr_accessor :index
|
||||
attr_accessor :selected
|
||||
attr_reader :sideSize
|
||||
|
||||
def initialize(viewport,sideSize,index,battleAnimations)
|
||||
super(viewport)
|
||||
@pkmn = nil
|
||||
@sideSize = sideSize
|
||||
@index = index
|
||||
@battleAnimations = battleAnimations
|
||||
# @selected: 0 = not selected, 1 = choosing action bobbing for this Pokémon,
|
||||
# 2 = flashing when targeted
|
||||
@selected = 0
|
||||
@frame = 0
|
||||
@updating = false
|
||||
@spriteX = 0 # Actual x coordinate
|
||||
@spriteY = 0 # Actual y coordinate
|
||||
@spriteXExtra = 0 # Offset due to "bobbing" animation
|
||||
@spriteYExtra = 0 # Offset due to "bobbing" animation
|
||||
@_iconBitmap = nil
|
||||
self.visible = false
|
||||
end
|
||||
|
||||
def dispose
|
||||
@_iconBitmap.dispose if @_iconBitmap
|
||||
@_iconBitmap = nil
|
||||
self.bitmap = nil if !self.disposed?
|
||||
super
|
||||
end
|
||||
|
||||
def x; return @spriteX; end
|
||||
def y; return @spriteY; end
|
||||
|
||||
def x=(value)
|
||||
@spriteX = value
|
||||
super(value+@spriteXExtra)
|
||||
end
|
||||
|
||||
def y=(value)
|
||||
@spriteY = value
|
||||
super(value+@spriteYExtra)
|
||||
end
|
||||
|
||||
def width; return (self.bitmap) ? self.bitmap.width : 0; end
|
||||
def height; return (self.bitmap) ? self.bitmap.height : 0; end
|
||||
|
||||
def visible=(value)
|
||||
@spriteVisible = value if !@updating # For selection/targeting flashing
|
||||
super
|
||||
end
|
||||
|
||||
# Set sprite's origin to bottom middle
|
||||
def pbSetOrigin
|
||||
return if !@_iconBitmap
|
||||
self.ox = @_iconBitmap.width/2
|
||||
self.oy = @_iconBitmap.height
|
||||
end
|
||||
|
||||
def pbSetPosition
|
||||
return if !@_iconBitmap
|
||||
pbSetOrigin
|
||||
if (@index%2)==0
|
||||
self.z = 50+5*@index/2
|
||||
else
|
||||
self.z = 50-5*(@index+1)/2
|
||||
end
|
||||
# Set original position
|
||||
p = Battle::Scene.pbBattlerPosition(@index,@sideSize)
|
||||
@spriteX = p[0]
|
||||
@spriteY = p[1]
|
||||
# Apply metrics
|
||||
@pkmn.species_data.apply_metrics_to_sprite(self, @index)
|
||||
end
|
||||
|
||||
def setPokemonBitmap(pkmn,back=false)
|
||||
@pkmn = pkmn
|
||||
@_iconBitmap.dispose if @_iconBitmap
|
||||
@_iconBitmap = GameData::Species.sprite_bitmap_from_pokemon(@pkmn, back)
|
||||
self.bitmap = (@_iconBitmap) ? @_iconBitmap.bitmap : nil
|
||||
pbSetPosition
|
||||
end
|
||||
|
||||
# This method plays the battle entrance animation of a Pokémon. By default
|
||||
# this is just playing the Pokémon's cry, but you can expand on it. The
|
||||
# recommendation is to create a PictureEx animation and push it into
|
||||
# the @battleAnimations array.
|
||||
def pbPlayIntroAnimation(pictureEx=nil)
|
||||
@pkmn.play_cry if @pkmn
|
||||
end
|
||||
|
||||
QUARTER_ANIM_PERIOD = Graphics.frame_rate*3/20
|
||||
SIXTH_ANIM_PERIOD = Graphics.frame_rate*2/20
|
||||
|
||||
def update(frameCounter=0)
|
||||
return if !@_iconBitmap
|
||||
@updating = true
|
||||
# Update bitmap
|
||||
@_iconBitmap.update
|
||||
self.bitmap = @_iconBitmap.bitmap
|
||||
# Pokémon sprite bobbing while Pokémon is selected
|
||||
@spriteYExtra = 0
|
||||
if @selected==1 # When choosing commands for this Pokémon
|
||||
case (frameCounter/QUARTER_ANIM_PERIOD).floor
|
||||
when 1 then @spriteYExtra = 2
|
||||
when 3 then @spriteYExtra = -2
|
||||
end
|
||||
end
|
||||
self.x = self.x
|
||||
self.y = self.y
|
||||
self.visible = @spriteVisible
|
||||
# Pokémon sprite blinking when targeted
|
||||
if @selected==2 && @spriteVisible
|
||||
case (frameCounter/SIXTH_ANIM_PERIOD).floor
|
||||
when 2, 5 then self.visible = false
|
||||
else self.visible = true
|
||||
end
|
||||
end
|
||||
@updating = false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Shadow sprite for Pokémon (used in battle)
|
||||
#===============================================================================
|
||||
class Battle::Scene::BattlerShadowSprite < RPG::Sprite
|
||||
attr_reader :pkmn
|
||||
attr_accessor :index
|
||||
attr_accessor :selected
|
||||
|
||||
def initialize(viewport,sideSize,index)
|
||||
super(viewport)
|
||||
@pkmn = nil
|
||||
@sideSize = sideSize
|
||||
@index = index
|
||||
@_iconBitmap = nil
|
||||
self.visible = false
|
||||
end
|
||||
|
||||
def dispose
|
||||
@_iconBitmap.dispose if @_iconBitmap
|
||||
@_iconBitmap = nil
|
||||
self.bitmap = nil if !self.disposed?
|
||||
super
|
||||
end
|
||||
|
||||
def width; return (self.bitmap) ? self.bitmap.width : 0; end
|
||||
def height; return (self.bitmap) ? self.bitmap.height : 0; end
|
||||
|
||||
# Set sprite's origin to centre
|
||||
def pbSetOrigin
|
||||
return if !@_iconBitmap
|
||||
self.ox = @_iconBitmap.width/2
|
||||
self.oy = @_iconBitmap.height/2
|
||||
end
|
||||
|
||||
def pbSetPosition
|
||||
return if !@_iconBitmap
|
||||
pbSetOrigin
|
||||
self.z = 3
|
||||
# Set original position
|
||||
p = Battle::Scene.pbBattlerPosition(@index,@sideSize)
|
||||
self.x = p[0]
|
||||
self.y = p[1]
|
||||
# Apply metrics
|
||||
@pkmn.species_data.apply_metrics_to_sprite(self, @index, true)
|
||||
end
|
||||
|
||||
def setPokemonBitmap(pkmn)
|
||||
@pkmn = pkmn
|
||||
@_iconBitmap.dispose if @_iconBitmap
|
||||
@_iconBitmap = GameData::Species.shadow_bitmap_from_pokemon(@pkmn)
|
||||
self.bitmap = (@_iconBitmap) ? @_iconBitmap.bitmap : nil
|
||||
pbSetPosition
|
||||
end
|
||||
|
||||
def update(frameCounter=0)
|
||||
return if !@_iconBitmap
|
||||
# Update bitmap
|
||||
@_iconBitmap.update
|
||||
self.bitmap = @_iconBitmap.bitmap
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,267 @@
|
||||
class Battle::Scene::Animation
|
||||
def initialize(sprites,viewport)
|
||||
@sprites = sprites
|
||||
@viewport = viewport
|
||||
@pictureEx = [] # For all the PictureEx
|
||||
@pictureSprites = [] # For all the sprites
|
||||
@tempSprites = [] # For sprites that exist only for this animation
|
||||
@animDone = false
|
||||
createProcesses
|
||||
end
|
||||
|
||||
def dispose
|
||||
@tempSprites.each { |s| s.dispose if s }
|
||||
end
|
||||
|
||||
def createProcesses; end
|
||||
def empty?; return @pictureEx.length==0; end
|
||||
def animDone?; return @animDone; end
|
||||
|
||||
def addSprite(s,origin=PictureOrigin::TopLeft)
|
||||
num = @pictureEx.length
|
||||
picture = PictureEx.new(s.z)
|
||||
picture.x = s.x
|
||||
picture.y = s.y
|
||||
picture.visible = s.visible
|
||||
picture.tone = s.tone.clone
|
||||
picture.setOrigin(0,origin)
|
||||
@pictureEx[num] = picture
|
||||
@pictureSprites[num] = s
|
||||
return picture
|
||||
end
|
||||
|
||||
def addNewSprite(x,y,name,origin=PictureOrigin::TopLeft)
|
||||
num = @pictureEx.length
|
||||
picture = PictureEx.new(num)
|
||||
picture.setXY(0,x,y)
|
||||
picture.setName(0,name)
|
||||
picture.setOrigin(0,origin)
|
||||
@pictureEx[num] = picture
|
||||
s = IconSprite.new(x,y,@viewport)
|
||||
s.setBitmap(name)
|
||||
@pictureSprites[num] = s
|
||||
@tempSprites.push(s)
|
||||
return picture
|
||||
end
|
||||
|
||||
def update
|
||||
return if @animDone
|
||||
@tempSprites.each { |s| s.update if s }
|
||||
finished = true
|
||||
@pictureEx.each_with_index do |p,i|
|
||||
next if !p.running?
|
||||
finished = false
|
||||
p.update
|
||||
setPictureIconSprite(@pictureSprites[i],p)
|
||||
end
|
||||
@animDone = true if finished
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
module Battle::Scene::Animation::BallAnimationMixin
|
||||
# Returns the color that the Pokémon turns when it goes into or out of its
|
||||
# Poké Ball.
|
||||
def getBattlerColorFromPokeBall(poke_ball)
|
||||
case poke_ball
|
||||
when :GREATBALL then return Color.new(132, 189, 247)
|
||||
when :SAFARIBALL then return Color.new(189, 247, 165)
|
||||
when :ULTRABALL then return Color.new(255, 255, 123)
|
||||
when :MASTERBALL then return Color.new(189, 165, 231)
|
||||
when :NETBALL then return Color.new(173, 255, 206)
|
||||
when :DIVEBALL then return Color.new( 99, 206, 247)
|
||||
when :NESTBALL then return Color.new(247, 222, 82)
|
||||
when :REPEATBALL then return Color.new(255, 198, 132)
|
||||
when :TIMERBALL then return Color.new(239, 247, 247)
|
||||
when :LUXURYBALL then return Color.new(255, 140, 82)
|
||||
when :PREMIERBALL then return Color.new(255, 74, 82)
|
||||
when :DUSKBALL then return Color.new(115, 115, 140)
|
||||
when :HEALBALL then return Color.new(255, 198, 231)
|
||||
when :QUICKBALL then return Color.new(140, 214, 255)
|
||||
when :CHERISHBALL then return Color.new(247, 66, 41)
|
||||
end
|
||||
return Color.new(255, 181, 247) # Poké Ball, Sport Ball, Apricorn Balls, others
|
||||
end
|
||||
|
||||
def addBallSprite(ballX, ballY, poke_ball)
|
||||
file_path = sprintf("Graphics/Battle animations/ball_%s", poke_ball)
|
||||
ball = addNewSprite(ballX, ballY, file_path, PictureOrigin::Center)
|
||||
@ballSprite = @pictureSprites.last
|
||||
if @ballSprite.bitmap.width >= @ballSprite.bitmap.height
|
||||
@ballSprite.src_rect.width = @ballSprite.bitmap.height / 2
|
||||
ball.setSrcSize(0, @ballSprite.bitmap.height / 2, @ballSprite.bitmap.height)
|
||||
end
|
||||
return ball
|
||||
end
|
||||
|
||||
def ballTracksHand(ball,traSprite,safariThrow=false)
|
||||
# Back sprite isn't animated, no hand-tracking needed
|
||||
if traSprite.bitmap.width<traSprite.bitmap.height*2
|
||||
ball.setVisible(7,true)
|
||||
ballStartX = traSprite.x
|
||||
ballStartX -= ball.totalDuration*(Graphics.width/(2*16)) if !safariThrow
|
||||
ballStartY = traSprite.y-traSprite.bitmap.height/2
|
||||
return ballStartX, ballStartY
|
||||
end
|
||||
# Back sprite is animated, make the Poké Ball track the trainer's hand
|
||||
coordSets = [[traSprite.x-44,traSprite.y-32],[-10,-36],[118,-4]]
|
||||
case @trainer.trainer_type
|
||||
when :POKEMONTRAINER_Leaf
|
||||
coordSets = [[traSprite.x-30,traSprite.y-30],[-18,-36],[118,-6]]
|
||||
when :POKEMONTRAINER_Brendan
|
||||
coordSets = [[traSprite.x-46,traSprite.y-40],[-4,-30],[118,-2]]
|
||||
when :POKEMONTRAINER_May
|
||||
coordSets = [[traSprite.x-44,traSprite.y-38],[-8,-30],[122,0]]
|
||||
end
|
||||
# Arm stretched out behind player
|
||||
ball.setVisible(0,true)
|
||||
ball.setXY(0,coordSets[0][0],coordSets[0][1])
|
||||
ball.moveDelta(0,5,-5*(Graphics.width/(2*16)),0) if !safariThrow
|
||||
ball.setDelta(0,-12,0) if safariThrow
|
||||
# Arm mid throw
|
||||
ball.setDelta(5,coordSets[1][0],coordSets[1][1])
|
||||
ball.moveDelta(5,2,-2*(Graphics.width/(2*16)),0) if !safariThrow
|
||||
ball.setDelta(5,34,0) if safariThrow
|
||||
# Start of throw
|
||||
ball.setDelta(7,coordSets[2][0],coordSets[2][1])
|
||||
ball.setDelta(7,-14,0) if safariThrow
|
||||
# Update Poké Ball trajectory's start position
|
||||
ballStartX = ballStartY = 0
|
||||
coordSets.each do |c|
|
||||
ballStartX += c[0]
|
||||
ballStartY += c[1]
|
||||
end
|
||||
ballStartX -= ball.totalDuration*(Graphics.width/(2*16)) if !safariThrow
|
||||
ballStartX += 8 if safariThrow # -12 + 34 - 14
|
||||
return ballStartX, ballStartY
|
||||
end
|
||||
|
||||
def trainerThrowingFrames(ball,trainer,traSprite)
|
||||
ball.setZ(0,traSprite.z-1)
|
||||
# Change trainer's frames
|
||||
size = traSprite.src_rect.width # Width per frame
|
||||
trainer.setSrc(0,size,0)
|
||||
trainer.setSrc(5,size*2,0)
|
||||
trainer.setSrc(7,size*3,0)
|
||||
trainer.setSrc(9,size*4,0)
|
||||
trainer.setSrc(18,0,0)
|
||||
# Alter trainer's positioning
|
||||
trainer.setDelta(0,-12,0)
|
||||
trainer.setDelta(5,34,0)
|
||||
trainer.setDelta(7,-14,0)
|
||||
trainer.setDelta(9,28,0)
|
||||
trainer.moveDelta(10,3,-6,6)
|
||||
trainer.setDelta(18,-4,0)
|
||||
trainer.setDelta(19,-26,-6)
|
||||
# Make ball track the trainer's hand
|
||||
ballStartX, ballStartY = ballTracksHand(ball,traSprite,true)
|
||||
return ballStartX, ballStartY
|
||||
end
|
||||
|
||||
def createBallTrajectory(ball,delay,duration,startX,startY,midX,midY,endX,endY)
|
||||
# NOTE: This trajectory is the same regardless of whether the player's
|
||||
# sprite is being shown on-screen (and sliding off while animating a
|
||||
# throw). Instead, that throw animation and initialDelay are designed
|
||||
# to make sure the Ball's trajectory starts at the same position.
|
||||
ball.setVisible(delay,true)
|
||||
a = 2*startY - 4*midY + 2*endY
|
||||
b = 4*midY - 3*startY - endY
|
||||
c = startY
|
||||
for i in 1..duration
|
||||
t = i.to_f/duration # t ranges from 0 to 1
|
||||
x = startX + (endX-startX)*t # Linear in t
|
||||
y = a*t**2 + b*t + c # Quadratic in t
|
||||
ball.moveXY(delay+i-1,1,x,y)
|
||||
end
|
||||
createBallTumbling(ball,delay,duration)
|
||||
end
|
||||
|
||||
def createBallTumbling(ball,delay,duration)
|
||||
# Animate ball frames
|
||||
numTumbles = 1
|
||||
numFrames = 1
|
||||
if @ballSprite && @ballSprite.bitmap.width>=@ballSprite.bitmap.height
|
||||
# 2* because each frame is twice as tall as it is wide
|
||||
numFrames = 2*@ballSprite.bitmap.width/@ballSprite.bitmap.height
|
||||
end
|
||||
if numFrames>1
|
||||
curFrame = 0
|
||||
for i in 1..duration
|
||||
thisFrame = numFrames*numTumbles*i/duration
|
||||
if thisFrame>curFrame
|
||||
curFrame = thisFrame
|
||||
ball.setSrc(delay+i-1,(curFrame%numFrames)*@ballSprite.bitmap.height/2,0)
|
||||
end
|
||||
end
|
||||
ball.setSrc(delay+duration,0,0)
|
||||
end
|
||||
# Rotate ball
|
||||
ball.moveAngle(delay,duration,360*3)
|
||||
ball.setAngle(delay+duration,0)
|
||||
end
|
||||
|
||||
def ballSetOpen(ball, delay, poke_ball)
|
||||
file_path = sprintf("Graphics/Battle animations/ball_%s_open", poke_ball)
|
||||
ball.setName(delay, file_path)
|
||||
if @ballSprite && @ballSprite.bitmap.width >= @ballSprite.bitmap.height
|
||||
ball.setSrcSize(delay, @ballSprite.bitmap.height / 2, @ballSprite.bitmap.height)
|
||||
end
|
||||
end
|
||||
|
||||
def ballSetClosed(ball, delay, poke_ball)
|
||||
file_path = sprintf("Graphics/Battle animations/ball_%s", poke_ball)
|
||||
ball.setName(delay, file_path)
|
||||
if @ballSprite && @ballSprite.bitmap.width >= @ballSprite.bitmap.height
|
||||
ball.setSrcSize(delay, @ballSprite.bitmap.height / 2, @ballSprite.bitmap.height)
|
||||
end
|
||||
end
|
||||
|
||||
def ballOpenUp(ball, delay, poke_ball, showSquish = true, playSE = true)
|
||||
if showSquish
|
||||
ball.moveZoomXY(delay, 1, 120, 80) # Squish
|
||||
ball.moveZoom(delay + 5, 1, 100) # Unsquish
|
||||
delay += 6
|
||||
end
|
||||
ball.setSE(delay, "Battle recall") if playSE
|
||||
ballSetOpen(ball, delay, poke_ball)
|
||||
end
|
||||
|
||||
def battlerAppear(battler,delay,battlerX,battlerY,batSprite,color)
|
||||
battler.setVisible(delay,true)
|
||||
battler.setOpacity(delay,255)
|
||||
battler.moveXY(delay,5,battlerX,battlerY)
|
||||
battler.moveZoom(delay,5,100,[batSprite,:pbPlayIntroAnimation])
|
||||
# NOTE: As soon as the battler sprite finishes zooming, and just as it
|
||||
# starts changing its tone to normal, it plays its intro animation.
|
||||
color.alpha = 0
|
||||
battler.moveColor(delay+5,10,color)
|
||||
end
|
||||
|
||||
def battlerAbsorb(battler,delay,battlerX,battlerY,color)
|
||||
color.alpha = 255
|
||||
battler.moveColor(delay,10,color)
|
||||
delay = battler.totalDuration
|
||||
battler.moveXY(delay,5,battlerX,battlerY)
|
||||
battler.moveZoom(delay,5,0)
|
||||
battler.setVisible(delay+5,false)
|
||||
end
|
||||
|
||||
# The regular Poké Ball burst animation.
|
||||
def ballBurst(delay, ballX, ballY, poke_ball)
|
||||
end
|
||||
|
||||
# The Poké Ball burst animation used when absorbing a wild Pokémon during a
|
||||
# capture attempt.
|
||||
def ballBurstCapture(delay, ballX, ballY, poke_ball)
|
||||
end
|
||||
|
||||
def ballCaptureSuccess(ball, delay, ballX, ballY)
|
||||
ball.setSE(delay, "Battle catch click")
|
||||
ball.moveTone(delay, 4, Tone.new(-64, -64, -64, 128))
|
||||
end
|
||||
|
||||
# The Poké Ball burst animation used when recalling a Pokémon.
|
||||
def ballBurstRecall(delay, ballX, ballY, poke_ball)
|
||||
end
|
||||
end
|
||||
869
Data/Scripts/011_Battle/004_Scene/008_Battle_Scene_Animations.rb
Normal file
869
Data/Scripts/011_Battle/004_Scene/008_Battle_Scene_Animations.rb
Normal file
@@ -0,0 +1,869 @@
|
||||
#===============================================================================
|
||||
# Shows the battle scene fading in while elements slide around into place
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::Intro < Battle::Scene::Animation
|
||||
def initialize(sprites,viewport,battle)
|
||||
@battle = battle
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
appearTime = 20 # This is in 1/20 seconds
|
||||
# Background
|
||||
if @sprites["battle_bg2"]
|
||||
makeSlideSprite("battle_bg",0.5,appearTime)
|
||||
makeSlideSprite("battle_bg2",0.5,appearTime)
|
||||
end
|
||||
# Bases
|
||||
makeSlideSprite("base_0",1,appearTime,PictureOrigin::Bottom)
|
||||
makeSlideSprite("base_1",-1,appearTime,PictureOrigin::Center)
|
||||
# Player sprite, partner trainer sprite
|
||||
@battle.player.each_with_index do |_p,i|
|
||||
makeSlideSprite("player_#{i+1}",1,appearTime,PictureOrigin::Bottom)
|
||||
end
|
||||
# Opposing trainer sprite(s) or wild Pokémon sprite(s)
|
||||
if @battle.trainerBattle?
|
||||
@battle.opponent.each_with_index do |_p,i|
|
||||
makeSlideSprite("trainer_#{i+1}",-1,appearTime,PictureOrigin::Bottom)
|
||||
end
|
||||
else # Wild battle
|
||||
@battle.pbParty(1).each_with_index do |_pkmn,i|
|
||||
idxBattler = 2*i+1
|
||||
makeSlideSprite("pokemon_#{idxBattler}",-1,appearTime,PictureOrigin::Bottom)
|
||||
end
|
||||
end
|
||||
# Shadows
|
||||
for i in 0...@battle.battlers.length
|
||||
makeSlideSprite("shadow_#{i}",((i%2)==0) ? 1 : -1,appearTime,PictureOrigin::Center)
|
||||
end
|
||||
# Fading blackness over whole screen
|
||||
blackScreen = addNewSprite(0,0,"Graphics/Battle animations/black_screen")
|
||||
blackScreen.setZ(0,999)
|
||||
blackScreen.moveOpacity(0,8,0)
|
||||
# Fading blackness over command bar
|
||||
blackBar = addNewSprite(@sprites["cmdBar_bg"].x,@sprites["cmdBar_bg"].y,
|
||||
"Graphics/Battle animations/black_bar")
|
||||
blackBar.setZ(0,998)
|
||||
blackBar.moveOpacity(appearTime*3/4,appearTime/4,0)
|
||||
end
|
||||
|
||||
def makeSlideSprite(spriteName,deltaMult,appearTime,origin=nil)
|
||||
# If deltaMult is positive, the sprite starts off to the right and moves
|
||||
# left (for sprites on the player's side and the background).
|
||||
return if !@sprites[spriteName]
|
||||
s = addSprite(@sprites[spriteName],origin)
|
||||
s.setDelta(0,(Graphics.width*deltaMult).floor,0)
|
||||
s.moveDelta(0,appearTime,(-Graphics.width*deltaMult).floor,0)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Shows wild Pokémon fading back to their normal color, and triggers their intro
|
||||
# animations
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::Intro2 < Battle::Scene::Animation
|
||||
def initialize(sprites,viewport,sideSize)
|
||||
@sideSize = sideSize
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
for i in 0...@sideSize
|
||||
idxBattler = 2*i+1
|
||||
next if !@sprites["pokemon_#{idxBattler}"]
|
||||
battler = addSprite(@sprites["pokemon_#{idxBattler}"],PictureOrigin::Bottom)
|
||||
battler.moveTone(0,4,Tone.new(0,0,0,0))
|
||||
battler.setCallback(10*i,[@sprites["pokemon_#{idxBattler}"],:pbPlayIntroAnimation])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Makes a side's party bar and balls appear
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::LineupAppear < Battle::Scene::Animation
|
||||
BAR_DISPLAY_WIDTH = 248
|
||||
|
||||
def initialize(sprites,viewport,side,party,partyStarts,fullAnim)
|
||||
@side = side
|
||||
@party = party
|
||||
@partyStarts = partyStarts
|
||||
@fullAnim = fullAnim # True at start of battle, false when switching
|
||||
resetGraphics(sprites)
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def resetGraphics(sprites)
|
||||
bar = sprites["partyBar_#{@side}"]
|
||||
case @side
|
||||
when 0 # Player's lineup
|
||||
barX = Graphics.width - BAR_DISPLAY_WIDTH
|
||||
barY = Graphics.height - 142
|
||||
ballX = barX + 44
|
||||
ballY = barY - 30
|
||||
when 1 # Opposing lineup
|
||||
barX = BAR_DISPLAY_WIDTH
|
||||
barY = 114
|
||||
ballX = barX - 44 - 30 # 30 is width of ball icon
|
||||
ballY = barY - 30
|
||||
barX -= bar.bitmap.width
|
||||
end
|
||||
ballXdiff = 32*(1-2*@side)
|
||||
bar.x = barX
|
||||
bar.y = barY
|
||||
bar.opacity = 255
|
||||
bar.visible = false
|
||||
for i in 0...Battle::Scene::NUM_BALLS
|
||||
ball = sprites["partyBall_#{@side}_#{i}"]
|
||||
ball.x = ballX
|
||||
ball.y = ballY
|
||||
ball.opacity = 255
|
||||
ball.visible = false
|
||||
ballX += ballXdiff
|
||||
end
|
||||
end
|
||||
|
||||
def getPartyIndexFromBallIndex(idxBall)
|
||||
# Player's lineup (just show balls for player's party)
|
||||
if @side==0
|
||||
return idxBall if @partyStarts.length<2
|
||||
return idxBall if idxBall<@partyStarts[1]
|
||||
return -1
|
||||
end
|
||||
# Opposing lineup
|
||||
# NOTE: This doesn't work well for 4+ opposing trainers.
|
||||
ballsPerTrainer = Battle::Scene::NUM_BALLS/@partyStarts.length # 6/3/2
|
||||
startsIndex = idxBall/ballsPerTrainer
|
||||
teamIndex = idxBall%ballsPerTrainer
|
||||
ret = @partyStarts[startsIndex]+teamIndex
|
||||
if startsIndex<@partyStarts.length-1
|
||||
# There is a later trainer, don't spill over into its team
|
||||
return -1 if ret>=@partyStarts[startsIndex+1]
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
bar = addSprite(@sprites["partyBar_#{@side}"])
|
||||
bar.setVisible(0,true)
|
||||
dir = (@side==0) ? 1 : -1
|
||||
bar.setDelta(0,dir*Graphics.width/2,0)
|
||||
bar.moveDelta(0,8,-dir*Graphics.width/2,0)
|
||||
delay = bar.totalDuration
|
||||
for i in 0...Battle::Scene::NUM_BALLS
|
||||
createBall(i,(@fullAnim) ? delay+i*2 : 0,dir)
|
||||
end
|
||||
end
|
||||
|
||||
def createBall(idxBall,delay,dir)
|
||||
# Choose ball's graphic
|
||||
idxParty = getPartyIndexFromBallIndex(idxBall)
|
||||
graphicFilename = "Graphics/Pictures/Battle/icon_ball_empty"
|
||||
if idxParty>=0 && idxParty<@party.length && @party[idxParty]
|
||||
if !@party[idxParty].able?
|
||||
graphicFilename = "Graphics/Pictures/Battle/icon_ball_faint"
|
||||
elsif @party[idxParty].status != :NONE
|
||||
graphicFilename = "Graphics/Pictures/Battle/icon_ball_status"
|
||||
else
|
||||
graphicFilename = "Graphics/Pictures/Battle/icon_ball"
|
||||
end
|
||||
end
|
||||
# Set up ball sprite
|
||||
ball = addSprite(@sprites["partyBall_#{@side}_#{idxBall}"])
|
||||
ball.setVisible(delay,true)
|
||||
ball.setName(delay,graphicFilename)
|
||||
ball.setDelta(delay,dir*Graphics.width/2,0)
|
||||
ball.moveDelta(delay,8,-dir*Graphics.width/2,0)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Makes a Pokémon's data box appear
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::DataBoxAppear < Battle::Scene::Animation
|
||||
def initialize(sprites,viewport,idxBox)
|
||||
@idxBox = idxBox
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
return if !@sprites["dataBox_#{@idxBox}"]
|
||||
box = addSprite(@sprites["dataBox_#{@idxBox}"])
|
||||
box.setVisible(0,true)
|
||||
dir = ((@idxBox%2)==0) ? 1 : -1
|
||||
box.setDelta(0,dir*Graphics.width/2,0)
|
||||
box.moveDelta(0,8,-dir*Graphics.width/2,0)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Makes a Pokémon's data box disappear
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::DataBoxDisappear < Battle::Scene::Animation
|
||||
def initialize(sprites,viewport,idxBox)
|
||||
@idxBox = idxBox
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
return if !@sprites["dataBox_#{@idxBox}"] || !@sprites["dataBox_#{@idxBox}"].visible
|
||||
box = addSprite(@sprites["dataBox_#{@idxBox}"])
|
||||
dir = ((@idxBox%2)==0) ? 1 : -1
|
||||
box.moveDelta(0,8,dir*Graphics.width/2,0)
|
||||
box.setVisible(8,false)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Makes a Pokémon's ability bar appear
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::AbilitySplashAppear < Battle::Scene::Animation
|
||||
def initialize(sprites,viewport,side)
|
||||
@side = side
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
return if !@sprites["abilityBar_#{@side}"]
|
||||
bar = addSprite(@sprites["abilityBar_#{@side}"])
|
||||
bar.setVisible(0,true)
|
||||
dir = (@side==0) ? 1 : -1
|
||||
bar.moveDelta(0,8,dir*Graphics.width/2,0)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Makes a Pokémon's ability bar disappear
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::AbilitySplashDisappear < Battle::Scene::Animation
|
||||
def initialize(sprites,viewport,side)
|
||||
@side = side
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
return if !@sprites["abilityBar_#{@side}"]
|
||||
bar = addSprite(@sprites["abilityBar_#{@side}"])
|
||||
dir = (@side==0) ? -1 : 1
|
||||
bar.moveDelta(0,8,dir*Graphics.width/2,0)
|
||||
bar.setVisible(8,false)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Make an enemy trainer slide on-screen from the right. Makes the previous
|
||||
# trainer slide off to the right first if it is on-screen.
|
||||
# Used at the end of battle.
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::TrainerAppear < Battle::Scene::Animation
|
||||
def initialize(sprites,viewport,idxTrainer)
|
||||
@idxTrainer = idxTrainer
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
delay = 0
|
||||
# Make old trainer sprite move off-screen first if necessary
|
||||
if @idxTrainer>0 && @sprites["trainer_#{@idxTrainer}"].visible
|
||||
oldTrainer = addSprite(@sprites["trainer_#{@idxTrainer}"],PictureOrigin::Bottom)
|
||||
oldTrainer.moveDelta(delay,8,Graphics.width/4,0)
|
||||
oldTrainer.setVisible(delay+8,false)
|
||||
delay = oldTrainer.totalDuration
|
||||
end
|
||||
# Make new trainer sprite move on-screen
|
||||
if @sprites["trainer_#{@idxTrainer+1}"]
|
||||
trainerX, trainerY = Battle::Scene.pbTrainerPosition(1)
|
||||
trainerX += 64+Graphics.width/4
|
||||
newTrainer = addSprite(@sprites["trainer_#{@idxTrainer+1}"],PictureOrigin::Bottom)
|
||||
newTrainer.setVisible(delay,true)
|
||||
newTrainer.setXY(delay,trainerX,trainerY)
|
||||
newTrainer.moveDelta(delay,8,-Graphics.width/4,0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Shows the player (and partner) and the player party lineup sliding off screen.
|
||||
# Shows the player's/partner's throwing animation (if they have one).
|
||||
# Doesn't show the ball thrown or the Pokémon.
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::PlayerFade < Battle::Scene::Animation
|
||||
def initialize(sprites,viewport,fullAnim=false)
|
||||
@fullAnim = fullAnim # True at start of battle, false when switching
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
# NOTE: The movement speeds of trainers/bar/balls are all different.
|
||||
# Move trainer sprite(s) off-screen
|
||||
spriteNameBase = "player"
|
||||
i = 1
|
||||
while @sprites[spriteNameBase+"_#{i}"]
|
||||
pl = @sprites[spriteNameBase+"_#{i}"]
|
||||
i += 1
|
||||
next if !pl.visible || pl.x<0
|
||||
trainer = addSprite(pl,PictureOrigin::Bottom)
|
||||
trainer.moveDelta(0,16,-Graphics.width/2,0)
|
||||
# Animate trainer sprite(s) if they have multiple frames
|
||||
if pl.bitmap && !pl.bitmap.disposed? && pl.bitmap.width>=pl.bitmap.height*2
|
||||
size = pl.src_rect.width # Width per frame
|
||||
trainer.setSrc(0,size,0)
|
||||
trainer.setSrc(5,size*2,0)
|
||||
trainer.setSrc(7,size*3,0)
|
||||
trainer.setSrc(9,size*4,0)
|
||||
end
|
||||
trainer.setVisible(16,false)
|
||||
end
|
||||
# Move and fade party bar/balls
|
||||
delay = 3
|
||||
if @sprites["partyBar_0"] && @sprites["partyBar_0"].visible
|
||||
partyBar = addSprite(@sprites["partyBar_0"])
|
||||
partyBar.moveDelta(delay,16,-Graphics.width/4,0) if @fullAnim
|
||||
partyBar.moveOpacity(delay,12,0)
|
||||
partyBar.setVisible(delay+12,false)
|
||||
partyBar.setOpacity(delay+12,255)
|
||||
end
|
||||
for i in 0...Battle::Scene::NUM_BALLS
|
||||
next if !@sprites["partyBall_0_#{i}"] || !@sprites["partyBall_0_#{i}"].visible
|
||||
partyBall = addSprite(@sprites["partyBall_0_#{i}"])
|
||||
partyBall.moveDelta(delay+2*i,16,-Graphics.width,0) if @fullAnim
|
||||
partyBall.moveOpacity(delay,12,0)
|
||||
partyBall.setVisible(delay+12,false)
|
||||
partyBall.setOpacity(delay+12,255)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Shows the enemy trainer(s) and the enemy party lineup sliding off screen.
|
||||
# Doesn't show the ball thrown or the Pokémon.
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::TrainerFade < Battle::Scene::Animation
|
||||
def initialize(sprites,viewport,fullAnim=false)
|
||||
@fullAnim = fullAnim # True at start of battle, false when switching
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
# NOTE: The movement speeds of trainers/bar/balls are all different.
|
||||
# Move trainer sprite(s) off-screen
|
||||
spriteNameBase = "trainer"
|
||||
i = 1
|
||||
while @sprites[spriteNameBase+"_#{i}"]
|
||||
trSprite = @sprites[spriteNameBase+"_#{i}"]
|
||||
i += 1
|
||||
next if !trSprite.visible || trSprite.x>Graphics.width
|
||||
trainer = addSprite(trSprite,PictureOrigin::Bottom)
|
||||
trainer.moveDelta(0,16,Graphics.width/2,0)
|
||||
trainer.setVisible(16,false)
|
||||
end
|
||||
# Move and fade party bar/balls
|
||||
delay = 3
|
||||
if @sprites["partyBar_1"] && @sprites["partyBar_1"].visible
|
||||
partyBar = addSprite(@sprites["partyBar_1"])
|
||||
partyBar.moveDelta(delay,16,Graphics.width/4,0) if @fullAnim
|
||||
partyBar.moveOpacity(delay,12,0)
|
||||
partyBar.setVisible(delay+12,false)
|
||||
partyBar.setOpacity(delay+12,255)
|
||||
end
|
||||
for i in 0...Battle::Scene::NUM_BALLS
|
||||
next if !@sprites["partyBall_1_#{i}"] || !@sprites["partyBall_1_#{i}"].visible
|
||||
partyBall = addSprite(@sprites["partyBall_1_#{i}"])
|
||||
partyBall.moveDelta(delay+2*i,16,Graphics.width,0) if @fullAnim
|
||||
partyBall.moveOpacity(delay,12,0)
|
||||
partyBall.setVisible(delay+12,false)
|
||||
partyBall.setOpacity(delay+12,255)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Shows a Pokémon being sent out on the player's side (including by a partner).
|
||||
# Includes the Poké Ball being thrown.
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::PokeballPlayerSendOut < Battle::Scene::Animation
|
||||
include Battle::Scene::Animation::BallAnimationMixin
|
||||
|
||||
def initialize(sprites,viewport,idxTrainer,battler,startBattle,idxOrder=0)
|
||||
@idxTrainer = idxTrainer
|
||||
@battler = battler
|
||||
@showingTrainer = startBattle
|
||||
@idxOrder = idxOrder
|
||||
@trainer = @battler.battle.pbGetOwnerFromBattlerIndex(@battler.index)
|
||||
sprites["pokemon_#{battler.index}"].visible = false
|
||||
@shadowVisible = sprites["shadow_#{battler.index}"].visible
|
||||
sprites["shadow_#{battler.index}"].visible = false
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
batSprite = @sprites["pokemon_#{@battler.index}"]
|
||||
shaSprite = @sprites["shadow_#{@battler.index}"]
|
||||
traSprite = @sprites["player_#{@idxTrainer}"]
|
||||
# Calculate the Poké Ball graphic to use
|
||||
poke_ball = (batSprite.pkmn) ? batSprite.pkmn.poke_ball : nil
|
||||
# Calculate the color to turn the battler sprite
|
||||
col = getBattlerColorFromPokeBall(poke_ball)
|
||||
col.alpha = 255
|
||||
# Calculate start and end coordinates for battler sprite movement
|
||||
ballPos = Battle::Scene.pbBattlerPosition(@battler.index,batSprite.sideSize)
|
||||
battlerStartX = ballPos[0] # Is also where the Ball needs to end
|
||||
battlerStartY = ballPos[1] # Is also where the Ball needs to end + 18
|
||||
battlerEndX = batSprite.x
|
||||
battlerEndY = batSprite.y
|
||||
# Calculate start and end coordinates for Poké Ball sprite movement
|
||||
ballStartX = -6
|
||||
ballStartY = 202
|
||||
ballMidX = 0 # Unused in trajectory calculation
|
||||
ballMidY = battlerStartY-144
|
||||
# Set up Poké Ball sprite
|
||||
ball = addBallSprite(ballStartX,ballStartY,poke_ball)
|
||||
ball.setZ(0,25)
|
||||
ball.setVisible(0,false)
|
||||
# Poké Ball tracking the player's hand animation (if trainer is visible)
|
||||
if @showingTrainer && traSprite && traSprite.x>0
|
||||
ball.setZ(0,traSprite.z-1)
|
||||
ballStartX, ballStartY = ballTracksHand(ball,traSprite)
|
||||
end
|
||||
delay = ball.totalDuration # 0 or 7
|
||||
# Poké Ball trajectory animation
|
||||
createBallTrajectory(ball,delay,12,
|
||||
ballStartX,ballStartY,ballMidX,ballMidY,battlerStartX,battlerStartY-18)
|
||||
ball.setZ(9,batSprite.z-1)
|
||||
delay = ball.totalDuration+4
|
||||
delay += 10*@idxOrder # Stagger appearances if multiple Pokémon are sent out at once
|
||||
ballOpenUp(ball,delay-2,poke_ball)
|
||||
ballBurst(delay,battlerStartX,battlerStartY-18,poke_ball)
|
||||
ball.moveOpacity(delay+2,2,0)
|
||||
# Set up battler sprite
|
||||
battler = addSprite(batSprite,PictureOrigin::Bottom)
|
||||
battler.setXY(0,battlerStartX,battlerStartY)
|
||||
battler.setZoom(0,0)
|
||||
battler.setColor(0,col)
|
||||
# Battler animation
|
||||
battlerAppear(battler,delay,battlerEndX,battlerEndY,batSprite,col)
|
||||
if @shadowVisible
|
||||
# Set up shadow sprite
|
||||
shadow = addSprite(shaSprite,PictureOrigin::Center)
|
||||
shadow.setOpacity(0,0)
|
||||
# Shadow animation
|
||||
shadow.setVisible(delay,@shadowVisible)
|
||||
shadow.moveOpacity(delay+5,10,255)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Shows a Pokémon being sent out on the opposing side.
|
||||
# Includes the Poké Ball being "thrown" (although here the Poké Ball just
|
||||
# appears in the spot where it opens up rather than being thrown to there).
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::PokeballTrainerSendOut < Battle::Scene::Animation
|
||||
include Battle::Scene::Animation::BallAnimationMixin
|
||||
|
||||
def initialize(sprites,viewport,idxTrainer,battler,startBattle,idxOrder)
|
||||
@idxTrainer = idxTrainer
|
||||
@battler = battler
|
||||
@showingTrainer = startBattle
|
||||
@idxOrder = idxOrder
|
||||
sprites["pokemon_#{battler.index}"].visible = false
|
||||
@shadowVisible = sprites["shadow_#{battler.index}"].visible
|
||||
sprites["shadow_#{battler.index}"].visible = false
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
batSprite = @sprites["pokemon_#{@battler.index}"]
|
||||
shaSprite = @sprites["shadow_#{@battler.index}"]
|
||||
# Calculate the Poké Ball graphic to use
|
||||
poke_ball = (batSprite.pkmn) ? batSprite.pkmn.poke_ball : nil
|
||||
# Calculate the color to turn the battler sprite
|
||||
col = getBattlerColorFromPokeBall(poke_ball)
|
||||
col.alpha = 255
|
||||
# Calculate start and end coordinates for battler sprite movement
|
||||
ballPos = Battle::Scene.pbBattlerPosition(@battler.index,batSprite.sideSize)
|
||||
battlerStartX = ballPos[0]
|
||||
battlerStartY = ballPos[1]
|
||||
battlerEndX = batSprite.x
|
||||
battlerEndY = batSprite.y
|
||||
# Set up Poké Ball sprite
|
||||
ball = addBallSprite(0,0,poke_ball)
|
||||
ball.setZ(0,batSprite.z-1)
|
||||
# Poké Ball animation
|
||||
createBallTrajectory(ball,battlerStartX,battlerStartY)
|
||||
delay = ball.totalDuration+6
|
||||
delay += 10 if @showingTrainer # Give time for trainer to slide off screen
|
||||
delay += 10*@idxOrder # Stagger appearances if multiple Pokémon are sent out at once
|
||||
ballOpenUp(ball,delay-2,poke_ball)
|
||||
ballBurst(delay,battlerStartX,battlerStartY-18,poke_ball)
|
||||
ball.moveOpacity(delay+2,2,0)
|
||||
# Set up battler sprite
|
||||
battler = addSprite(batSprite,PictureOrigin::Bottom)
|
||||
battler.setXY(0,battlerStartX,battlerStartY)
|
||||
battler.setZoom(0,0)
|
||||
battler.setColor(0,col)
|
||||
# Battler animation
|
||||
battlerAppear(battler,delay,battlerEndX,battlerEndY,batSprite,col)
|
||||
if @shadowVisible
|
||||
# Set up shadow sprite
|
||||
shadow = addSprite(shaSprite,PictureOrigin::Center)
|
||||
shadow.setOpacity(0,0)
|
||||
# Shadow animation
|
||||
shadow.setVisible(delay,@shadowVisible)
|
||||
shadow.moveOpacity(delay+5,10,255)
|
||||
end
|
||||
end
|
||||
|
||||
def createBallTrajectory(ball,destX,destY)
|
||||
# NOTE: In HGSS, there isn't a Poké Ball arc under any circumstance (neither
|
||||
# when throwing out the first Pokémon nor when switching/replacing a
|
||||
# fainted Pokémon). This is probably worth changing.
|
||||
ball.setXY(0,destX,destY-4)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Shows a Pokémon being recalled into its Poké Ball
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::BattlerRecall < Battle::Scene::Animation
|
||||
include Battle::Scene::Animation::BallAnimationMixin
|
||||
|
||||
def initialize(sprites,viewport,idxBattler)
|
||||
@idxBattler = idxBattler
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
batSprite = @sprites["pokemon_#{@idxBattler}"]
|
||||
shaSprite = @sprites["shadow_#{@idxBattler}"]
|
||||
# Calculate the Poké Ball graphic to use
|
||||
poke_ball = (batSprite.pkmn) ? batSprite.pkmn.poke_ball : nil
|
||||
# Calculate the color to turn the battler sprite
|
||||
col = getBattlerColorFromPokeBall(poke_ball)
|
||||
col.alpha = 0
|
||||
# Calculate end coordinates for battler sprite movement
|
||||
ballPos = Battle::Scene.pbBattlerPosition(@idxBattler,batSprite.sideSize)
|
||||
battlerEndX = ballPos[0]
|
||||
battlerEndY = ballPos[1]
|
||||
# Set up battler sprite
|
||||
battler = addSprite(batSprite,PictureOrigin::Bottom)
|
||||
battler.setVisible(0,true)
|
||||
battler.setColor(0,col)
|
||||
# Set up Poké Ball sprite
|
||||
ball = addBallSprite(battlerEndX,battlerEndY,poke_ball)
|
||||
ball.setZ(0,batSprite.z+1)
|
||||
# Poké Ball animation
|
||||
ballOpenUp(ball,0,poke_ball)
|
||||
delay = ball.totalDuration
|
||||
ballBurstRecall(delay,battlerEndX,battlerEndY,poke_ball)
|
||||
ball.moveOpacity(10,2,0)
|
||||
# Battler animation
|
||||
battlerAbsorb(battler,delay,battlerEndX,battlerEndY,col)
|
||||
if shaSprite.visible
|
||||
# Set up shadow sprite
|
||||
shadow = addSprite(shaSprite,PictureOrigin::Center)
|
||||
# Shadow animation
|
||||
shadow.moveOpacity(0,10,0)
|
||||
shadow.setVisible(delay,false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Shows a Pokémon flashing after taking damage
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::BattlerDamage < Battle::Scene::Animation
|
||||
def initialize(sprites,viewport,idxBattler,effectiveness)
|
||||
@idxBattler = idxBattler
|
||||
@effectiveness = effectiveness
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
batSprite = @sprites["pokemon_#{@idxBattler}"]
|
||||
shaSprite = @sprites["shadow_#{@idxBattler}"]
|
||||
# Set up battler/shadow sprite
|
||||
battler = addSprite(batSprite,PictureOrigin::Bottom)
|
||||
shadow = addSprite(shaSprite,PictureOrigin::Center)
|
||||
# Animation
|
||||
delay = 0
|
||||
case @effectiveness
|
||||
when 0 then battler.setSE(delay, "Battle damage normal")
|
||||
when 1 then battler.setSE(delay, "Battle damage weak")
|
||||
when 2 then battler.setSE(delay, "Battle damage super")
|
||||
end
|
||||
4.times do # 4 flashes, each lasting 0.2 (4/20) seconds
|
||||
battler.setVisible(delay,false)
|
||||
shadow.setVisible(delay,false)
|
||||
battler.setVisible(delay+2,true) if batSprite.visible
|
||||
shadow.setVisible(delay+2,true) if shaSprite.visible
|
||||
delay += 4
|
||||
end
|
||||
# Restore original battler/shadow sprites visibilities
|
||||
battler.setVisible(delay,batSprite.visible)
|
||||
shadow.setVisible(delay,shaSprite.visible)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Shows a Pokémon fainting
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::BattlerFaint < Battle::Scene::Animation
|
||||
def initialize(sprites,viewport,idxBattler,battle)
|
||||
@idxBattler = idxBattler
|
||||
@battle = battle
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
batSprite = @sprites["pokemon_#{@idxBattler}"]
|
||||
shaSprite = @sprites["shadow_#{@idxBattler}"]
|
||||
# Set up battler/shadow sprite
|
||||
battler = addSprite(batSprite,PictureOrigin::Bottom)
|
||||
shadow = addSprite(shaSprite,PictureOrigin::Center)
|
||||
# Get approx duration depending on sprite's position/size. Min 20 frames.
|
||||
battlerTop = batSprite.y-batSprite.height
|
||||
cropY = Battle::Scene.pbBattlerPosition(@idxBattler,
|
||||
@battle.pbSideSize(@idxBattler))[1]
|
||||
cropY += 8
|
||||
duration = (cropY-battlerTop)/8
|
||||
duration = 10 if duration<10 # Min 0.5 seconds
|
||||
# Animation
|
||||
# Play cry
|
||||
delay = 10
|
||||
cry = GameData::Species.cry_filename_from_pokemon(batSprite.pkmn)
|
||||
if cry
|
||||
battler.setSE(0, cry, nil, 75) # 75 is pitch
|
||||
delay = GameData::Species.cry_length(batSprite.pkmn) * 20 / Graphics.frame_rate
|
||||
end
|
||||
# Sprite drops down
|
||||
shadow.setVisible(delay,false)
|
||||
battler.setSE(delay,"Pkmn faint")
|
||||
battler.moveOpacity(delay,duration,0)
|
||||
battler.moveDelta(delay,duration,0,cropY-battlerTop)
|
||||
battler.setCropBottom(delay,cropY)
|
||||
battler.setVisible(delay+duration,false)
|
||||
battler.setOpacity(delay+duration,255)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Shows the player's Poké Ball being thrown to capture a Pokémon
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::PokeballThrowCapture < Battle::Scene::Animation
|
||||
include Battle::Scene::Animation::BallAnimationMixin
|
||||
|
||||
def initialize(sprites,viewport,
|
||||
poke_ball,numShakes,critCapture,battler,showingTrainer)
|
||||
@poke_ball = poke_ball
|
||||
@numShakes = (critCapture) ? 1 : numShakes
|
||||
@critCapture = critCapture
|
||||
@battler = battler
|
||||
@showingTrainer = showingTrainer # Only true if a Safari Zone battle
|
||||
@shadowVisible = sprites["shadow_#{battler.index}"].visible
|
||||
@trainer = battler.battle.pbPlayer
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
# Calculate start and end coordinates for battler sprite movement
|
||||
batSprite = @sprites["pokemon_#{@battler.index}"]
|
||||
shaSprite = @sprites["shadow_#{@battler.index}"]
|
||||
traSprite = @sprites["player_1"]
|
||||
ballPos = Battle::Scene.pbBattlerPosition(@battler.index,batSprite.sideSize)
|
||||
battlerStartX = batSprite.x
|
||||
battlerStartY = batSprite.y
|
||||
ballStartX = -6
|
||||
ballStartY = 246
|
||||
ballMidX = 0 # Unused in arc calculation
|
||||
ballMidY = 78
|
||||
ballEndX = ballPos[0]
|
||||
ballEndY = 112
|
||||
ballGroundY = ballPos[1]-4
|
||||
# Set up Poké Ball sprite
|
||||
ball = addBallSprite(ballStartX,ballStartY,@poke_ball)
|
||||
ball.setZ(0,batSprite.z+1)
|
||||
@ballSpriteIndex = (@numShakes>=4 || @critCapture) ? @tempSprites.length-1 : -1
|
||||
# Set up trainer sprite (only visible in Safari Zone battles)
|
||||
if @showingTrainer && traSprite
|
||||
if traSprite.bitmap.width>=traSprite.bitmap.height*2
|
||||
trainer = addSprite(traSprite,PictureOrigin::Bottom)
|
||||
# Trainer animation
|
||||
ballStartX, ballStartY = trainerThrowingFrames(ball,trainer,traSprite)
|
||||
end
|
||||
end
|
||||
delay = ball.totalDuration # 0 or 7
|
||||
# Poké Ball arc animation
|
||||
ball.setSE(delay,"Battle throw")
|
||||
createBallTrajectory(ball,delay,16,
|
||||
ballStartX,ballStartY,ballMidX,ballMidY,ballEndX,ballEndY)
|
||||
ball.setZ(9,batSprite.z+1)
|
||||
ball.setSE(delay+16,"Battle ball hit")
|
||||
# Poké Ball opens up
|
||||
delay = ball.totalDuration+6
|
||||
ballOpenUp(ball,delay,@poke_ball,true,false)
|
||||
# Set up battler sprite
|
||||
battler = addSprite(batSprite,PictureOrigin::Bottom)
|
||||
# Poké Ball absorbs battler
|
||||
delay = ball.totalDuration
|
||||
ballBurstCapture(delay,ballEndX,ballEndY,@poke_ball)
|
||||
delay = ball.totalDuration+4
|
||||
# NOTE: The Pokémon does not change color while being absorbed into a Poké
|
||||
# Ball during a capture attempt. This may be an oversight in HGSS.
|
||||
battler.setSE(delay,"Battle jump to ball")
|
||||
battler.moveXY(delay,5,ballEndX,ballEndY)
|
||||
battler.moveZoom(delay,5,0)
|
||||
battler.setVisible(delay+5,false)
|
||||
if @shadowVisible
|
||||
# Set up shadow sprite
|
||||
shadow = addSprite(shaSprite,PictureOrigin::Center)
|
||||
# Shadow animation
|
||||
shadow.moveOpacity(delay,5,0)
|
||||
shadow.moveZoom(delay,5,0)
|
||||
shadow.setVisible(delay+5,false)
|
||||
end
|
||||
# Poké Ball closes
|
||||
delay = battler.totalDuration
|
||||
ballSetClosed(ball,delay,@poke_ball)
|
||||
ball.moveTone(delay,3,Tone.new(96,64,-160,160))
|
||||
ball.moveTone(delay+5,3,Tone.new(0,0,0,0))
|
||||
# Poké Ball critical capture animation
|
||||
delay = ball.totalDuration+3
|
||||
if @critCapture
|
||||
ball.setSE(delay,"Battle ball shake")
|
||||
ball.moveXY(delay,1,ballEndX+4,ballEndY)
|
||||
ball.moveXY(delay+1,2,ballEndX-4,ballEndY)
|
||||
ball.moveXY(delay+3,2,ballEndX+4,ballEndY)
|
||||
ball.setSE(delay+4,"Battle ball shake")
|
||||
ball.moveXY(delay+5,2,ballEndX-4,ballEndY)
|
||||
ball.moveXY(delay+7,1,ballEndX,ballEndY)
|
||||
delay = ball.totalDuration+3
|
||||
end
|
||||
# Poké Ball drops to the ground
|
||||
for i in 0...4
|
||||
t = [4,4,3,2][i] # Time taken to rise or fall for each bounce
|
||||
d = [1,2,4,8][i] # Fraction of the starting height each bounce rises to
|
||||
delay -= t if i==0
|
||||
if i>0
|
||||
ball.setZoomXY(delay,100+5*(5-i),100-5*(5-i)) # Squish
|
||||
ball.moveZoom(delay,2,100) # Unsquish
|
||||
ball.moveXY(delay,t,ballEndX,ballGroundY-(ballGroundY-ballEndY)/d)
|
||||
end
|
||||
ball.moveXY(delay+t,t,ballEndX,ballGroundY)
|
||||
ball.setSE(delay+2*t,"Battle ball drop",100-i*7)
|
||||
delay = ball.totalDuration
|
||||
end
|
||||
battler.setXY(ball.totalDuration,ballEndX,ballGroundY)
|
||||
# Poké Ball shakes
|
||||
delay = ball.totalDuration+12
|
||||
for i in 0...[@numShakes,3].min
|
||||
ball.setSE(delay,"Battle ball shake")
|
||||
ball.moveXY(delay,2,ballEndX-2*(4-i),ballGroundY)
|
||||
ball.moveAngle(delay,2,5*(4-i)) # positive means counterclockwise
|
||||
ball.moveXY(delay+2,4,ballEndX+2*(4-i),ballGroundY)
|
||||
ball.moveAngle(delay+2,4,-5*(4-i)) # negative means clockwise
|
||||
ball.moveXY(delay+6,2,ballEndX,ballGroundY)
|
||||
ball.moveAngle(delay+6,2,0)
|
||||
delay = ball.totalDuration+8
|
||||
end
|
||||
if @numShakes==0 || (@numShakes<4 && !@critCapture)
|
||||
# Poké Ball opens
|
||||
ball.setZ(delay,batSprite.z-1)
|
||||
ballOpenUp(ball,delay,@poke_ball,false)
|
||||
ballBurst(delay,ballEndX,ballGroundY,@poke_ball)
|
||||
ball.moveOpacity(delay+2,2,0)
|
||||
# Battler emerges
|
||||
col = getBattlerColorFromPokeBall(@poke_ball)
|
||||
col.alpha = 255
|
||||
battler.setColor(delay,col)
|
||||
battlerAppear(battler,delay,battlerStartX,battlerStartY,batSprite,col)
|
||||
if @shadowVisible
|
||||
shadow.setVisible(delay+5,true)
|
||||
shadow.setZoom(delay+5,100)
|
||||
shadow.moveOpacity(delay+5,10,255)
|
||||
end
|
||||
else
|
||||
# Pokémon was caught
|
||||
ballCaptureSuccess(ball,delay,ballEndX,ballGroundY)
|
||||
end
|
||||
end
|
||||
|
||||
def dispose
|
||||
if @ballSpriteIndex>=0
|
||||
# Capture was successful, the Poké Ball sprite should stay around after
|
||||
# this animation has finished.
|
||||
@sprites["captureBall"] = @tempSprites[@ballSpriteIndex]
|
||||
@tempSprites[@ballSpriteIndex] = nil
|
||||
end
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# Shows the player throwing a Poké Ball and it being deflected
|
||||
#===============================================================================
|
||||
class Battle::Scene::Animation::PokeballThrowDeflect < Battle::Scene::Animation
|
||||
include Battle::Scene::Animation::BallAnimationMixin
|
||||
|
||||
def initialize(sprites,viewport,poke_ball,battler)
|
||||
@poke_ball = poke_ball
|
||||
@battler = battler
|
||||
super(sprites,viewport)
|
||||
end
|
||||
|
||||
def createProcesses
|
||||
# Calculate start and end coordinates for battler sprite movement
|
||||
batSprite = @sprites["pokemon_#{@battler.index}"]
|
||||
ballPos = Battle::Scene.pbBattlerPosition(@battler.index,batSprite.sideSize)
|
||||
ballStartX = -6
|
||||
ballStartY = 246
|
||||
ballMidX = 190 # Unused in arc calculation
|
||||
ballMidY = 78
|
||||
ballEndX = ballPos[0]
|
||||
ballEndY = 112
|
||||
# Set up Poké Ball sprite
|
||||
ball = addBallSprite(ballStartX,ballStartY,@poke_ball)
|
||||
ball.setZ(0,90)
|
||||
# Poké Ball arc animation
|
||||
ball.setSE(0,"Battle throw")
|
||||
createBallTrajectory(ball,0,16,
|
||||
ballStartX,ballStartY,ballMidX,ballMidY,ballEndX,ballEndY)
|
||||
# Poké Ball knocked back
|
||||
delay = ball.totalDuration
|
||||
ball.setSE(delay,"Battle ball drop")
|
||||
ball.moveXY(delay,8,-32,Graphics.height-96+32) # Back to player's corner
|
||||
createBallTumbling(ball,delay,8)
|
||||
end
|
||||
end
|
||||
83
Data/Scripts/011_Battle/004_Scene/009_Battle_DebugScene.rb
Normal file
83
Data/Scripts/011_Battle/004_Scene/009_Battle_DebugScene.rb
Normal file
@@ -0,0 +1,83 @@
|
||||
#===============================================================================
|
||||
# Used when generating new trainers for battle challenges
|
||||
#===============================================================================
|
||||
class Battle::DebugSceneNoLogging
|
||||
def initialize
|
||||
@battle = nil
|
||||
@lastCmd = [0,0,0,0]
|
||||
@lastMove = [0,0,0,0]
|
||||
end
|
||||
|
||||
# Called whenever the battle begins.
|
||||
def pbStartBattle(battle)
|
||||
@battle = battle
|
||||
@lastCmd = [0,0,0,0]
|
||||
@lastMove = [0,0,0,0]
|
||||
end
|
||||
|
||||
def pbBlitz(keys)
|
||||
return rand(30)
|
||||
end
|
||||
|
||||
# Called whenever a new round begins.
|
||||
def pbBeginCommandPhase; end
|
||||
def pbBeginAttackPhase; end
|
||||
def pbShowOpponent(idxTrainer); end
|
||||
def pbDamageAnimation(battler,effectiveness=0); end
|
||||
def pbCommonAnimation(animName,user=nil,target=nil); end
|
||||
def pbAnimation(moveID,user,targets,hitNum=0); end
|
||||
def pbEndBattle(result); end
|
||||
def pbWildBattleSuccess; end
|
||||
def pbTrainerBattleSuccess; end
|
||||
def pbBattleArenaJudgment(b1,b2,r1,r2); end
|
||||
def pbBattleArenaBattlers(b1,b2); end
|
||||
|
||||
def pbRefresh; end
|
||||
|
||||
def pbDisplayMessage(msg,brief=false); end
|
||||
def pbDisplayPausedMessage(msg); end
|
||||
def pbDisplayConfirmMessage(msg); return true; end
|
||||
def pbShowCommands(msg,commands,defaultValue); return 0; end
|
||||
|
||||
def pbSendOutBattlers(sendOuts,startBattle=false); end
|
||||
def pbRecall(idxBattler); end
|
||||
def pbItemMenu(idxBattler,firstAction); return -1; end
|
||||
def pbResetMoveIndex(idxBattler); end
|
||||
|
||||
def pbHPChanged(battler,oldHP,showAnim=false); end
|
||||
def pbFaintBattler(battler); end
|
||||
def pbEXPBar(battler,startExp,endExp,tempExp1,tempExp2); end
|
||||
def pbLevelUp(pkmn,battler,oldTotalHP,oldAttack,oldDefense,
|
||||
oldSpAtk,oldSpDef,oldSpeed); end
|
||||
def pbForgetMove(pkmn,moveToLearn); return 0; end # Always forget first move
|
||||
|
||||
def pbCommandMenu(idxBattler,firstAction)
|
||||
return 1 if rand(15)==0 # Bag
|
||||
return 4 if rand(10)==0 # Call
|
||||
return 0 # Fight
|
||||
end
|
||||
|
||||
def pbFightMenu(idxBattler,megaEvoPossible=false)
|
||||
battler = @battle.battlers[idxBattler]
|
||||
50.times do
|
||||
break if yield rand(battler.move.length)
|
||||
end
|
||||
end
|
||||
|
||||
def pbChooseTarget(idxBattler,target_data,visibleSprites=nil)
|
||||
targets = @battle.allOtherSideBattlers(idxBattler).map { |b| b.index }
|
||||
return -1 if targets.length==0
|
||||
return targets.sample
|
||||
end
|
||||
|
||||
def pbPartyScreen(idxBattler,canCancel=false)
|
||||
replacements = []
|
||||
@battle.eachInTeamFromBattlerIndex(idxBattler) do |_b,idxParty|
|
||||
replacements.push(idxParty) if !@battle.pbFindBattler(idxParty,idxBattler)
|
||||
end
|
||||
return if replacements.length==0
|
||||
50.times do
|
||||
break if yield replacements[rand(replacements.length)],self
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user