距“公共事件的战斗特效”上个版本放出有一年了,直到现在我仍然认为这个是最灵活,可扩展性最强的战斗特效系统。无他,利用公共事件可以避免和很多脚本的冲突。 然而,每次调用战斗特效都要还原HP很麻烦,而且还原HP有时不是能完全恢复原样的。要真的让公共事件达到想怎么用就怎么用的程度,只能从改变RGSS的执行顺序上作文章。 这次修改,我最后达到的状况是: ·对所有RGSS的修改,仅限于Scene_Battle类,且改动很少,对诸如Game_Battler类等绝无一丝改动。 ·在保证Phase4完整顺序的前提下,更改其内部执行顺序,100%完美化视觉效果,并简化公共事件中的脚本书写复杂度。 ·纯插件制作,可以插入默认的战斗系统或CP制战斗系统。但是RTAB不适用。 理论: 考查Scene_Battle中Phase4的执行顺序: Step1:开始 Step2:应用行动效果 Step3:行动方动画 Step4:对象方动画 Step5:伤害处理 Step6:刷新 以前的公共事件战斗特效要还原HP,是因为HP已经在Step2发生了改动(技能被实际应用了),自然想到 如果不让技能在那么早就被应用,不是可以省去一堆麻烦事了? 那么就来想想技能应用最晚可以放在哪里—— Step3是行动方动画,技能成功与否,对行动方的动画是没有影响的。 Step4是对象方动画,这里需要调用到技能行动的结果——是否命中,所以无论如何,对象方动画肯定只能在技能应用的后面 也就是说技能最晚可以是在Step3和Step4之间才应用。 那么只要将make_skill_action_result中的相关项移到该位置,并外包条件判断以免影响不相干的动作,即可。 即然技能应用放在这里了,而之前技能的公共事件ID已经被调用,我们当然可以用公共事件ID来做判断: 有公共事件——直接调用公共事件 无公共事件——通常应用技能效果 这就意味着有些利用了通常技能效果(改其他东西)的特效,其应用步骤要放在公共事件里。这样对公共事件中的执行顺序提出了要求。好在这并不是太大的问题。 强烈推荐将所有技能调用的公共事件放在同一个事件里的方法,用条件分歧框住每一个特殊效果。 另外,这个插件把状态窗口每执行一条事件指令就刷新的功能禁止了,默认情况下是每执行完一个事件才刷新,为了避免刷新不畅的问题,定义了$scene.status_refresh方法,可以在公共事件中手工刷新。 实践: 将以下脚本插入到Main的前面。然后看公共事件的脚本书写方法。 class Scene_Battle attr_reader :active_battler attr_reader :skill attr_accessor :target_battlers attr_accessor :animation2_id #-------------------------------------------------------------------------- # ● 刷新画面 #-------------------------------------------------------------------------- def update # 执行战斗事件中的情况下 if $game_system.battle_interpreter.running? # 刷新解释器 $game_system.battle_interpreter.update # 强制行动的战斗者不存在的情况下 if $game_temp.forcing_battler == nil # 执行战斗事件结束的情况下 unless $game_system.battle_interpreter.running? # 继续战斗的情况下、再执行战斗事件的设置 if @common_event_id == 0 unless judge setup_battle_event end end end # 如果不是结束战斗回合的情况下 if @phase != 5 and @common_event_id == 0 # 刷新状态窗口 @status_window.refresh end end end # 系统 (计时器)、刷新画面 $game_system.update $game_screen.update # 计时器为 0 的情况下 if $game_system.timer_working and $game_system.timer == 0 # 中断战斗 $game_temp.battle_abort = true end # 刷新窗口 @help_window.update @party_command_window.update @actor_command_window.update @status_window.update @message_window.update # 刷新活动块 @spriteset.update # 处理过渡中的情况下 if $game_temp.transition_processing # 清除处理过渡中标志 $game_temp.transition_processing = false # 执行过渡 if $game_temp.transition_name == "" Graphics.transition(20) else Graphics.transition(40, "Graphics/Transitions/" + $game_temp.transition_name) end end # 显示信息窗口中的情况下 if $game_temp.message_window_showing return end # 显示效果中的情况下 if @spriteset.effect? return end # 游戏结束的情况下 if $game_temp.gameover # 切换到游戏结束画面 $scene = Scene_Gameover.new return end # 返回标题画面的情况下 if $game_temp.to_title # 切换到标题画面 $scene = Scene_Title.new return end # 中断战斗的情况下 if $game_temp.battle_abort # 还原为战斗前的 BGM $game_system.bgm_play($game_temp.map_bgm) # 战斗结束 battle_end(1) return end # 等待中的情况下 if @wait_count > 0 # 减少等待计数 @wait_count -= 1 return end # 强制行动的角色存在、 # 并且战斗事件正在执行的情况下 if $game_temp.forcing_battler == nil and $game_system.battle_interpreter.running? return end # 回合分支 case @phase when 1 # 自由战斗回合 update_phase1 when 2 # 同伴命令回合 update_phase2 when 3 # 角色命令回合 update_phase3 when 4 # 主回合 update_phase4 when 5 # 战斗结束回合 update_phase5 end end #-------------------------------------------------------------------------- # ● 生成特技行动结果 #-------------------------------------------------------------------------- def make_skill_action_result # 获取特技 @skill = $data_skills[@active_battler.current_action.skill_id] # 如果不是强制行动 unless @active_battler.current_action.forcing # 因为 SP 耗尽而无法使用的情况下 unless @active_battler.skill_can_use?(@skill.id) # 清除强制行动对像的战斗者 $game_temp.forcing_battler = nil # 移至步骤 1 @phase4_step = 1 return end end # 在帮助窗口显示特技名 @help_window.set_text(@skill.name, 1) # 设置动画 ID @animation1_id = @skill.animation1_id @animation2_id = @skill.animation2_id # 设置公共事件 ID @common_event_id = @skill.common_event_id # 设置对像侧战斗者 set_target_battlers(@skill.scope) end #-------------------------------------------------------------------------- # ● 一般特技效果应用(公共事件用) #-------------------------------------------------------------------------- def normal_skill_effect # 应用特技效果 for target in @target_battlers target.skill_effect(@active_battler, @skill) end end #-------------------------------------------------------------------------- # ● 特技的状态变化应用(公共事件用) #-------------------------------------------------------------------------- def state_apply # 应用状态变化 for target in @target_battlers target.states_plus(@skill.plus_state_set) target.states_minus(@skill.minus_state_set) end end #-------------------------------------------------------------------------- # ● 状态窗口刷新(公共事件用) #-------------------------------------------------------------------------- def status_refresh # 刷新状态窗口 @status_window.refresh end #-------------------------------------------------------------------------- # ● 刷新画面 (主回合步骤 4 : 对像方动画) #-------------------------------------------------------------------------- def update_phase4_step4 # 公共事件 ID 有效的情况下 if @common_event_id > 0 # 设置事件 common_event = $data_common_events[@common_event_id] $game_system.battle_interpreter.setup(common_event.list, 0) @common_event_id = -1 return # 公共事件 ID 无效的情况下 elsif @common_event_id == 0 # 一般特技效果应用 if @active_battler.current_action.kind == 1 @active_battler.sp -= @skill.sp_cost normal_skill_effect end end # 对像方动画 for target in @target_battlers target.animation_id = @animation2_id target.animation_hit = (target.damage != "Miss") end # 限制动画长度、最低 8 帧 @wait_count = 8 # 移至步骤 5 @phase4_step = 5 end #-------------------------------------------------------------------------- # ● 刷新画面 (主回合步骤 5 : 显示伤害) #-------------------------------------------------------------------------- def update_phase4_step5 # 隐藏帮助窗口 @help_window.visible = false # 刷新状态窗口 @status_window.refresh # 显示伤害 for target in @target_battlers if target.damage != nil target.damage_pop = true end end if @active_battler.damage != nil @active_battler.damage_pop = true end # 移至步骤 6 @phase4_step = 6 end #-------------------------------------------------------------------------- # ● 刷新画面 (主回合步骤 6 : 刷新) #-------------------------------------------------------------------------- def update_phase4_step6 # 清除强制行动对像的战斗者 $game_temp.forcing_battler = nil # 移至步骤 1 @phase4_step = 1 end end 公共事件脚本书写需知: 关于“前趋”“SP覆写”“覆写”和“后继”的说明: 前趋处理:这些脚本(含外包的条件分歧)总是放在公共事件靠前的位置,它们在技能没有实际起作用时就被改写,通常是改变攻击对象的效果。 后继处理:这些脚本(含外包的条件分歧)总是放在公共事件靠后的位置,它们在技能生效后追加一些效果,通常是一些特殊的效果,比如追加伤害,强制会心一击,HP吸收等。 由于战斗特效操作对象的不同,以及一些相关共性,我们在公共事件中插入三条通用脚本: 脚本1:$scene.active_battler.sp-=\ $scene.skill.sp_cost 脚本2:$scene.status_refresh 脚本3:$scene.normal_skill_effect 细心的读者会发现,这三条脚本执行的就是在RGSS中,当技能不附带公共事件时所执行的东西,只不过这里换了个写法而已。 这三个脚本不能放在任何条件分歧里,作为默认应用技能的步骤,脚本2的前后各跟一个标签事件 实际写法如下: (所有的前趋脚本) 脚本:$scene.active_battler.sp-=\ $scene.skill.sp_cost 标签:SP消耗结束 脚本:$scene.status_refresh 脚本:$scene.normal_skill_effect 标签:伤害计算结束 (所有的后继脚本) 凡是不按照常规方法消耗SP,但是伤害计算通式的技能效果脚本(比如消耗HP代替SP,或特定状态下半减SP消耗),计为“覆写SP”,应当插入在脚本1的前面(在前趋脚本之后),其后跟标签跳转事件,跳转到“SP消耗结束”处 凡是不按照常规公式计算伤害值的技能效果脚本(比如比例伤害),应当插入在脚本2与脚本3之间,其后跟标签跳转事件,跳转到“伤害计算结束”处。 若有既不常规消耗SP,也不常规计算伤害的效果脚本,则插入到脚本1之前,但是标签跳转到脚本2以后,但请注意手工刷新状态窗口。也可以拆成两个脚本按上面的方法处理。 举例如下: [前趋脚本] 条件分歧:........ 脚本:....(特殊方法SP消耗的脚本) 标签跳转:SP消耗结束 分歧结束 脚本:$scene.active_battler.sp-=\ $scene.skill.sp_cost 标签:SP消耗结束 条件分歧:........ 脚本:....(特殊计算伤害值的脚本) 标签跳转:伤害计算结束 分歧结束 脚本:$scene.normal_skill_effect 标签:伤害计算结束 [后继脚本] 公共事件特效范例: 一、全体化/全域化 效果:当技能范围为敌单体时,攻击敌全体; 当技能范围为我方单体或自身时,攻击我方全体; 当技能范围为我方单体HP0时,攻击我方全体HP0; 当技能范围为无时,攻击战场上所有对象。 处理:前趋 脚本: s=$scene.skill.scope $scene.target_battlers=[] $scene.set_target_battlers(2) if s==1 $scene.set_target_battlers(4) if s%4==3 $scene.set_target_battlers(6) if s==5 (t=$game_troop.enemies+$game_party.actors for battler in t.clone t.delete(battler) if not battler.exist? end $scene.target_battlers=t) if s==0 二、敌/己/全方随机对象 效果:当技能范围为敌单或敌全时,随机选定敌方单体; 当技能范围为我单或我全时,随机选定我方单体; 当技能范围为我单或我全HP0时,随机选定我方单体HP0; 当技能范围为无时,随机选定战场上一个对象; 当技能范围为自身时,不作处理。 处理:前趋 条件分歧:$scene.active_battler.is_a?(Game_Enemy) 脚本: s=($scene.skill.scope+1)/2 t=$game_party.random_target_actor if s==1 t=$game_troop.random_target_enemy if s==2 t=$game_troop.random_target_enemy(true) if s==3 (x=$game_party.actors+$game_troop.enemies t=x[rand(x.size)]) if s==0 $scene.target_battlers=[t] 除此以外的情况下 脚本: s=($scene.skill.scope+1)/2 t=$game_troop.random_target_enemy if s==1 t=$game_party.random_target_actor if s==2 t=$game_party.random_target_actor(true) if s==3 (x=$game_troop.enemies+$game_party.actors t=x[rand(x.size)]) if s==0 $scene.target_battlers=[t] 分歧结束 三、HP吸收 效果:攻击者增加等同于伤害值的HP 处理:后继 脚本: a=$scene.active_battler a.damage=0 for t in $scene.target_battlers if t.damage.is_a?(Numeric) a.damage -= t.damage a.hp += t.damage end end 四、SP伤害 效果:本来伤害对方HP,改成伤害对方SP 处理:覆写 脚本: a=$scene.active_battler s=$scene.skill for t in $scene.target_battlers t1=t.clone.skill_effect(a,s) if t1.damage.is_a?(Numeric) t.damage=t1.damage t.sp-=t.damage end end $scene.state_apply 五、SP吸收 效果:攻击者增加等同于伤害值的SP。 处理:后继 脚本: a=$scene.active_battler a.damage=0 for t in $scene.target_battlers if t.damage.is_a?(Numeric) a.damage -= t.damage a.sp += t.damage end end 六、SP同等伤害 效果:攻击对象损失等同于HP损失的SP。 处理:后继 脚本: for t in $scene.target_battlers t.sp-=t.damage if t.damage.is_a?(Numeric) end 七、反馈 效果:攻击对象损失所有的SP,并损失相当于其SP损失量的HP(参考Starcraft的Feedback)。 处理:覆写 脚本: s=$scene.skill for t in $scene.target_battlers t.damage=t.sp t.sp=0 t.hp-=t.damage end $scene.state_apply 八、消耗HP发动 效果:本来是消耗SP发动的技能变成消耗HP发动,如果HP不足则发动后死亡。 处理:SP覆写 脚本: s=$scene.skill $scene.active_battler.hp-=s.sp_cost 九、SP节约 效果:中了特定状态(例为22)发动技能只消耗常规一半的SP,中了另一状态(23)则无差别消耗1点SP。 处理:SP覆写 脚本: s=$scene.skill a=$scene.active_battler if a.state?(22) a.sp-=s.sp_cost/2 elsif a.state?(23) a.sp-=[s.sp_cost,1].min end 十、现有HP比例伤害 效果:按照技能的威力设置,和攻击对象的HP,计算损害百分比的HP,属性和防御修正有效。 处理:覆写 脚本: s=$scene.skill for t in $scene.target_battlers e=t.element_correct(s.element_set) t.damage=t.hp*s.power*e/10000 t.damage/=2 if t.guarding? t.hp-=t.damage end $scene.state_apply 十一、现有HP差分比例伤害 效果:按照技能的威力设置,和攻击对象的HP与其最大HP的差值,计算损害百分比的HP,属性和防御修正无效。 处理:覆写 脚本: s=$scene.skill for t in $scene.target_battlers t.damage=(t.maxhp-t.hp)*s.power/100 t.hp-=t.damage end $scene.state_apply 十二、最大HP比例伤害 效果:按照技能的威力设置,和攻击对象的最大HP,计算损害百分比的HP,属性有效,无视防御修正。 处理:覆写 脚本: s=$scene.skill for t in $scene.target_battlers e=t.element_correct(s.element_set) t.damage=t.maxhp*s.power*e/10000 t.hp-=t.damage end $scene.state_apply 十三、自身HP比例伤害 效果:按照技能的威力设置,和攻击者的HP,计算损害百分比的HP,属性和防御修正有效。 处理:覆写 脚本: s=$scene.skill a=$scene.active_battler for t in $scene.target_battlers e=t.element_correct(s.element_set) t.damage=a.hp*s.power*e/10000 t.damage/=2 if t.guarding? t.hp-=t.damage end $scene.state_apply 十四、自身HP差分比例伤害 效果:按照技能的威力设置,和攻击者的HP与其最大HP的差值,计算损害百分比的HP,属性有效,无视防御修正。 处理:覆写 脚本: s=$scene.skill a=$scene.active_battler for t in $scene.target_battlers e=t.element_correct(s.element_set) t.damage=(a.maxhp-a.hp)*s.power*e/10000 t.hp-=t.damage end $scene.state_apply 十五、自身最大HP比例伤害 效果:按照技能的威力设置,和攻击者的最大HP,计算损害百分比的HP,属性和防御修正无效。 处理:覆写 脚本: s=$scene.skill a=$scene.active_battler for t in $scene.target_battlers t.damage=a.maxhp*s.power/100 t.hp-=t.damage end $scene.state_apply 十六、舍命一击 效果:攻击者攻击后死亡。 处理:后继 脚本: $scene.active_battler.hp=0 $scene.active_battler.damage="" 十七、强制会心一击 效果:强制造成会心一击(伤害值2倍)。 处理:后继 脚本: for t in $scene.target_battlers if t.damage.is_a?(Numeric) t.hp-=t.damage t.damage*=2 end end 十八、技能反射 效果:攻击对象有特定状态(24)时,技能被反射到另外一方的随机对象。 处理:前趋+后继 脚本(前趋): x=$scene.target_battlers x1=x.clone for t in x1 if t.state?(24) x.delete(t) c=(t.is_a?(Game_Actor) ? $game_troop.random_target_enemy : $game_party.random_target_actor) x.push(c) end end @d=x.clone 脚本(后继): for i in [email protected] t=$scene.target_battlers[i] t1=@d[i] t.damage=t1.hp-t.hp end 十九、复活对不死系反效果(即死) 效果:用复活类技能攻击对象为不死系(属性9)时,造成敌人无条件即死。 处理:覆写 脚本: a=$scene.active_battler s=$scene.skill for t in $scene.target_battlers if t.element_rate(9)>=150 t.add_state(1) else t.skill_effect(a,s) end end 二十、即死对不死系反效果(完全回复) 效果:用即死类技能攻击对象为不死系时,造成敌人完全回复。 处理:覆写 脚本: a=$scene.active_battler s=$scene.skill for t in $scene.target_battlers if t.element_rate(9)>=150 t.recover_all else t.skill_effect(a,s) end end |