- 好友
- 7
- 在线时间
- 0 小时
- 最后登录
- 2025-10-14
见习骑士

- UID
- 3102512
- 第纳尔
- 2440
- 精华
- 0
- 互助
- 33
- 荣誉
- 0
- 贡献
- 0
- 魅力
- 84
- 注册时间
- 2019-9-6
 
 鲜花( 64)  鸡蛋( 0)
|
本帖最后由 huagao 于 2025-10-12 13:13 编辑
这次是确实更新了
今天上班群里吹水时聊到了外部通用触发器的这档子事,之前我把rubik的prsnt里面十字座标打包成外部触发器,一键添加,其实是通过改process全部添加的。既然答应了要发贴子那就干脆给大伙吃点好的。
所以本帖是我的个人*.proces系列的一些小修改,因为今天我还需要赶紧打逸剑风云决,就还是捡重点的发一下,其他模块慢慢补充,后面大伙如果有什么需要的我会再加
前面说几点重点:
1.任何process文件操作前记得备份。另外不清楚wse的process有没有改动,我没用过wse,wse选手得自行检查。
2.process和平时在*.module里面的编辑不一样,属于根正苗红的python语言,注意缩进! 注意缩进! 注意缩进!!!python的缩进要求是很严格的,决定了代码块的层次,以及把用制表符的习惯改了,用空格! 因为中文站的代码粘贴不会保留缩进,我举例子的很多代码你得自己去调整缩进!
3.这个帖子主要还是科普为主,我本人是不喜欢发现成的osp的,每个人需求不一样,想要现成的也不现实。process_operations因为篇幅原因懒得逐句逐句解析,所以想看详细解析的去看第二部分prsnt。
按照目前的顺序,暂时写了三个不同的部分用于展示 ,对应一二三节
添加简单条件控制;
批量列装触发器;
通过自定义flag实现条件控制列装触发器。
先来个大伙喜闻乐见的,关于CF_warning的,当一个脚本最外部层级可能返回false,从而导致整个脚本break出去的时候,会弹这个warning,提示你加cf_前缀(can fail),我们看一下具体的代码
- elif (can_fail_statement == 0 and current_depth == 0
- and (is_can_fail_operation(opcode)
- or ((opcode == call_script) and (statement[1].startswith("cf_", 7))))
- and (not statement_name.startswith("cf_"))):
- print "WARNING: Script can fail at operation #" + str(i) + ". Use cf_ at the beginning of its name: " + statement_name
复制代码 很多人想取消这个提示,简单的办法就是直接注释掉这一句,记得注释完要加pass。
这里我提供一个新方案,即手动控制编译条件,也不用每次去文件里面翻位置。
先在文件的开头加上控制条件- ... ...
- from module_presentations import *
- from module_map_icons import *
- from module_tableau_materials import *
- from module_animations import *
- SHOW_CF_WARNINGS = False #huagao
- #SHOW_CF_WARNINGS = True #huagao
复制代码 即想关掉这个warning,就用false,想重新恢复提示,就用true
然后再print的那一步加上if条件判断,这一步的缩进需要改,所以我不用站内的代码粘贴,大伙自行对比ms代码方便直观了解缩进
elif (can_fail_statement == 0 and current_depth == 0
and (is_can_fail_operation(opcode)
or ((opcode == call_script) and (statement[1].startswith("cf_", 7))))
and (not statement_name.startswith("cf_"))):
if SHOW_CF_WARNINGS:
print "WARNING: Script can fail at operation #" + str(i) + ". Use cf_ at the beginning of its name: " + statement_name
因为cf的warning毕竟是属于战团本身的警告输出,留一个开关也显得规范一些。这也是我们搓ms的一个重要思想,对于游戏已有但是我们不想要的东西,要做加法(加条件去控制)而不是减法(直接注释掉),因为很多东西你根本就不晓得它会出现在什么其他的地方。
然后来说个更深恶痛绝的,即WARNING: Local variable never used,很多时候自己搓代码搓着搓着就忘记了,但是编译的时候就看着很不顺眼。这里其实和上面一样,留一个开关就好了,等我真的哪天想抽空搞一下这些没用的玩意的时候再打开。
- i = 0
- while (i < len(local_vars)):
- if (local_var_uses[i] == 0 and not(local_vars[i].startswith("unused"))):
- print "WARNING: Local variable never used: " + local_vars[i] + ", at: " + str(statement_name)
- i = i + 1
- if (len(local_vars) > 128):
- print "WARNING: Script uses more than 128 local wariables: " + str(statement_name) + "variables count:" + str(len(local_vars))
复制代码 这一段的两个静态检查,一个是操作块存在只有赋值定义,没有使用痕迹,且命名不是unused开头的局部变量时,输出WARNING: Local variable never used,然后检查局部变量有没有超过128个,这里我只针对WARNING: Local variable never used说,参考cf脚本的
- SHOW_CF_WARNINGS = False #huagao
- #SHOW_CF_WARNINGS = True #huagao
- SHOW_UNUSED_VAR_WARNINGS = False #huagao
- #SHOW_UNUSED_VAR_WARNINGS = True #huagao
复制代码 然后在print "WARNING: Local variable never used: " + local_vars + ", at: " + str(statement_name)这里:
i = 0
while (i < len(local_vars)):
if (local_var_uses == 0 and not(local_vars.startswith("unused"))):
if SHOW_UNUSED_VAR_WARNINGS:
print "WARNING: Local variable never used: " + local_vars + ", at: " + str(statement_name)
反正注意缩进就完事了
上面这两个warning的改动都用的一个方案,我是觉得归纳起来比较方便后面调整,不然一个个去找挺费劲的。
|
大伙自行对照ms,这一块我尽可能写详细一些,希望苦手们可以慢慢入python的门,首先
- import string
- from module_info import *
- from module_presentations import *
- from ID_meshes import *
- from process_common import *
- from process_operations import *
复制代码 除了第一句是导入Python标准库中的模块意外,其他全部是ms自己的自定义模块,这个没什么好说的。下面就是两个函数,def save_presentations负责向机器码文件中写入编译后的机器码,save_python_header负责生成对应的ID_prsnt文件。
- def save_presentations(variable_list,variable_uses,tag_uses,quick_strings): #定义函数,括号里面是参数
- ofile = open(export_dir + "presentations.txt","w") #输出的路径,就是你info里面自己写的路径
- ofile.write("presentationsfile version 1\n") #写入抬头和版本,打开你的机器码文件会发现第一句 presentationsfile version 1 ,换行
- ofile.write(" %d\n"%(len(presentations))) #写入prsnt元素数量,骑砍的机器码里面任何一个模块都会有这个东西,txt修改第一步啊嗯
- for presentation in presentations: #遍历每一个prsnt,从这里开始就是prsnt的机器码具体输出内容
- ofile.write("prsnt_%s %d %d "%(presentation[0], presentation[1], presentation[2])) #写入prsnt的几个元素,通常元素角标从0开始,对照prsnt的注释对应为id、flags、背景mesh、触发器。<font color="#ff0000">注意这里没有换行,因为触发器list还没有写入</font>
- save_simple_triggers(ofile,presentation[3], variable_list,variable_uses,tag_uses,quick_strings) #写入触发器list,这个save_simple_triggers在item_process里面也会用到,presentation[3]即为触发器列表,后面跟的是用得到的参数
- ofile.write("\n")
- ofile.close() #换行结束
复制代码 往prsnt机器码文本写入内容的save_presentations函数,这个也是我们修改主要动工的地方(这里提一嘴item trigger、prsnt trigger等这些都由“浮点数+操作块”组成的各种触发器用的都是simple trigger的编译函数)。
为了方便不了解python的modder,我已经尽量把注释写满了,大家可以尝试根据自己需要动手,下面举一个例子。
栗子.批量添加十字坐标
首先十字座标的打包写法我已经在prsnt的那篇帖子里面写过了https://bbs.mountblade.com.cn/thread-2099117-1-1.html,我们如果需要将pos_tool批量添加的话,需要在这一步入手,
- save_simple_triggers(ofile,presentation[3], variable_list,variable_uses,tag_uses,quick_strings)
复制代码
你可以重新创建一个新的列表,手动把pos tool加进去
- presentation_triggers = presentation[3] + pos_tool
- save_simple_triggers(ofile,presentation_triggers, variable_list,variable_uses,tag_uses,quick_strings)#huagao
复制代码 也可以用extend扩展,extend是python对于列表的的扩展函数- presentation[3].extend(pos_tool)
- save_simple_triggers(ofile,presentation[3], variable_list,variable_uses,tag_uses,quick_strings)#huagao
复制代码
最后,阿格兰我知道你要问什么。如果有多个tool都要添加呢 代码写法如下- presentation_triggers = presentation[3] + pos_tool + quit_tool_debug #方案一
复制代码- presentation[3].extend(pos_tool)
- presentation[3].extend(quit_tool_debug) #方案二
复制代码
|
这里我们看一下mt的process,顺便就第一第二小节的operation的条件控制案例和prsnt的批量添加触发器案例的思路结合一下,进阶一下新概念,即条件控制批量添加触发器。
我们先来看代码,首先导入部分就不提了
- mission_template_name_pos = 0
- mission_template_flags_pos = 1
- mission_template_types_pos = 2
- mission_template_desc_pos = 3
- mission_template_groups_pos =4
- mission_template_triggers_pos = 5
复制代码
这些是一个mt的组成元素的常量名,只是提高可读性,方便缩写例如 mission_template[1]就是flags
然后是保存trigger的函数save_triggers和那些生成信息group的函数save_mission_template_group,这俩一般我不动,所以不展示了。 只是提一下要分清楚mission_template[4]、mission_template[5] 即 mission_template[mission_template_groups_pos]、mission_template[mission_template_triggers_pos],这俩玩意本质是列表list,所以会单独写处理函数。 而且和prsnt以及item的触发器不同的是,前俩这俩由“浮点数+操作块”组成的各种触发器用的都是simple trigger的编译函数,mt这种有仨浮点数+操作块的触发器用的是trigger的编译函数
继续往下看
- def save_mission_templates(variables,variable_uses,tag_uses,quick_strings):
- file = open(export_dir + "mission_templates.txt","w")
- file.write("missionsfile version 1\n")
- file.write(" %d\n"%(len(mission_templates)))
- for mission_template in mission_templates:
- file.write("mst_%s %s %d "%(convert_to_identifier(mission_template[mission_template_name_pos]),convert_to_identifier(mission_template[mission_template_name_pos]),mission_template[mission_template_flags_pos]))
- file.write(" %d\n"%(mission_template[mission_template_types_pos]))
- file.write("%s \n"%(string.replace(mission_template[mission_template_desc_pos]," ","_")))
- file.write("\n%d "%len(mission_template[mission_template_groups_pos]))
- for group in mission_template[mission_template_groups_pos]:
- save_mission_template_group(file,group)
- save_triggers(file,convert_to_identifier(mission_template[mission_template_name_pos]), mission_template[mission_template_triggers_pos],variables,variable_uses,tag_uses,quick_strings)
- file.write("\n")
- file.close()
复制代码 save_mission_templates 主函数,这里就是基础的字符串,常量等简单元素,例如mt的名字和flag等等就直接写入,而group和trigger这两list就是用上面定义好的函数写入,最后保存收了个尾。
现在我们引入一个新需求案例,例如我现在有一个mt的触发器
- anim_check = (
- 0, 0, 0, [
- (key_clicked, key_y),
- ],
- [
- (get_player_agent_no,":agent_player"),
- (agent_get_animation, ":anim", ":agent_player",1),
- (assign, reg6, ":anim"),
- (display_message, "@anim_up_is_:__{reg6}", 0x3C3CF0),
- (agent_get_animation, ":anim", ":agent_player",0),
- (assign, reg7, ":anim"),
- (display_message, "@anim_down_is_:__{reg7}", 0x3C3CF0),
- ])
复制代码
首先,我们需要一个类似slot的识别标志,来注明我们需要批量处理的mt,但是process是不认你自己内部定义的slot操作的,而且mt是没有slot的。我们需要去mt的header头文件里面,从flag下手
- mtf_arena_fight = 0x00000001
- mtf_team_fight = 0x00000001
- mtf_battle_mode = 0x00000002
- mtf_commit_casualties = 0x00000010
- mtf_no_blood = 0x00000100
- mtf_synch_inventory = 0x00010000
复制代码 因为mt的flag空余位多的是,这里你往高位都还有挺多用的,低位上都建议先不用,免得混乱不好读。给没有改过flag的引申一下我们手动添加flag的原则,直白点讲建议每一位遵从十六进制1、2、4、8的规则添加,每一位到8之后就需要向高位进,以免或运算之后混乱
举个栗子
- mtf_team_fight = 0x00000001
- mtf_battle_mode = 0x00000002
- mtf_ unused_a = 0x00000004
- mtf_unused_b = 0x00000008
- mtf_commit_casualties = 0x00000010
- mtf_ unused_c = 0x00000020
- mtf_ unused_d = 0x00000040
- mtf_ unused_e = 0x00000080
- mtf_no_blood = 0x00000100
复制代码- mtf_huagao_gongfu = 0x00020000
复制代码- "lead_charge",mtf_battle_mode|mtf_synch_inventory|mtf_huagao_gongfu, ... ...
复制代码
在所有需要配置触发器的mt里面,添加flag。然后转到process里面,找到最后的写入环节,因为有现成的遍历,我们正好就在里面操作,将“如果具有huagao gongfu这个flag,就把anim_check这个触发器添加进trigger的list里面”的逻辑添加进去
for group in mission_template[mission_template_groups_pos]: save_mission_template_group(file,group) if mission_template[1] & mtf_huagao_gongfu: #huagao mission_template[5].extend([anim_check]) #huagao save_triggers(file,convert_to_identifier(mission_template[mission_template_name_pos]), mission_template[mission_template_triggers_pos],variables,variable_uses,tag_uses,quick_strings)
最后编译一下去mt的机器码里面检查,lead charge的尾部确实添加进去了
0.000000 0.000000 0.000000 1 71 1 21 ... ...
这里其实对日常的开发还是挺有帮助的,例如
对具有mtf_huagao_gongfu这个flag的mt添加anim_check;
对具有mtf_huagao_skill这个flag的mt添加anim_skill;
对具有mtf_huagao_fly这个flag的mt添加anim_fly。
扩展一下就是
if mission_template[1] & mtf_huagao_gongfu: #huagao mission_template[5].extend([anim_check]) #huagao if mission_template[1] & mtf_huagao_skill: #huagao mission_template[5].extend([anim_skill]) #huagao if mission_template[1] & mtf_huagao_fly: #huagao mission_template[5].extend([anim_fly]) #huagao save_triggers(file,convert_to_identifier(mission_template[mission_template_name_pos]), mission_template[mission_template_triggers_pos],variables,variable_uses,tag_uses,quick_strings)
|
最后给大伙提一个冷知识,有兴趣可以去看看,ms里面有一个批处理文件不会调用执行的东西,process_line_correction.py,是关于脚本代码自动缩进的,python是用缩进来表示层级结构的,这个函数可以看出来ms的try begin等层级操作函数对应python层级结构的规则表达,新手可以研究一下来了。
我不会每一个process都写,这里只是拿典型一点的三个process举不同的例子。后面看有什么需求再添加吧,process因为有python的入门门槛问题在中文站一直没有系统化的帖子,我就抛砖引玉,希望这个帖子可以帮助新modder从ms到python的进化。
|
鲜花鸡蛋黑暗路西法 在 前天 13:01 送朵鲜花 并说:我非常同意你的观点,送朵鲜花鼓励一下 偃靖 在 3 天前 送朵鲜花 并说:我非常同意你的观点,送朵鲜花鼓励一下
|