战斗的人生 发表于 2020-11-1 17:12:53

划时代的工具——python场景工具【AoE2ScenarioParser】

本帖最后由 战斗的人生 于 2020-11-9 01:15 编辑

工具原贴地址:https://github.com/KSneijders/AoE2ScenarioParser/blob/master/README.md#aoe2scenarioparser

这是一个可以编辑后缀为.aoe2scenario的帝国时代2DE战役文件的工具。原作者ID:KSneijders。
我暂且给他命名为:python场景工具

一、功能与介绍:


查看添加编辑移除
触发√√√√
条件√√√√
效果√√√√
单位
√√√

这个工具是一个python工具箱,可以通过编写代码,编辑帝国时代2DE的场景文件。写好代码后,运行代码,就可以编辑文件了。

二、工具安装:
此部分十分重要,请务必严格按照步骤来。
本部分教程由木匠大佬Carpenter提供,强烈推荐大家去模组下载他的联机场景金特~

1)   基本工具需求
Python 3.7 (或以上版本,经过实测这个辣鸡包要用到3.7以上的函数。他简介里要求的3.6根本跑不起来)
Python IDE (综合配置环境),建议选择Visual Studio(强烈建议)

命令行控制工具,没有则建议使用电脑自带的cmd,菜单-任务-运行“cmd”即可打开,也就是下面这玩意儿

python3.7和Visual Studio可以在软件官网上安装,cmd则是电脑自带。

2) 命令行配置系统
使用命令行能快速配置,防止手工点击各种辣鸡下载站收获各种安装捆绑全家桶。
首先,为了完成系统环境的配置,我们对系统内置包进行升级。需要升级的包括pip,python。
首先,打开cmd(或者Anaconda Prompt),在窗口输入
python -m pip install --upgrade pip然后敲击回车,等待安装完成

然后,继续在此窗口,分别输入以下命令并回车pip install python
pip upgrade python安装和升级python。
这样我们就完成了环境的安装。

3) AoE2ScenarioParser本体安装
依然是在cmd窗口,分别输入以下命令并敲回车pip install AoE2ScenarioParser
pip install bidict以上,我们完成了所有环境与工具安装。接下来就是正式使用了。

三、正式使用:

1)测试
首先,我们创建一个文件名后缀为 .py 的文件

然后用VS打开,输入from AoE2ScenarioParser.aoe2_scenario import AoE2Scenario接着点击“运行”或者键盘上单击F5运行或者ctrl+F5运行,如果得到以下结果,说明工具箱安装完成。如果报错,说明前面安装过程中出了问题,请对照步骤,再安装一次。


2)通用代码
通用代码如下:from AoE2ScenarioParser.aoe2_scenario import AoE2Scenario
# Information about the conditions & effects and their attributes
from AoE2ScenarioParser.datasets.conditions import Condition
from AoE2ScenarioParser.datasets.effects import Effect
from AoE2ScenarioParser.datasets.trigger_lists import DiplomacyState, Operator, ButtonLocation, PanelLocation, \
    TimeUnit, VisibilityState, DifficultyLevel, TechnologyState, Comparison, ObjectAttribute, Attribute

# Information of unit/tech/terrain name and their ID
from AoE2ScenarioParser.datasets.buildings import Building, GaiaBuilding
from AoE2ScenarioParser.datasets.techs import Tech
from AoE2ScenarioParser.datasets.heroes import Hero
from AoE2ScenarioParser.datasets.terrains import Terrain
from AoE2ScenarioParser.datasets.units import Unit, GaiaUnit

# Enum of players
from AoE2ScenarioParser.datasets.players import Player, PlayerColor

input_path = " "
output_path = " "
scenario = AoE2Scenario(input_path)

# 代码正文开始

# 代码正文结尾

scenario.write_to_file(output_path)其中,“#”后面的是注释。
需要重点说明的是这两句:input_path = " "
output_path = " "input_path后的双引号内是战役读取路径,output_path后的双引号内是战役存储路径,比如我设为:input_path = "D:/Age of emperor2/Mine/Half-work/cooperation/测试0.aoe2scenario"
output_path = "D:/Age of emperor2/Mine/Half-work/cooperation/测试1.aoe2scenario"就可以读取这个文件夹内名字为“测试0”的场景文件,运行代码后得到的是一个新建的名字为“测试1”的场景文件。这两个文件名也可以设为同一个,但我推荐设为不同的名字,这样方便测试和debug。
文件夹路径可以直接复制粘贴。

其他的部分可以直接复制粘贴。建议将这些代码新建为一个新文件,以后每次要用可以直接使用。

3)代码正文
终于,我们来到了正式使用部分。在文末的压缩包中,我会附上所有可以用到的帮助文档。当然你也可以到最上面的原贴地址中查找。
在开始之前,我要介绍一个VS功能,折叠代码。
#region 标记文字
your python code
#endregion它的效果是这样的,可以极大提升代码可读性。

接下来我将分别介绍触发代码写法和单位代码写法。写好需要的代码后,运行代码,就可以编辑场景文件了。注意,触发代码和地图代码并非都要写。如果你想编辑触发,那就写触发代码;如果想编辑单位,那就写单位代码。因为我还没有用到单位代码的所有功能,所以以下只介绍“新建单位功能”,其他功能以后更新。
注意:当读取路径和存储路径相同时不要多次运行代码,因为每运行一次代码场景文件都会被编辑一次。但读取路径和存储路径不同时就不会有这个问题,因为每次运行代码后者都会被完全覆盖。这也是我推荐两个路径设置不同的原因之一。

a)触发部分
触发部分代码分为三个部分,触发编码库导入、触发声明和触发代码。

(1)触发编码库导入
触发编码库导入部分如下,直接复制粘贴即可,放在正文开头即可
trigger_manager = scenario.object_manager.trigger_manager                # 导入触发编码
(2)触发声明
触发声明和触发代码部分有前后关系,触发声明必须放在触发代码之前。
触发声明代码全文如下:
替换触发 = trigger_manager.add_trigger("")
替换触发.enabled =                                 # 是否开启
替换触发.looping =                                 # 是否循环
替换触发.description_stid =                         # 触发文本描述 ID
替换触发.display_as_objective =               # 在任务栏显示
替换触发.display_on_screen =                         # 在屏幕上显示
替换触发.short_description_stid =               # 简短描述顺序 ID
替换触发.header =                                 # 是否作为标题
替换触发.description_order =                         # 触发任务栏描述顺序
替换触发.mute_objectives =                         # 禁止发出提示音
替换触发.description = ""                        # 触发文本描述
替换触发.name =                                 # 触发名
替换触发.short_description = ""                        # 简短描述
替换触发.trigger_id =                         # 触发ID ?用于python代码,无效
替换触发.condition_order =                         # !不明
替换触发.conditions =                         # !不明
替换触发.effect_order =                         # !不明
替换触发.effects =                                 # !不明其中“替换触发”为代码正文的名称,可以自己定义;在游戏中显示的触发名是由 trigger_manager.add_trigger("")中的双引号内部分定义的。
注意:实际使用时,并不需要把以上每一行代码都复制上,只编写自己需要用到的部分即可。例如,我想新建一个默认开启且循环的触发,我只需要这样写:
t1_1 = trigger_manager.add_trigger("【勇者 S +1 】")
t1_1.enabled = 1            # 是否开启
t1_1.looping = 1            # 是否循环
就可以了。这个触发的代码正文名为“ t1_1 ”,为它新建条件与效果时引用的就是这个名字。

(3)触发代码
定义之后,在代码正文内我们就得到了一个名为“替换触发”的触发,可以在触发代码部分为这个触发新建条件与效果了。

所有条件代码如下,其中“替换条件”为该条件在代码正文内的名称,可以自己定义,每个条件的名字必须独立;“替换触发”为该条件所在的触发的代码正文名。与触发代码一样,条件代码也不需要复制每一行,只复制自己需要的即可。
# 条件:无
替换条件 = 替换触发.add_condition(Condition.NONE)

# 将单位带入指定区域
替换条件 = 替换触发.add_condition(Condition.BRING_OBJECT_TO_AREA)
替换条件.unit_object =               # 单位地图 ID
替换条件.area_1_x =
替换条件.area_1_y =               # 起始点 xy 坐标
替换条件.area_2_x =
替换条件.area_2_y =               # 终止点 xy 坐标
替换条件.inverted =               # 反向条件

# 条件:将单位带给指定单位
替换条件 = 替换触发.add_condition(Condition.BRING_OBJECT_TO_OBJECT)
替换条件.unit_object =               # 单位地图 ID
替换条件.next_object =               # 目标单位地图 ID
替换条件.inverted =                         # 反向条件

# 条件:拥有物件数目 >=
替换条件 = 替换触发.add_condition(Condition.OWN_OBJECTS)
替换条件.amount_or_quantity =         # 数值
替换条件.object_list =               # 物件固有 ID
替换条件.player =                         # 起始玩家      
替换条件.object_group =               # 物件组
替换条件.object_type =               # 物件类型

# 条件:区域内物件数目 <=
替换条件 = 替换触发.add_condition(Condition.OWH_FEWER_OBJECTS)
替换条件.amount_or_quantity =         # 数值
替换条件.object_list =               # 物件固有 ID
替换条件.player =                         # 起始玩家
替换条件.area_1_x =
替换条件.area_1_y =                         # 起始点 xy 坐标
替换条件.area_2_x =
替换条件.area_2_y =                         # 终止点 xy 坐标
替换条件.object_group =               # 物件组
替换条件.object_type =               # 物件类型

# 条件:区域内物件数目 >=
替换条件 = 替换触发.add_condition(Condition.OBJECT_IN_AREA)
替换条件.amount_or_quantity =         # 数值
替换条件.object_list =               # 物件固有 ID
替换条件.player =                         # 起始玩家
替换条件.area_1_x =
替换条件.area_1_y =                         # 起始点 xy 坐标
替换条件.area_2_x =
替换条件.area_2_y =                         # 终止点 xy 坐标
替换条件.object_group =               # 物件组
替换条件.object_type =               # 物件类型
替换条件.inverted =                         # 反向条件

# 条件:消灭单位
替换条件 = 替换触发.add_condition(Condition.DESTROY_OBJECT)
替换条件.unit_object =               # 单位地图 ID
替换条件.inverted =                         # 反向条件

# 条件:捕获单位
替换条件 = 替换触发.add_condition(Condition.DESTROY_OBJECT)
替换条件.unit_object =               # 单位地图 ID
替换条件.player =                         # 起始玩家
替换条件.inverted =                         # 反向条件

# 条件:堆积属性
替换条件 = 替换触发.add_condition(Condition.ACCUMULATE_ATTRIBUTE)
替换条件.amount_or_quantity =               # 数值
替换条件.resource_type_or_tribute_list =               # 资源ID
替换条件.player =                                 # 起始玩家
替换条件.inverted =                                 # 反向条件

# 条件:研究科技
替换条件 = 替换触发.add_condition(Condition.RESEARCH_TECHNOLOGY)
替换条件.player =                         # 起始玩家
替换条件.technology =               # 科技ID
替换条件.inverted =                         # 反向条件

# 条件:定时器
替换条件 = 替换触发.add_condition(Condition.TIMER)
替换条件.timer =                         # 定时器
替换条件.inverted =                         # 反向条件

# 条件:选择单位
替换条件 = 替换触发.add_condition(Condition.OBJECT_SELECTED)
替换条件.unit_object =               # 单位地图 ID
替换条件.inverted =                         # 反向条件

# 条件:AI 信号
替换条件 = 替换触发.add_condition(Condition.AI_SIGNAL)
替换条件.ai_signal =                         # AI 信号 ID
替换条件.inverted =                         # 反向条件

# 条件:玩家被打败
替换条件 = 替换触发.add_condition(Condition.PLAYER_DEFEATED)
替换条件.player =                         # 起始玩家
替换条件.inverted =                         # 反向条件

# 条件:单位已有目标
替换条件 = 替换触发.add_condition(Condition.OBJECT_HAS_TARGET)
替换条件.unit_object =               # 单位地图 ID
# 替换条件.next_object =               # 目标单位地图 ID
# 替换条件.object_list =               # 物件固有 ID
# 替换条件.object_group =               # 物件组
# 替换条件.object_type =               # 物件类型
替换条件.inverted =               # 反向条件

# 条件:单位可视
替换条件 = 替换触发.add_condition(Condition.OBJECT_VISIBLE)
替换条件.unit_object =               # 单位地图 ID

# 条件:单位不可视
替换条件 = 替换触发.add_condition(Condition.OBJECT_NOT_VISIBLE)
替换条件.unit_object =               # 单位地图 ID

# 条件:研究科技中
替换条件 = 替换触发.add_condition(Condition.RESEARCHING_TECH)
替换条件.player =                         # 起始玩家
替换条件.technology =               # 科技ID
替换条件.inverted =                         # 反向条件

# 条件:已驻扎单位
替换条件 = 替换触发.add_condition(Condition.UNITS_GARRISONED)
替换条件.amount_or_quantity =               # 数值
替换条件.unit_object =                         # 单位地图 ID
替换条件.inverted =                                 # 反向条件

# 条件:难度等级 <=
替换条件 = 替换触发.add_condition(Condition.DIFFICULTY_LEVEL)
#替换条件.condition_type =                         # ?条件类型?
替换条件.amount_or_quantity =               # 数值
替换条件.inverted =                                 # 反向条件

# 条件:概率
替换条件 = 替换触发.add_condition(Condition.CHANCE)
替换条件.amount_or_quantity =               # 数值

# 条件:科技研发状态
替换条件 = 替换触发.add_condition(Condition.TECHNOLOGY_STATE)
替换条件.amount_or_quantity =               # 数值
替换条件.player =                                 # 起始玩家
替换条件.technology =                         # 科技ID
替换条件.inverted =                                 # 反向条件

# 条件:检测变量
替换条件 = 替换触发.add_condition(Condition.VARIABLE_VALUE)
替换条件.amount_or_quantity =               # 数值
替换条件.inverted =                                 # 反向条件
替换条件.variable =                                 # 变量 ID
替换条件.comparison =                         # 数值比较
      # = 0;< 1;> 2;<= 3;>= 4

# 条件:单位 HP
替换条件 = 替换触发.add_condition(Condition.OBJECT_HP)
替换条件.amount_or_quantity =               # 数值
替换条件.unit_object =                         # 单位地图 ID
替换条件.inverted =                                 # 反向条件
替换条件.comparison =                         # 数值比较
      # = 0;< 1;> 2;<= 3;>= 4

# 条件:同盟关系
替换条件 = 替换触发.add_condition(Condition.DIPLOMACY_STATE)
替换条件.amount_or_quantity =               # 数值
      # 同盟 = 0;中立 = 2;敌对 = 3
替换条件.player =                                 # 起始玩家
替换条件.target_player =                         # 对象玩家
效果代码与条件代码一样。全文如下:
# 效果:无
替换效果 = 替换触发.add_effect(Effect.NONE)

# 改变外交态度
替换效果 = 替换触发.add_effect(Effect.CHANGE_DIPLOMACY)
替换效果.diplomacy =                         # 外交
                # 同盟 = 0;中立 = 2;敌对 = 3
替换效果.player_source =                         # 起始玩家
替换效果.player_target =                         # 对象玩家

# 研究科技
替换效果 = 替换触发.add_effect(Effect.RESEARCH_TECHNOLOGY)
替换效果.player_source =                         # 起始玩家
替换效果.technology =                         # 科技 ID
替换效果.force_research_technology =               # 强制研发科技

# 送出聊天
替换效果 = 替换触发.add_effect(Effect.SEND_CHAT)
替换效果.player_source =                         # 起始玩家
替换效果.string_id =                                 # 文本 ID
替换效果.message = ""                        # 文本
替换效果.sound_name =                         # wem 文件名

# 播放音乐
替换效果 = 替换触发.add_effect(Effect.SEND_CHAT)
替换效果.player_source =                         # 起始玩家
替换效果.location_x =
替换效果.location_y =                         # 位置坐标 xy
替换效果.sound_name =                         # wem 文件名

# 贡品
替换效果 = 替换触发.add_effect(Effect.TRIBUTE)
替换效果.quantity =                                 # 数值
替换效果.tribute_list =                         # 资源 ID
替换效果.player_source =                         # 起始玩家
替换效果.player_target =                         # 对象玩家

# 开启城门
替换效果 = 替换触发.add_effect(Effect.UNLOCK_GATE)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.selected_object_id =                         # 城门地图 ID

# 闭锁城门
替换效果 = 替换触发.add_effect(Effect.LOCK_GATE)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.selected_object_id =                         # 城门地图 ID

# 激活触发
替换效果 = 替换触发.add_effect(Effect.ACTIVATE_TRIGGER)
替换效果.trigger_id =                         # 触发 ID

# 关闭触发
替换效果 = 替换触发.add_effect(Effect.DEACTIVATE_TRIGGER)
替换效果.trigger_id =                         # 触发 ID

# 发送 AI 信号
替换效果 = 替换触发.add_effect(Effect.AI_SCRIPT_GOAL)
替换效果.ai_script_goal =                         # AI 信号 ID

# 产生物件
替换效果 = 替换触发.add_effect(Effect.CREATE_OBJECT)
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.location_x =
替换效果.location_y =                         # 位置坐标 xy
替换效果.item_id =                                 # 朝向数字
替换效果.facet =                                 # 开启朝向

# 指派物件
替换效果 = 替换触发.add_effect(Effect.TASK_OBJECT)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.location_x =
替换效果.location_y =                         # 位置坐标 xy
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.selected_object_id =                         # 选择单位地图 ID

# 宣布胜利
替换效果 = 替换触发.add_effect(Effect.DECLARE_VICTORY)
替换效果.player_source =                         # 起始玩家
替换效果.enabled_or_victory =                         # 胜利或失败

# 杀死物件
替换效果 = 替换触发.add_effect(Effect.KILL_OBJECT)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.selected_object_id =                         # 选择单位地图 ID

# 移除物件
替换效果 = 替换触发.add_effect(Effect.REMOVE_OBJECT)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.selected_object_id =                         # 选择单位地图 ID

# 改变视角
替换效果 = 替换触发.add_effect(Effect.CHANGE_VIEW)
替换效果.player_source =                         # 起始玩家
替换效果.location_x =
替换效果.location_y =                         # 位置坐标 xy
替换效果.scroll =                                 # 是否瞬移

# 卸下
替换效果 = 替换触发.add_effect(Effect.UNLOAD)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.location_x =
替换效果.location_y =                         # 位置坐标 xy
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.selected_object_id =                         # 选择单位地图 ID

# 改变所有权
替换效果 = 替换触发.add_effect(Effect.CHANGE_OWNERSHIP)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.player_target =                         # 对象玩家
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.selected_object_id =                         # 选择单位地图 ID

# 巡逻
替换效果 = 替换触发.add_effect(Effect.PATROL)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.location_x =
替换效果.location_y =                         # 位置坐标 xy
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.selected_object_id =                         # 选择单位地图 ID

# 显示信息
替换效果 = 替换触发.add_effect(Effect.DISPLAY_INSTRUCTIONS)
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.string_id =                                 # 文本 ID
替换效果.display_time =                         # 显示时间
替换效果.instruction_panel_position =               # 显示位置
替换效果.play_sound =                         # 是否播放音效
替换效果.message = ""                        # 文本
替换效果.sound_name =                         # wem 文件名

# 清除信息
替换效果 = 替换触发.add_effect(Effect.CLEAR_INSTRUCTIONS)
替换效果.instruction_panel_position =               # 显示位置

# 冻结单位
替换效果 = 替换触发.add_effect(Effect.FREEZE_OBJECT)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.selected_object_id =                         # 选择单位地图 ID

# 开启高级按钮
#替换效果 = 替换触发.add_effect(Effect.USE_ADVANCED_BUTTONS)
# 原作者:请不要使用这个效果

# 损害物件
替换效果 = 替换触发.add_effect(Effect.DAMAGE_OBJECT)
替换效果.quantity =                                 # 数值
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.selected_object_id =                         # 选择单位地图 ID

# 放置地基
替换效果 = 替换触发.add_effect(Effect.PLACE_FOUNDATION)
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.location_x =
替换效果.location_y =                         # 位置坐标 xy

# 改变物件名字
替换效果 = 替换触发.add_effect(Effect.CHANGE_OBJECT_NAME)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.string_id =                                 # 文本 ID
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.message = ""                        # 文本
替换效果.selected_object_id =                         # 选择单位地图 ID

# 改变物件生命值
替换效果 = 替换触发.add_effect(Effect.HANGE_OBJECT_HP)
替换效果.quantity =                                 # 数值
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.operation =                         # 改变方式
                # 设置 = 1;增加 = 2;减少 = 3;相乘 = 4;相除 = 5
替换效果.selected_object_id =                         # 选择单位地图 ID

# 改变物件攻击力
替换效果 = 替换触发.add_effect(Effect.CHANGE_OBJECT_ATTACK)
替换效果.aa_quantity =                         # 攻击防御专用数值
替换效果.aa_armor_or_attack_type =               # 攻击护甲类型数值
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.operation =                         # 改变方式
                # 设置 = 1;增加 = 2;减少 = 3;相乘 = 4;相除 = 5
替换效果.selected_object_id =                         # 选择单位地图 ID

# 停止物件
替换效果 = 替换触发.add_effect(Effect.STOP_OBJECT)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.selected_object_id =                         # 选择单位地图 ID

# 移动攻击
替换效果 = 替换触发.add_effect(Effect.ATTACK_MOVE)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.location_x =
替换效果.location_y =                         # 位置坐标 xy
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.selected_object_id =                         # 选择单位地图 ID

# 改变物件护甲
替换效果 = 替换触发.add_effect(Effect.CHANGE_OBJECT_ARMOR)
替换效果.aa_quantity =                         # 攻击防御专用数值
替换效果.aa_armor_or_attack_type =               # 攻击护甲类型数值
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.operation =                         # 改变方式
                # 设置 = 1;增加 = 2;减少 = 3;相乘 = 4;相除 = 5
替换效果.selected_object_id =                         # 选择单位地图 ID

# 改变物件射程
替换效果 = 替换触发.add_effect(Effect.CHANGE_OBJECT_RANGE)
替换效果.quantity =               # 数值
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.operation =                         # 改变方式
                # 设置 = 1;增加 = 2;减少 = 3;相乘 = 4;相除 = 5
替换效果.selected_object_id =                         # 选择单位地图 ID

# 改变物件移动速度
替换效果 = 替换触发.add_effect(Effect.CHANGE_OBJECT_SPEED)
替换效果.quantity =                                 # 数值
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.selected_object_id =                         # 选择单位地图 ID

# 治疗物件
替换效果 = 替换触发.add_effect(Effect.HEAL_OBJECT)
替换效果.quantity =                                 # 数值
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.selected_object_id =                         # 选择单位地图 ID

# 传送物件
替换效果 = 替换触发.add_effect(Effect.TELEPORT_OBJECT)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.location_x =
替换效果.location_y =                         # 位置坐标 xy
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.selected_object_id =                         # 选择单位地图 ID

# 改变物件姿态
替换效果 = 替换触发.add_effect(Effect.CHANGE_OBJECT_STANCE)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.location_x =
替换效果.location_y =                         # 位置坐标 xy
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.attack_stance =                         # 姿态
                # 进攻 = 0;防御 = 1;坚守 = 2;投降 = 3
替换效果.selected_object_id =                         # 选择单位地图 ID

# 显示定时器
替换效果 = 替换触发.add_effect(Effect.DISPLAY_TIMER)
替换效果.string_id =                                 # 文本 ID
替换效果.display_time =                         # 定时器时间
替换效果.time_unit =                         # 时间单位
                # 秒 = 0;分 = 1;年 = 2
替换效果.variable_or_timer =                         # 调用定时器 ID
替换效果.message = ""                        # 文本

# 启用或禁用单位生产
替换效果 = 替换触发.add_effect(Effect.ENABLE_DISABLE_OBJECT)
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.enabled_or_victory =                         # 启用或禁用
替换效果.item_id =                                 # 生产位置

# 启用或禁用科技
替换效果 = 替换触发.add_effect(Effect.ENABLE_DISABLE_TECHNOLOGY)
替换效果.player_source =                         # 起始玩家
替换效果.technology =                         # 科技 ID
替换效果.enabled_or_victory =                         # 启用或禁用
替换效果.item_id =                                 # ?

# 修改生产成本
替换效果 = 替换触发.add_effect(Effect.CHANGE_OBJECT_COST)
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.food =                                 # 木材成本
替换效果.wood =                                 # 食物成本
替换效果.stone =                                 # 石料成本
替换效果.gold =                                 # 黄金成本

# 设置玩家可见
替换效果 = 替换触发.add_effect(Effect.SET_PLAYER_VISIBILITY)
替换效果.player_source =                         # 起始玩家
替换效果.player_target =                         # 对象玩家
替换效果.visibility_state =                         # 可见模式

# 改变单位头像
替换效果 = 替换触发.add_effect(Effect.CHANGE_OBJECT_ICON)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.location_x =
替换效果.location_y =                         # 位置坐标 xy
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.object_list_unit_id_2 =                         # 头像 ID
替换效果.selected_object_id =                         # 选择单位地图 ID

# 替换物件
替换效果 = 替换触发.add_effect(Effect.REPLACE_OBJECT)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.player_target =                         # 对象玩家
替换效果.location_x =
替换效果.location_y =                         # 位置坐标 xy
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_group =                         # 物件组
替换效果.object_type =                         # 物件类型
替换效果.object_list_unit_id_2 =                         # 目标单位固有 ID
替换效果.selected_object_id =                         # 选择单位地图 ID

# 改变物件描述
替换效果 = 替换触发.add_effect(Effect.CHANGE_OBJECT_DESCRIPTION)
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.string_id =                                 # 文本 ID
替换效果.message = ""                        # 文本

# 改变玩家名称
替换效果 = 替换触发.add_effect(Effect.CHANGE_PLAYER_NAME)
替换效果.player_source =                         # 起始玩家
替换效果.string_id =                                 # 文本 ID
替换效果.message = ""                        # 文本

# 改变训练位置
替换效果 = 替换触发.add_effect(Effect.CHANGE_TRAIN_LOCATION)
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.object_list_unit_id_2 =                         # 目标单位固有 ID
替换效果.button_location =                         # 按钮位置

# 改变训练位置
替换效果 = 替换触发.add_effect(Effect.CHANGE_RESEARCH_LOCATION)
替换效果.player_source =                         # 起始玩家
替换效果.technology =                         # 科技 ID
替换效果.object_list_unit_id_2 =                         # 目标单位固有 ID
替换效果.button_location =                         # 按钮位置

# 改变文明名称
替换效果 = 替换触发.add_effect(Effect.CHANGE_CIVILIZATION_NAME)
替换效果.player_source =                         # 起始玩家
替换效果.string_id =                                 # 文本 ID
替换效果.message = ""                        # 文本

# 产生驻扎单位
替换效果 = 替换触发.add_effect(Effect.CREATE_GARRISONED_OBJECT)
# 替换效果.number_of_units_selected =               # ?选择单位数目
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
替换效果.area_1_x =
替换效果.area_1_y =                                 # 起始范围坐标 xy
替换效果.area_2_x =
替换效果.area_2_y =                                 # 终止范围坐标 xy
替换效果.object_list_unit_id_2 =                         # 目标单位固有 ID
替换效果.selected_object_id =                         # 选择单位地图 ID

# 应答 AI 信号
替换效果 = 替换触发.add_effect(Effect.ACKNOWLEDGE_AI_SIGNAL)
替换效果.ai_signal_value =                         # 应答 AI 信号

# 修改属性
替换效果 = 替换触发.add_effect(Effect.MODIFY_ATTRIBUTE)
替换效果.quantity =                                 # 数值(攻击护甲修改需*256)
替换效果.object_list_unit_id =                         # 物件固有 ID
替换效果.player_source =                         # 起始玩家
# 替换效果.item_id =                                 # 物件ID
替换效果.operation =                         # 改变方式
                # 设置 = 1;增加 = 2;减少 = 3;相乘 = 4;相除 = 5
替换效果.object_attributes =                         # 物件属性

# 修改资源
替换效果 = 替换触发.add_effect(Effect.MODIFY_RESOURCE)
替换效果.quantity =                                 # 数值
替换效果.tribute_list =                         # 资源 ID
替换效果.player_source =                         # 起始玩家
替换效果.operation =                         # 改变方式
                # 设置 = 1;增加 = 2;减少 = 3;相乘 = 4;相除 = 5

# 根据变量修改资源
替换效果 = 替换触发.add_effect(Effect.MODIFY_RESOURCE_BY_VARIABLE)
替换效果.tribute_list =                         # 资源 ID
替换效果.player_source =                         # 起始玩家
替换效果.operation =                         # 改变方式
                # 设置 = 1;增加 = 2;减少 = 3;相乘 = 4;相除 = 5
替换效果.from_variable =                         # 变量 ID

# 修改变量
替换效果 = 替换触发.add_effect(Effect.CHANGE_VARIABLE)
替换效果.quantity =                                 # 数值
替换效果.operation =                         # 改变方式
                # 设置 = 1;增加 = 2;减少 = 3;相乘 = 4;相除 = 5
替换效果.from_variable =                         # 变量 ID
替换效果.message = ""                        # 文本

# 清除定时器
替换效果 = 替换触发.add_effect(Effect.CLEAR_TIMER)
替换效果.variable_or_timer =                         # 调用定时器 ID
接下来,我用一个示例,来帮助大家理解条件和效果代码写法。
首先定义一个触发:
t1_1 = trigger_manager.add_trigger("【勇者 S +1 】")
t1_1.enabled = 1            # 是否开启
t1_1.looping = 1            # 是否循环然后为它创建条件与效果:
# 区域内物件数目 >=
c1_1_1 = t1_1.add_condition(Condition.OBJECT_IN_AREA)
c1_1_1.amount_or_quantity = 1            # 数值
c1_1_1.object_list = 1304                # 物件固有 ID
c1_1_1.player = 1                        # 起始玩家
c1_1_1.area_1_x = 200
c1_1_1.area_1_y = 222                        # 起始点 xy 坐标
c1_1_1.area_2_x = 200
c1_1_1.area_2_y = 222                        # 终止点 xy 坐标

# 传送物件
e1_1_1 = t1_1.add_effect(Effect.TELEPORT_OBJECT)
e1_1_1.object_list_unit_id = 1304                        # 物件固有 ID
e1_1_1.player_source = 1                        # 起始玩家
e1_1_1.location_x = 239
e1_1_1.location_y = 239                        # 位置坐标 xy
e1_1_1.area_1_x = 200
e1_1_1.area_1_y = 222                              # 起始范围坐标 xy
e1_1_1.area_2_x = 200
e1_1_1.area_2_y = 222                              # 终止范围坐标 xy

# 移除物件
e1_1_2 = t1_1.add_effect(Effect.REMOVE_OBJECT)
e1_1_2.object_list_unit_id = 1304                        # 物件固有 ID
e1_1_2.player_source = 1                        # 起始玩家
e1_1_2.area_1_x = 239
e1_1_2.area_1_y = 239                              # 起始范围坐标 xy
e1_1_2.area_2_x = 239
e1_1_2.area_2_y = 239                              # 终止范围坐标 xy

# 修改变量
e1_1_3 = t1_1.add_effect(Effect.CHANGE_VARIABLE)
e1_1_3.quantity = 1                              # 数值
e1_1_3.operation = 2                        # 改变方式
                # 设置 = 1;增加 = 2;减少 = 3;相乘 = 4;相除 = 5
e1_1_3.from_variable = 11                        # 变量 ID
e1_1_3.message = "勇者力量"                        # 文本

# 修改变量
e1_1_4 = t1_1.add_effect(Effect.CHANGE_VARIABLE)
e1_1_4.quantity = 15                              # 数值
e1_1_4.operation = 2                        # 改变方式
                # 设置 = 1;增加 = 2;减少 = 3;相乘 = 4;相除 = 5
e1_1_4.from_variable = 15                        # 变量 ID
e1_1_4.message = "勇者力量增加值"                        # 文本这样,我们就得到了一个完整的触发。

(4)触发组写法
可能写到这里,读者会问:我为了简便操作而来,可你写一个触发的时间够我在地编做二十个了!
这自然。只做一两个触发,根本用不到这个工具。因此,我要介绍一个新概念——触发组。
触发是达成条件,发动效果。而单个触发往往不能满足我们的需求,所以我们需要多个触发共同作用,这就是触发组。在RPG战役和联机场景中,触发组就更常见了,RPG战役中往往一个技能就需要包含几十个触发的触发组。而一个写好的触发组复制粘贴,肯定是要比地编的单个触发复制粘贴要方便很多的。
借用我正在制作的战役的示例。首先,我们定义一组触发,并折叠起来,这样方便阅读:

之后,我们为每一个触发新建条件、效果,并把每一个触发折叠起来,

这样,就得到了一组触发,如图。

需要类似触发组,就复制粘贴,然后运用VScode的替换功能,选取复制部分替换。注意:一定要同时替换触发代码正文名、条件代码正文名和效果代码正文名。
最后,我们得到了数组类似的触发组,如图。(注意图片左边的代码行数)

这是我正在设计的一个战役的其中一个主角的技能。大概是90个触发。而技能与他类似的角色还有9个。这900+触发运用代码编写,可以节省大量工作量。而联机场景中动辄2、3000重复触发,使用这个工具的意义就更大了。

最后是条件和效果中可能运用到的常数列表,也会附加在文末压缩包内。其中单位属性、资源ID和攻击防御类型,建议通过DE大典查找。
class DiplomacyState(IntEnum):                # 外交信息
    ALLY = 0                # 盟友=0
    NEUTRAL = 1                # 中立=1
    ENEMY = 3                # 敌人=3


class Operator(IntEnum):                # 数值运算
    SET = 1                        # 设置=1
    ADD = 2                # 增加=2
    SUBTRACT = 3                # 减少=3
    MULTIPLY = 4                # 相乘=4
    DIVIDE = 5                # 相除=5


class ButtonLocation(IntEnum):                # 建筑内位置编号
    LOCATION_0_0 = 0      # 0
    LOCATION_1_0 = 2      # 2
    LOCATION_2_0 = 3      # 3
    LOCATION_3_0 = 4      # 4
    LOCATION_4_0 = 5      # 5
    LOCATION_0_1 = 6      # 6
    LOCATION_1_1 = 7      # 7
    LOCATION_2_1 = 8      # 8
    LOCATION_3_1 = 9      # 9
    LOCATION_4_1 = 10      # 10
    LOCATION_0_2 = 11      # 11
    LOCATION_1_2 = 12      # 12
    LOCATION_2_2 = 13      # 13
    LOCATION_3_2 = 14      # 14
    # LOCATION_4_2 = 15? (Actually placed at 0_0 at the moment)


class PanelLocation(IntEnum):                #显示信息位置
    TOP = 0                # 0
    """Panel at the top of the screen. ~13% from the top"""
    BETWEEN = 1                # 1
    """Panel between the top and the center of the screen. ~33% from the top"""
    CENTER = 2                # 2
    """Panel close to the center of the screen. ~45% from the top"""


class TimeUnit(IntEnum):                # 时间类型
    YEARS = 2                # 年(游戏)=2
    """In-Game years. A year is 5 seconds in-game time."""
    MINUTES = 1                # 分=1
    """In-Game minutes."""
    SECONDS = 0                # 秒=0
    """In-Game seconds."""


class VisibilityState(IntEnum):                # 是否可视
    VISIBLE = 0                # 可视=0
    EXPLORED = 1                # 已探索=1
    INVISIBLE = 2                # 不可视=2


class DifficultyLevel(IntEnum):                # 游戏难度
    EASIEST = 4                # 最易=4
    STANDARD = 3                # 标准=3
    MODERATE = 2                # 中等=2
    HARD = 1                # 困难=1
    HARDEST = 0                # 极难=0
    # EXTREME = 5# ???


class TechnologyState(IntEnum):      # 科技属性
    DISABLED = 4                # 不可用=4
    NOT_READY = 3                # 暂时不可研发=3
    READY = 2                # 可研发=2
    RESEARCHING = 1      # 研发中=1
    DONE = 0                # 研发完毕=0
    # QUEUED = 5# ???


class Comparison(IntEnum):                # 数值比较
    EQUAL = 0                # 相等      =0
    LESS = 1                # <      =1
    LARGER = 2                # >      =2
    LESS_OR_EQUAL = 3      # <=      =3
    LARGER_OR_EQUAL = 4      # >=      =4


class ObjectAttribute(IntEnum):                # 单位属性
    HIT_POINTS = 0                  # 生命值
    LINE_OF_SIGHT = 1               # 视野
    GARRISON_CAPACITY = 2         # 驻扎容量
    UNIT_SIZE_X = 3               # 单位尺寸(碰撞体积X)
    UNIT_SIZE_Y = 4               # 单位尺寸(碰撞体积Y)
    MOVEMENT_SPEED = 5            # 移动速度
    ROTATION_SPEED = 6            # 旋转速度
    ARMOR = 8                     # 护甲(或许有特殊计算方法?)
    ATTACK = 9                      # 攻击力(或许有特殊计算方法?)
    ATTACK_RELOAD_TIME = 10         # 攻击间隔(攻击重新加载时间)
    ACCURACY_PERCENT = 11         # 准确度百分比(命中率百分比)
    MAX_RANGE = 12                  # 最大射程
    WORK_RATE = 13                  # 工作效率
    CARRY_CAPACITY = 14             # 运载能力(资源携带能力)
    BASE_ARMOR = 15               # 基础护甲(默认1000点)
    PROJECTILE_UNIT = 16            # 投射物 ID
    ICON_GRAPHICS_ANGLE = 17      # 图标角度
    TERRAIN_DEFENSE_BONUS = 18      # 地形防御奖励(地形伤害加成 ID)
    ENABLE_SMART_PROJECTILES = 19   # 启用智能炮弹(弹道学模式)
    MINIMUM_RANGE = 20            # 最小射程
    ARNOUNT_OF_1ST_RESOURCES = 21   # 资源储备(首位资源储存)
    BLAST_WIDTH = 22                # 爆炸广度(溅射半径)
    SEARCH_RADIUS = 23            # 搜索半径
    HERO_STATUS = 40                # 英雄状态
    FRAME_DELAY = 41                # 帧延迟
    TRAIN_LOCATION = 42             # 训练位置
    TRAIN_BUTTON = 43               # 训练按钮
    BLAST_LEVEL = 44                # 爆炸等级(攻击伤害等级)
    OBJECT_NAME_ID = 50             # 单位名称(字符串 ID)
    SHORT_DESCRIPTION_ID = 51       # 简短介绍(字符串 ID)
    TERRAIN_RESTRICTION_ID = 53   # 地形限制 ID
    DEAD_UNIT_ID = 57               # 死亡单位 ID
    RESOURCE_COSTS = 100            # 花费成本
    TRAIN_TIME = 101                # 训练时间
    TOTAL_MISSILES = 102            # 投射单位总数(投射单位初数量)
    FOOD_COSTS = 103                # 食物成本
    WOOD_COSTS = 104                # 木材成本
    GOLD_COSTS = 105                # 黄金成本
    STONE_COSTS = 106               # 石料成本
    MAX_TOTAL_MISSILES = 107      # 最大投射物数量
    REGENERATION_RATE = 109         # 再生率(再生间隔)


class Attribute(IntEnum):                # 资源ID
    FOOD_STORAGE = 0
    WOOD_STORAGE = 1
    STONE_STORAGE = 2
    GOLD_STORAGE = 3
    POPULATION_HEADROOM = 4
    CONVERSION_RANGE = 5
    CURRENT_AGE = 6
    RELICS_CAPTURED = 7
    UNUSED_RESOURCE_008 = 8
    TRADE_GOODS = 9
    UNUSED_RESOURCE_010 = 10
    CURRENT_POPULATION = 11
    CORPSE_DECAY_TIME = 12
    REMARKABLE_DISCOVERY = 13
    MONUMENTS_CAPTURED = 14
    MEAT_STORAGE = 15
    BERRY_STORAGE = 16
    FISH_STORAGE = 17
    UNUSED_RESOURCE_018 = 18
    TOTAL_UNITS_OWNED = 19
    UNITS_KILLED = 20
    TECHNOLOGY_COUNT = 21
    PERCENT_MAP_EXPLORED = 22
    CASTLE_AGE_TECH_ID = 23
    IMPERIAL_AGE_TECH_ID = 24
    FEUDAL_AGE_TECH_ID = 25
    ATTACK_WARNING_SOUND_ID = 26
    ENABLE_MONK_CONVERSION = 27
    ENABLE_BUILDING_CONVERSION = 28
    UNUSED_RESOURCE_029 = 29
    UNUSED_RESOURCE_030 = 30
    UNUSED_RESOURCE_031 = 31
    BONUS_POPULATION_CAP = 32
    FOOD_MAINTENANCE = 33
    FAITH = 34
    FAITH_RECHARGING_RATE = 35
    FARM_FOOD_AMOUNT = 36
    CIVILIAN_POPULATION = 37
    UNUSED_RESOURCE_038 = 38
    ALL_TECHS_ACHIEVED = 39
    MILITARY_POPULATION = 40
    CONVERSIONS = 41
    STANDING_NDERS = 42
    RAZINGS = 43
    KILL_RATIO = 44
    SURVIVAL_TO_FINISH = 45
    TRIBUTE_INEFFICIENCY = 46
    GOLD_MINING_PRODUCTIVITY = 47
    TOWN_CENTER_UNAVAILABLE = 48
    GOLD_COUNTER = 49
    REVEAL_ALLY = 50
    UNUSED_RESOURCE_051 = 51
    MONASTERIES = 52
    TRIBUTE_SENT = 53
    ALL_MONUMENTS_CAPTURED = 54
    ALL_RELICS_CAPTURED = 55
    ORE_STORAGE = 56
    KIDNAP_STORAGE = 57
    DARK_AGE_TECH_ID = 58
    UNUSED_RESOURCE_059 = 59
    UNUSED_RESOURCE_060 = 60
    UNUSED_RESOURCE_061 = 61
    BUILDING_HOUSING_RATE = 62
    TAX_GATHER_RATE = 63
    GATHER_ACCUMULATOR = 64
    SALVAGE_DECAY_RATE = 65
    UNUSED_RESOURCE_066 = 66
    CAN_CONVERT = 67
    HIT_POINTS_KILLED = 68
    KILLED_P1 = 69
    KILLED_P2 = 70
    KILLED_P3 = 71
    KILLED_P4 = 72
    KILLED_P5 = 73
    KILLED_P6 = 74
    KILLED_P7 = 75
    KILLED_P8 = 76
    CONVERSION_RESISTANCE = 77
    TRADE_VIG_RATE = 78
    STONE_MINING_PRODUCTIVITY = 79
    QUEUED_UNITS = 80
    TRAINING_COUNT = 81
    START_WITH_UNIT_444_PTWC = 82
    BOARDING_RECHARGE_RATE = 83
    STARTING_VILLAGERS = 84
    RESEARCH_COST_MODIFIER = 85
    RESEARCH_TIME_MODIFIER = 86
    CONVERT_BOATS = 87
    FISH_TRAP_FOOD_AMOUNT = 88
    HEAL_RATE_MODIFIER = 89
    HEALING_RANGE = 90
    STARTING_FOOD = 91
    STARTING_WOOD = 92
    STARTING_STONE = 93
    STARTING_GOLD = 94
    ENABLE_PTWC_KIDNAP_LOOT = 95
    BERSERKER_HEAL_TIMER = 96
    DOMINANT_SHEEP_CONTROL = 97
    BUILDING_COST_SUM = 98
    TECH_COST_SUM = 99
    RELIC_INCOME_SUM = 100
    TRADE_INCOME_SUM = 101
    P1_TRIBUTE = 102
    P2_TRIBUTE = 103
    P3_TRIBUTE = 104
    P4_TRIBUTE = 105
    P5_TRIBUTE = 106
    P6_TRIBUTE = 107
    P7_TRIBUTE = 108
    P8_TRIBUTE = 109
    P1_KILL_VALUE = 110
    P2_KILL_VALUE = 111
    P3_KILL_VALUE = 112
    P4_KILL_VALUE = 113
    P5_KILL_VALUE = 114
    P6_KILL_VALUE = 115
    P7_KILL_VALUE = 116
    P8_KILL_VALUE = 117
    P1_RAZINGS = 118
    P2_RAZINGS = 119
    P3_RAZINGS = 120
    P4_RAZINGS = 121
    P5_RAZINGS = 122
    P6_RAZINGS = 123
    P7_RAZINGS = 124
    P8_RAZINGS = 125
    P1_RAZING_VALUE = 126
    P2_RAZING_VALUE = 127
    P3_RAZING_VALUE = 128
    P4_RAZING_VALUE = 129
    P5_RAZING_VALUE = 130
    P6_RAZING_VALUE = 131
    P7_RAZING_VALUE = 132
    P8_RAZING_VALUE = 133
    STANDING_CASTLES = 134
    HIT_POINTS_RAZED = 135
    KILLS_BY_P1 = 136
    KILLS_BY_P2 = 137
    KILLS_BY_P3 = 138
    KILLS_BY_P4 = 139
    KILLS_BY_P5 = 140
    KILLS_BY_P6 = 141
    KILLS_BY_P7 = 142
    KILLS_BY_P8 = 143
    RAZINGS_BY_P1 = 144
    RAZINGS_BY_P2 = 145
    RAZINGS_BY_P3 = 146
    RAZINGS_BY_P4 = 147
    RAZINGS_BY_P5 = 148
    RAZINGS_BY_P6 = 149
    RAZINGS_BY_P7 = 150
    RAZINGS_BY_P8 = 151
    VALUE_KILLED_BY_OTHERS = 152
    VALUE_RAZED_BY_OTHERS = 153
    KILLED_BY_OTHERS = 154
    RAZED_BY_OTHERS = 155
    TRIBUTE_FROM_P1 = 156
    TRIBUTE_FROM_P2 = 157
    TRIBUTE_FROM_P3 = 158
    TRIBUTE_FROM_P4 = 159
    TRIBUTE_FROM_P5 = 160
    TRIBUTE_FROM_P6 = 161
    TRIBUTE_FROM_P7 = 162
    TRIBUTE_FROM_P8 = 163
    VALUE_CURENT_UNITS = 164
    VALUE_CURRENT_BUILDINGS = 165
    FOOD_TOTAL = 166
    WOOD_TOTAL = 167
    STONE_TOTAL = 168
    GOLD_TOTAL = 169
    TOTAL_VALUE_OF_KILLS = 170
    TOTAL_TRIBUTE_RECEIVED = 171
    TOTAL_VALUE_OF_RAZINGS = 172
    TOTAL_CASTLES_BUILT = 173
    TOTAL_WONDERS_BUILT = 174
    TRIBUTE_SCORE = 175
    CONVERT_MIN_ADJUSFIENT = 176
    CONVERT_MAX_ADJUSTMENT = 177
    CONVERT_RESIST_MIN_ADJUSTMENT = 178
    CONVERT_RESIST_MAX_ADJUSTMENT = 179
    CONVERT_BUILDING_MIN = 180
    CONVERT_BUILDING_MAX = 181
    CONVERT_BUILDING_CHANCE = 182
    REVEAL_ENEMY = 183
    VALUE_WONDERS_CASTLES = 184
    FOOD_SCORE = 185
    WOOD_SCORE = 186
    STONE_SCORE = 187
    GOLD_SCORE = 188
    CHOPPING_PRODUCTIVITY = 189
    FOOD_GATHERING_PRODUCTIVITY = 190
    RELIC_GOLD_PRODUCTION_RATE = 191
    CONVERTED_UNITS_DIE = 192
    THEOCRACY = 193
    CRENELLATIONS = 194
    CONSTRUCTION_RATE_MODIFIER = 195
    HUN_WONDER_DISCOUNT = 196
    SPIES_DISCOUNT = 197
    UNUSED_RESOURCE_198 = 198
    UNUSED_RESOURCE_199 = 199
    UNUSED_RESOURCE_200 = 200
    UNUSED_RESOURCE_201 = 201
    UNUSED_RESOURCE_202 = 202
    UNUSED_RESOURCE_203 = 203
    UNUSED_RESOURCE_204 = 204
    FEITORIA_FOOD_PRODUCTIVITY = 205
    FEITORIA_WOOD_PRODUCTIVITY = 206
    FEITORIA_STONE_PRODUCTIVITY = 207
    FEITORIA_GOLD_PRODUCTIVITY = 208
    REVEAL_ENEMY_TOWN_CENTERS = 209
    RELICS_VISIBLE_ON_MAP = 210
    ELEVATION_HIGHER_BONUS = 211
    ELEVATION_LOWER_BONUS = 212
    RAIDING_PRODUCTIVITY = 213
    MERCENARY_KIPCHAK_COUNT = 214
    MERCENARY_KIPCHAK_LIMIT = 215
    SHEPHERD_PRODUCTIVITY = 216
    SHARED_LINE_OF_SIGHT = 217
b)单位部分
本工具可以对单位执行新建、查找、编辑和移除。十分抱歉,我目前只使用和测试过了新建功能,因此无法对后三项功能进行介绍。大家有需要的可以自行到原地址学习。以下只介绍新建单位功能。但请相信我,这是一个十分十分强大的功能。
单位部分代码分为两部分,单位编码导入和单位代码。
单位编码导入代码如下,复制粘贴到代码正文开头即可:
unit_manager = scenario.object_manager.unit_manager单位代码全文如下,除非标注出来,否者只能填写整数:
unit = unit_manager.add_unit(
      player = ,                        # 玩家 ID
      unit_id = ,                        # 单位固有 ID,请查找DE大典
      x = ,                        # 单位 x 坐标,可填写小数
      y = ,                        # 单位 y 坐标,可填写小数
      z = ,                        # 单位 z 坐标,可填写小数
      rotation = ,                        # 单位的朝向,有 0-15 共16个方向
      garrisoned_in_id = ,                        # 单位所驻扎的位置,需要填写地图 ID
      animation_frame = ,                        # 单位初始动画帧数,绝大多数情况用不到
      reference_id =                         # 单位地图 ID,不填则由地编自动分配
)                              # 注意:后括号前不加“ , ”其余每一行末尾必须加半角“ , ” 与触发代码一样,以上代码也可以只取所需部分。

接下来,我将向大家介绍这个功能的一种神奇的应用,我称之为“二阶导式新建单位”。
我先放出效果图:

以上只是我为了测试效果而随意画的。理论上,这个工具可以画出任何形状的图形——不用你一个一个单位地手点。
做法很简单。首先,我们使用任何编程软件,比如C++,matlab,推荐使用matlab。

然后编辑代码来进行运算,得到需要的单位的坐标。

然后,输出要写在python场景工具里的代码,注意一定要严格按照格式

最后,将得到的代码复制粘贴到python场景工具的代码正文部分,记得前面要加上单位编码导入。
运行工具,我们就得到了所需的图形。
这种方法,我们写的代码是“输出文件的代码的代码”,因此我将之命名为“二阶导式新建单位”。
虽然这种方法十分复杂,但是熟练掌握之后,你可以绘制任何图形,拥有无限的可能性。当然,如果你有什么新的应用,也欢迎分享给大家。

最后,感谢木匠,游戏ID:Carpenter,提供的环境安装教程。
最后的最后,感谢本工具原作者:KSneijders!

帮助文档下载:(其中DE大典来自夜游神的原贴:https://www.hawkaoe.net/bbs/thread-146061-1-1.html)


鸑鷟67 发表于 2020-11-1 17:59:56

好,很有精神!(指用上这个工具以后可以大量制造触发,完成以前受限于工作量而难以完成的各种富有创新精神的触发群)

cxt 发表于 2020-11-1 18:46:39

本帖可称目前撅腚版最牛B教程,甚至不输cly的json教程,是撅腚版技术层面的一次核心突破,即使是新人也能很快上手,运用这些技术做出有亮点的战役。

cly806 发表于 2020-11-1 23:54:48

好,很有精神!(当c++帝国遇上python的奇妙反应)

newtonerdai 发表于 2020-11-2 01:16:58

DE大典里没有单位属性,我就整理了一下注释。希望你可以补充进帖子里~

(搜索“单位属性”即可快速定位到你帖子里的相应位置)

    HIT_POINTS = 0                  # 生命值
    LINE_OF_SIGHT = 1               # 视野
    GARRISON_CAPACITY = 2         # 驻扎容量
    UNIT_SIZE_X = 3               # 单位尺寸(碰撞体积X)
    UNIT_SIZE_Y = 4               # 单位尺寸(碰撞体积Y)
    MOVEMENT_SPEED = 5            # 移动速度
    ROTATION_SPEED = 6            # 旋转速度
    ARMOR = 8                     # 护甲(或许有特殊计算方法?)
    ATTACK = 9                      # 攻击力(或许有特殊计算方法?)
    ATTACK_RELOAD_TIME = 10         # 攻击间隔(攻击重新加载时间)
    ACCURACY_PERCENT = 11         # 准确度百分比(命中率百分比)
    MAX_RANGE = 12                  # 最大射程
    WORK_RATE = 13                  # 工作效率
    CARRY_CAPACITY = 14             # 运载能力(资源携带能力)
    BASE_ARMOR = 15               # 基础护甲(默认1000点)
    PROJECTILE_UNIT = 16            # 投射物 ID
    ICON_GRAPHICS_ANGLE = 17      # 图标角度
    TERRAIN_DEFENSE_BONUS = 18      # 地形防御奖励(地形伤害加成 ID)
    ENABLE_SMART_PROJECTILES = 19   # 启用智能炮弹(弹道学模式)
    MINIMUM_RANGE = 20            # 最小射程
    ARNOUNT_OF_1ST_RESOURCES = 21   # 资源储备(首位资源储存)
    BLAST_WIDTH = 22                # 爆炸广度(溅射半径)
    SEARCH_RADIUS = 23            # 搜索半径
    HERO_STATUS = 40                # 英雄状态
    FRAME_DELAY = 41                # 帧延迟
    TRAIN_LOCATION = 42             # 训练位置
    TRAIN_BUTTON = 43               # 训练按钮
    BLAST_LEVEL = 44                # 爆炸等级(攻击伤害等级)
    OBJECT_NAME_ID = 50             # 单位名称(字符串 ID)
    SHORT_DESCRIPTION_ID = 51       # 简短介绍(字符串 ID)
    TERRAIN_RESTRICTION_ID = 53   # 地形限制 ID
    DEAD_UNIT_ID = 57               # 死亡单位 ID
    RESOURCE_COSTS = 100            # 花费成本
    TRAIN_TIME = 101                # 训练时间
    TOTAL_MISSILES = 102            # 投射单位总数(投射单位初数量)
    FOOD_COSTS = 103                # 食物成本
    WOOD_COSTS = 104                # 木材成本
    GOLD_COSTS = 105                # 黄金成本
    STONE_COSTS = 106               # 石料成本
    MAX_TOTAL_MISSILES = 107      # 最大投射物数量
    REGENERATION_RATE = 109         # 再生率(再生间隔)


战斗的人生 发表于 2020-11-2 01:35:44

newtonerdai 发表于 2020-11-2 01:16
DE大典里没有单位属性,我就整理了一下注释。希望你可以补充进帖子里~

(搜索“单位属性”即可快速定位到 ...

好,明天我添加进常数列表里~

尼麻 发表于 2020-11-2 05:49:52

一脸懵懂进来然后一脸懵懂地走开{:158:}

我是谁004 发表于 2020-11-2 07:17:34

不错(*๓´╰╯`๓)♡可以拿来解读文件格式

戴子玲 发表于 2020-11-2 10:53:17

很具有潜力的触发工具,关于最后的使用单位绘图,我之前做过一些,也有一些经验,不过是在红警里的。
比如在地图上绘制迷宫、图案、文字、图像等。但红警2的单位不能像帝国那样密铺,只能按tile来排列,比较遗憾。




战斗的人生 发表于 2020-11-2 12:13:41

我是谁004 发表于 2020-11-2 07:17
不错(*๓´╰╯`๓)♡可以拿来解读文件格式

{:164:}这工具得在程序员手里才能开发得好,我就只会最基础的应用

战斗的人生 发表于 2020-11-2 12:15:00

戴子玲 发表于 2020-11-2 10:53
很具有潜力的触发工具,关于最后的使用单位绘图,我之前做过一些,也有一些经验,不过是在红警里的。
比如 ...

我也想到了读取图片像素点,得到位置矩阵,然后输出代码,但我不会就没写上去……
我还没测试过他的坐标可以精确到多少,我输出的时候就直接把f%输出上去了,也不知道精确到几位小数

我是谁004 发表于 2020-11-2 18:42:16

戴子玲 发表于 2020-11-2 10:53
很具有潜力的触发工具,关于最后的使用单位绘图,我之前做过一些,也有一些经验,不过是在红警里的。
比如 ...

这种以前也做过,不算很完善
https://www.hawkaoe.net/bbs/forum.php?mod=viewthread&tid=135073&highlight=rio

春田一九零三 发表于 2020-11-2 20:43:14

{:149:}学习一下,代工绘图的时代来临了么

砖烧白开水 发表于 2020-12-30 00:23:15

本帖最后由 砖烧白开水 于 2020-12-30 01:25 编辑

好了,在用了

changing 发表于 2021-6-18 09:14:23

太牛了,完全看不懂,没基础。
页: [1]
查看完整版本: 划时代的工具——python场景工具【AoE2ScenarioParser】