mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2026-07-22 15:47:00 +00:00
915 lines
25 KiB
Ruby
915 lines
25 KiB
Ruby
##=============================================================================
|
|
## Easy Questing System - Refactored with Extensible Mode System
|
|
## Original by M3rein
|
|
# Refactored using by Claude
|
|
# Adapted for Pokemon Infinite Fusion by chardub
|
|
##=============================================================================
|
|
## Main entry point for the quest log
|
|
##=============================================================================
|
|
|
|
def pbQuestlog
|
|
ensure_quests_repaired
|
|
loop do
|
|
if $Trainer&.pokenav&.last_opened_quest_mode == :LIST || Settings::KANTO
|
|
ql = Questlog.new
|
|
break unless ql.switch_to_map
|
|
$Trainer&.pokenav&.last_opened_quest_mode = :MAP
|
|
else
|
|
qm = showQuestMap
|
|
break unless qm&.reopen_map
|
|
$Trainer&.pokenav&.last_opened_quest_mode = :LIST
|
|
end
|
|
end
|
|
end
|
|
|
|
def ensure_quests_repaired
|
|
return if $Trainer.quests_repaired
|
|
fix_quest_ids
|
|
$Trainer.quests_repaired = true
|
|
end
|
|
|
|
##=============================================================================
|
|
## QuestSprite - Sprite class for quest list items
|
|
##=============================================================================
|
|
|
|
class QuestSprite < IconSprite
|
|
attr_accessor :quest
|
|
end
|
|
|
|
##=============================================================================
|
|
## QuestMode - Base class for quest filtering modes
|
|
##=============================================================================
|
|
|
|
class QuestCategory
|
|
attr_reader :name, :button_text
|
|
attr_accessor :last_index
|
|
def initialize(name, button_text)
|
|
@name = name
|
|
@button_text = button_text
|
|
@last_index = 0
|
|
end
|
|
|
|
# Override this method to define filtering logic
|
|
def filter_quests(all_quests)
|
|
raise NotImplementedError, "Subclasses must implement filter_quests"
|
|
end
|
|
|
|
# Override to customize empty message
|
|
def empty_message
|
|
"No quests"
|
|
end
|
|
|
|
# Override to customize title
|
|
def title
|
|
@name
|
|
end
|
|
end
|
|
|
|
##=============================================================================
|
|
## Built-in Quest Modes
|
|
##=============================================================================
|
|
|
|
|
|
class CompletedQuestMode < QuestCategory
|
|
def initialize
|
|
super("Completed Quests", "Completed")
|
|
end
|
|
def button_path
|
|
return "Graphics/Pictures/eqi/quest_button_complete"
|
|
end
|
|
|
|
def filter_quests(all_quests)
|
|
all_quests.select { |q| q.completed }
|
|
end
|
|
|
|
def empty_message
|
|
_INTL("No completed quests")
|
|
end
|
|
end
|
|
|
|
|
|
class MainQuestMode < QuestCategory
|
|
def initialize
|
|
super("Main Quests", "Main Quests")
|
|
end
|
|
|
|
def button_path
|
|
return "Graphics/Pictures/eqi/quest_button_main"
|
|
end
|
|
def filter_quests(all_quests)
|
|
return all_quests.select { |q| !q.completed && q.type == :MAIN_QUEST }
|
|
end
|
|
|
|
def empty_message
|
|
_INTL("No ongoing main quests")
|
|
end
|
|
end
|
|
|
|
class SideQuestMode < QuestCategory
|
|
def initialize
|
|
super("Side Quests", "Side Quests")
|
|
end
|
|
|
|
def button_path
|
|
return "Graphics/Pictures/eqi/quest_button_side"
|
|
end
|
|
|
|
def filter_quests(all_quests)
|
|
return all_quests.select { |q| !q.completed && q.type != :MAIN_QUEST }
|
|
end
|
|
|
|
def empty_message
|
|
_INTL("No side quests")
|
|
end
|
|
end
|
|
|
|
# class LocationQuestMode < QuestMode
|
|
# attr_reader :location
|
|
#
|
|
# def initialize(location)
|
|
# @location = location
|
|
# super("#{location} Quests", location)
|
|
# end
|
|
#
|
|
# def filter_quests(all_quests)
|
|
# return all_quests.select { |q| !q.completed && q.location.include?(@location) }
|
|
# end
|
|
#
|
|
# def empty_message
|
|
# _INTL("No quests in {1}", @location)
|
|
# end
|
|
# end
|
|
|
|
##=============================================================================
|
|
## Questlog - Main quest interface controller (Refactored)
|
|
##=============================================================================
|
|
|
|
class Questlog
|
|
attr_reader :switch_to_map
|
|
# Scene constants
|
|
SCENE_MAIN = 0
|
|
SCENE_LIST = 1
|
|
SCENE_DETAIL = 2
|
|
|
|
# UI constants
|
|
MAX_VISIBLE_QUESTS = 6
|
|
FADE_SPEED = 32
|
|
ANIMATION_FRAMES = 12
|
|
CHAR_ANIMATION_INTERVAL = 6
|
|
|
|
def initialize(open_quest: nil, from_map: false)
|
|
@from_map = from_map
|
|
@switch_to_map = false
|
|
initialize_data
|
|
initialize_modes
|
|
initialize_viewport
|
|
|
|
if open_quest
|
|
create_sprites(false)
|
|
setup_open_quest(open_quest)
|
|
else
|
|
create_sprites(false)
|
|
animate_intro
|
|
end
|
|
main_loop
|
|
cleanup
|
|
end
|
|
|
|
private
|
|
|
|
##---------------------------------------------------------------------------
|
|
## Initialization
|
|
##---------------------------------------------------------------------------
|
|
|
|
def setup_open_quest(quest)
|
|
@skip_menu = true
|
|
|
|
# Find which mode contains this quest
|
|
@current_mode = @modes.find { |mode| mode.filter_quests($Trainer.quests).include?(quest) }
|
|
|
|
# Fall back to first mode if not found (e.g. completed quests shown via direct open)
|
|
@current_mode ||= @modes.first
|
|
|
|
@filtered_quests = @current_mode.filter_quests($Trainer.quests)
|
|
@quest_list_menu_index = @filtered_quests.index(quest) || 0
|
|
@box = 0
|
|
|
|
# Jump straight to detail view
|
|
@scene = SCENE_DETAIL
|
|
create_detail_background
|
|
create_character_sprite("char", quest, 62, 130)
|
|
draw_quest_details(quest)
|
|
animate_detail_in
|
|
end
|
|
|
|
def initialize_data
|
|
$Trainer.quests = [] if $Trainer.quests.nil?
|
|
|
|
@page = 0
|
|
@main_menu_index = 0
|
|
@quest_list_menu_index = 0
|
|
@scene = SCENE_MAIN
|
|
@current_mode = nil
|
|
@box = 0 # Visible quest index (0-5)
|
|
@frame = 0
|
|
@filtered_quests = []
|
|
|
|
@scroll_timer = 12 # Cooldown counter for holding up/down
|
|
@scroll_delay = 6 # Frames to wait before repeating movement
|
|
|
|
fix_broken_TR_quests
|
|
end
|
|
|
|
def initialize_modes
|
|
# Register all available modes here
|
|
@modes = []
|
|
@modes << MainQuestMode.new if Settings::HOENN
|
|
@modes << SideQuestMode.new
|
|
@modes << CompletedQuestMode.new
|
|
|
|
# You can dynamically add location-based modes:
|
|
# @modes << LocationQuestMode.new("Cerulean City")
|
|
# @modes << LocationQuestMode.new("Viridian Forest")
|
|
end
|
|
|
|
def initialize_viewport
|
|
@viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
|
|
@viewport.z = 100002
|
|
@sprites = {}
|
|
end
|
|
|
|
def create_sprites(main_page = true)
|
|
create_main_bitmap
|
|
create_background
|
|
create_mode_buttons #if main_page
|
|
draw_main_text
|
|
end
|
|
|
|
def create_main_bitmap
|
|
@sprites["main"] = BitmapSprite.new(Graphics.width, Graphics.height, @viewport)
|
|
@sprites["main"].z = 1
|
|
@sprites["main"].opacity = 0
|
|
@main = @sprites["main"].bitmap
|
|
pbSetSystemFont(@main)
|
|
end
|
|
|
|
def create_background
|
|
@sprites["bg0"] = IconSprite.new(0, 0, @viewport)
|
|
bg_path = isDarkMode ?
|
|
"Graphics/Pictures/Pokegear/bg_dark" :
|
|
"Graphics/Pictures/Pokegear/bg"
|
|
@sprites["bg0"].setBitmap(bg_path)
|
|
@sprites["bg0"].opacity = 0
|
|
end
|
|
|
|
def create_mode_buttons
|
|
default_button_path = "Graphics/Pictures/eqi/quest_button"
|
|
@modes.size.times do |i|
|
|
@sprites["btn#{i}"] = IconSprite.new(0, 0, @viewport)
|
|
button_path = @modes[i].button_path
|
|
if button_path
|
|
@sprites["btn#{i}"].setBitmap(button_path)
|
|
else
|
|
@sprites["btn#{i}"].setBitmap(default_button_path)
|
|
end
|
|
@sprites["btn#{i}"].x = 84
|
|
@sprites["btn#{i}"].y = 130 + 56 * i
|
|
@sprites["btn#{i}"].src_rect.height = (@sprites["btn#{i}"].bitmap.height / 2).round
|
|
@sprites["btn#{i}"].src_rect.y = i == 0 ? (@sprites["btn#{i}"].bitmap.height / 2).round : 0
|
|
@sprites["btn#{i}"].opacity = 0
|
|
end
|
|
end
|
|
|
|
def draw_main_text
|
|
pbDrawOutlineText(@main, -160, 8, 512, 384, _INTL("Quest Log"),
|
|
Color.new(255, 255, 255), Color.new(0, 0, 0), 1)
|
|
if can_switch_mode?
|
|
pbDrawOutlineText(@main, 160, 8, 512, 384, _INTL("L/R : MAP"),
|
|
Color.new(255, 255, 255), Color.new(0, 0, 0), 1)
|
|
end
|
|
|
|
|
|
# Draw button labels and quest counts
|
|
@modes.each_with_index do |mode, i|
|
|
quest_count = mode.filter_quests($Trainer.quests).size
|
|
y_pos = 142 + (56 * i)
|
|
pbDrawOutlineText(@main, 0, y_pos, 512, 384,
|
|
_INTL("{1}: {2}", mode.button_text, quest_count),
|
|
Color.new(255, 255, 255), Color.new(0, 0, 0), 1)
|
|
end
|
|
end
|
|
|
|
def animate_intro
|
|
ANIMATION_FRAMES.times do |i|
|
|
Graphics.update
|
|
@sprites["bg0"]&.opacity += FADE_SPEED if i < 8
|
|
|
|
# Fade in all mode buttons
|
|
@modes.size.times do |j|
|
|
@sprites["btn#{j}"]&.opacity += FADE_SPEED if i > 3
|
|
end
|
|
|
|
@sprites["main"]&.opacity += 64 if i > 7
|
|
end
|
|
end
|
|
|
|
##---------------------------------------------------------------------------
|
|
## Main Loop
|
|
##---------------------------------------------------------------------------
|
|
|
|
def main_loop
|
|
@frame = 0
|
|
|
|
loop do
|
|
@frame += 1
|
|
Graphics.update
|
|
Input.update
|
|
|
|
break if handle_input
|
|
@frame = 0 if @frame == 18
|
|
end
|
|
end
|
|
|
|
def handle_input
|
|
case @scene
|
|
when SCENE_MAIN
|
|
return handle_main_input
|
|
when SCENE_LIST
|
|
return handle_list_input
|
|
when SCENE_DETAIL
|
|
return handle_detail_input
|
|
end
|
|
return false
|
|
end
|
|
|
|
def handle_main_input
|
|
if (Input.trigger?(Input::L) || Input.trigger?(Input::R)) && can_switch_mode?
|
|
@switch_to_map = true
|
|
pbSEPlay("GUI storage show party panel")
|
|
$Trainer&.pokenav&.last_opened_quest_mode = :MAP
|
|
return true
|
|
end
|
|
return true if Input.trigger?(Input::B)
|
|
|
|
if Input.trigger?(Input::C)
|
|
show_quest_list(@main_menu_index)
|
|
end
|
|
if @scroll_timer > 0
|
|
@scroll_timer -= 1
|
|
else
|
|
if Input.press?(Input::DOWN)
|
|
switch_button(:DOWN)
|
|
@scroll_timer = @scroll_delay
|
|
elsif Input.press?(Input::UP)
|
|
switch_button(:UP)
|
|
@scroll_timer = @scroll_delay
|
|
end
|
|
end
|
|
|
|
false
|
|
end
|
|
|
|
def can_switch_mode?
|
|
return Settings::HOENN && (@scene != SCENE_DETAIL)
|
|
end
|
|
|
|
def handle_list_input
|
|
if (Input.trigger?(Input::L) || Input.trigger?(Input::R)) && can_switch_mode?
|
|
@switch_to_map = true
|
|
return true
|
|
end
|
|
if Input.trigger?(Input::B)
|
|
return_to_main
|
|
elsif Input.trigger?(Input::C)
|
|
show_quest_detail
|
|
else
|
|
handle_scroll_input
|
|
end
|
|
animate_arrows
|
|
return false
|
|
end
|
|
|
|
def handle_scroll_input
|
|
# Only scroll when timer allows
|
|
if @scroll_timer > 0
|
|
@scroll_timer -= 1
|
|
return
|
|
end
|
|
|
|
if Input.press?(Input::DOWN)
|
|
move_selection(:DOWN)
|
|
@scroll_timer = @scroll_delay
|
|
elsif Input.press?(Input::UP)
|
|
move_selection(:UP)
|
|
@scroll_timer = @scroll_delay
|
|
end
|
|
end
|
|
|
|
|
|
def handle_detail_input
|
|
if Input.trigger?(Input::B)
|
|
return true
|
|
end
|
|
animate_character if [6, 12, 18].include?(@frame)
|
|
return false
|
|
end
|
|
|
|
##---------------------------------------------------------------------------
|
|
## Navigation
|
|
##---------------------------------------------------------------------------
|
|
|
|
def update_button_selection(index, selected)
|
|
return unless @sprites["btn#{index}"]
|
|
height = (@sprites["btn#{index}"].bitmap.height / 2).round
|
|
@sprites["btn#{index}"].src_rect.y = selected ? height : 0
|
|
end
|
|
|
|
def switch_button(dir)
|
|
max_index = @modes.size - 1
|
|
if dir == :DOWN
|
|
return if @main_menu_index >= max_index
|
|
update_button_selection(@main_menu_index, false)
|
|
@main_menu_index += 1
|
|
update_button_selection(@main_menu_index, true)
|
|
else
|
|
return if @main_menu_index <= 0
|
|
update_button_selection(@main_menu_index, false)
|
|
@main_menu_index -= 1
|
|
update_button_selection(@main_menu_index, true)
|
|
end
|
|
end
|
|
|
|
|
|
def move_selection(dir)
|
|
return if @filtered_quests.empty?
|
|
|
|
if dir == :DOWN
|
|
return if @quest_list_menu_index == @filtered_quests.size - 1
|
|
|
|
deselect_current_quest
|
|
@quest_list_menu_index += 1
|
|
@box += 1
|
|
@box = 5 if @box > 5
|
|
select_current_quest
|
|
|
|
refresh_quest_list if @box == 5
|
|
else
|
|
return if @quest_list_menu_index == 0
|
|
|
|
deselect_current_quest
|
|
@quest_list_menu_index -= 1
|
|
@box -= 1
|
|
@box = 0 if @box < 0
|
|
select_current_quest
|
|
|
|
refresh_quest_list if @box == 0
|
|
end
|
|
|
|
#pbWait(4)
|
|
end
|
|
|
|
def deselect_current_quest
|
|
@sprites["quest#{@box}"].src_rect.y = 0 if @sprites["quest#{@box}"]
|
|
end
|
|
|
|
def select_current_quest
|
|
if @sprites["quest#{@box}"]
|
|
@sprites["quest#{@box}"].src_rect.y = (@sprites["quest#{@box}"].bitmap.height / 2).round
|
|
end
|
|
end
|
|
|
|
##---------------------------------------------------------------------------
|
|
## Scene Transitions
|
|
##---------------------------------------------------------------------------
|
|
|
|
def return_to_main
|
|
pbWait(1)
|
|
dispose_quest_list_sprites
|
|
fade_to_main
|
|
reset_list_state
|
|
redraw_main_screen
|
|
animate_main_return
|
|
end
|
|
|
|
def fade_to_main
|
|
ANIMATION_FRAMES.times do |i|
|
|
Graphics.update
|
|
fade_sprites_out(i)
|
|
end
|
|
|
|
dispose_list_sprites
|
|
clear_bitmaps
|
|
end
|
|
|
|
def fade_sprites_out(index)
|
|
@sprites["main"].opacity -= FADE_SPEED if @sprites["main"]
|
|
@sprites["bg0"].opacity += FADE_SPEED if @sprites["bg0"].opacity < 255
|
|
|
|
if index > 3
|
|
@sprites["bg1"].opacity -= FADE_SPEED if @sprites["bg1"]
|
|
@sprites["bg2"].opacity -= FADE_SPEED if @sprites["bg2"]
|
|
@sprites["pager"].opacity -= FADE_SPEED if @sprites["pager"]
|
|
@sprites["pager2"].opacity -= FADE_SPEED if @sprites["pager2"]
|
|
end
|
|
|
|
@sprites["char"].opacity -= FADE_SPEED if @sprites["char"]
|
|
@sprites["char2"].opacity -= FADE_SPEED if @sprites["char2"]
|
|
@sprites["text"].opacity -= FADE_SPEED if @sprites["text"]
|
|
@sprites["up"].opacity -= FADE_SPEED if @sprites["up"]
|
|
@sprites["down"].opacity -= FADE_SPEED if @sprites["down"]
|
|
|
|
fade_quest_sprites
|
|
end
|
|
|
|
def fade_quest_sprites
|
|
MAX_VISIBLE_QUESTS.times do |i|
|
|
@sprites["quest#{i}"].opacity -= FADE_SPEED if @sprites["quest#{i}"]
|
|
end
|
|
end
|
|
|
|
def dispose_list_sprites
|
|
@sprites["up"].dispose if @sprites["up"]
|
|
@sprites["down"].dispose if @sprites["down"]
|
|
end
|
|
|
|
def clear_bitmaps
|
|
@main.clear if @main
|
|
@text.clear if @text
|
|
@text2.clear if @text2
|
|
end
|
|
|
|
def reset_list_state
|
|
@scene = SCENE_MAIN
|
|
end
|
|
|
|
def redraw_main_screen
|
|
pbDrawOutlineText(@main, 0, 2, 512, 384, _INTL("Quest Log"),
|
|
Color.new(255, 255, 255), Color.new(0, 0, 0), 1)
|
|
|
|
@modes.each_with_index do |mode, i|
|
|
quest_count = mode.filter_quests($Trainer.quests).size
|
|
y_pos = 142 + (56 * i)
|
|
pbDrawOutlineText(@main, 0, y_pos, 512, 384,
|
|
_INTL("{1}: {2}", mode.button_text, quest_count),
|
|
Color.new(255, 255, 255), Color.new(0, 0, 0), 1)
|
|
end
|
|
end
|
|
|
|
def animate_main_return
|
|
ANIMATION_FRAMES.times do |i|
|
|
Graphics.update
|
|
@sprites["bg0"].opacity += FADE_SPEED if i < 8
|
|
|
|
@modes.size.times do |j|
|
|
@sprites["btn#{j}"].opacity += FADE_SPEED if i > 3
|
|
end
|
|
|
|
@sprites["main"].opacity += 48 if i > 5
|
|
end
|
|
end
|
|
|
|
##---------------------------------------------------------------------------
|
|
## Quest List Display
|
|
##---------------------------------------------------------------------------
|
|
|
|
def show_quest_list(mode_index)
|
|
pbWait(2)
|
|
@scene = SCENE_LIST
|
|
@current_mode = @modes[mode_index]
|
|
|
|
@quest_list_menu_index = @current_mode.last_index
|
|
@box = [@quest_list_menu_index, MAX_VISIBLE_QUESTS - 1].min
|
|
@filtered_quests = @current_mode.filter_quests($Trainer.quests)
|
|
|
|
create_arrow_sprites
|
|
fade_to_list
|
|
clear_bitmaps
|
|
display_quest_list
|
|
end
|
|
|
|
|
|
def create_arrow_sprites
|
|
@sprites["up"] = create_arrow(36, false)
|
|
@sprites["down"] = create_arrow(360, true)
|
|
@sprites["down"].visible = @filtered_quests.size > MAX_VISIBLE_QUESTS
|
|
@sprites["down"].opacity = 0
|
|
end
|
|
|
|
def create_arrow(y_pos, flip)
|
|
arrow = IconSprite.new(0, 0, @viewport)
|
|
arrow.setBitmap("Graphics/Pictures/EQI/quest_arrow")
|
|
arrow.zoom_x = 1.25
|
|
arrow.zoom_y = 1.25
|
|
arrow.x = Graphics.width / 2 + (flip ? 21 : 0)
|
|
arrow.y = y_pos
|
|
arrow.z = 2
|
|
arrow.angle = flip ? 180 : 0
|
|
arrow.visible = false
|
|
arrow
|
|
end
|
|
|
|
def fade_to_list
|
|
10.times do |i|
|
|
Graphics.update
|
|
|
|
if i > 1
|
|
@modes.size.times do |j|
|
|
@sprites["btn#{j}"].opacity -= FADE_SPEED
|
|
end
|
|
@sprites["main"].opacity -= FADE_SPEED
|
|
fade_detail_sprites
|
|
end
|
|
end
|
|
end
|
|
|
|
def fade_detail_sprites
|
|
@sprites["bg1"].opacity -= FADE_SPEED if @sprites["bg1"]
|
|
@sprites["bg2"].opacity -= FADE_SPEED if @sprites["bg2"]
|
|
@sprites["pager"].opacity -= FADE_SPEED if @sprites["pager"]
|
|
@sprites["pager2"].opacity -= FADE_SPEED if @sprites["pager2"]
|
|
@sprites["char"].opacity -= FADE_SPEED if @sprites["char"]
|
|
@sprites["char2"].opacity -= FADE_SPEED if @sprites["char2"]
|
|
@sprites["text"].opacity -= FADE_SPEED if @sprites["text"]
|
|
@sprites["text2"].opacity -= FADE_SPEED if @sprites["text2"]
|
|
end
|
|
|
|
def display_quest_list
|
|
[@filtered_quests.size, MAX_VISIBLE_QUESTS].min.times do |i|
|
|
create_quest_sprite(i, @filtered_quests[i])
|
|
draw_quest_name_on_main(i, @filtered_quests[i])
|
|
end
|
|
|
|
if @filtered_quests.empty?
|
|
pbDrawOutlineText(@main, 0, 175, 512, 384, @current_mode.empty_message,
|
|
pbColor(:WHITE), pbColor(:BLACK), 1)
|
|
end
|
|
|
|
pbDrawOutlineText(@main, 0, 2, 512, 384, @current_mode.title,
|
|
Color.new(255, 255, 255), Color.new(0, 0, 0), 1)
|
|
|
|
animate_quest_list
|
|
end
|
|
|
|
def create_quest_sprite(index, quest)
|
|
sprite_key = "quest#{index}"
|
|
@sprites[sprite_key] = QuestSprite.new(0, 0, @viewport)
|
|
sprite = @sprites[sprite_key]
|
|
sprite.setBitmap("Graphics/Pictures/EQI/quest_button")
|
|
sprite.quest = quest
|
|
sprite.x = 94
|
|
sprite.y = 42 + 52 * index
|
|
sprite.src_rect.height = (sprite.bitmap.height / 2).round
|
|
sprite.src_rect.y = (sprite.bitmap.height / 2).round if index == @quest_list_menu_index
|
|
sprite.opacity = 0
|
|
|
|
draw_quest_name_on_main(index, quest)
|
|
set_quest_list_sprite(index,quest)
|
|
end
|
|
|
|
|
|
def draw_quest_name_on_main(index, quest)
|
|
y_pos = get_cell_y_position(index)
|
|
pbDrawOutlineText(@main, 11, y_pos, 512, 384,
|
|
quest.name,
|
|
quest.default_color,
|
|
Color.new(0, 0, 0),
|
|
1)
|
|
end
|
|
|
|
def get_cell_y_position(index)
|
|
56 + (52 * index)
|
|
end
|
|
|
|
def animate_quest_list
|
|
ANIMATION_FRAMES.times do |i|
|
|
Graphics.update
|
|
@sprites["main"].opacity += FADE_SPEED if i < 8
|
|
@sprites["down"].opacity += FADE_SPEED if i > 3
|
|
|
|
[@filtered_quests.size, MAX_VISIBLE_QUESTS].min.times do |j|
|
|
@sprites["quest#{j}"].opacity += FADE_SPEED if i > 3
|
|
@sprites["quest_icon#{j}"].opacity += FADE_SPEED if i > 3 # Fade in icon
|
|
end
|
|
end
|
|
end
|
|
|
|
def set_quest_list_sprite(index, quest)
|
|
quest_button = @sprites["quest#{index}"]
|
|
icon_key = "quest_icon#{index}"
|
|
|
|
if @sprites[icon_key]
|
|
sprite = @sprites[icon_key]
|
|
sprite.setBitmap("Graphics/Characters/#{quest.sprite}")
|
|
sprite.x = quest_button.x - 64
|
|
sprite.y = quest_button.y - 20
|
|
sprite.src_rect.width = (sprite.bitmap.width / 4).round
|
|
sprite.src_rect.height = (sprite.bitmap.height / 4).round
|
|
sprite.src_rect.x = 0
|
|
sprite.src_rect.y = 0
|
|
sprite.visible = true
|
|
else
|
|
create_character_sprite(icon_key, quest, quest_button.x - 64, quest_button.y - 20)
|
|
end
|
|
end
|
|
|
|
|
|
|
|
def refresh_quest_list
|
|
@main.clear if @main
|
|
|
|
MAX_VISIBLE_QUESTS.times do |i|
|
|
quest_index = @quest_list_menu_index - @box + i
|
|
next if quest_index < 0 || quest_index >= @filtered_quests.size
|
|
|
|
quest = @filtered_quests[quest_index]
|
|
|
|
# Update the quest button
|
|
sprite = @sprites["quest#{i}"]
|
|
sprite.quest = quest if sprite
|
|
sprite.src_rect.y = (i == @box ? (sprite.bitmap.height / 2).round : 0) if sprite
|
|
|
|
draw_quest_name_on_main(i, quest)
|
|
set_quest_list_sprite(i, quest)
|
|
end
|
|
|
|
# Update arrow visibility
|
|
@sprites["up"].visible = @quest_list_menu_index > 0
|
|
@sprites["down"].visible = @quest_list_menu_index < @filtered_quests.size - 1
|
|
|
|
# Redraw the title
|
|
pbDrawOutlineText(@main, 0, 2, 512, 384, @current_mode.title,
|
|
Color.new(255, 255, 255), Color.new(0, 0, 0), 1)
|
|
end
|
|
|
|
|
|
|
|
##---------------------------------------------------------------------------
|
|
## Quest Detail Display
|
|
##---------------------------------------------------------------------------
|
|
|
|
def dispose_quest_list_sprites
|
|
MAX_VISIBLE_QUESTS.times do |i|
|
|
if @sprites["quest#{i}"]
|
|
@sprites["quest#{i}"].dispose
|
|
@sprites.delete("quest#{i}")
|
|
end
|
|
if @sprites["quest_icon#{i}"]
|
|
@sprites["quest_icon#{i}"].dispose
|
|
@sprites.delete("quest_icon#{i}")
|
|
end
|
|
end
|
|
end
|
|
|
|
def show_quest_detail
|
|
return if @filtered_quests.empty?
|
|
@current_mode.last_index = @quest_list_menu_index
|
|
|
|
dispose_quest_list_sprites
|
|
quest = @filtered_quests[@quest_list_menu_index]
|
|
pbWait(1)
|
|
|
|
@scene = SCENE_DETAIL
|
|
create_detail_background
|
|
fade_to_detail
|
|
create_character_sprite("char", quest, 62, 130)
|
|
draw_quest_details(quest)
|
|
animate_detail_in
|
|
end
|
|
|
|
|
|
def create_detail_background
|
|
@sprites["bg1"] = IconSprite.new(0, 0, @viewport)
|
|
@sprites["bg1"].setBitmap("Graphics/Pictures/EQI/quest_page1")
|
|
@sprites["bg1"].opacity = 0
|
|
|
|
@sprites["pager"] = IconSprite.new(0, 0, @viewport)
|
|
@sprites["pager"].setBitmap("Graphics/Pictures/EQI/quest_pager")
|
|
@sprites["pager"].x = 442
|
|
@sprites["pager"].y = 3
|
|
@sprites["pager"].z = 1
|
|
@sprites["pager"].opacity = 0
|
|
end
|
|
|
|
def fade_to_detail
|
|
8.times do
|
|
Graphics.update
|
|
@sprites["up"]&.opacity -= FADE_SPEED
|
|
@sprites["down"]&.opacity -= FADE_SPEED
|
|
@sprites["main"]&.opacity -= FADE_SPEED
|
|
@sprites["bg1"]&.opacity += FADE_SPEED if @sprites["bg1"]
|
|
@sprites["pager"]&.opacity = 0 if @sprites["pager"]
|
|
@sprites["char"]&.opacity -= FADE_SPEED if @sprites["char"]
|
|
|
|
fade_quest_list_sprites
|
|
end
|
|
|
|
@sprites["up"]&.dispose
|
|
@sprites["down"]&.dispose
|
|
end
|
|
|
|
def fade_quest_list_sprites
|
|
MAX_VISIBLE_QUESTS.times do |i|
|
|
@sprites["quest#{i}"].opacity -= FADE_SPEED if @sprites["quest#{i}"]
|
|
end
|
|
end
|
|
|
|
def create_character_sprite(spriteId,quest,x,y, max_height=nil)
|
|
@sprites[spriteId] = IconSprite.new(0, 0, @viewport)
|
|
@sprites[spriteId].setBitmap("Graphics/Characters/#{quest.sprite}")
|
|
@sprites[spriteId].x = x
|
|
@sprites[spriteId].y = y
|
|
@sprites[spriteId].src_rect.height = max_height ? max_height : (@sprites[spriteId].bitmap.height / 4).round
|
|
@sprites[spriteId].src_rect.width = (@sprites[spriteId].bitmap.width / 4).round
|
|
@sprites[spriteId].opacity = 0
|
|
end
|
|
|
|
def draw_quest_details(quest)
|
|
@main.clear if @main
|
|
@text.clear if @text
|
|
@text2.clear if @text2
|
|
|
|
pbDrawOutlineText(@main, 188, 54, 512, 384, quest.name,
|
|
Color.new(255, 172, 115), Color.new(0, 0, 0))
|
|
drawTextExMulti(@main, 188, 84, 318, 8, quest.desc,
|
|
Color.new(255, 255, 255), Color.new(0, 0, 0))
|
|
pbDrawOutlineText(@main, 188, 330, 512, 384, quest.location,
|
|
Color.new(255, 172, 115), Color.new(0, 0, 0))
|
|
|
|
|
|
draw_completion_status(quest)
|
|
end
|
|
|
|
def draw_completion_status(quest)
|
|
if quest.completed
|
|
pbDrawOutlineText(@main, 8, 315, 512, 384, _INTL("Completed"),
|
|
pbColor(:LIGHTBLUE), Color.new(0, 0, 0))
|
|
else
|
|
pbDrawOutlineText(@main, 8, 315, 512, 384, _INTL("Not Completed"),
|
|
pbColor(:LIGHTRED), Color.new(0, 0, 0))
|
|
end
|
|
end
|
|
|
|
def animate_detail_in
|
|
10.times do |i|
|
|
Graphics.update
|
|
@sprites["bg0"].opacity += FADE_SPEED
|
|
@sprites["main"].opacity += FADE_SPEED
|
|
@sprites["bg1"].opacity += FADE_SPEED if @sprites["bg1"]
|
|
@sprites["char"].opacity += FADE_SPEED if i > 1
|
|
end
|
|
end
|
|
|
|
##---------------------------------------------------------------------------
|
|
## Animations
|
|
##---------------------------------------------------------------------------
|
|
|
|
def animate_arrows
|
|
return unless @sprites["up"] && !@sprites["up"].disposed?
|
|
return unless @sprites["down"] && !@sprites["down"].disposed?
|
|
|
|
if [2, 4, 14, 16].include?(@frame)
|
|
@sprites["up"].y -= 1
|
|
@sprites["down"].y -= 1
|
|
elsif [6, 8, 10, 12].include?(@frame)
|
|
@sprites["up"].y += 1
|
|
@sprites["down"].y += 1
|
|
end
|
|
end
|
|
|
|
def animate_character
|
|
["char", "char2"].each do |char_key|
|
|
next unless @sprites[char_key]
|
|
|
|
sprite = @sprites[char_key]
|
|
sprite.src_rect.x += (sprite.bitmap.width / 4).round
|
|
sprite.src_rect.x = 0 if sprite.src_rect.x >= sprite.bitmap.width
|
|
end
|
|
end
|
|
|
|
##---------------------------------------------------------------------------
|
|
## Cleanup
|
|
##---------------------------------------------------------------------------
|
|
|
|
def cleanup
|
|
if @switch_to_map
|
|
showBlk(1) # instant black
|
|
else
|
|
ANIMATION_FRAMES.times do |i|
|
|
Graphics.update
|
|
@sprites["bg0"].opacity -= FADE_SPEED if @sprites["bg0"] && i > 3
|
|
@sprites["bg1"].opacity -= FADE_SPEED if @sprites["bg1"] && i > 3
|
|
@sprites["pager"].opacity -= FADE_SPEED if @sprites["pager"] && i > 3
|
|
@modes.size.times do |j|
|
|
@sprites["btn#{j}"].opacity -= FADE_SPEED if @sprites["btn#{j}"]
|
|
end
|
|
|
|
@sprites["main"].opacity -= FADE_SPEED if @sprites["main"]
|
|
@sprites["char"].opacity -= 40 if @sprites["char"]
|
|
@sprites["char2"].opacity -= 40 if @sprites["char2"]
|
|
end
|
|
end
|
|
pbDisposeSpriteHash(@sprites)
|
|
@viewport.dispose
|
|
pbWait(1)
|
|
end
|
|
end |