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

Project1

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

[讨论] RGSS1的更多bug以及事件脚本返回值问题终极分析

[复制链接]

Lv5.捕梦者 (版主)

遠航の猫咪

梦石
3
星屑
23206
在线时间
2387 小时
注册时间
2005-10-15
帖子
1166

开拓者

跳转到指定楼层
1
发表于 2017-12-15 09:34:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

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

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

x
本帖最后由 SailCat 于 2017-12-16 03:58 编辑

原贴见此:https://rpg.blue/thread-376149-1-1.html
由于是旧站贴子,不再回复

以下补充两条:

1. 装备系统自动状态bug。

原RGSS1中装备防具会强制附加其自动状态,若卸除防具就会强制解除。
若防具A和防具B(不在同一位置)都指向同一个自动状态,先同时装备防具A和B,再卸除其中任何一个,自动状态就会消失。
修改方法:增加一个计数器,考量有多少装备指向了这个自动状态,只有全部卸除了才能解除。
可参考:https://rpg.blue/thread-404129-1-1.html

2. 技能公式的各种bug。

2.1 失明状态下物理技能恒missbug
原RGSS1的技能特效中,当技能的atk_f不为0时,其命中率要乘算使用者的命中率
使用者的命中率一般都是100,默认系统只有失明了才不是100
但因为一个失误,那个乘算公式写成了 hit *= user.hit / 100,导致等式右边的计算结果恒为零,即hit恒为零,即失明时物理技能恒miss
修改方法:Game Battler 3#120:hit = hit * user.hit / 100

2.2 淬攻击力的回复技能符号bug。
如果回复类技能受atk_f影响,攻击力会被减算,而不是加算
原因:原技能公式直接以power值加上atk_f的攻击力,当power小于0时,绝对值反而减小。
修改方法:Game Battler 3#128:  power = skill.power + user.atk * skill.atk_f / (skill.power > 0 ? 100 : -100)

2.3 没有威力(但有atk_f)的伤害值恒为miss的bug
如果技能的威力设置为0,但因为有atk_f的影响,实际可以打出伤害值,表现为对象扣血但弹出伤害为miss
原因:判定将伤害覆写为Miss的条件中漏掉了对atk_f的判定
修改方法:Game Battler 3#187: if skill.power == 0 and skill.atk_f == 0



另外关于那个事件脚本返回nil或false的问题。经测试:

1) 返回nil并不会卡死啊……for循环(不带break)的返回就是nil,从不卡死
原解释器脚本:
    # 返回值为 false 的情况下
    if result == false
      # 结束
      return false
    end很明显只有脚本返回值是false时才会返回false(卡死)

2)如果脚本在2行或以上,即使返回false也不会卡死
     当且仅当脚本为1行,且返回值是false时,卡死

3)关于这个卡死是不是真的bug——这是一个feature,因为没处理好,成了bug
事件返回值是false还是true到有什么区别?
RUBY 代码复制下载
  1. # 尝试执行事件列表、返回值为 false 的情况下
  2.       if execute_command == false
  3.         return
  4.       end
  5.       # 推进索引
  6.       @index += 1


这已经是解释器update代码的最后部分,如果执行事件指令的结果是false,将直接返回,否则,将索引推到下一个后,继续解析事件指令。
也就是说,事件返回true或者false,将决定索引是否下移。
如果下移,系统将不刷新,直接执行下条指令(除非执行了连续100条无刷新的指令,会强制刷新)
如果不下移,系统将刷新至少一帧,刷新完之后执行下条指令
指令默认不是一帧执行一条的,一帧可以执行很多条,大部分事件指令的解释器返回都是true
但有些指令,天生就是要阻塞后续执行,直到其执行完毕的
典型的比如显示文章——
不知道有没有试过用脚本显示文章(在RGSS1的变量代入没有“脚本”选项的年代,这个需求还挺经常遇到的)
如果在事件脚本中用$game_temp.message_text="xxx",会有两个问题

第一,这个对话框并不会立即显示,后面可能会继续执行很多其他指令,直到某个无法预知的时间点才显示
第二,这个对话框如果其后没有别的显示文章事件,用C键关不掉
第一个问题的解决办法,很简单的一条就是在那一句面加上return false,阻塞事件继续向下执行,返回刷新,因此这实际上是设计成feature
理论上,在那一句面加上return false也可以,但我试了的结果是卡死,因此这feature没做好,成了bug
原因在哪呢?
查看默认的解释器,有以下指令的返回值(可能)是false
显示文章(101)、显示选择项(102)、数值输入(103)、文章选项(104)(均为在文本框显示时)返回
输入键(105)、删除事件(116)、场所移动(201)、滚动(已在滚动时)(205)、准备渐变(221)、执行渐变(222)、战斗处理(301)、商店处理(302)、名称输入(303)、强制行动(立即行动)(339)、战斗中断(340)、调用各种画面(351-354)
全部察看之后可以发现,这些事件指令要么牵涉到场景的转换,要么牵涉到输入等待,要么不能同时执行两次。因此设置了false的返回值阻止继续执行后面的指令。
这其中,有很多事件,在command_xxx的最后执行过了@index +=1的操作,这样相当于解释器指针在执行完这些指令后,已经被移到了下一行,返回false不是为了跳过指针操作,是为了刷新
另外的一些事件,在command_xxx中返回false之前,并没有执行指针下移操作,这样相当于刷新一帧再回来的时候,解释器的指针还在这条事件指令上
这就可以解释为什么显示文章连续执行的时候不会乱,因为显示完第一条(返回true)后,到显示第二条时,$game_temp.message_text被设置过,直接就返回false,等你把对话框关了,回到解释器,指令还在这里
所有指令中,总是返回false,且指针不下移的只有两个,就是353(game over)和354(回title),原因也好理解。场景转换后的新场景连解释器都没有,自然剩下的指令都扔了,也无所谓指针了。
回到脚本:355(事件脚本)这个指令是个多行指令,要合并执行,它在执行完后返回之前的指针,默认是在"n-1"行这个位置。执行完以后,如果返回true,解释器就会默认下移一行,到了n行位置,这就是下一个事件了。
但如果返回的是false,画面刷新了以后解释器的位置在第n-1行。如果脚本有超过1行,这一行的指令代码是655。
655是不能执行的,系统会直接返回true并下移。这就是为什么2行以上的脚本即使返回false也不会卡,什么都不会发生(当然会多一次刷新)
惟一的问题在脚本只有一行的时候,刷完回来解释器发现这还是355的脚本指令,继续执行,false,返回,刷新回来,355,继续执行……卡死,而且由于反复执行Graphics.update并不会报错退出。
怎么解决这个问题,既保留返回false的刷新机制,又避免脚本卡死:
很简单:让脚本在返回false的时候把指针下移一行……
RUBY 代码复制下载
  1. result = eval(script)
  2.     # 返回值为 false 的情况下
  3.     if result == false
  4.       # 推进索引
  5.       @index += 1
  6.       # 结束
  7.       return false
  8.     end
  9.     # 继续
  10.     return true


当然还有一个粗暴的办法,就是去掉这几行判定,让它永远返回true,不过那样的话,一旦需要执行类似公共事件随机遇敌(你要用脚本去改变parameters然后调用Scene_Battle)等需要刷新的效果时。为了避免执行出现问题,就需要在这段脚本之后插入一个1帧的等待指令。
让事件解释器停止解释返回刷新并不只能把返回值做成false,有很多刷新条件都可以。这其中,设置等待帧数,是最容易达成且没有副作用的一项。

至于脚本显示文章的第二个(C键关不掉)的问题:
需要增补以下两行脚本事件:
@message_waiting = true
$game_temp.message_proc = Proc.new {@message_waiting = false}
注意@message_waiting设为true将会和等待一样引发刷新,所以……不需要再返回false。


评分

参与人数 2星屑 +80 +1 收起 理由
miantouchi + 1 精品文章
RyanBern + 80 精品文章

查看全部评分

SailCat (小猫子·要开心一点) 共上站 24 次,发表过 11 篇文章 上 次 在: [2006年01月28日11:41:18 星期六] 从 [162.105.120.91] 到本站一游。

Lv5.捕梦者 (版主)

梦石
1
星屑
23999
在线时间
3339 小时
注册时间
2011-7-8
帖子
3926

开拓者

2
发表于 2017-12-15 12:22:10 手机端发表。 | 只看该作者
原来如此,我只知道有时候需要玄学的等待一帧,今天知道原理了,٩(ˊvˋ*)و
回复 支持 反对

使用道具 举报

Lv4.逐梦者 (版主)

梦石
0
星屑
9532
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

3
发表于 2017-12-15 18:19:11 | 只看该作者
大概知道为什么要有一个 false 在那里了,原来 false 的作用是阻塞。那看来就是使用脚本的姿势不正确的问题了,以至于用了这么多年 XP 仍然会踩坑。

因此是不是阻塞是人为控制的,因此在需要阻塞的时候还真的要这样了
RUBY 代码复制
  1. $game_temp.message_text = "hello"
  2. false


不需要阻塞的时候估计就是这样
RUBY 代码复制
  1. $game_switches[1] = false
  2. ##
回复 支持 反对

使用道具 举报

Lv5.捕梦者 (版主)

遠航の猫咪

梦石
3
星屑
23206
在线时间
2387 小时
注册时间
2005-10-15
帖子
1166

开拓者

4
 楼主| 发表于 2017-12-15 22:40:29 | 只看该作者
XP的技能公式不能要了,考虑重写……
SailCat (小猫子·要开心一点) 共上站 24 次,发表过 11 篇文章 上 次 在: [2006年01月28日11:41:18 星期六] 从 [162.105.120.91] 到本站一游。
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1387
在线时间
184 小时
注册时间
2007-2-28
帖子
145
5
发表于 2017-12-16 02:32:30 | 只看该作者
一直没发现失明竟然真的是100%MISS!
XP的技能公式确实挺有毒的,能写出个更合理的就更好了

点评

技能100%miss,普攻是能中的  发表于 2017-12-16 02:48
回复 支持 反对

使用道具 举报

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

本版积分规则

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

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

GMT+8, 2024-11-30 18:30

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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