设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 4385|回复: 12
打印 上一主题 下一主题

[RMVA发布] 帮朋友制作的一个事件薄菜单.RMVA脚本

[复制链接]

Lv1.梦旅人

梦石
0
星屑
60
在线时间
9 小时
注册时间
2007-2-23
帖子
26
跳转到指定楼层
1
发表于 2013-4-13 17:39:16 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

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

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

x
本帖最后由 rrobin 于 2013-4-13 18:23 编辑

朋友在做一个侦探类的游戏,需要记录发成过的案件以及得到的线索,于是就帮忙做了一个
效果图:


未命名.jpg (46.57 KB, 下载次数: 21)

未命名.jpg

Lv1.梦旅人

梦石
0
星屑
60
在线时间
9 小时
注册时间
2007-2-23
帖子
26
2
 楼主| 发表于 2013-4-13 17:40:06 | 只看该作者
效果图:
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
60
在线时间
9 小时
注册时间
2007-2-23
帖子
26
3
 楼主| 发表于 2013-4-13 17:53:49 | 只看该作者
#-----------------------------------------------------------------------------
# 游戏任务事件对象
#-----------------------------------------------------------------------------

class Game_EventVariables
  attr_accessor :Chapter        #进行了的章节
  attr_accessor :Last_Chapter   #正在进行的章节
  def initialize
    @Chapter = []
    @Last_Chapter = -1
  end

  # 新的一章开始时调用
  # 此调用必须!! 否则保存的事件薄数据将会错误
  # 最好在新章节开始时过场事件内调用
  def StartChapter(name)
    chapter = EventBookDef.getChapter(name)
    if !EventBookDef.has_Chapter?(chapter.id)
      msgbox("使用了未定义的章节名<#{name}>")
      return
    end
    if @Chapter.include?(chapter.id)
      msgbox("已经进行过了此章节<#{name}>")
      return
    end
    @Chapter[chapter.id] = Game_SaveChapter.new(chapter.id)
    @Last_Chapter = chapter.id
  end
  
  
  # 获得一个案件的线索时调用 传入案件名字以及对应的线索名字
  def FindKey(caseName,keyName)
    chapter = EventBookDef.getChapterByIndex(@Last_Chapter)
    if chapter == nil
      msgbox("获得线索时未找到当前章节,确认是否在章节开始时调用过StartChapter脚本")
      return
    end
    caseTemp = chapter.getCase(caseName)
    if caseTemp == nil
      msgbox("未在当前章节找到案件<#{caseName}>")
      return
    end
    keyIndex = caseTemp.getKeyIndex(keyName)
    if keyIndex == -1
      msgbox("未在当前章节案件<#{caseName}>中找到线索<#{keyName}>")
      return
    end
    @Chapter[@Last_Chapter].getCase(caseTemp.id).addKey(keyIndex)
  end
end

# 用来保存的数据
class Game_SaveChapter
attr_accessor :id
attr_accessor :case
  def initialize(id)
    @id = id
    @case = []          # 正在进行中的案件,保存index
  end
  
  def getCase(index)
    return @case[index]  if @case.size > index
    @case[index] = Game_SaveCase.new(index)
    return @case[index]
  end
end

class Game_SaveCase
attr_accessor :id
attr_accessor :Keys       # 已获得的Key,保存index
  def initialize(id)
    @id = id
    @Keys = []
  end
  
  def addKey(key_id)
    @Keys.push key_id unless @Keys.include?(key_id)
  end
end


# 用来显示的数据

class Game_Chapter
attr_accessor :name
attr_accessor :id
  def initialize(name,id)
   @name = name
   @id = id
   @case = {}
end

def addCase(name)
   return @case[name] if @case.include?(name)
   @case[name] = Game_Case.new(name,@case.size)
end

def getCase(name)
    return nil unless @case.include?(name)
    return @case[name]
  end
  
  def getCaseName(index)
    @case.each { |p| return p[1].name if p[1].id == index}
    return "未知案件"
  end

end


class Game_Case
  attr_accessor :name
  attr_accessor :id
  def initialize(name,id)
    @name = name
    @id = id
    @KEY = []
  end
  
  def Key(index)
      return nil unless @key.size > index
      return @key[index]
  end

  def addKey(keyname, keydetail)
    @key.each{|p| return if p.name == keyname }
    @key.push(Game_EventKey.new(keyname,keydetail))  
  end

  def getKeyIndex(keyname)
    i = 0
    until i >= @key.size
      return i if @key.name == keyname  
      i += 1
    end
    return -1
  end
end


class Game_EventKey
  attr_accessor :name
  attr_accessor :detail
  
  def initialize(name,detail)
    @name = name
    @detail = detail
  end
end
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
60
在线时间
9 小时
注册时间
2007-2-23
帖子
26
4
 楼主| 发表于 2013-4-13 17:54:41 | 只看该作者
#-----------------------------------------------------------------------------
# 事件薄系统宏
#-----------------------------------------------------------------------------

module EventBookDef
  
  def self.init()
    @Chapter = {}
    create_all_chapter
    @ChapterCount = @Chapter.size
  end
  
  Menu  = "事件薄"
  
  # 文件存放路径
  ResFolder = "Graphics/EventBook/"
  # 事件薄封面图
  ResCover =  "cover"
  # 标签图
  ResTag   =  "tag"
  
  # 事件薄侧标签最大显示个数
  BookTagPreCount = 5
  
  # 这里最好自己用注释做一些分类,按章节,按案件内容随个人喜好, 这里并不需要顺序的添加
  # 章节里线索信息
  def self.create_all_chapter
    addKey("章节1","案件1","线索1","看看这里能不能编辑需要显示的文字,看看这里能不能编辑需要显示的
文字.看看这里能不能编辑需要显示的文字,看看这里能不能编辑需要
显示的文字")
    addKey("章节1","案件1","线索2","测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行")
    addKey("章节1","案件1","线索3","测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行")
    addKey("章节1","案件2","线索1","测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行")
    addKey("章节1","案件2","线索1","测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行")
    addKey("章节1","案件2","线索1","测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行")
    addKey("章节1","案件3","线索1","测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行测试多行")
  end
  
  def self.addChapter(chapter)
    @Chapter[chapter] = Game_Chapter.new(chapter,@Chapter.size) unless @Chapter.include?(chapter)
    return @Chapter[chapter]
  end
  
  def self.getChapter(chapter)
    return @Chapter[chapter] if @Chapter.include?(chapter)
    return addChapter(chapter)
  end
  
  def self.has_Chapter?(index)
    @ChapterCount > index
  end
  
  def self.getChapterByIndex(index)
    @Chapter.each do |p|
      return p[1] if p[1].id == index
    end
    return nil
  end
  
  def self.getChapterName(index)
   
    @Chapter.each do |p|
      return p[1].name if p[1].id == index
    end
    return "未知章节"
  end
  
  def self.getCaseName(chapter,case_id)
    return "未知案件" unless @Chapter.include?(chapter)
    return @Chapter[chapter].getCaseName(case_id)
  end
  
  def self.addKey(chapter,_case,key,detail)
    getChapter(chapter).addCase(_case).addKey(key,detail)
  end

  def self.setDetailData(data)
    @detailData = data
  end
  
  def self.getDetailData()
    return @detailData
  end
  
  PointText = "..."
end
  
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
60
在线时间
9 小时
注册时间
2007-2-23
帖子
26
5
 楼主| 发表于 2013-4-13 17:55:09 | 只看该作者
#-----------------------------------------------------------------------------
# 事件薄主界面
#-----------------------------------------------------------------------------

# 事件薄标签
class EventNoteTag < Sprite
attr_accessor:info
  def initialize(viewport = nil)
    super(viewport)
    create_tag
  end
  
  def dispose
    self.bitmap.dispose if bitmap
    super
  end
  
  def selected
    self.zoom_x = 1.1
    self.zoom_y = 1.1
  end
  
  def unselected
    self.zoom_x = 1
    self.zoom_y = 1
  end
  
  def create_tag
    self.bitmap = Cache.load_bitmap(EventBookDef::ResFolder,EventBookDef::ResTag).clone
  end
  
  def setPos(x,y)
    self.x = x
    self.y = y
  end
  
  def update
    super
  end
  
  def info=(info)
    @info = info
    update_info
  end

  def update_info
    #self.contents.draw_text(self.bitmap.rect,"",1)
    self.bitmap.clear
    self.bitmap = Cache.load_bitmap(EventBookDef::ResFolder,EventBookDef::ResTag).clone
    self.bitmap.draw_text(self.bitmap.rect,info,1)
  end
end

# 事件薄标签菜单
class EventNoteMenu < Window
attr_accessor:preCount        #一页可显示标签数
attr_accessor:index           #当前光标所在位置

attr_reader:startIndex        #当前页开始位置
attr_reader:endIndex          #当前页结束位置

  def initialize(preCount = 1,x,y,w,h)
     super(x,y,w,h)
     @preCount = preCount
     @viewport = Viewport.new
     @tags = []
     @tagsData = []
     @pointTag = []
     @index = -1
     @last_index = -2
     @maxSize = 0
     @startIndex = 0
     @last_startIndex = -1
     @maxSize > @preCount ? @endIndex = @preCount : @endIndex = @maxSize
     create_onePageTags
     create_pointTags
     update_tagsContent
     update_tags
     #select(0)
   end
   
  def dispose
    @viewport.dispose if @viewport
    super
  end
   
  def create_onePageTags
    count = 0
    until count == @preCount || count == @maxSize
      @tags.push(EventNoteTag.new(@viewport))
      count+=1
    end
    @startIndex = 0 if @maxSize
  end  
  
  def create_pointTags
    return unless @maxSize > @preCount
    @pointTag[0] = EventNoteTag.new(@viewport)
    @pointTag[0].x = x
    @pointTag[0].y = y
    @pointTag[0].info = EventBookDef::PointText
    @pointTag[1] = EventNoteTag.new(@viewport)
    @pointTag[1].info = EventBookDef::PointText
    @pointTag[1].x = x
    @pointTag[1].y = y
  end
  
  def setData(tagsData)
    @tagsData.clear if @tagsData
    @tagsData = tagsData
    @maxSize = @tagsData.size
    @maxSize > @preCount ? @endIndex = @preCount : @endIndex = @maxSize
    @tags.each {|tag| tag.dispose}
    @tags.clear
    @pointTag.each{|tag| tag.dispose }
    @pointTag.clear
    create_onePageTags
    create_pointTags
    update_tagsContent
    @index = -1
    @last_index = -2
    update_tags
    select(0)
  end
  
  def getData
    return @tagsData[@startIndex + @index] if @index && @startIndex
    return nil
  end
  
  def cursor_movable?
    @index >= 0 && @index < @preCount
  end
  
  def cursor_up(wrap = false)
    @index -= 1
    select(@index)
  end
  
  def cursor_down(wrap = false)   
    @index += 1
    select(@index)
  end
  
  def pageUp
    @index -= @preCount
    select([@index,@startIndex].max)
  end
  
  def pageDown
    @index += @preCount
    select([@index,@endIndex].min)
  end
  
  def select(index)
    return unless @maxSize != 0
    @index = index
    if @index < 0
      if @startIndex > 0
        @startIndex -= 1
        @endIndex -= 1
      else
        Sound.play_buzzer
      end
      @index = 0
      update_tagsContent
      Sound.play_cursor
    else
      if @index == (@endIndex - @startIndex)
        if @endIndex != @maxSize
          @startIndex += 1
          @endIndex += 1
        else
          Sound.play_buzzer
        end
        @index -= 1
        update_tagsContent
        Sound.play_cursor
      end
    end
    @tags[@index].selected if @index >= 0
    @tags[@last_index].unselected if @last_index >= 0 &&  @index != @last_index
    update_tags
  end
  
  def process_cursor_move
    return unless cursor_movable?
    @last_index = @index
    cursor_down (Input.trigger?(:DOWN))  if Input.repeat?(:DOWN)
    cursor_up   (Input.trigger?(:UP))    if Input.repeat?(:UP)
    pageUp      if Input.trigger?(:R)
    pageDown    if Input.trigger?(:L)
    Sound.play_cursor if @index != @last_index
  end

  def update
    super
    process_cursor_move
  end
  
  def update_tags
    #return unless @index != @last_index
    index = 0
    height = 0
    until index == @preCount || index == @maxSize
      @tags[index].setPos(x,(index+1) * @tags[index].height + y) if index != @index
      @tags[index].setPos(x, @tags[index-1].height * index+@tags[index].height + y) if index > 0
      height = @tags[index].y
      index += 1
    end
    update_pointTags(height)
  end
  
  def update_pointTags(height)
      return unless @maxSize > @preCount
      @startIndex == 0 ? @pointTag[0].visible = false : @pointTag[0].visible = true
      @endIndex == @maxSize ? @pointTag[1].visible = false : @pointTag[1].visible = true
      @pointTag[1].setPos(x,height+@pointTag[1].height)
  end
  
  def update_tagsContent
    index = 0
    until index == @preCount || index == @maxSize
    @tags[index].info = @tagsData[@startIndex + index][:text]
    index += 1
    end
  end
end
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
60
在线时间
9 小时
注册时间
2007-2-23
帖子
26
6
 楼主| 发表于 2013-4-13 17:55:36 | 只看该作者
#--------------------------------------------------------------------------------
# 事件薄详细内容窗口
#--------------------------------------------------------------------------------
class Window_EventBook < Window_Selectable
  #--------------------------------------------------------------------------
  # ● 定义实例变量
  #--------------------------------------------------------------------------
  attr_accessor :BGSprite
  attr_accessor :type
  
  def initialize
    @BGSprite = Sprite.new(Viewport.new)
    @BGSprite.bitmap = Cache.load_bitmap(EventBookDef::ResFolder,EventBookDef::ResCover)
    bitmapTemp = Cache.load_bitmap(EventBookDef::ResFolder,EventBookDef::ResTag)
    if @BGSprite != nil
      super(([email protected] - bitmapTemp.width)/2,(Graphics.height - @BGSprite.height)/2, @BGSprite.width, @BGSprite.height)
    else
      super(([email protected] - bitmapTemp.width)/2,(Graphics.height - @BGSprite.height)/2, Graphics.width, Graphics.height)
    end
    @BGSprite.x = self.x
    @BGSprite.y = self.y
    self.windowskin = nil
    preCount = EventBookDef::BookTagPreCount + 2#@BGSprite.height / bitmapTemp.height
    book_x = x + @BGSprite.width
    book_y = y + (@BGSprite.height - bitmapTemp.height*preCount)/2
    preCount -= 2 #这里减去上下翻页提示数量
    @book_menu = EventNoteMenu.new(preCount,book_x,book_y,bitmapTemp.width,bitmapTemp.height*preCount)
    bitmapTemp.dispose
    @type = 0
    @dirty = true
    activate
  end
  
  def Type?(type)
    @type == type
  end
  
  def type=(type)
    @type = type
    @dirty = true
  end
  
  def switchChapters
    return unless @book_menu != nil
    if @type == 0 && @dirty
      data = []
      i = 0
      if $game_eventVar.Last_Chapter == -1
        msgbox("未调用任何StartChapter")
        @dirty = false
        return
      end
      until i > $game_eventVar.Last_Chapter
        data.push({:text=>EventBookDef.getChapterByIndex(i).name,:context => i})
        i+=1
      end
       @book_menu.setData(data)
        @dirty = false
    end
  end

  def switchEvent
    return unless @book_menu != nil
    if @type == 1 && @dirty
     data = []
     @chapter = @book_menu.getData
     if @chapter == nil
       @dirty = false
       @type = 0
       return
     end
     caseTemp = $game_eventVar.Chapter[@book_menu.getData[:context]].case
     caseTemp.each {|p| data.push({:text=>EventBookDef.getCaseName(@chapter[:text],p.id),:context=>p.id})}
     @book_menu.setData(data)
     @dirty = false
    end
  end
  
  def update
    super
    @book_menu.update
    switchChapters
    switchEvent
  end
  
  def selectEvent
     data = {:chapter=>@chapter,:case=>@book_menu.getData}
     EventBookDef.setDetailData(data)
  end
end
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
60
在线时间
9 小时
注册时间
2007-2-23
帖子
26
7
 楼主| 发表于 2013-4-13 17:56:02 | 只看该作者
#-------------------------------------------------------------------------
# 事件薄界面
#-------------------------------------------------------------------------

class Scene_EventBook < Scene_MenuBase
   def start
    super
    create_book
  end
  
  def create_book
    @book_window = Window_EventBook.new
    @book_window.set_handler(:cancel, method(:on_cancel))
    @book_window.set_handler(:ok, method(:on_ok))
  end
  
  def on_cancel
    case @book_window.type
    when 1
      @book_window.type = 0
      @book_window.activate
    when 0
      return_scene
    end
  end
  
  def on_ok
    case @book_window.type
    when 0
      @book_window.type = 1
      @book_window.activate
    when 1
      @book_window.selectEvent
      SceneManager.call(Scene_EventDetail)
    end
  end
end
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
60
在线时间
9 小时
注册时间
2007-2-23
帖子
26
8
 楼主| 发表于 2013-4-13 17:56:25 | 只看该作者
#------------------------------------------------------------------------------
# 事件薄案件详细内容场景
#------------------------------------------------------------------------------


class Scene_EventDetail < Scene_Base
  def start
    super
    create_detailWindow
  end
  
  def create_detailWindow
    @detail_window = Window_EventDetail.new()
    @detail_window.set_handler(:cancel,method(:return_scene))
  end
  
end

#------------------------------------------------------------------------------
# 事件薄案件详细内容窗口
#------------------------------------------------------------------------------

class Window_EventDetail < Window_Selectable
   def initialize
    super(0, 0, Graphics.width, Graphics.height)
    @data = EventBookDef.getDetailData
    @line = 0
    create_tile
    create_key_content
    activate
  end

  def create_tile
      str = @data[:case][:text]
      p str
      draw_text_ex((Graphics.width-text_size(str).width)/2,Font.default_size * @line,str)
      @line += 1
  end
   
  
  def create_key_content
     # 画线索的名字
     chapter = @data[:chapter]
     castTemp = $game_eventVar.Chapter[chapter[:context]].getCase(@data[:case][:context])
     i = 0
     until i >= castTemp.Keys.size
       chapterIns = EventBookDef.getChapterByIndex(chapter[:context])
       caseIns = chapterIns.getCase(@data[:case][:text])
       keyIns = caseIns.Key(castTemp.Keys[i])
       draw_text_ex(4, Font.default_size*@line,keyIns.name)
       @line += 1
       draw_text_ex(20,Font.default_size*@line,keyIns.detail)
       @line += 1
       i+=1
     end
   end
  
  # 难道需要自动换行?
    #--------------------------------------------------------------------------
  # ● 文字的处理
  #     c    : 文字
  #     text : 绘制处理中的字符串缓存(字符串可能会被修改)
  #     pos  : 绘制位置 {:x, :y, :new_x, :height}
  #--------------------------------------------------------------------------
  alias parent_process_character process_character
  def process_character(c, text, pos)
    case c
    when "\r"   # 回车
      return
    when "\n"   # 换行
      return
    when "\f"   # 翻页
      return
    when "\e"   # 控制符
      process_escape_character(obtain_escape_code(text), text, pos)
    else        # 普通文字
      process_normal_character(c,pos)
      process_next_character(text.slice(0,1),text,pos)
    end
  end
  
  
  def process_next_character(c,text,pos)
    case c
    when "\r"
      return
    when "\n"
      return
    when "\f"
      return
    when "\e"
      return
    else
      next_pos = pos[:x] + text_size(c).width * 2 + self.padding
      if next_pos > width
        process_new_line(text,pos)
        @line += 1
      end
    end
  end
  
end
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
60
在线时间
9 小时
注册时间
2007-2-23
帖子
26
9
 楼主| 发表于 2013-4-13 18:00:45 | 只看该作者
下面是在原始脚本里添加的:
DataManager里
  #--------------------------------------------------------------------------
  # ● 生成各种游戏对象
  #--------------------------------------------------------------------------
  def self.create_game_objects
    $game_temp          = Game_Temp.new
    $game_system        = Game_System.new
    $game_timer         = Game_Timer.new
    $game_message       = Game_Message.new
    $game_switches      = Game_Switches.new
    $game_variables     = Game_Variables.new
    $game_self_switches = Game_SelfSwitches.new
    $game_actors        = Game_Actors.new
    $game_party         = Game_Party.new
    $game_troop         = Game_Troop.new
    $game_map           = Game_Map.new
    $game_player        = Game_Player.new
    $game_eventVar      = Game_EventVariables.new
  end

SceneManager里
#--------------------------------------------------------------------------
  # ● 运行
  #--------------------------------------------------------------------------
  def self.run
    DataManager.init
    EventBookDef.init
    Audio.setup_midi if use_midi?
    @scene = first_scene_class.new
    @scene.main while @scene
  end

Window_MenuCommand里
#--------------------------------------------------------------------------
  # ● 独自添加指令用
  #--------------------------------------------------------------------------
  def add_original_commands
    add_command(EventBookDef::Menu, :eventBook)
  end

Scene_Menu里
  #--------------------------------------------------------------------------
  # ● 生成指令窗口
  #--------------------------------------------------------------------------
  def create_command_window
    @command_window = Window_MenuCommand.new
    @command_window.set_handler(:item,      method(:command_item))
    @command_window.set_handler(:skill,     method(:command_personal))
    @command_window.set_handler(:equip,     method(:command_personal))
    @command_window.set_handler(:status,    method(:command_personal))
    @command_window.set_handler(:formation, method(:command_formation))
    @command_window.set_handler(:save,      method(:command_save))
    @command_window.set_handler(:game_end,  method(:command_game_end))
    @command_window.set_handler(:cancel,    method(:return_scene))
    @command_window.set_handler(:eventBook, method(:command_openBook))
  end

# 事件薄
  def command_openBook
      SceneManager.call(Scene_EventBook)
  end
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
60
在线时间
9 小时
注册时间
2007-2-23
帖子
26
10
 楼主| 发表于 2013-4-13 18:09:28 | 只看该作者
本帖最后由 rrobin 于 2013-4-13 18:19 编辑

未使用任何自定义脚本可使用此文件直接替代工程下Data文件里的对应文件
Scripts.rar (149.74 KB, 下载次数: 85)

工程中的调用


资源: Garphics.rar (29.56 KB, 下载次数: 86)
拷贝到工程目录就行,无需导入

线索详细内容的编辑在这里

第一个参数为章节名,第二个参数为案件名,第三个参数为线索名,第四个参数为详细内容
详细内容支持自动换行
编辑详细内容时不需要像编辑对话框内容那么辛苦,还要去注意输入回车换行,直接在txt里一行键入所有内容,然后拷贝到这里就可以了
回复 支持 反对

使用道具 举报

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

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-11-15 14:39

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表