じ☆ve冰风 发表于 2024-4-19 23:39:24

【半原创】队伍系统(又名角色仓库)

很早就想做这个队伍系统了,应该有人做过类似的,不过还是自己做一个分享一下吧。应该有一定的实用价值。
内容还不是很完善,有时间会改进的。
具体的说明全在代码里了,在新的RMXP工程中可以正常运行。

最近炒的第二顿冷饭,这个人物仓库系统重新写了一下。增添了战斗换人的若干内容,修复了一些BUG。
新功能没用做特别多,因为功能越多脚本冲突越大,你懂的。如果外挂脚本过多,很可能需要整合才可使用。
如果已经使用了旧脚本,则强烈建议用这个新版本的队伍系统。
2.0 版本使用方法依然在脚本当中,这次附上了范例。
测试次数较少,如果发现错误欢迎报告。
RUBY 代码
#=============================================================================
# 队伍系统 Ver 2.1
#-----------------------------------------------------------------------------
# 类似于 Aveyond 的队伍系统(根据阿月系列的游戏产生的灵感)
# By :RyanBern
#-----------------------------------------------------------------------------
# 功能特色:
#-----------------------------------------------------------------------------
# 1.更改队伍中成员的最大数量,有四名出战队员,但是替补队员可以有很多个。
# 2.对 Game_Party 的队员设置和 Scene_Battle 的部分方法有较大改动,可能造成脚本
#   冲突。
# 3.为队伍增加“领队”角色,作为“领队”的成员在地图上显示他的图形。
# 4.在战斗命令中增添“换人”命令,可以将替补队员换上场。
# 5.如果队伍的出战队员全部阵亡,则直接判定玩家全灭,不管有无替补队员。但是如果
#   在地图上,则是所有队员阵亡才会被判定全灭。
# 6.事件编译器中,对全体同伴的处理均包括对替补队员的处理。
# 7.(Ver 2.1)战斗中可以设置自动替换阵亡队员,自动替换的时机为所有该行动的成员
#   行动完毕之后。注意,如果某个队员的行动本来就是“换人”,不过他在回合开始后
#   才阵亡,那么他本轮的替换指令将作废。
#-----------------------------------------------------------------------------
# 使用方法:
#-----------------------------------------------------------------------------
# 1.粘贴到默认脚本后面,Main组前面即可。
# 2.在菜单中,左侧窗口被激活时,按 A 键可以改变领队(leader)的设置,按 S 键
#   可以改变出战的队员。
# 3.为队员设置“无法出战”的状态,即该队员不能被设置为出战队员。具体方法是
#   使用事件脚本,例如,让 1 号角色无法出战:
#   $game_actors.battle_disabled = true
#   让 1 号角色恢复可以出战的状态:
#   $game_actors.battle_disabled = false
#   ###
# 4.可在下方设置替补队员在战斗胜利之后是否获得 EXP 奖励。
#-----------------------------------------------------------------------------
# 更新记录:
#   2015.04.22 : 重构脚本,增加战斗换人功能。
#   2015.10.09 : 增加阵亡队员自动替换替补队员的功能。
#=============================================================================
module RB
end

moduleRB::Party
# “换人”命令的术语
Words_Swap = "换人"

# 替补队员是否能在战斗胜利后获得 EXP 奖励,设置为 true 时可以获得奖励,设置
# 为 false 时则不能。
Get_Exp_Reserve = false

# 角色阵亡时,是否自动切换替补队员,设置为 true 则开启此功能。
Auto_Swap = false
end

class Game_Temp
attr_accessor :gain_exp_flag
end

class Game_Party
attr_reader :battle_actors
alias old_ini initialize
def initialize
    @leader_id = 0
    @battle_actors = []
    old_ini
end
def leader
    return@leader_id == 0 ? nil : $game_actors[@leader_id]
end
def set_leader(actor_id)
    @leader_id = actor_id
    $game_player.refresh
    $game_map.need_refresh = true
end
def actors
    all_flag = !$game_temp.in_battle || (RB::Party::Get_Exp_Reserve && $game_temp.gain_exp_flag)
    return all_flag ? @actors : @battle_actors
end
def all_actors
    return@actors
end
def reserved_actors
    return@actors - @battle_actors
end
#--------------------------------------------------------------------------
# ● 加入同伴
#   actor_id : 角色 ID
#--------------------------------------------------------------------------
def add_actor(actor_id)
    # 获取角色
    actor = $game_actors
    # 同伴人数未满 4 人、本角色不在队伍中的情况下
    unless@actors.include?(actor)
      # 添加角色
      @actors.push(actor)
      @battle_actors.push(actor)if@battle_actors.size < 4
      self.set_leader(actor.id)ifself.leader.nil?
      # 还原主角
      $game_player.refresh
    end
end
#--------------------------------------------------------------------------
# ● 角色离开
#   actor_id : 角色 ID
#--------------------------------------------------------------------------
def remove_actor(actor_id)
    actor = $game_actors
    # 删除角色
    @actors.delete(actor)
    @battle_actors.delete(actor)
    self.set_leader(self.actors.id)ifself.leader == actor
    # 还原主角
    $game_player.refresh
end
#--------------------------------------------------------------------------
# ● 设置初期同伴
#--------------------------------------------------------------------------
def setup_starting_members
    @actors = []
    @battle_actors = []
    for i in$data_system.party_members
      @actors.push($game_actors)
      @battle_actors.push($game_actors)if@battle_actors.size < 4
    end
    self.set_leader(@actors.id)unless@actors.empty?
end
#--------------------------------------------------------------------------
# ● 设置战斗测试用同伴
#--------------------------------------------------------------------------
def setup_battle_test_members
    @actors = []
    @battle_actors = []
    for battler in$data_system.test_battlers
      actor = $game_actors
      actor.level = battler.level
      gain_weapon(battler.weapon_id, 1)
      gain_armor(battler.armor1_id, 1)
      gain_armor(battler.armor2_id, 1)
      gain_armor(battler.armor3_id, 1)
      gain_armor(battler.armor4_id, 1)
      actor.equip(0, battler.weapon_id)
      actor.equip(1, battler.armor1_id)
      actor.equip(2, battler.armor2_id)
      actor.equip(3, battler.armor3_id)
      actor.equip(4, battler.armor4_id)
      actor.recover_all
      @actors.push(actor)
      @battle_actors.push(actor)
    end
    @items = {}
    for i in1...$data_items.size
      if$data_items.name != ""
      occasion = $data_items.occasion
      if occasion == 0or occasion == 1
          @items = 99
      end
      end
    end
end
#--------------------------------------------------------------------------
# ● 同伴成员的还原
#--------------------------------------------------------------------------
def refresh
    # 游戏数据载入后角色对像直接从 $game_actors
    # 分离。
    # 回避由于载入造成的角色再设置的问题。
    new_actors = []
    new_battle_actors = []
    @actors.eachdo |actor|
      if$data_actors != nil
      new_actors.push($game_actors)
      end
    end
    @battle_actors.eachdo |actor|
      if$data_actors != nil
      new_battle_actors.push($game_actors)
      end
    end
    @actors = new_actors
    @battle_actors = new_battle_actors
end
#--------------------------------------------------------------------------
# ● 全灭判定
#--------------------------------------------------------------------------
def all_dead?
    # 同伴人数为 0 的情况下
    ifself.actors.size == 0
      returnfalse
    end
    # 同伴中无人 HP 在 0 以上
    for actor inself.actors
      if actor.hp > 0
      returnfalse
      end
    end
    # 全灭
    returntrue
end
#--------------------------------------------------------------------------
# ● 对像角色的随机确定
#   hp0 : 限制为 HP 0 的角色
#--------------------------------------------------------------------------
def random_target_actor(hp0 = false)
    # 初始化轮流
    roulette = []
    # 循环
    for actor in@battle_actors
      # 符合条件的场合
      if(not hp0 and actor.exist?)or(hp0 and actor.hp0?)
      # 获取角色职业的位置 [位置]
      position = $data_classes.position
      # 前卫的话 n = 4、中卫的话 n = 3、后卫的话 n = 2
      n = 4 - position
      # 添加角色的轮流 n 回
      n.timesdo
          roulette.push(actor)
      end
      end
    end
    # 轮流大小为 0 的情况
    if roulette.size == 0
      returnnil
    end
    # 转轮盘赌,决定角色
    return roulette
end
#--------------------------------------------------------------------------
# ● 对像角色的顺序确定
#   actor_index : 角色索引
#--------------------------------------------------------------------------
def smooth_target_actor(actor_index)
    # 取得对像
    actor = @battle_actors
    # 对像存在的情况下
    if actor != niland actor.exist?
      return actor
    end
    # 循环
    for actor in@actors
      # 对像存在的情况下
      if actor.exist?
      return actor
      end
    end
end

end

class Game_Actor
attr_reader :battle_disabled
def leader?
    returnself == $game_party.leader
end
def active
    return$game_party.battle_actors.include?(self)
end
def battle_disabled=(bool)
    @battle_disabled = bool
    $game_party.battle_actors.delete(self)if bool
end
end

class Game_Player
#--------------------------------------------------------------------------
# ● 刷新
#--------------------------------------------------------------------------
def refresh
    # 同伴人数为 0 的情况下
    if$game_party.actors.size == 0or$game_party.leader == nil
      # 清除角色的文件名及对像
      @character_name = ""
      @character_hue = 0
      # 分支结束
      return
    end
    # 获取带头的角色
    if$game_party.leader != nil
      actor = $game_party.leader
      # 设置角色的文件名及对像
      @character_name = actor.character_name
      @character_hue = actor.character_hue
      # 初始化不透明度和合成方式子
      @opacity = 255
      @blend_type = 0
    end
end
end

class Game_BattleAction
attr_accessor :reserved_actor_id
unless method_defined? :rb_clear_20150422
    alias rb_clear_20150422 clear
    def clear
      rb_clear_20150422
      @reserved_actor_id = 0
    end
end
end

class Window_Base < Window
def draw_actor_battle_position(actor, x, y)
    if actor.leader?
      if actor.active
      text = "领队|出战"
      else
      text = "领队"
      end
      color = knockout_color
    else
      color = disabled_color
      if actor.battle_disabled
      text = "无法出战"
      elsif actor.active
      text = "出战"
      color = normal_color
      else
      text = "待机"
      end
    end
    self.contents.font.color = color
    self.contents.draw_text(x, y, 120, 32, text)
end
end

#==============================================================================
# ■ Window_Selectable
#------------------------------------------------------------------------------
#  拥有光标的移动以及滚动功能的窗口类。
#==============================================================================

class Window_Selectable < Window_Base
#--------------------------------------------------------------------------
# ● 定义实例变量
#--------------------------------------------------------------------------
attr_accessor :row_height               # 行高
#--------------------------------------------------------------------------
# ● 初始画对像
#   x      : 窗口的 X 坐标
#   y      : 窗口的 Y 坐标
#   width: 窗口的宽
#   height : 窗口的高
#   row_height : 行高 默认是32
#--------------------------------------------------------------------------
alias rb_initialize_20150421 initialize
def initialize(x, y, width, height, row_height = 32)
    @row_height = row_height
    rb_initialize_20150421(x, y, width, height)
end
#--------------------------------------------------------------------------
# ● 获取开头行
#--------------------------------------------------------------------------
def top_row
    # 将窗口内容的传送源 Y 坐标、1 行的高 @row_height 等分
    returnself.oy / @row_height
end
#--------------------------------------------------------------------------
# ● 设置开头行
#   row : 显示开头的行
#--------------------------------------------------------------------------
def top_row=(row)
    # row 未满 0 的场合更正为 0
    if row < 0
      row = 0
    end
    # row 超过 row_max - 1 的情况下更正为 row_max - 1
    if row > row_max - 1
      row = row_max - 1
    end
    # row 1 行高的 @row_height 倍、窗口内容的传送源 Y 坐标
    self.oy = row * @row_height
end
#--------------------------------------------------------------------------
# ● 获取 1 页可以显示的行数
#--------------------------------------------------------------------------
def page_row_max
    # 窗口的高度,设置画面的高度减去 32 ,除以 1 行的高度 @row_height
    return(self.height - 32) / @row_height
end
#--------------------------------------------------------------------------
# ● 更新光标举行
#--------------------------------------------------------------------------
def update_cursor_rect
    # 光标位置不满 0 的情况下
    if@index < 0
      self.cursor_rect.empty
      return
    end
    # 获取当前的行
    row = @index / @column_max
    # 当前行被显示开头行前面的情况下
    if row < self.top_row
      # 从当前行向开头行滚动
      self.top_row = row
    end
    # 当前行被显示末尾行之后的情况下
    if row > self.top_row + (self.page_row_max - 1)
      # 从当前行向末尾滚动
      self.top_row = row - (self.page_row_max - 1)
    end
    # 计算光标的宽
    cursor_width = self.width / @column_max - 32
    # 计算光标坐标
    x = @index % @column_max * (cursor_width + 32)
    y = @index / @column_max * @row_height - self.oy
    # 更新国标矩形
    self.cursor_rect.set(x, y, cursor_width, @row_height)
end
end

class Window_MenuStatus
def initialize
    super(0, 0, 480, 480, 112)
    refresh
    self.active = false
    self.index = -1
end
def refresh
    ifself.contents != nil
      self.contents.dispose
      self.contents = nil
    end
    @item_max = $game_party.actors.size
    self.contents = Bitmap.new(width - 32, @item_max == 0 ? 32 : @item_max * 112)
    for i in0...$game_party.actors.size
      x = 64
      y = i * 112
      actor = $game_party.actors
      draw_actor_graphic(actor, x - 40, y + 80)
      draw_actor_name(actor, x, y)
      draw_actor_class(actor, x + 144, y)
      draw_actor_level(actor, x, y + 32)
      draw_actor_state(actor, x + 90, y + 32)
      draw_actor_exp(actor, x, y + 64)
      draw_actor_hp(actor, x + 236, y + 32)
      draw_actor_sp(actor, x + 236, y + 64)
      draw_actor_battle_position(actor, x + 236, y)
    end
end
def update_cursor_rect
    super
end
end

class Window_Target
def initialize
    super(0, 0, 336, 480, 112)
    self.z += 10
    @item_max = $game_party.actors.size
    self.contents = Bitmap.new(width - 32, @item_max == 0 ? 32 : @item_max * 112)
    refresh
end
def update_cursor_rect
    super
end
end

class Window_ReservedActors < Window_Selectable
def initialize
    super(0, 64, 640, 256, 112)
    self.opacity = 160
    self.index = 0
    self.active = true
    @column_max = 2
    refresh
end
def actor
    return@data
end
def refresh
    ifself.contents != nil
      self.contents.dispose
      self.contents = nil
    end
    @data = []
    $game_party.all_actors.eachdo |actor|
      @data0
      self.contents = Bitmap.new(width - 32, (@item_max + 1) / 2 * 128)
      @data.each_with_indexdo |actor, index|
      x = 4 + index % 2 * (288 + 32)
      y = index / 2 * 112
      draw_actor_graphic(actor, x + 16, y + 80)
      draw_actor_hp(actor, x + 48, y + 20)
      draw_actor_sp(actor, x + 48, y + 52)
      end
    end
end
def update_help
    # 帮助窗口显示角色的状态
    self.actor == nil ? @help_window.set_text("") : @help_window.set_actor(self.actor)
end
end

class Scene_Menu
unless method_defined? :rb_update_command_20150421
    alias rb_update_command_20150421 update_command
    def update_command
      if Input.trigger?(Input::X)
      $game_system.se_play($data_system.decision_se)
      @command_window.active = false
      @status_window.active = true
      @status_window.index = 0
      @leader_adjust = true
      return
      end
      if Input.trigger?(Input::Y)
      $game_system.se_play($data_system.decision_se)
      @command_window.active = false
      @status_window.active = true
      @status_window.index = 0
      @battler_adjust = true
      return
      end
      rb_update_command_20150421
    end
end
unless method_defined? :rb_update_status_20150421
    alias rb_update_status_20150421 update_status
    def update_status
      if@leader_adjust
      update_leader
      return
      end
      if@battler_adjust
      update_battler
      return
      end
      rb_update_status_20150421
    end
end
def update_leader
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @leader_adjust = false
      @status_window.active = false
      @status_window.index = -1
      @command_window.active = true
      return
    end
    if Input.trigger?(Input::C)
      if$game_party.actors.size == 0
      $game_system.se_play($data_system.buzzer_se)
      else
      $game_system.se_play($data_system.decision_se)
      $game_party.set_leader($game_party.actors[@status_window.index].id)
      @status_window.refresh
      end
    end
end
def update_battler
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @battler_adjust = false
      @status_window.active = false
      @status_window.index = -1
      @command_window.active = true
      return
    end
    if Input.trigger?(Input::C)
      actor = $game_party.actors[@status_window.index]
      if actor == nil || actor.battle_disabled ||
      (actor.active && $game_party.battle_actors.size == 1) ||
      (!actor.active && $game_party.battle_actors.size == 4)
      $game_system.se_play($data_system.buzzer_se)
      else
      $game_system.se_play($data_system.decision_se)
      actor.active ? $game_party.battle_actors.delete(actor) : $game_party.battle_actors.push(actor)
      @status_window.refresh
      end
    end
end
end

class Scene_Battle
def generate_modified_command_window
    if@actor_command_window != nil
      @actor_command_window.dispose
      @actor_command_window = nil
    end
    s1 = $data_system.words.attack
    s2 = $data_system.words.skill
    s3 = $data_system.words.guard
    s4 = $data_system.words.item
    s5 = RB::Party::Words_Swap
    @actor_command_window = Window_Command.new(160, )
    @actor_command_window.y = 128
    @actor_command_window.back_opacity = 160
    @actor_command_window.active = false
    @actor_command_window.visible = false
    @modified_generated = true
end
unless method_defined? :rb_phase3_setup_command_window_20150422
    alias rb_phase3_setup_command_window_20150422 phase3_setup_command_window
    def phase3_setup_command_window
      generate_modified_command_window unless@modified_generated
      rb_phase3_setup_command_window_20150422
    end
end
def make_auto_swap_actors
    returnunlessRB::Party::Auto_Swap
    available_actors = $game_party.reserved_actors.reject{|actor| actor.dead?}
    dead_actors = $game_party.battle_actors.select{|actor| actor.dead?}
    returnif available_actors.empty? || dead_actors.empty?
    n = .min
    dead_actors.each_with_indexdo |actor, i|
      breakif i >= n
      actor.current_action.kind = 3
      actor.current_action.reserved_actor_id = available_actors.id
      @action_battlers0and@active_battler.slip_damage?
      @active_battler.slip_damage_effect
      @active_battler.damage_pop = true
    end
    # 自然解除状态
    @active_battler.remove_states_auto
    # 刷新状态窗口
    @status_window.refresh
    # 移至步骤 2
    @phase4_step = 2
end
def update_phase4_step2
    # 如果不是强制行动
    unless@active_battler.current_action.forcing
      # 限制为 [敌人为普通攻击] 或 [我方为普通攻击] 的情况下
      if@active_battler.restriction == 2or@active_battler.restriction == 3
      # 设置行动为攻击
      @active_battler.current_action.kind = 0
      @active_battler.current_action.basic = 0
      end
      # 限制为 [不能行动] 的情况下
      if@active_battler.restriction == 4 && !@auto_swap
      # 清除行动强制对像的战斗者
      $game_temp.forcing_battler = nil
      # 移至步骤 1
      @phase4_step = 1
      return
      end
    end
    # 清除对像战斗者
    @target_battlers = []
    # 行动种类分支
    case@active_battler.current_action.kind
    when0# 基本
      make_basic_action_result
    when1# 特技
      make_skill_action_result
    when2# 物品
      make_item_action_result
    when3# 换人
      make_swap_action_result
    end
    # 移至步骤 3
    if@phase4_step == 2
      @phase4_step = 3
    end
end
def make_swap_action_result
    # 获取角色
    @reserved_actor = $game_actors[@active_battler.current_action.reserved_actor_id]
    # 无法替换的情况下
    if@reserved_actor == nil || @reserved_actor.active
      # 移至步骤 1
      @phase4_step = 1
      return
    end
    # 在帮助窗口显示文字
    text = "与#{@reserved_actor.name}交换"
    @help_window.set_text(text, 1)
    # 设置动画 ID
    @animation1_id = 0
    index = $game_party.actors.index(@active_battler)
    $game_party.actors = @reserved_actor
end
unless method_defined? :rb_start_phase5_20150422
    alias rb_start_phase5_20150422 start_phase5
    def start_phase5
      $game_temp.gain_exp_flag = true
      rb_start_phase5_20150422
      $game_temp.gain_exp_flag = false
    end
end
end

截图效果如下:


这个换人的效果比较短,只是角色闪了一下,人就换好了。目前正在改进当中。


附范例一枚:

             本帖来自P1论坛作者李少安,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:https://rpg.blue/forum.php?mod=viewthread&tid=332273若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。
页: [1]
查看完整版本: 【半原创】队伍系统(又名角色仓库)