- 好友
- 21
- 在线时间
- 3375 小时
- 最后登录
- 2021-12-30
波耶[MOD制作小组]
殿堂筑师
 
- UID
- 324735
- 第纳尔
- 3966
- 精华
- 1
- 互助
- 47
- 荣誉
- 25
- 贡献
- 0
- 魅力
- 65
- 注册时间
- 2010-10-15

 鲜花( 172)  鸡蛋( 67)
|
本帖最后由 Borr 于 2018-3-7 09:39 编辑
在制作过程中曾遇到了几个MS无比坑爹的事情。有些难以理解的错误经过了无数编译、重进程序调试才终于找到原因,居然是MS自身的问题。 这里和大家分享一下,如果诸位有发现其他的,请也分享一下,减少大家被坑的次数。
这个可能有不少人都知道,MS不会对负数求余。 你给它个(store_mod,XXX, -2, a),它给你返回来个负数。
坑爹指数:低
|
这个其实是position_set_z_to_ground_level这个命令的问题。
计算坡度的时候,少不了要先把一个位置降到地表上,读出z坐标,然后再向前后左右挪一点,看看z高度如何变化。
然后悲剧地发现,position_set_z_to_ground_level这厮把你的点放置在地表,那个地表高度是原来的位置高度有关的!
准确地说,如果位置原先高于地表,用position_set_z_to_ground_level降到地表,z坐标实际上比真实的地表高度要稍微偏离那么一点。保险的做法是:
(position_set_z_to_ground_level,posX), # 先降到地表附近
(position_move_z,posX,一小段负距离), #让这个位置沉到地面以下
(position_set_z_to_ground_level,posX), # 再从下方升回地表
(position_get_z, ":z", posX), #这时读出来的才是。。未必真实但是一致的地面高度
如果不知道这个,计算坡度简直是各种杯具洗具啊。特别是“挪一挪”会超出地表的时候。
坑爹指数:高
|
如果要fixed point 的变量的n次方,一定要用 (store_pow, XXX, x*FPMultiplier), 千万不要图省事直接用乘的。
比如,(store_mul, XXXsq, XXX,XXX), 会在结果里边把 FPMultiplier多乘一遍。原因是store_mul是不支持FP变量的。
虽然这个并不是什么错误,但是ms设计成这样坑死新手没商量。 弄个浮点运算会死啊!
坑爹指数:低
|
在FP时候,不要对0求平方根,手动把它设成0. (store_sqrt,reg1, 0), 按照FPMulitplier的数值不同,结果可能超出你的想象。。。TNND 这是文科生编的系统么
坑爹指数:低
|
在使用overlay_set_size时,如果一旦把某一个方向的尺寸设为0,再次设置为非零尺寸的时候,会失效,overlay尺寸一直保持为零。所以,一定要保持非零尺寸,切记切记!
坑爹指数:高 完全无法预期
|
很早以前发现的坑爹事:
官方论坛上Lav发布的header_operations.py详解里的troop_get_upgrade_troop
troop_get_upgrade_troop = 1561 # (troop_get_upgrade_troop, <destination>, <troop_id>, <upgrade_path>),
# Retrieves possible directions for non-hero troop upgrade. Use 0 to retrieve first upgrade path, and 1 to return second. Result of -1 means there's no such upgrade path for this troop.
官方自带的header_operations.py里的troop_get_upgrade_troop
troop_get_upgrade_troop = 1561 # (troop_get_upgrade_troop,<destination>,<troop_id>,<upgrade_path>), #upgrade_path can be: 0 = get first node, 1 = get second node (returns -1 if not available)
这两者都说,如果没有后续的升级兵种,就返回-1。按常规来讲,没有找到符合条件的兵种的时候,返回值应该就是-1。 但实测发现,返回的是0(即玩家)。 早期的骑砍版本,仍然根据返回值是否大于-1来判定兵种是否可以升级,结果玩家在村子里招募到XX个玩家,因为顶级兵升级成玩家了。
|
我发现了一个算是骑砍MS里最大的坑了。 同一个mission_template里面,那些关于特殊时刻的触发器(比如ti_on_agent_killed_or_wounded,ti_on_agent_hit等)如果使用过多次,很容易出现冲突,说的就是返回值问题。
就以ti_on_agent_killed_or_wounded为例。如果同一个mission_template里面,前面一个或者几个以ti_on_agent_killed_or_wounded为条件的触发器设了返回值,最后一个以ti_on_agent_killed_or_wounded为条件的触发器没有设返回值。 最终的结果完全出乎意料之外。最后一个没有设返回值,前面几个以ti_on_agent_killed_or_wounded为条件的触发器设的返回值都无效,相当于没有设返回值。 如果都设了返回值,以最后一个设的返回值为准。 这太坑了,前面的几个同条件的触发器已经设了返回值,凭什么最后一个没有设返回值,就把前面设的返回值抹去? 当然,这并不意味着,同样的触发条件,最后一个触发器的内容抹掉了前面所有触发器的内容。 内容方面,只要不冲突,几个触发器里的内容都是有效的,可以共存的。比如ti_on_agent_killed_or_wounded,可以实现被锐器杀死变成打晕,还可以实现NPC击倒敌人,获得额外的武器点。分两个触发器写,两个效果都是有效的。只是返回值方面会出问题。
那些把同条件的触发器合并写在一起的人,是无法体会这个有多坑。反过来,这也教导了所有人,在同一个mission_template里面,要把同条件的触发器合并写在一个触发器里面。 这里的同条件,都是指的特殊时刻相同,而不是指检测周期相同。
|
又新增一条坑爹的。那个获取agent某块骨头位置的操作仅限于agent活着的情况,agent倒下之后,再用这个操作就容易跳出。我的MOD已经应验,我在代码里获取玩家头骨的位置,以此为基准来调整镜头的位置,结果玩家一倒下就跳出。
究其原理应该是agent倒下之后,尸体会析化消失,骨头也不存在了,获取骨头位置就自然出问题。我问了一些玩家,开启保留尸体也无济于事。
获取agent骨头位置的操作特有用,特别是获取头骨(编号9)的位置。获取头骨的位置(头骨的最低点,看起来是脖子的位置),再往上移动40个单位就能一次性确定agent头顶血条的位置。没有这个操作的时候,确定头顶血条的位置特麻烦,要判断agent是否骑马。如果人物或者马匹的骨骼被放大了,血条位置就又要特别地一一判断然后进行设定。
获取头骨的位置还可以判断是否爆头,用ti_on_agent_hit能获得被击中的pos,只要这个pos等于或高于agent头骨的位置,就是爆头了。
骨骼的编号,根据官方lav提供的ms版本,他提到用openBRF打开人物或者马匹的骨骼的brf文件,就能获取骨骼的名字和编号,右侧的预览图还可以直观看到具体是哪一块骨骼,相应的mesh线框会加粗。
|
又更新一坑。 "game_get_skill_modifier_for_troop"这个script的作用是让特定的兵种获得特定技能的额外加成,绿字显示。 对其他技能加成没有什么问题,但千万不能对tracking(跟踪)技能进行加成,我有血的教训。我曾经添加了一本工具书,让持有这本书的NPC的跟踪技能获得1点额外加成。 结果玩家在大地图上行走的时候,走两步就一卡,走两步就一卡。注释掉相关的代码,在大地图上一点都不卡了。
也不要玩文字游戏,把tracking(跟踪)技能的名字变一下。没用的,游戏引擎是认技能ID的。我之前就把跟踪和向导合并,屏蔽向导,把向导的效果加到跟踪里面,最后把跟踪改名为向导。那本工具书名义上是加向导,但是实际上是加的跟踪,结果卡得一塌糊涂。后来赶紧换回来,那本工具书就又真正地加向导,不加跟踪了。虽然解决了卡的问题,但那个时候没有真正弄明白为什么卡。
|
更新一个坑:
ti_on_agent_hit这一条件返回的造成伤害的物品ID是武器本身而非子弹。也就是说如果一个agent使用猎弩射出钢弩箭对另一agent造成伤害时,该条件返回的物品id是猎弩而非钢弩箭
rubik:
ti_on_agent_hit的参数众多,第五个参数即为远程武器弹药的ID(如果使用的是远程武器),这个坑坑在官方自带的MS对于很多东西的解释过于简略。
|
这个想必做过mod的都被坑过。 千万不要直接用close_window接第一条对话。
再补个坑,跟汉化有关。
dialog里面上下标识为start:close_window的组会在编译时根据列表位置加上.x后缀方便汉化识别,然后坑就来了,如果MOD在这个文件的非尾端位置加了start:close_window的话,就会导致原有的同标识对话出现错乱。
避免方法:尽可能避免start:close_window对话,中间多跳转一次。实在不可避免就要做好一个一个往下重新排布汉化的觉悟
|
的确,这两位长得很像,有时不注意就写串了。 这两个有时候可以互换的--- 但是 --- neq|opcode会改变opcode的编号,这个在编译的过程中是检查不出来的。然而运行中,会有红字跳出来说有个没有定义过的opcode。 是不是很纳闷没定义的opcode是怎么通过编译的? Ctrl+F找一下 neq| 也许就能发现问题所在。
|
返回有的时候用的change_screen_return. 但是有的时候,特别是菜单选项发生改变的时候,再点这个返回就没有效果了。
老无:返回“上一菜单”,在反复交叉跳转中,“上一菜单”这个内存容易发生变化,加上引擎部分功能仍在运行,在反复跳转中可能栈内存有被清理和覆盖的问题。我在其他地方也有发现。
所以安全起见,还是直接用(jump_to_menu,"mnu_XXX"),直接设定目标,比较保险。
|
再更一坑。
add_visitor_to_current_scene想来大家都挺常用的。当然在mt里边要先把相应的entry_point的属性设置好,要不然刷不出来,大家都是知道的。【当然这一点对新手来说已经相当得坑了】
但是,新的npc加进来以后,怎么获取刷出来的agent_id呢?reg0里边是木有的。
下边这个就是比较坑的事情了: 如果刚刚执行完add_visitor_to_current_scene,agent列表是没有刷新的。这个时候,无论是try_for_agents,还是用(try_for_range,":agent",0,1000)硬来,都是无法找到新加入的npc的agent_id。 这一点和spawn_agent非常不同。
所以,如果要对add_visitor_to_current_scene刷进来的人进行操作,最好是稍微延迟一下,等到下一帧【我一般会用另一个靠前的触发器,再延迟比如0.05秒再执行】再用try_for_agents,你就会惊喜地发现,这些npc们出现了。
这对编程上来说,还是挺麻烦的。本来一步做完的的事,非要分成两步。而且一次也许不是只要add_visitor_to_current_scene一个人,而是要加一批人进来,这时候彼此之间是不知道对方存在的,在一些判断上,需要注意规避。
|
【高危bug】
mod进入深水区后,有时候会遇到,战斗结束,或者对话结束,游戏会出现各种花屏、卡死导致游戏强退。 这个是困扰了我们2年多的一个bug,经过无言的深度挖掘,终于找到了原因。
问题在于那个total_victory的那个隐藏菜单。如果一个菜单只有一个选项并且逻辑真的时候,会自动运行。如果自动运行没有退出选项,就会进入无尽【死】循环模式。本体的代码里甚至加了一个注释,他们有意利用这个自动循环来执行各种战斗以后可能遇到的事情,比如战利品、俘虏、领主对话啥的。 问题在于,原版考虑到了原版的各种情况,但未必会考虑到你的mod的各种情况。所以有些时候那程序找不到出口直接死循环,游戏卡死。
所以,大家可以留个心眼,如果发现花屏的时候,去瞅一眼total_victory那个菜单。
坑爹的是,这种自循环的功能,本体的作者似乎并不忌讳。也许别的地方还有。
【小声的说:这个bug,貌似官方那边也没有意识到。】 |
游戏一开始,玩家就飙升了十几级。 这个不是什么新鲜事,很多人都有遇到过。原因也很简单,大多时候出在对势力的初始化上。玩家的troop编号是零。没有初始化的变量都是零,所以万一什么地方没弄好,本来应该加在别的troop上的东西,就全都堆到玩家头上了。
是不是把正常的初始化代码全走一遍,就万事大吉了呢? 理论和实际情况也大多如此。我在这里只是说一个特殊情况:
如果想去掉某一个已经做进去的势力,不建议删代码,也不建议把constants里边的kingdoms_end提前。还是保持原样为好。否则那头疼的升级音效搞不好就回来了。
如果想去掉某个势力,有个比较简单办法就是在faction_slot里边,把slot_faction_state设置成非活动的势力,这样很多代码看到以后,就不检查这个势力了。当然,自然还得把这个势力相关的一些城市啊,npc啊,势力说明那些挪走或者关掉,才算搞定。
|
如果一定要照顾npc颜值而使用add_visitors_to_current_scene的话,需要注意:进场景以后,entry_point_set_position对于add_visitor而言是无效的。就算你把entry_point挪到某个地方,add_visitor还是会从原先没挪过的位置把npc刷出来。
这里只能说,怎么能这么坑。 MS作者得有多恨add_visitor这个命令啊。一个命令好多不能适用的情况。但是英雄类npc必须要用add_visitor才不会变成随机脸,也是醉了。
|
大家瞬移的时候一定发现了,玩家部队飞过去以后,方向是保持不变的。这是因为,party_set_position命令只读取xy坐标,z,方向,是不管的。
这样,如果我们希望在游戏过程中将一个图标转个方向,怎么办呢?
只能这样了:
(party_get_position,pos1,":party"),
(position_move_y,pos1,一点点距离),
(party_set_ai_behavior,":party",ai_bhvr_travel_to_point),
(party_set_ai_target_position,pos1),
然后等图标部队自己转弯吧【瀑布汗】
好在即便速度0【py中可调】,方向还是能转过来的。
|
另外新增一坑,也是关于对话的。凡是操作块里出现change_screen类的操作,后面的一句话不能是玩家说的,一旦是玩家说的,就会直接略过游戏自带的特殊界面,而直接显示玩家的对话。后面的一句话依然要求是对方说的,可以是新增的对话,也可以是已经存在的对话。 虽然对方连说两段话不符合一般的对话习惯,但是涉及到change_screen类的操作,必须这样做。
|
严格地说,这个虽然并不能怪MS,但是被坑了一脸血,不得不提。
就是有不少菜单,对话结束的时候,你会发现,有的地方有leave_encounter,有的地方没有。
【注意了】
如果是遇到了队伍,结束时的确需要离开encounter的,必须加。
反之,如果没有遇到队伍,一定不能加,否则下次遇到队伍的时候,会几率性出一些莫名奇妙的事情。
这说明leave_encounter这个东西是一个必要的,但又不是很干净的一个操作,会有延迟效果。
同时,这个问题也增加了设计对话、菜单的难度。需要仔细的考虑当时是否遇到了其他部队。
|
详见40楼。
联机GUID坑
骑砍制作估计是以为自己不会销量超过1000000,因此超过1000000的guid,如果直接拿到GUID然后对玩家ban 临时ban 踢出等操作将直接导致服务器崩溃。
解决办法可以参考admini Tools里面的代码 |
在MS提供的用来判断一个部队看到另一个部队的那个script里边,一定不要给玩家部队的trigger_result设成0.
虽然表面上看没有什么效果,但是如果发生在玩家隐身的阶段(比如跟随模式或者被俘虏等),
会导致玩家部队图标消失。
|
|
评分
-
查看全部评分
鲜花鸡蛋jj95198 在2018-4-24 15:40 送朵鲜花 并说:学习了,少走弯路 蛋清 在2016-7-11 14:11 送朵鲜花 并说:进来查坑交学费 蛋清 在2016-7-11 14:11 送朵鲜花 并说:进来查坑交学费 蛋清 在2016-7-11 14:11 送朵鲜花 并说:进来查坑交学费 蛋清 在2016-7-11 14:11 送朵鲜花 并说:进来查坑交学费 蛋清 在2016-7-11 14:11 送朵鲜花 并说:进来查坑交学费
|