本帖最后由 我只玩MID 于 2025-4-23 07:10 编辑
在制作《骑马与砍杀:战团》MOD时,众所周知,脚本系统本身并不支持类似 Python 的“列表”结构。这意味着我们无法直接创建一个只包含特定阵营(比如某几个“非法”阵营)的集合来进行遍历,而是通常需要循环所有阵营(或指定范围)并通过条件判断筛选目标。这种方式不仅繁琐,也影响效率。那么,有没有办法模拟类似 Python 中的“列表”功能,从而只遍历我们关心的几个特定阵营,而不是全体 fac_ 阵营?答案是:可以,通过“伪列表”,完全可以实现这一目标。
不过,如果只是为了存储少量特定阵营,单独去构建一个“伪列表”似乎显得不太有必要。因此,接下来我将介绍进阶的内容 —— 如何为每个阵营单独记录它所拥有的全部野怪部队,并演示如何方便地调用这些数据。
第一步:在 module_constants.py 中定义用于计数的 Slot我们首先需要为每个阵营记录它拥有的野怪部队数量,并创建每个阵营对应的列表。为此,在 module_constants.py 中添加二个新的 Slot 定义: - slot_faction_bandit_party_number = 200 # 两个slot使用不同的调用方法,一个是faction_set_slot 一个是 troop_set_slot 所以值可以是相同的
- slot_store_faction_bandit_party_list = 301 ##储存阵营野怪的部队的列表
复制代码
第二步:在 module_scripts.py 中新增一个脚本
这个脚本的作用是在每次新的部队生成时,将这个部队储存到我们的“伪列表”中。所以,在 module_scripts.py 的最后添加一个新的脚本:
- ("add_faction_bandit_party_list", [ # 将一个野怪部队添加到所属阵营的野怪列表中
- (store_script_param, ":party_no", 1), # 获取传入的部队编号
- (store_faction_of_party, ":party_faction", ":party_no"), # 获取该部队所属的阵营
- (try_begin),
- (neg|is_between, ":party_faction", kingdoms_begin, kingdoms_end), # 排除王国阵营,只处理野怪等非国家阵营 # 在我的mod中处于性能考虑屏蔽了王国阵营
- (faction_get_slot, ":party_number", ":party_faction", slot_faction_bandit_party_number), # 获取该阵营当前记录的野怪部队数量
- (store_add, ":faction_bandit_party_list", slot_store_faction_bandit_party_list, ":party_faction"), # 计算该阵营的“伪列表”起始 Slot 编号
- (assign, ":is_passed", -1), # 标志变量,初始为 -1,表示未找到插入位置
- # 遍历该阵营已记录的野怪部队 Slot
- (try_for_range, ":list_id", 0, ":party_number"),
- (eq, ":is_passed", -1), # 只在未插入时继续判断
- (troop_get_slot, ":party_id", ":list_id", ":faction_bandit_party_list"), # 获取当前列表中的部队 ID
- # 校验部队是否有效,如果无效则视作可插入位置
- (try_begin),
- (party_is_active, ":party_id"),
- (store_faction_of_party, ":party_id_faction", ":party_id"),
- (else_try),
- (assign, ":party_id_faction", ":party_faction"),
- (try_end),
- # 如果部队阵营不匹配 或 非活跃 或 编号非法,则覆盖当前槽位
- (this_or_next|neq, ":party_id_faction", ":party_faction"),
- (this_or_next|le, ":party_id", centers_end),
- (neg|party_is_active, ":party_id"),
- (troop_set_slot, ":list_id", ":faction_bandit_party_list", ":party_no"), # 将部队编号写入列表
- (assign, ":is_passed", ":list_id"), # 标记插入位置
- # 如果原槽位的部队属于其他阵营,则尝试将其重新插入对应阵营的列表
- (try_begin),
- (neq, ":party_id_faction", ":party_faction"),
- (call_script, "script_add_faction_bandit_party_list", ":party_id"),
- (try_end),
- (try_end),
- # 如果前面没有找到可覆盖的位置,则在末尾新加一条记录
- (try_begin),
- (eq, ":is_passed", -1),
- (troop_set_slot, ":party_number", ":faction_bandit_party_list", ":party_no"), # 在末尾追加部队编号
- (val_add, ":party_number", 1), # 阵营部队数量+1
- (faction_set_slot, ":party_faction", slot_faction_bandit_party_number, ":party_number"), # 写入新的部队数量
- (try_end),
- (try_end),
- ]),
复制代码 我们已经成功创建了一个用于储存各个阵营野怪部队的“伪列表”。这个机制具有良好的扩展性:即使新增了阵营,也无需手动重新配置,只需在部队生成的地方调用一次 script_add_faction_bandit_party_list 脚本即可完成记录。
例如,在使用如下语句生成部队时:
- (spawn_around_party, ":center_no", "pt_knight_garrison_g"),
- (assign, ":party_no", reg0),
- (party_set_faction, ":party_no", ":center_knights"),
- (call_script, "script_add_faction_bandit_party_list", ":party_no"),
复制代码 需要注意的是,若你随后通过 (party_set_faction, "sparty_no", ":center_knights") 等方式手动设置了该部队的阵营,务必确保在设置阵营之后再调用 script_add_faction_bandit_party_list 脚本。否则,由于默认情况下部队模板的阵营可能与你设置的不一致,就会导致错误地将该部队记录到错误的阵营列表中。
战团自身通过代码自动生成的野怪部队,如果希望它们也能被完整地记录进各自阵营的“野怪部队列表”中,同样需要在这些部队创建之后手动调用一次 script_add_faction_bandit_party_list 脚本。
在完成所有前置准备后,我们现在就可以随时调用“伪列表”中储存的各阵营野怪部队了。调用方式非常简单。 下面以调用 不法之徒(fac_outlaws) 阵营的全部野怪部队为例,示范如何获取并遍历获取一个离玩家最近的不法之徒野怪部队: - (assign, ":faction_no", "fac_outlaws"), # 设定要查询的阵营为不法之徒(fac_outlaws)
- (assign, ":party_distance", 99999), # 初始化最近距离为一个极大值(用来后续比较)
- (assign, ":attack_party", -1), # 初始化攻击目标为 -1,表示尚未找到合适目标
- (faction_get_slot, ":party_number", ":faction_no", slot_faction_bandit_party_number), # 获取该阵营已记录的野怪部队数量
- (store_add, ":faction_bandit_party_list", slot_store_faction_bandit_party_list, ":faction_no"), # 获取该阵营对应的野怪部队列表槽位起始值
- (try_for_range, ":list_id", 0, ":party_number"), # 遍历该阵营所有登记在册的野怪部队
- (troop_get_slot, ":party_id", ":list_id", ":faction_bandit_party_list"), # 从伪列表中读取当前部队的 ID
-
- (gt, ":party_id", centers_end), # 排除 ID 属于城镇等固定据点的情况
- (party_is_active, ":party_id"), # 确保该部队仍处于活动状态(未被消灭)
- (store_faction_of_party, ":party_faction", ":party_id"), # 获取该部队当前所属阵营
- (eq, ":party_faction", ":faction_no"), # 再次确认该部队确实属于指定阵营(防止阵营变化后数据未更新)
- (store_distance_to_party_from_party, ":distance", "p_main_party", ":party_id"), # 计算主角与该部队的距离
- (lt, ":distance", ":party_distance"), # 如果该部队比当前记录的最近部队更近
- (assign, ":party_distance", ":distance"), # 更新记录的最近距离
- (assign, ":attack_party", ":party_id"), # 更新攻击目标部队 ID
- (try_end),
复制代码通过这种“伪列表”方法,避免了每次都遍历所有阵营的情况,极大提升了性能,特别是在频繁检查特定阵营或部队时。通过预先存储和管理相关部队信息,减少了不必要的循环,从而优化了游戏的运行效率,即使加入新的阵营或部队,相关操作依然可以顺利执行,而无需重新调整复杂的循环结构。并且这种方法不仅适用于部队,也可以轻松扩展到储存特定物品、人物等数据。
总结优势:
1、性能优化:每次只针对特定阵营或条件进行处理,避免了遍历所有数据的性能损耗。
2、灵活调用:通过动态存储阵营的部队列表,能够随时快速地获取目标部队或信息。
|