查看: 660|回复: 3

[原创发布] 摸金系统

[复制链接]
梦石
0
星屑
1554
在线时间
523 小时
注册时间
2015-8-23
回帖
83
发表于 2026-7-9 14:08:53 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有账号?注册会员

×
本帖最后由 寂寞的青椒 于 2026-7-14 18:23 编辑

这个是模拟三角洲的摸金系统,不全像,但是效果类似,可玩性很高,配合物品颜色描绘脚本使用效果更棒


[fold=摸金脚本]#==============================================================================
# [PS0] 摸金模式 - 容器开箱系统 (指定物品池版)
#==============================================================================

module LOOT_CONFIG
  BASE_SCAN_TIME = 30          # 基础扫描时间(帧数)
  QUALITY_TIME_BONUS = 25      # 每级品质增加的时间
  ITEM_COUNT_MIN = 1
  ITEM_COUNT_MAX = 6
  WINDOW_WIDTH = 440
  WINDOW_HEIGHT = 350
  
  # ========== 物品池配置 ==========
  # 方式1:指定物品ID范围(推荐)
  ITEM_ID_RANGE = 1..30        # 只使用1-30号物品
  
  # 方式2:手动指定物品ID列表(如果需要更精确的控制)
  # 如果设置了 ITEM_ID_LIST,则会忽略 ITEM_ID_RANGE
  # ITEM_ID_LIST = [1, 2, 3, 5, 8, 13, 21]
  
  # 是否排除名称为空的物品
  EXCLUDE_EMPTY_NAME = true    # true=排除空名称物品,false=不排除
  
  # 是否排除没有名称且没有图标的物品(彻底空白)
  EXCLUDE_COMPLETELY_EMPTY = true
end

#==============================================================================
# ■ Game_Interpreter (修改)
#==============================================================================
class Game_Interpreter
  def open_container(container_id, item_list = nil)
    $container_data ||= {}
   
    $container_data[container_id] ||= Game_Container.new
    container = $container_data[container_id]
   
    if !container.opened
      if item_list.nil? || item_list.empty?
        item_list = get_valid_item_list
      end
      container.generate_items(item_list)
    elsif !container.has_items?
      if !item_list.nil? && !item_list.empty?
        container.generate_items(item_list)
      elsif !get_valid_item_list.empty?
        container.generate_items(get_valid_item_list)
      end
    end
   
    if container.is_empty?
      $game_message.add("容器是空的")
      return
    end
   
    SceneManager.scene.create_loot_window(container)
  end
  
  # 获取有效的物品列表(排除空白物品)
  def get_valid_item_list
    items = []
   
    # 获取物品ID列表
    if defined?(LOOT_CONFIG::ITEM_ID_LIST) && LOOT_CONFIG::ITEM_ID_LIST.is_a?(Array)
      id_list = LOOT_CONFIG::ITEM_ID_LIST
    else
      id_list = LOOT_CONFIG::ITEM_ID_RANGE.to_a
    end
   
    id_list.each do |i|
      item = $data_items
      next if item.nil?
      
      # 排除完全空白的物品
      if LOOT_CONFIG::EXCLUDE_COMPLETELY_EMPTY
        next if item.name.nil? || item.name.empty?
        next if item.icon_index == 0 && (item.description.nil? || item.description.empty?)
      end
      
      # 排除名称为空的物品
      if LOOT_CONFIG::EXCLUDE_EMPTY_NAME
        next if item.name.nil? || item.name.empty?
      end
      
      # 排除没有图标的物品(可选)
      # next if item.icon_index == 0
      
      items << item
    end
   
    return items
  end
end

#==============================================================================
# ■ Game_Container
#==============================================================================
class Game_Container
  attr_reader :items
  attr_reader :looted_flags
  attr_accessor :opened
  
  def initialize
    @items = []
    @looted_flags = []
    @opened = false
  end
  
  def generate_items(item_list)
    count = rand(LOOT_CONFIG::ITEM_COUNT_MAX - LOOT_CONFIG::ITEM_COUNT_MIN + 1) + LOOT_CONFIG::ITEM_COUNT_MIN
    @items = []
    @looted_flags = []
   
    if item_list && item_list.size > 0
      count.times do
        item = item_list.sample
        @items << item if item
        @looted_flags << false
      end
    end
    @opened = true
  end
  
  def get_remaining_indices
    indices = []
    @looted_flags.each_with_index do |flag, i|
      indices << i if !flag
    end
    return indices
  end
  
  def loot_item(index)
    if index >= 0 && index < @items.size && !@looted_flags[index]
      @looted_flags[index] = true
      return true
    end
    return false
  end
  
  def all_looted?
    return !@looted_flags.include?(false)
  end
  
  def get_item_by_index(index)
    return @items[index]
  end
  
  def has_items?
    return @items.size > 0
  end
  
  def is_empty?
    return get_remaining_indices.empty?
  end
end

#==============================================================================
# ■ Window_LootDisplay
#==============================================================================
class Window_LootDisplay < Window_Base
  
  attr_reader :closed
  
  def initialize(container)
    x = (Graphics.width - LOOT_CONFIG::WINDOW_WIDTH) / 2
    y = (Graphics.height - LOOT_CONFIG::WINDOW_HEIGHT) / 2
   
    super(x, y, LOOT_CONFIG::WINDOW_WIDTH, LOOT_CONFIG::WINDOW_HEIGHT)
   
    @closed = false
    @container = container
    @current_index = 0
    @scan_progress = 0
    @displaying = false
    @finished = false
    @cursor_index = 0
    @selection_mode = false
    @input_delay = 0
    @waiting_for_input = false
    @is_scanning = false
    @current_item = nil
    @scan_timer = 0
    @revealed_items = []
   
    self.opacity = 255
    self.visible = true
    self.active = true
   
    @remaining_indices = @container.get_remaining_indices
    @display_indices = @remaining_indices.clone
   
    refresh
    start_display
  end
  
  def start_display
    @displaying = true
    @current_index = 0
    @finished = false
    @selection_mode = false
    @cursor_index = 0
    @waiting_for_input = false
    @is_scanning = false
    @scan_progress = 0
    @revealed_items = []
   
    @remaining_indices = @container.get_remaining_indices
    @display_indices = @remaining_indices.clone
   
    if @display_indices.size > 0
      start_scan_current
    end
    refresh
  end
  
  def start_scan_current
    if @current_index < @display_indices.size
      item_index = @display_indices[@current_index]
      @current_item = @container.get_item_by_index(item_index)
      @is_scanning = true
      @scan_progress = 0
      
      total_frames = get_scan_time(@current_item)
      @scan_step = 100.0 / total_frames
      
      refresh
    else
      @displaying = false
      @selection_mode = true
      @cursor_index = 0
      @waiting_for_input = false
      @remaining_indices = @container.get_remaining_indices
      refresh
    end
  end
  
  def get_scan_time(item)
    return LOOT_CONFIG::BASE_SCAN_TIME if item.nil?
    quality = get_quality_level(item)
    return LOOT_CONFIG::BASE_SCAN_TIME + quality * LOOT_CONFIG::QUALITY_TIME_BONUS
  end
  
  def get_quality_level(item)
    return 0 if item.nil?
    if item.is_a?(RPG::EquipItem)
      c = item.up || 0
    else
      n = item.note
      a = n.split{/<(?:Quality|品质)\s*(.+)>/i}
      c = a[1].to_i
    end
    return c
  end
  
  def get_quality_color(quality)
    case quality
    when 0..1
      return Color.new(255, 255, 255)
    when 2..3
      return Color.new(128, 255, 128)
    when 4..5
      return Color.new(128, 128, 255)
    when 6..7
      return Color.new(255, 0, 255)
    when 8..9
      return Color.new(255, 128, 128)
    when 10..11
      return Color.new(255, 128, 0)
    else
      return Color.new(255, 255, 128)
    end
  end
  
  def get_quality_text(quality)
    case quality
    when 0..1
      return "普通"
    when 2..3
      return "平庸"
    when 4..5
      return "精良"
    when 6..7
      return "卓越"
    when 8..9
      return "神秘"
    when 10..11
      return "传说"
    else
      return "特殊"
    end
  end
  
  def safe_contents
    return nil if @closed
    return nil if disposed?
    return contents if contents && !contents.disposed?
    return nil
  end
  
  def refresh
    return if @closed
    return if disposed?
   
    c = safe_contents
    return if c.nil?
   
    begin
      c.clear
      c.font.color = normal_color
      
      if !@selection_mode
        c.draw_text(0, 0, contents_width, 32, "【扫描中...】", 1)
      else
        c.draw_text(0, 0, contents_width, 32, "【选择物品】", 1)
      end
      
      if @display_indices.empty?
        c.draw_text(0, 40, contents_width, line_height, "容器是空的...", 1)
        return
      end
      
      if !@selection_mode
        y = 35
        item_height = 50
        max_display = 5
        
        @revealed_items.each_with_index do |item, idx|
          rect = Rect.new(20, y + idx * item_height, 380, item_height - 5)
         
          quality = get_quality_level(item)
          border_color = get_quality_color(quality)
          c.fill_rect(rect.x - 2, rect.y - 2, rect.width + 4, rect.height + 4,
                     Color.new(border_color.red, border_color.green, border_color.blue, 80))
         
          draw_item_name(item, rect.x + 5, rect.y + 5, true, 300)
         
          c.font.color = get_quality_color(quality)
          c.font.size = 14
          c.draw_text(rect.x + 280, rect.y + 5, 80, 20, get_quality_text(quality))
          c.font.size = 20
          c.font.color = normal_color
         
          c.font.color = Color.new(100, 255, 100)
          c.draw_text(rect.x + 360, rect.y + 5, 30, 24, "✓")
          c.font.color = normal_color
        end
        
        scan_y = 35 + @revealed_items.size * item_height
        
        if @is_scanning && @current_item
          rect = Rect.new(20, scan_y, 380, item_height - 5)
         
          c.fill_rect(rect.x - 2, rect.y - 2, rect.width + 4, rect.height + 4,
                     Color.new(255, 255, 200, 80 * @scan_progress / 100))
         
          if @scan_progress < 100
            scan_line_y = rect.y + ((rect.height - 5) * @scan_progress / 100)
            c.fill_rect(rect.x, scan_line_y, rect.width, 2, Color.new(255, 255, 200, 200))
          end
         
          if @scan_progress >= 100
            draw_item_name(@current_item, rect.x + 5, rect.y + 5, true, 300)
            quality = get_quality_level(@current_item)
            c.font.color = get_quality_color(quality)
            c.font.size = 14
            c.draw_text(rect.x + 280, rect.y + 5, 80, 20, get_quality_text(quality))
            c.font.size = 20
            c.font.color = normal_color
            c.font.color = Color.new(100, 255, 100)
            c.draw_text(rect.x + 360, rect.y + 5, 30, 24, "✓")
            c.font.color = normal_color
          else
            c.font.color = Color.new(200, 200, 200, 100 + (100 * @scan_progress / 100))
            c.draw_text(rect.x + 30, rect.y + 5, 250, 24, "■■■■■■■■■■")
            c.font.color = normal_color
            
            c.font.color = Color.new(200, 200, 200)
            c.draw_text(rect.x + 280, rect.y + 5, 80, 20, sprintf("%d%%", @scan_progress))
          end
         
          c.font.color = Color.new(200, 200, 200)
          c.font.size = 14
          c.draw_text(0, contents_height - 25, contents_width, 20,
                    sprintf("扫描 %d/%d", @revealed_items.size + 1, @display_indices.size), 0)
          c.font.size = 20
        end
        
      else
        @remaining_indices = @container.get_remaining_indices
        
        if @remaining_indices.empty?
          c.draw_text(0, 40, contents_width, line_height, "所有物品已取走!", 1)
          return
        end
        
        if @cursor_index >= @remaining_indices.size
          @cursor_index = @remaining_indices.size - 1
        end
        if @cursor_index < 0
          @cursor_index = 0
        end
        
        y = 35
        max_display = 5
        start_index = 0
        
        if @remaining_indices.size > max_display
          if @cursor_index >= max_display - 1
            start_index = @cursor_index - (max_display - 1)
            if start_index + max_display > @remaining_indices.size
              start_index = @remaining_indices.size - max_display
            end
          end
        end
        
        end_index = [start_index + max_display, @remaining_indices.size].min
        
        for i in start_index...end_index
          item_index = @remaining_indices
          item = @container.get_item_by_index(item_index)
          rect = Rect.new(20, y, 380, line_height)
         
          if i == @cursor_index
            c.fill_rect(rect.x - 5, rect.y - 2, rect.width + 10, rect.height + 4,
                                    Color.new(255, 255, 255, 50))
          end
         
          if item
            draw_item_name(item, rect.x, rect.y, true, 300)
          end
          y += line_height
        end
        
        if @remaining_indices.size > max_display
          if start_index > 0
            c.font.color = Color.new(255, 255, 255)
            c.draw_text(0, 35, 20, line_height, "▲")
          end
          if end_index < @remaining_indices.size
            c.font.color = Color.new(255, 255, 255)
            c.draw_text(0, contents_height - 40, 20, line_height, "▼")
          end
        end
        
        c.font.color = Color.new(255, 255, 128)
        hint_text = "方向键选择 | 确定键选取 | 取消键关闭"
        c.draw_text(0, contents_height - 30, contents_width, line_height, hint_text, 1)
      end
    rescue RGSSError
      # 忽略
    end
  end
  
  def update
    super if !@closed && !disposed?
    return if @closed
    return if disposed?
   
    begin
      if @displaying && !@selection_mode
        if @is_scanning
          @scan_progress += @scan_step
         
          if @scan_progress >= 100
            @scan_progress = 100
            @is_scanning = false
            
            if @current_item
              @revealed_items << @current_item
            end
            
            Sound.play_equip
            
            @scan_timer = 20
            refresh
          else
            refresh
          end
        else
          @scan_timer -= 1
          if @scan_timer <= 0
            @current_index += 1
            if @current_index >= @display_indices.size
              @displaying = false
              @selection_mode = true
              @cursor_index = 0
              @waiting_for_input = false
              @remaining_indices = @container.get_remaining_indices
              refresh
            else
              start_scan_current
            end
          end
        end
      elsif @selection_mode
        if @waiting_for_input
          @waiting_for_input = false
          return
        end
        
        if @input_delay > 0
          @input_delay -= 1
        else
          @remaining_indices = @container.get_remaining_indices
         
          if @remaining_indices.empty?
            close
            return
          end
         
          if @cursor_index >= @remaining_indices.size
            @cursor_index = @remaining_indices.size - 1
          end
         
          moved = false
         
          if Input.repeat?(:DOWN)
            if @cursor_index < @remaining_indices.size - 1
              @cursor_index += 1
              moved = true
            end
          elsif Input.repeat?(:UP)
            if @cursor_index > 0
              @cursor_index -= 1
              moved = true
            end
          end
         
          if moved
            refresh
            @input_delay = 8
          end
         
          if Input.trigger?(:C)
            if @cursor_index < @remaining_indices.size && @cursor_index >= 0
              item_index = @remaining_indices[@cursor_index]
              
              if !@container.looted_flags[item_index]
                if @container.loot_item(item_index)
                  item = @container.get_item_by_index(item_index)
                  $game_party.gain_item(item, 1) if item
                  Sound.play_equip
                  
                  @waiting_for_input = true
                  
                  @remaining_indices = @container.get_remaining_indices
                  
                  if @remaining_indices.empty?
                    @selection_mode = false
                    @finished = true
                    Sound.play_save
                    close
                  else
                    if @cursor_index >= @remaining_indices.size
                      @cursor_index = @remaining_indices.size - 1
                    end
                    refresh
                  end
                end
              end
            end
          elsif Input.trigger?(:B)
            close
          end
        end
      end
    rescue RGSSError
      # 忽略
    end
  end
  
  def close
    return if @closed
    @closed = true
    self.visible = false
    self.active = false
    begin
      self.dispose if !self.disposed?
    rescue
    end
  end
  
  def closed?
    return @closed
  end
end

#==============================================================================
# ■ Scene_Map
#==============================================================================
class Scene_Map < Scene_Base
  attr_reader :loot_window
  
  alias :loot_start :start unless method_defined?(:loot_start)
  
  def start
    loot_start
    @loot_window = nil
  end
  
  def create_loot_window(container)
    if @loot_window && !@loot_window.closed?
      begin
        @loot_window.close
      rescue
      end
      @loot_window = nil
    end
   
    @loot_window = Window_LootDisplay.new(container)
    @loot_window.z = 200
  end
  
  alias :loot_update :update unless method_defined?(:loot_update)
  
  def update
    if @loot_window && !@loot_window.closed?
      begin
        @loot_window.update
        update_basic
        return
      rescue RGSSError
        @loot_window = nil
      end
    end
   
    loot_update
  end
  
  alias :loot_terminate :terminate unless method_defined?(:loot_terminate)
  
  def terminate
    if @loot_window && !@loot_window.closed?
      begin
        @loot_window.close
      rescue
      end
      @loot_window = nil
    end
    loot_terminate
  end
end

#==============================================================================
# [PS0] End of Script
#==============================================================================[/fold]

[fold=物品颜色描绘脚本]#在下面if c <= 0处修改强化升到各级时显示的颜色
#c代表着升级次数
#==============================================================================
# [PS0]物品颜色描绘
#      Window_Base_Itemcolor
#------------------------------------------------------------------------------
#     在物品、技能选项中显示物品品质并显示品质框和修改物品名颜色。
#==============================================================================
# [更新记录]
#    - 2016.05.05 BY somebody
#    - 恢复了 “在【非“装备”类物品中】备注栏使用【<品质 7>】字样,来控制显示颜色”的功能,物品颜色与品质无关,如需在
#“变色”之余,使物品有个好的性能,需要自行修改【数据库】
#    - 2012.02.17 By wyongcan
#      * 修改为适合装备系统增强  不会读取说明中的品质
#    - 2012.01.03 By 仲秋启明
#      * 修改为VA定义
#    - 2011.12.27 By 仲秋启明
#      * 移植至RGSS3,遵循PS0协议;
#      * 优化数据库备注中设定方法
#    - 2011.08.22 By 冰舞蝶恋
#      * 蓝本(实用·极简 -- 按品质,给物品描绘色彩边框)
#    - 2010.08.06 By 仲秋启明
#      * 蓝本(物品颜色描绘脚本(完整无冲突版))
#------------------------------------------------------------------------------
# [使用方法]
#    - 替换原Window_Base中的draw_item_name定义或复制到Main之前
#==============================================================================

$_PS0 = {} if $_PS0 == nil  
$_PS0["Window_Base_Itemcolor"] = 20111227
#==============================================================================
# [PS0] 通用配置模块  下面if c <= 0处修改强化升到各级时显示的颜色  c代表着升级次数
#==============================================================================
module PS0
  module Window_Base_Itemcolor
    Color1 = Color.new(255, 255, 255)  # 一般品质的色彩(白,1)
    Color2 = Color.new(128, 255, 128)  # 平庸品质的色彩(绿,2)
    Color3 = Color.new(128, 128, 255)  # 精良品质的色彩(蓝,3)
    Color4 = Color.new(255, 0, 255)    # 卓越品质的色彩(紫,4)
    Color5 = Color.new(255, 128, 128)  # 神秘品质的色彩(红,5)
    Color6 = Color.new(255, 128, 0)    # 传说品质的色彩(橙,6)
    Color7 = Color.new(255, 255, 128)  # 特殊品质的色彩(黄,7)
  end
end
#==============================================================================
# ■ Window_Base
#==============================================================================
class Window_Base < Window
  def draw_item_name(item, x, y, enabled = true, width = 172)
    return unless item
      n = item.note
      a = n.split{/<(?:Quality|品质)\s*(.+)>/i}
    item.up = 0 if item.is_a?(RPG::EquipItem) && item.up == nil
    c = 0
    if item.is_a?(RPG::EquipItem)
    then
    c = item.up
    else
    c = a[1].to_i
    end
      if c <= 0
        color = PS0::Window_Base_Itemcolor::Color1
      elsif c <= 2
        color = PS0::Window_Base_Itemcolor::Color2
      elsif c <= 4
        color = PS0::Window_Base_Itemcolor::Color3
      elsif c <= 6
        color = PS0::Window_Base_Itemcolor::Color4
      elsif c <= 8
        color = PS0::Window_Base_Itemcolor::Color5
      elsif c <= 10
        color = PS0::Window_Base_Itemcolor::Color6
      elsif c <= 12
        color = PS0::Window_Base_Itemcolor::Color7
      else
        color = Color.new(0, 0, 0, 0)
      end
      self.contents.fill_rect(x, y, 24, 1, color)
      self.contents.fill_rect(x, y, 1, 24, color)
      self.contents.fill_rect(x, y+23, 24, 1, color)
      self.contents.fill_rect(x+23, y, 1, 24, color)
      draw_icon(item.icon_index, x, y, enabled)
      change_color(color, enabled)
      if item.is_a?(RPG::EquipItem) && item.up != nil && item.up != 0
        draw_text(x + 24, y, width, line_height, item.name + "+" + item.up.to_s)
        return
      end
      draw_text(x + 24, y, width, line_height, item.name)
    end
end
#==============================================================================
# [PS0] End of Script
#==============================================================================
[/fold]
梦石
0
星屑
1554
在线时间
523 小时
注册时间
2015-8-23
回帖
83
 楼主| 发表于 2026-7-9 14:12:44 | 显示全部楼层
事件页脚本填写open_container(1),可以启动脚本,后面的数字是每个容器的号码,这样容器就是独立的随机物品了
回复 1 0

使用道具 举报

梦石
0
星屑
291
在线时间
42 小时
注册时间
2026-7-11
回帖
8
发表于 2026-7-12 13:24:07 | 显示全部楼层
请问一下有实现的例子吗,能不能让我参考一下
回复

使用道具 举报

梦石
0
星屑
1554
在线时间
523 小时
注册时间
2015-8-23
回帖
83
 楼主| 发表于 2026-7-14 13:04:43 | 显示全部楼层
TAIGUMODAO 发表于 2026-7-12 13:24
请问一下有实现的例子吗,能不能让我参考一下

你直接开工程按照脚本前端注释来操作就可以实现效果了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部