分析代码:#########################################################
### Encounter list UI ###
### Based on the original resource by raZ and friends ###
#########################################################
# 这是UI外观的图片文件名,位于Graphics/UI文件夹
WINDOWSKIN = "base.png"
# 自定义遭遇类型名称的哈希表
USER_DEFINED_NAMES = {
:Land => "草丛",
:LandDay => "草丛 (白天)",
:LandNight => "草丛 (夜晚)",
:LandMorning => "草丛 (早晨)",
:LandAfternoon => "草丛 (下午)",
:LandEvening => "草丛 (黄昏)",
:PokeRadar => "宝可雷达",
:Cave => "洞穴",
:CaveDay => "洞穴 (白天)",
:CaveNight => "洞穴 (夜晚)",
:CaveMorning => "洞穴 (早晨)",
:CaveAfternoon => "洞穴 (下午)",
:CaveEvening => "洞穴 (黄昏)",
:Water => "冲浪",
:WaterDay => "冲浪 (白天)",
:WaterNight => "冲浪 (夜晚)",
:WaterMorning => "冲浪 (早晨)",
:WaterAfternoon => "冲浪 (下午)",
:WaterEvening => "冲浪 (黄昏)",
:OldRod => "钓鱼 (旧钓竿)",
:GoodRod => "钓鱼 (好钓竿)",
:SuperRod => "钓鱼 (超级钓竿)",
:RockSmash => "碎岩",
:HeadbuttLow => "头槌 (稀有)",
:HeadbuttHigh => "头槌 (常见)",
:BugContest => "捕虫大赛"
}
# 辅助方法:检查玩家是否拥有某个精灵(从队伍和电脑中)
def player_owns_species?(species_id)
return false unless $player
# 检查队伍
$player.party.each do |pkmn|
return true if pkmn.species == species_id
end
# 检查电脑存储
return player_owns_in_pc?(species_id) if $player.pc && $player.pc.boxes
return false
end
# 辅助方法:检查玩家PC中是否拥有精灵
def player_owns_in_pc?(species_id)
$player.pc.boxes.each do |box|
box.each do |pkmn|
next unless pkmn
return true if pkmn.species == species_id
end
end
return false
end
# 辅助方法:检查玩家是否见过某个精灵
def player_has_seen_species?(species_id)
return false unless $player && $player.pokedex
# 尝试多种常见的"见过"判断方法
# 方法1:使用seen?方法
begin
return true if $player.pokedex.seen?(species_id)
rescue
end
# 方法2:检查图鉴数据数组(索引0通常是"见过"状态)
begin
return true if $player.pokedex.data &&
$player.pokedex.data[species_id] &&
$player.pokedex.data[species_id][0]
rescue
end
# 方法3:如果拥有该精灵,也说明一定见过
return player_owns_species?(species_id)
end
class EncounterList_Scene
def initialize
@viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
@viewport.z = 99999
@sprites = {}
@encounter_tables = {}
@index = 0
@current_page = 0
@items_per_page = 5
@total_pages = 1
# 加载遭遇数据
load_encounter_data
end
# 加载和处理遭遇数据
def load_encounter_data
return unless File.exist?("Data/encounters.dat")
begin
data = load_data("Data/encounters.dat")
return unless data.is_a?(Hash) && data[$game_map.map_id] && data[$game_map.map_id][1]
# 获取遭遇类型和ID的映射
encounter_type_mapping = {}
EncounterTypes.constants.each do |const|
next if [:Names, :EnctypeChances, :EnctypeDensities, :EnctypeCompileDens].include?(const)
type_id = EncounterTypes.const_get(const)
encounter_type_mapping[type_id] = const
end
# 遍历每个遭遇类型
encounter_types = data[$game_map.map_id][1]
encounter_types.each_with_index do |encounters, type_id|
if encounters && encounter_type_mapping[type_id]
@encounter_tables[encounter_type_mapping[type_id]] = encounters
end
end
# 设置最大遭遇数和遭遇类型数量
unless @encounter_tables.empty?
@max_enc, @eLength = get_max_encounters(@encounter_tables)
end
rescue => e
# 发生错误时保持默认值
@max_enc, @eLength = [1, 1]
end
end
# 获取最大遭遇数和遭遇类型数量
def get_max_encounters(data)
max_count = 0
keys = data.keys
keys.each do |key|
arr = data[key]
# 提取所有精灵等级并去重
level_count = arr.map { |e| e[1] }.uniq.length
max_count = level_count if level_count > max_count
end
return max_count, keys.length
end
def pbStartScene
# 检查UI资源文件是否存在
ui_file_path = "Graphics/UI/EncounterUI/#{WINDOWSKIN}"
raise _INTL("缺少UI所需的图像文件。请确保图像文件在Graphics/UI文件夹中,并且命名正确。") unless File.file?(ui_file_path)
# 创建UI精灵
create_ui_elements(ui_file_path)
# 根据数据情况绘制场景
if !@encounter_tables.empty? && @encounter_tables.keys.any?
@index = 0 if @index < 0 || @index >= @encounter_tables.keys.length
draw_present
else
draw_absent
end
pbFadeInAndShow(@sprites) { pbUpdate }
end
# 创建UI元素
def create_ui_elements(ui_file_path)
# 背景
addBackgroundPlane(@sprites, "bg", "EncounterUI/bg", @viewport)
# 基础窗口
@sprites["base"] = IconSprite.new(0, 0, @viewport)
@sprites["base"].setBitmap(ui_file_path)
@sprites["base"].ox = @sprites["base"].bitmap.width / 2
@sprites["base"].oy = @sprites["base"].bitmap.height / 2
@sprites["base"].x = Graphics.width / 2
@sprites["base"].y = Graphics.height / 2
@sprites["base"].opacity = 200
# 位置窗口
@sprites["locwindow"] = Window_AdvancedTextPokemon.new("")
@sprites["locwindow"].viewport = @viewport
@sprites["locwindow"].width = 512
@sprites["locwindow"].height = 344
@sprites["locwindow"].x = (Graphics.width - @sprites["locwindow"].width) / 2
@sprites["locwindow"].y = (Graphics.height - @sprites["locwindow"].height) / 2
@sprites["locwindow"].windowskin = nil
# 计算位置偏移
@h = (Graphics.height - @sprites["base"].bitmap.height) / 2
@w = (Graphics.width - @sprites["base"].bitmap.width) / 2
# 文本显示区域
@sprites["encounterlist"] = Window_AdvancedTextPokemon.newWithSize("", @w + 28, @h + 100, 500, 300, @viewport)
@sprites["encounterlist"].windowskin = RPG::Cache.windowskin(WINDOWSKIN)
@sprites["encounterlist"].text = ""
# 导航箭头
create_navigation_arrows
end
# 创建导航箭头
def create_navigation_arrows
# 右箭头
@sprites["rightarrow"] = AnimatedSprite.new("Graphics/UI/right_arrow", 8, 32, 32, 1, @viewport)
@sprites["rightarrow"].x = Graphics.width - @sprites["rightarrow"].bitmap.width
@sprites["rightarrow"].y = Graphics.height / 2 - @sprites["rightarrow"].bitmap.height / 2
@sprites["rightarrow"].visible = false
@sprites["rightarrow"].play
# 左箭头
@sprites["leftarrow"] = AnimatedSprite.new("Graphics/UI/left_arrow", 8, 32, 32, 1, @viewport)
@sprites["leftarrow"].x = 0
@sprites["leftarrow"].y = Graphics.height / 2 - @sprites["leftarrow"].bitmap.height / 2
@sprites["leftarrow"].visible = false
@sprites["leftarrow"].play
end
def pbEncounter
loop do
Graphics.update
Input.update
pbUpdate
# 左右键切换遭遇类型
handle_encounter_type_navigation
# 上下键分页
handle_pagination_navigation
# 退出
if Input.trigger?(Input::C) || Input.trigger?(Input::B)
pbPlayCancelSE
break
end
end
end
# 处理遭遇类型导航
def handle_encounter_type_navigation
return if @encounter_tables.empty?
keys = @encounter_tables.keys
return if keys.length <= 1
# 右箭头导航
if Input.trigger?(Input::RIGHT) && @index < keys.length - 1
pbPlayCursorSE
hide_sprites
@index += 1
@current_page = 0
draw_present
# 左箭头导航
elsif Input.trigger?(Input::LEFT) && @index > 0
pbPlayCursorSE
hide_sprites
@index -= 1
@current_page = 0
draw_present
end
end
# 处理分页导航
def handle_pagination_navigation
enc_array, _ = get_enc_data
return unless enc_array && enc_array.length > @items_per_page
@total_pages = (enc_array.length.to_f / @items_per_page).ceil
# 下一页
if Input.trigger?(Input::DOWN) && @current_page < @total_pages - 1
pbPlayCursorSE
@current_page += 1
draw_present
# 上一页
elsif Input.trigger?(Input::UP) && @current_page > 0
pbPlayCursorSE
@current_page -= 1
draw_present
end
end
def draw_present
# 更新箭头可见性
update_arrow_visibility
# 获取遭遇数据
enc_array, curr_key = get_enc_data
if curr_key
# 获取遭遇类型名称
name = USER_DEFINED_NAMES[curr_key] || curr_key.to_s
# 显示遭遇信息
loctext = _INTL("<ac><c2=43F022E8>{1}: {2}</c2></ac>", $game_map.name, name)
# 显示精灵数量
pokemon_count = enc_array ? enc_array.length : 0
loctext += sprintf("<al><c2=7FF05EE8>此区域遭遇精灵数量: %s</c2></al>", pokemon_count)
# 生成遭遇列表文本
encounter_text = generate_encounter_text(enc_array)
# 更新UI显示
loctext += sprintf("<c2=63184210>-----------------------------------------</c2>")
@sprites["locwindow"].setText(loctext)
@sprites["encounterlist"].text = encounter_text
@sprites["encounterlist"].visible = true
else
@sprites["encounterlist"].visible = false
draw_absent
end
end
# 更新箭头可见性
def update_arrow_visibility
return unless @sprites["rightarrow"] && @sprites["leftarrow"]
if !@encounter_tables.empty?
keys = @encounter_tables.keys
@sprites["rightarrow"].visible = (@index < keys.length - 1)
@sprites["leftarrow"].visible = (@index > 0)
else
@sprites["rightarrow"].visible = false
@sprites["leftarrow"].visible = false
end
end
# 生成遭遇列表文本
def generate_encounter_text(enc_array)
if !enc_array || enc_array.empty?
return "<c2=FF0000>此遭遇类型下没有发现精灵!</c2>"
end
# 计算分页信息
@total_pages = (enc_array.length.to_f / @items_per_page).ceil
@current_page = 0 if @current_page >= @total_pages
start_index = @current_page * @items_per_page
end_index = [start_index + @items_per_page - 1, enc_array.length - 1].min
# 初始化文本
encounter_text = sprintf("<c2=FFA500>第 %d/%d 页</c2>\n\n", @current_page + 1, @total_pages)
# 显示当前页的精灵数据
(start_index..end_index).each do |global_index|
encounter_data = enc_array[global_index]
next unless encounter_data.is_a?(Array) && encounter_data.length >= 2
species_id, level = encounter_data
if species_id.is_a?(Numeric) && species_id > 0
# 获取精灵状态
seen, caught = get_pokemon_status(species_id)
# 获取精灵名称
species_name = get_species_name(species_id)
# 添加精灵信息到文本
encounter_text += sprintf("%2d. %s Lv.%s\n",
global_index + 1, species_name, level)
else
encounter_text += sprintf("<c2=FF0000>%2d. 无效ID:%s</c2>\n", global_index + 1, species_id.inspect)
end
end
# 添加分页提示
if @total_pages > 1
encounter_text += "\n<c2=FFA500>上/下键切换页面</c2>\n"
end
return encounter_text
end
# 获取精灵状态信息
def get_pokemon_status(species_id)
seen = false
caught = false
begin
caught = player_owns_species?(species_id)
seen = player_has_seen_species?(species_id)
rescue => e
puts "判断精灵状态时出错: #{e.message}"
end
return seen, caught
end
# 获取状态显示信息
def get_status_display_info(seen, caught)
end
# 获取精灵名称
def get_species_name(species_id)
begin
if defined?(PBSpecies) && PBSpecies.respond_to?(:getName)
return PBSpecies.getName(species_id).to_s
end
return "精灵#{species_id}"
rescue
return "ID#{species_id}"
end
end
def draw_absent
loctext = _INTL("<ac><c2=43F022E8>{1}</c2></ac>", $game_map.name)
if !File.exist?("Data/encounters.dat")
loctext += sprintf("<al><c2=FF0000>找不到遭遇数据文件</c2></al>")
loctext += sprintf("<al><c2=FFA500>检查Data/encounters.dat是否存在</c2></al>")
else
loctext += sprintf("<al><c2=7FF05EE8>此区域没有定义遭遇</c2></al>")
loctext += sprintf("<al><c2=FFA500>使用C键关闭或探索其他区域</c2></al>")
end
loctext += sprintf("<c2=63184210>-----------------------------------------</c2>")
@sprites["locwindow"].setText(loctext)
end
def get_enc_data
return [], nil if @encounter_tables.empty?
keys = @encounter_tables.keys
# 确保索引在有效范围内
@index = [[@index, 0].max, keys.length - 1].min
curr_key = keys[@index]
return [], curr_key unless curr_key && @encounter_tables[curr_key].is_a?(Array)
# 处理遭遇数据
return process_encounter_data(@encounter_tables[curr_key]), curr_key
end
# 处理遭遇数据,合并相同精灵的等级范围
def process_encounter_data(encounter_data)
pokemon_info = {}
encounter_data.each do |entry|
next unless entry.is_a?(Array) && entry.length >= 2
species_id = entry[0]
level = entry[1]
# 验证数据有效性
next unless species_id.is_a?(Numeric) && species_id > 0 && level.is_a?(Numeric) && level > 0
if pokemon_info.key?(species_id)
# 合并已存在的精灵等级范围
update_level_range(pokemon_info[species_id], level)
else
# 添加新精灵
pokemon_info[species_id] = { :level => level }
end
end
# 转换为所需格式并排序
return format_and_sort_encounters(pokemon_info)
end
# 更新精灵等级范围
def update_level_range(info, new_level)
current_level = info[:level]
# 计算最小和最大等级
min_level = [
current_level.is_a?(Array) ? current_level[0] : current_level,
new_level
].min
max_level = [
current_level.is_a?(Array) ? current_level[1] : current_level,
new_level
].max
# 更新等级信息
if min_level == max_level
info[:level] = min_level
else
info[:level] = [min_level, max_level]
end
end
# 格式化并排序遭遇数据
def format_and_sort_encounters(pokemon_info)
enc_array = []
pokemon_info.each do |species_id, info|
level = info[:level]
# 格式化等级显示
level_text = if level.is_a?(Array) && level[0] != level[1]
"#{level[0]}-#{level[1]}"
else
level.to_s
end
enc_array << [species_id, level_text]
end
# 按精灵ID排序
return enc_array.sort { |a, b| a[0] <=> b[0] }
end
def pbUpdate
pbUpdateSpriteHash(@sprites)
# 更新可见的精灵
@sprites["rightarrow"].update if @sprites["rightarrow"] && @sprites["rightarrow"].visible
@sprites["leftarrow"].update if @sprites["leftarrow"] && @sprites["leftarrow"].visible
@sprites["encounterlist"].update if @sprites["encounterlist"] && @sprites["encounterlist"].visible
end
def hide_sprites
@sprites["encounterlist"].visible = false if @sprites["encounterlist"]
end
def pbEndScene
pbFadeOutAndHide(@sprites) { pbUpdate }
pbDisposeSpriteHash(@sprites)
@viewport.dispose
end
end
class EncounterList_Screen
def initialize(scene)
@scene = scene
end
def pbStartScreen
@scene.pbStartScene
@scene.pbEncounter
@scene.pbEndScene
end
end
# 查看当前地图遭遇精灵的方法
def pbViewEncounters
scene = EncounterList_Scene.new
screen = EncounterList_Screen.new(scene)
screen.pbStartScreen
end