#=============================================================================== # Base class for all three menu classes below #=============================================================================== class BattleMenuBase 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 = PokeBattle_SceneConstants::MESSAGE_BASE_COLOR TEXT_SHADOW_COLOR = PokeBattle_SceneConstants::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 CommandMenuDisplay < BattleMenuBase # 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 FightMenuDisplay < BattleMenuBase 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).id_number * 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: ---
TYPE/{1}",moveType) else @msgBox.text = _ISPRINTF("PP: {1: 2d}/{2: 2d}
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).id_number @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 TargetMenuDisplay < BattleMenuBase 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