Update 6.8

This commit is contained in:
chardub
2026-07-10 15:42:06 -04:00
parent 5b85e72cb2
commit 6a6f126a18
7871 changed files with 493194 additions and 224826 deletions
@@ -0,0 +1,584 @@
class FusionMovesOptionsScene < PokemonOption_Scene
attr_reader :all_moves
attr_reader :selected_moves
attr_reader :move_slots
def initialize(poke1, poke2)
@poke1 = poke1
@poke2 = poke2
@fused_pokemon = @poke1
@head_species = @fused_pokemon.species_data.head_pokemon
@body_species = @fused_pokemon.species_data.body_pokemon
@selected_moves = []
@index_vertical = 0
@index_horizontal = 0
@selBaseColor = Color.new(48, 96, 216)
@selShadowColor = Color.new(32, 32, 32)
@counterBaseColor = pbColor(:LIGHT_TEXT_MAIN_COLOR)
@counterShadowColor = pbColor(:LIGHT_TEXT_SHADOW_COLOR)
@counterFullBaseColor = pbColor(:GREEN)
@counterFullShadowColor = pbColor(:DARKGREEN)
@maxMovesNb = [listUniqueAvailableMoves.length, 4].min
end
def initUIElements
Kernel.pbClearText()
@sprites["pokeicon_fused"] = PokemonIconSprite.new(@fused_pokemon.species, @viewport)
@sprites["pokeicon_fused"].x = 12
@sprites["pokeicon_fused"].y = 0
@sprites["titleMsg"] = Window_UnformattedTextPokemon.newWithSize(
_INTL("Select the moves you want to keep"), 64, 0, Graphics.width, 64, @viewport)
@sprites["title"] = Window_UnformattedTextPokemon.newWithSize(_INTL(""), 0, 32, Graphics.width, 64, @viewport)
@sprites["textbox"] = pbCreateMessageWindow
@sprites["textbox"].letterbyletter = false
@sprites["textbox"].height = @sprites["textbox"].height + 24
@sprites["textbox"].y = @sprites["textbox"].y - 24
@sprites["textbox"].baseColor = Color.new(64, 64, 64) # dark gray text
@sprites["textbox"].shadowColor = Color.new(168, 168, 168) # lighter shadow
if isDarkMode
@sprites["textbox"].baseColor, @sprites["textbox"].shadowColor = @sprites["textbox"].shadowColor, @sprites["textbox"].baseColor
end
addBackgroundPlane(@sprites, "bg_moves", "Fusion/movesOverlay", @viewport)
addBackgroundPlane(@sprites, "bg_stats", "Fusion/statsOverlay", @viewport)
@sprites["bg_stats"].visible = false
@sprites["counter"] = Window_UnformattedTextPokemon.newWithSize(
_INTL("0 / {1}", @maxMovesNb), 386, 226, Graphics.width, 84, @viewport)
@sprites["counter"].setSkin("Graphics/Windowskins/invisible")
showPokemonIcons
pbSetSystemFont(@sprites["textbox"].contents)
end
def updateCounter
count = @selected_moves.length
@sprites["counter"].text = _INTL("{1} / {2}", count, @maxMovesNb)
if count == @maxMovesNb
@sprites["counter"].baseColor = @counterFullBaseColor
@sprites["counter"].shadowColor = @counterFullShadowColor
else
@sprites["counter"].baseColor = @counterBaseColor
@sprites["counter"].shadowColor = @counterShadowColor
end
end
def getSelectedMoves
return @selected_moves
end
CURSOR_X_OFFSET = 8
CURSOR_Y_OFFSET = 16
def showPokemonIcons
@sprites["pokeicon_1"] = PokemonIconSprite.new(@head_species.species, @viewport)
@sprites["pokeicon_1"].x = 264
@sprites["pokeicon_1"].y = 50
@sprites["pokeicon_2"] = PokemonIconSprite.new(@body_species.species, @viewport)
@sprites["pokeicon_2"].x = 388
@sprites["pokeicon_2"].y = 50
@sprites["pokecursor"] = IconSprite.new(0, 0, @viewport)
@sprites["pokecursor"].setBitmap("Graphics/Pictures/Fusion/cursor")
@sprites["pokecursor"].x = @sprites["pokeicon_1"].x + CURSOR_X_OFFSET
@sprites["pokecursor"].y = @sprites["pokeicon_1"].y + CURSOR_Y_OFFSET
@sprites["pokecursor"].visible = true
end
def pbStartScene(inloadscreen = false)
super
@typebitmap = AnimatedBitmap.new("Graphics/Pictures/types")
@sprites["overlay"] = BitmapSprite.new(Graphics.width, Graphics.height, @viewport)
@sprites["overlay"].z = 9999
pbSetSystemFont(@sprites["overlay"].bitmap)
@sprites["option"].nameBaseColor = MessageConfig::BLUE_TEXT_MAIN_COLOR
@sprites["option"].nameShadowColor = MessageConfig::BLUE_TEXT_SHADOW_COLOR
@changedColor = true
for i in 0...@PokemonOptions.length
@sprites["option"][i] = (@PokemonOptions[i].get || 0)
end
@sprites["title"] = Window_UnformattedTextPokemon.newWithSize(_INTL(""), 0, 66, Graphics.width, 64, @viewport)
@sprites["title"].setSkin("Graphics/Windowskins/invisible")
@sprites["option"].setSkin("Graphics/Windowskins/invisible")
# echoln @sprites["option"].bitmap.text_size
# @sprites["option"].bitmap.text_size=10
updatePokemonCursor(0)
updateDescription(0)
updateCounter
pbFadeInAndShow(@sprites) { pbUpdate }
end
def getOptionsWidth(rect)
width = super(rect)
return width + 24
end
def draw_move_info(pokemonMove)
@sprites["bg_stats"].visible = false
@sprites["bg_moves"].visible = true
move = GameData::Move.get(pokemonMove.id)
label_base_color = Color.new(248, 248, 248)
label_shadow_color = Color.new(104, 104, 104)
value_base_color = Color.new(248, 248, 248)
value_shadow_color = Color.new(104, 104, 104)
@sprites["title"].text = _INTL("{1}", move.name)
damage = move.base_damage == 0 ? "-" : move.base_damage.to_s
accuracy = move.accuracy == 0 ? "100" : move.accuracy.to_s
pp = move.total_pp.to_s
if !move
damage = "-"
accuracy = "-"
pp = "-"
end
start_y = 110
gap_height = 32
textpos = [
[_INTL("Type"), 20, start_y, 0, label_base_color, label_shadow_color],
[_INTL("Category"), 20, start_y + (gap_height * 1), 0, label_base_color, label_shadow_color],
[_INTL("Power"), 20, start_y + (gap_height * 2), 0, label_base_color, label_shadow_color],
["#{damage}", 148, start_y + (gap_height * 2), 0, value_base_color, value_shadow_color],
[_INTL("Accuracy"), 20, start_y + (gap_height * 3), 0, label_base_color, label_shadow_color],
["#{accuracy}%", 148, start_y + (gap_height * 3), 0, value_base_color, value_shadow_color],
[_INTL("PP"), 20, start_y + (gap_height * 4), 0, label_base_color, label_shadow_color],
["#{pp}", 148, start_y + (gap_height * 4), 0, value_base_color, value_shadow_color]
]
imagepos = []
type_number = GameData::Type.get(move.type).id_number
category = move.category
imagepos.push(["Graphics/Pictures/types", 140, start_y + (gap_height * 0) + 8, 0, type_number * 28, 64, 28])
imagepos.push(["Graphics/Pictures/category", 140, start_y + (gap_height * 1) + 8, 0, category * 28, 64, 28])
if !move
imagepos = []
end
@sprites["overlay"].bitmap.clear
pbDrawTextPositions(@sprites["overlay"].bitmap, textpos)
pbDrawImagePositions(@sprites["overlay"].bitmap, imagepos)
end
def draw_pokemon_info
@sprites["bg_stats"].visible = true
@sprites["bg_moves"].visible = false
label_base_color = Color.new(248, 248, 248)
label_shadow_color = Color.new(104, 104, 104)
value_base_color = Color.new(248, 248, 248)
value_shadow_color = Color.new(104, 104, 104)
@sprites["title"].text = ""
start_y = 78
gap_height = 32
textpos = [
[_INTL("HP"), 20, start_y, 0, label_base_color, label_shadow_color],
[_INTL("{1}", @fused_pokemon.totalhp), 158, start_y, 0, label_base_color, label_shadow_color],
[_INTL("Attack"), 20, start_y + (gap_height * 1), 0, label_base_color, label_shadow_color],
[_INTL("{1}", @fused_pokemon.attack), 158, start_y + (gap_height * 1), 0, label_base_color, label_shadow_color],
[_INTL("Defense"), 20, start_y + (gap_height * 2), 0, label_base_color, label_shadow_color],
[_INTL("{1}", @fused_pokemon.defense), 158, start_y + (gap_height * 2), 0, label_base_color, label_shadow_color],
[_INTL("Sp. Attack"), 20, start_y + (gap_height * 3), 0, label_base_color, label_shadow_color],
[_INTL("{1}", @fused_pokemon.spatk), 158, start_y + (gap_height * 3), 0, value_base_color, value_shadow_color],
[_INTL("Sp. Defense"), 20, start_y + (gap_height * 4), 0, label_base_color, label_shadow_color],
[_INTL("{1}", @fused_pokemon.spdef), 158, start_y + (gap_height * 4), 0, value_base_color, value_shadow_color],
[_INTL("Speed"), 20, start_y + (gap_height * 5), 0, label_base_color, label_shadow_color],
[_INTL("{1}", @fused_pokemon.speed), 158, start_y + (gap_height * 5), 0, value_base_color, value_shadow_color],
]
@sprites["overlay"].bitmap.clear
pbDrawTextPositions(@sprites["overlay"].bitmap, textpos)
end
# def draw_pokemon_type
# type1_number = GameData::Type.get(@poke1.type1).id_number
# type2_number = GameData::Type.get(@poke1.type2).id_number
# type1rect = Rect.new(0, type1_number * 28, 64, 28)
# type2rect = Rect.new(0, type2_number * 28, 64, 28)
# if @poke1.type1 == @poke1.type2
# overlay.blt(130, 78, @typebitmap.bitmap, type1rect)
# else
# overlay.blt(96, 78, @typebitmap.bitmap, type1rect)
# overlay.blt(166, 78, @typebitmap.bitmap, type2rect)
# end
# end
def updatePokemonCursor(index)
index = 0 if !index
if @sprites["pokecursor"]
if index == 0
highlighted_value = @sprites["option"] ? (@sprites["option"][0] || 0) : 0
@sprites["pokecursor"].visible = true
@sprites["pokecursor"].x = highlighted_value == 0 ? @sprites["pokeicon_1"].x : @sprites["pokeicon_2"].x
@sprites["pokecursor"].y = highlighted_value == 0 ? @sprites["pokeicon_1"].y : @sprites["pokeicon_2"].y
@sprites["pokecursor"].x += CURSOR_X_OFFSET
@sprites["pokecursor"].y += CURSOR_Y_OFFSET
else
@sprites["pokecursor"].visible = false
end
end
end
def pbUpdate
pbUpdateSpriteHash(@sprites)
if @sprites["option"].mustUpdateDescription || @sprites["option"].mustUpdateOptions
updatePokemonCursor(@sprites["option"].index)
updateDescription(@sprites["option"].index)
@sprites["option"].descriptionUpdated
end
end
def updateDescription(index)
index = 0 if !index
begin
return if !@move_slots
col = @sprites["option"] ? (@sprites["option"][index] || 0) : 0
if index == 0
# Header row — show pokemon info panel
draw_pokemon_info
species = col == 0 ? @head_species : @body_species
@sprites["textbox"].text = _INTL("\nSelect all moves from {1}", GameData::Species.get(species).name)
return
end
slot = @move_slots[index - 1]
return if !slot
move = slot[col]
if move
draw_move_info(move)
@sprites["textbox"].text = _INTL(getMoveDescription(move))
else
@sprites["overlay"].bitmap.clear
@sprites["textbox"].text = getDefaultDescription
end
rescue => e
@sprites["textbox"].text = getDefaultDescription
end
end
def getDefaultDescription
return _INTL("No move selected")
end
def getMoveForIndex(index)
# Offset by 1 to skip the all moves button
move_index = index - 1
return nil if move_index < 0
highlighted_value = @sprites["option"] ? (@sprites["option"][index] || 0) : 0
case move_index
when 0 then highlighted_value == 0 ? @poke1.moves[0] : @poke2.moves[0]
when 1 then highlighted_value == 0 ? @poke1.moves[1] : @poke2.moves[1]
when 2 then highlighted_value == 0 ? @poke1.moves[2] : @poke2.moves[2]
when 3 then highlighted_value == 0 ? @poke1.moves[3] : @poke2.moves[3]
end
end
def listUniqueAvailableMoves
moves = []
moves += @poke1.moves
moves += @poke2.moves
return moves.uniq { |m| m.id }
end
def pbFadeInAndShow(sprites, visiblesprites = nil)
return if !@changedColor
super
end
def getMoveName(move)
return " - " if !@sprites["option"] && !move
move = @poke1.moves[@sprites["option"].index] if !move
return GameData::Move.get(move.id).name
end
def getMoveDescription(move)
return " - " if !@sprites["option"] && !move
move = @poke1.moves[@sprites["option"].index] if !move
return GameData::Move.get(move.id).description
end
def pbGetOptions(inloadscreen = false)
@move_slots = (0..3).map { |i| [@poke2.moves[i], @poke1.moves[i]] }
# Row 0: the "select all" header row
header = EnumOption.new(
"",
["", ""],
proc { 0 },
proc {},
["", ""]
)
move_options = @move_slots.map do |slot|
left_name = slot[0] ? GameData::Move.get(slot[0].id).name : "-"
right_name = slot[1] ? GameData::Move.get(slot[1].id).name : "-"
EnumOption.new(
"",
[left_name, right_name],
proc { 0 },
proc {},
["", ""]
)
end
return [header] + move_options
end
def pbOptions
pbActivateWindow(@sprites, "option") {
loop do
Graphics.update
Input.update
pbUpdate
if @sprites["option"].mustUpdateOptions
for i in 0...@PokemonOptions.length
@PokemonOptions[i].set(@sprites["option"][i])
end
end
@index_vertical = @sprites["option"].index
@index_horizontal = @sprites["option"][@index_vertical] || 0
if Input.trigger?(Input::USE)
# Confirm
if @index_vertical == @PokemonOptions.length
if @selected_moves.length > 0 && validateSelectedMoves
echoln @maxMovesNb
if @selected_moves.length < @maxMovesNb && listUniqueAvailableMoves.length > @selected_moves.length
nb_more = @maxMovesNb - @selected_moves.length
plural_s = nb_more > 1 ? "s" : ""
if pbConfirmMessage(_INTL("You can still select \\C[1]{1}\\C[0] additional move{2}. Are you sure you want to continue?", nb_more, plural_s))
break
end
else
break
end
else
pbPlayBuzzerSE
end
next
end
# Select all
if @index_vertical == 0
col = @index_horizontal
@selected_moves = @move_slots.map { |slot| slot[col] }.compact
(0...@PokemonOptions.length).each { |i| @sprites["option"].setValueNoRefresh(i, col) }
@sprites["option"].refresh
pbSEPlay("GUI naming confirm")
updateCounter
updateDescription(@index_vertical)
# Auto-jump to Confirm
@sprites["option"].index = @PokemonOptions.length
@sprites["option"].refresh
updateCounter
updatePokemonCursor(@PokemonOptions.length)
next
end
# Individual move row (rows 1-4, slot index is vertical - 1)
slot_index = @index_vertical - 1
move = @move_slots[slot_index][@index_horizontal]
next if !move
already_selected = @selected_moves.any? { |m| m.id == move.id }
if already_selected
@selected_moves.reject! { |m| m.id == move.id }
else
if @selected_moves.length >= 4
pbPlayBuzzerSE
else
@selected_moves << move
# Auto-jump to Confirm when 4th move is selected
if @selected_moves.length == @maxMovesNb
pbSEPlay("GUI naming confirm")
(0...@PokemonOptions.length).each { |i| @sprites["option"].setValueNoRefresh(i, @sprites["option"][@index_vertical] || 0) }
@sprites["option"].index = @PokemonOptions.length
@sprites["option"].refresh
updatePokemonCursor(@PokemonOptions.length)
end
end
end
@sprites["option"].refresh
updateCounter
updateDescription(@index_vertical)
end
end
}
end
def set_all_moves_to_index(index)
[1, 2, 3, 4].each { |i| @sprites["option"][i] = index }
source = index == 0 ? @poke1 : @poke2
@move1 = source.moves[0]
@move2 = source.moves[1]
@move3 = source.moves[2]
@move4 = source.moves[3]
@sprites["option"].refresh
updatePokemonCursor(@sprites["option"].index)
updateCounter
updateDescription(@sprites["option"].index)
end
def isConfirmedOnKeyPress
return false
end
def initOptionsWindow
x_pos = 0
y_pos = @sprites["title"].height
item_height = 32 # standard row height in Essentials
num_items = @PokemonOptions.length + 1 # +1 for Confirm
window_height = item_height * num_items + 4 # +4 for border padding
optionsWindow = Window_PokemonOptionFusionMoves.new(@PokemonOptions, x_pos, y_pos, Graphics.width,
window_height + 32,
self)
optionsWindow.viewport = @viewport
optionsWindow.visible = true
return optionsWindow
end
def validateSelectedMoves
return @selected_moves.length > 0 && @selected_moves.length <= 4
end
#Same as Option, but without pbRefreshSceneMap
def pbEndScene
pbPlayCloseMenuSE
pbFadeOutAndHide(@sprites) { pbUpdate }
# Set the values of each option
for i in 0...@PokemonOptions.length
@PokemonOptions[i].set(@sprites["option"][i])
end
pbDisposeMessageWindow(@sprites["textbox"])
pbDisposeSpriteHash(@sprites)
@viewport.dispose
end
end
class Window_PokemonOptionFusionMoves < Window_PokemonOption
OPTIONS_X_OFFSET = 0
COLUMNS_GAP = 20
def initialize(options, x, y, width, height, scene)
@scene = scene
super(options, x, y, width, height)
@mustUpdateOptions = true
@mustUpdateDescription = true
@confirmed = false
end
def drawCursor(index, rect)
if self.index == index
unless index == 0
optionwidth = rect.width * 9 / 20
col = self[index] || 0
if @options[index].is_a?(EnumOption) && @options[index].values.length > 1
col0_x = optionwidth + rect.x + 12 + OPTIONS_X_OFFSET
col1_x = col0_x + (rect.width - col0_x) / 2 + COLUMNS_GAP
xpos = col == 0 ? col0_x : col1_x
arrow_x = xpos - @selarrow.bitmap.width - 2
else
arrow_x = rect.x + 175
end
pbCopyBitmap(self.contents, @selarrow.bitmap, arrow_x, rect.y)
end
end
return Rect.new(rect.x + 16, rect.y, rect.width - 16, rect.height)
end
def drawItem(index, _count, rect)
return if dont_draw_item(index)
rect = drawCursor(index, rect)
if index == @options.length
optionwidth = rect.width * 9 / 20
base_color = Color.new(
[@nameBaseColor.red + 80, 255].min,
[@nameBaseColor.green + 80, 255].min,
[@nameBaseColor.blue + 80, 255].min
)
shadow_color = Color.new(
[base_color.red - 60, 0].max,
[base_color.green - 60, 0].max,
[base_color.blue - 60, 0].max
)
pbDrawShadowText(self.contents, 216, rect.y, optionwidth, rect.height,
_INTL(" Confirm"), base_color, shadow_color)
return
end
return unless @options[index].is_a?(EnumOption) && @options[index].values.length > 1
optionwidth = rect.width * 9 / 20
col0_x = optionwidth + rect.x + 12 + OPTIONS_X_OFFSET
col1_x = col0_x + (rect.width - col0_x) / 2 + COLUMNS_GAP
col_width = col1_x - col0_x - COLUMNS_GAP
@options[index].values.each_with_index do |value, col|
slot_index = index - 1
move = slot_index >= 0 ? @scene.move_slots&.[](slot_index)&.[](col) : nil
is_selected = move && @scene.selected_moves.any? { |m| m.id == move.id }
base = is_selected ? @selBaseColor : Color.new(180, 180, 180)
shadow = is_selected ? @selShadowColor : Color.new(80, 80, 80)
xpos = col == 0 ? col0_x : col1_x
pbDrawShadowText(self.contents, xpos, rect.y, col_width, rect.height, value, base, shadow)
end
end
def dont_draw_item(index)
return false
# return index == @options.length
end
def update
old_index = self.index
super
if self.index != old_index && self.index < @options.length
if old_index < @options.length
@optvalues[self.index] = @optvalues[old_index]
else
# Coming from confirm -> go to unselected one (makes it easier to quickly swap between the two)
current = @optvalues[self.index] || 0
@optvalues[self.index] = current == 0 ? 1 : 0
end
refresh
end
end
end