本帖最后由 奥杜因阿卡托什 于 2024-8-8 09:17 编辑
之前加过各种各样的主动技能,但是一直没让AI用上,现在终于是把波士战的AI搓出来了。而且用了一些手段把这个AI封装了,能够流水线化地设置。效果看视频。
下面放代码。注意这次的代码不是可以直接拿去用的,因为有很多我自己的系统和技能。看看框架即可。
先看slot
- #AI相关
- #下述的各种信息都是在获取信息的触发器里分析的,除此之外还有血量、盾量、弹药量等能直接获取的信息。
- slot_ai_battle_mode = 100#根据目前装备分析自己的战斗模式,分为剑盾1、枪兵2、双手3、步射4、混战骑5、枪骑6、游骑7。
- slot_ai_action_number = 101#当前正在执行的行为,序号每个ai的都不尽相同。
- slot_ai_target = 102#目标,主要用于各种位移类技能。索敌范围暂定为30米,超过这个范围就会丢失目标,需要重新索敌。boss战无距离限制。
- slot_ai_target_distance = 103#目标的距离(单位米)
- slot_ai_target_battle_mode = 104#目标战斗模式
- slot_ai_ally_number = 105#友军总数
- slot_ai_ally_number_5m = 106#五米内友军总数
- slot_ai_enemy_number = 107#敌军总数
- slot_ai_enemy_number_5m = 108#五米内敌军总数
复制代码 header我也加了,加在header_mission_template里
- #ai战斗模式分析
- ai_saber = 1 #剑盾(带盾+单手武器/双手武器+步行)
- ai_pikeman = 2 #矛兵(带盾+长杆武器+步行)
- ai_berserker = 3 #双手豪杰(不带盾+近战+步行)
- ai_archer = 4 #步射(远程+步行)
- ai_cavalry = 5 #混战骑兵(骑马+非长杆近战)
- ai_lancer = 6 #枪骑兵(骑马+长杆/或可以骑枪冲锋)
- ai_ranger = 7 #游骑兵(骑马+远程)
复制代码 触发器其实一共也就两个,核心的就一个,可以说是非常轻量化集成化了。
- #第一个触发器,刷出agent的时候储存一下波士信息。
- (ti_on_agent_spawn, 0, 0,
- [],
- [
- (store_trigger_param_1, ":agent_no"),
- (agent_is_human, ":agent_no"),
- (agent_is_alive, ":agent_no"),
- (agent_set_slot, ":agent_no", slot_ai_target, -1),#清空
- (agent_get_troop_id, ":troop_no", ":agent_no"),
- (eq, ":troop_no", "trp_starkhook_megalith_berserker"),#岩雷狂战士
- (assign, "$mission_boss_1", ":agent_no"),
- #$mission_boss_1这里可以填123,最多支持三人组波士(腐败结晶人x),不过目前来说不能把两个波士设置成同一个兵种,不然AI触发器就没法控制了。
- ]),
复制代码- #boss战AI
- #要用在哪个mt里,就把boss_trigger_starkhook_megalith_berserker这个写在这个mt的common trigger之后,一键装载了属于是。
- boss_trigger_starkhook_megalith_berserker = (1, 0, 0,#斯塔胡克岩雷狂战士
- [
- (assign, "$mission_boss_agent", -1),
- (try_begin),
- (ge, "$mission_boss_1", 0),
- (agent_is_alive, "$mission_boss_1"),
- (agent_get_troop_id, ":troop_no", "$mission_boss_1"),
- (eq, ":troop_no", "trp_starkhook_megalith_berserker"),#岩雷狂战士
- (assign, "$mission_boss_agent", "$mission_boss_1"),
- (else_try),
- (ge, "$mission_boss_2", 0),
- (agent_is_alive, "$mission_boss_2"),
- (agent_get_troop_id, ":troop_no", "$mission_boss_2"),
- (eq, ":troop_no", "trp_starkhook_megalith_berserker"),#岩雷狂战士
- (assign, "$mission_boss_agent", "$mission_boss_2"),
- (else_try),
- (ge, "$mission_boss_3", 0),
- (agent_is_alive, "$mission_boss_3"),
- (agent_get_troop_id, ":troop_no", "$mission_boss_3"),
- (eq, ":troop_no", "trp_starkhook_megalith_berserker"),#岩雷狂战士
- (assign, "$mission_boss_agent", "$mission_boss_3"),
- (try_end),
- (ge, "$mission_boss_agent", 0),
- ],
- [
- #AI状态获取(主要获取距离相关的信息),信息储存进slot里
- #—————————————————————————————————获取—————————————————————————————————
- (call_script, "script_agent_ai_battle_mode", "$mission_boss_agent"),#战斗模式分析
- (assign, ":agent_battle_mode", reg1),
- #目标
- (agent_get_slot, ":target_agent_no", "$mission_boss_agent", slot_ai_target),
- (try_begin),
- (lt, ":target_agent_no", 0),#boss战特供锁定玩家
- (assign, ":target_agent_no", "$mission_player_agent"),
- (agent_set_slot, "$mission_boss_agent", slot_ai_target, ":target_agent_no"),
- (try_end),
- (agent_get_position, pos1, "$mission_boss_agent"),
- (try_begin),
- (ge, ":target_agent_no", 0),
- (call_script, "script_agent_ai_battle_mode", ":target_agent_no"),#战斗模式分析
- (assign, ":target_battle_mode", reg1),
- (agent_get_position, pos2, ":target_agent_no"),
- (get_distance_between_positions_in_meters, ":distance_no", pos1, pos2),#距离
- (try_end),
- #AI行为处理
- #使用权重进行分析,每一种状态都会影响特定行为的权重,最后执行权重更高的行为。权重和状态的关系另外见表。
- #—————————————————————————————————分析—————————————————————————————————
- (assign, ":action_observe", 1000),#观察
- (assign, ":action_sprint", 1000),#冲刺
- (call_script, "script_agent_ai_weight_input", 6, 1000, 1000, 1000, 1000, 1000, 1000),#slot0野盲击,slot1旋刃斩,slot2血星冲击,slot3赤潮战号,slot4血涌战号,slot5血钢战吼
- (try_begin),
- (eq, ":agent_battle_mode", ai_berserker),#双手
- (val_sub, ":action_observe", 20),
- (val_add, ":action_sprint", 60),
- (else_try),
- (eq, ":agent_battle_mode", ai_archer),#步射
- (val_add, ":action_observe", 80),
- (val_sub, ":action_sprint", 10),
- (call_script, "script_agent_ai_weight_input", 6, -1000, -1000, -1000, 70, 70, 70),
- (try_end),
- (try_begin),
- (agent_get_ammo, ":cur_ammo", "$mission_boss_agent", 0),#弹药量
- (ge, ":cur_ammo", 3),
- (val_add, ":action_observe", 10),
- (val_sub, ":action_sprint", 10),
- (try_end),
- (call_script, "script_get_state_count", "$mission_boss_agent", "itm_state_blood_burst"),#血潮汹涌
- (assign, ":bloodburst_count", reg1),
- (try_begin),
- (lt, ":bloodburst_count", 2),
- (call_script, "script_agent_ai_weight_input", 6, 0, 0, -1000, 60, -10, -40),
- (else_try),
- (is_between, ":bloodburst_count", 2, 5),
- (call_script, "script_agent_ai_weight_input", 6, 0, 0, 20, 10, 10, 10),
- (else_try),
- (ge, ":bloodburst_count", 5),
- (call_script, "script_agent_ai_weight_input", 6, -10, -10, 50, -1000, 70, 50),
- (try_end),
- (call_script, "script_get_state_timer", "$mission_boss_agent", "itm_state_war_anger"),#血脉偾张
- (try_begin),
- (gt, reg1, 2),#还剩两秒以上
- (call_script, "script_agent_ai_weight_input", 6, 0, 0, 0, 0, 0, -1000),
- (try_end),
- (try_begin),
- (lt, ":distance_no", 2),
- (val_sub, ":action_observe", 40),
- (call_script, "script_agent_ai_weight_input", 6, 100, 120, 0, -50, -80, -1000),
- (else_try),
- (lt, ":distance_no", 4),
- (call_script, "script_agent_ai_weight_input", 6, 120, 100, 30, 0, 30, 20),
- (else_try),
- (is_between, ":distance_no", 4, 6),
- (call_script, "script_agent_ai_weight_input", 6, -10, -10, 0, 40, 40, 50),
- (else_try),
- (is_between, ":distance_no", 6, 10),
- (val_add, ":action_observe", 10),
- (call_script, "script_agent_ai_weight_input", 6, -1000, -1000, 20, -30, 40, 50),
- (else_try),
- (ge, ":distance_no", 11),
- (val_add, ":action_sprint", 30),
- (call_script, "script_agent_ai_weight_input", 6, -1000, -1000, 50, -60, 40, 50),
- (try_end),
- (try_begin),
- (this_or_next|eq, ":target_battle_mode", ai_archer),
- (eq, ":target_battle_mode", ai_ranger),
- (val_sub, ":action_observe", 70),
- (val_add, ":action_sprint", 80),
- (call_script, "script_agent_ai_weight_input", 3, 0, 0, 70),
- (try_end),
- (try_begin),
- (agent_slot_ge, "$mission_boss_agent", slot_agent_skill_timer, 1),#技能后摇
- (call_script, "script_agent_ai_weight_input", 6, -1000, -1000, -1000, -1000, -1000, -1000),
- (try_end),
- #—————————————————————————————————执行—————————————————————————————————
- (try_begin),#下半身
- (gt, ":action_observe", ":action_sprint"),#观察
- (agent_set_speed_limit, "$mission_boss_agent", 5),
- (else_try),
- (agent_set_speed_limit, "$mission_boss_agent", 114514),
- (try_end),
- (call_script, "script_agent_ai_weight_output"),
- (assign, ":chosen_action", reg1),
- (try_begin),
- (agent_slot_eq, "$mission_boss_agent", slot_ai_action_number, ":chosen_action"),#避免反复执行同一个行动
- (assign, ":chosen_action", 0),
- (try_end),
- (try_begin),#上半身
- (eq, ":chosen_action", 1),#重盲击
- (call_script, "script_cf_close_combat_technique", "$mission_boss_agent", "itm_active_heavy_casual_attack"),
- (else_try),
- (eq, ":chosen_action", 2),#旋刃斩
- (call_script, "script_cf_close_combat_technique", "$mission_boss_agent", "itm_active_sweep_away"),
- (else_try),
- (eq, ":chosen_action", 3),#血星冲击
- (call_script, "script_cf_close_combat_technique", "$mission_boss_agent", "itm_active_blood_strike"),
- (else_try),
- (eq, ":chosen_action", 4),#赤潮战誓
- (call_script, "script_sorcery_chant_technique", "$mission_boss_agent", "itm_active_warcy_red_tide"),
- (else_try),
- (eq, ":chosen_action", 5),#血涌战誓
- (call_script, "script_sorcery_chant_technique", "$mission_boss_agent", "itm_active_warcy_bloodburst"),
- (else_try),
- (eq, ":chosen_action", 6),#血钢战吼
- (call_script, "script_sorcery_chant_technique", "$mission_boss_agent", "itm_active_warcy_bloodsteel"),
- (try_end),
- (agent_set_slot, "$mission_boss_agent", slot_ai_action_number, ":chosen_action"),#记录本次执行的动作
- (call_script, "script_agent_ai_weight_clear", 6),#清空
- (display_message, "@————————————————————————————————"),
- ]),
复制代码 用到的脚本
- #分析当前装备模式
- #剑盾1、枪兵2、双手3、步射4、混战骑5、枪骑6、游骑7,标签定义在header_mission_template里。
- #输入对象agent,返回装备模式序号,返回后储存进slot_ai_battle_mode
- ("agent_ai_battle_mode", [
- (store_script_param_1, ":agent_no"),
- (assign, ":battle_mode_no", 0),
- (agent_get_wielded_item, ":weapon_no_1", ":agent_no", 0),#右手
- (agent_get_wielded_item, ":weapon_no_2", ":agent_no", 1),#左手
- (agent_get_horse, ":horse_no", ":agent_no"),
- (try_begin),
- (ge, ":horse_no", 0),#骑马
- (gt, ":weapon_no_1", 0),
- (item_get_type, ":type_no", ":weapon_no_1"),
- (this_or_next|eq, ":type_no", itp_type_bow),#远程
- (this_or_next|eq, ":type_no", itp_type_crossbow),
- (this_or_next|eq, ":type_no", itp_type_thrown),
- (this_or_next|eq, ":type_no", itp_type_pistol),
- (eq, ":type_no", itp_type_musket),
- (assign, ":battle_mode_no", ai_ranger), #游骑兵
- (else_try),
- (ge, ":horse_no", 0),#骑马
- (gt, ":weapon_no_1", 0),
- (item_get_type, ":type_no", ":weapon_no_1"),
- (this_or_next|eq, ":type_no", itp_type_polearm),#长杆
- (item_has_property, ":weapon_no_1", itp_couchable),#骑枪冲锋
- (assign, ":battle_mode_no", ai_lancer), #枪骑兵
- (else_try),
- (ge, ":horse_no", 0),#骑马
- (gt, ":weapon_no_1", 0),
- (assign, ":battle_mode_no", ai_cavalry), #混战骑兵
- (else_try),
- (lt, ":horse_no", 0),#步行
- (gt, ":weapon_no_1", 0),
- (item_get_type, ":type_no", ":weapon_no_1"),
- (this_or_next|eq, ":type_no", itp_type_bow),#远程
- (this_or_next|eq, ":type_no", itp_type_crossbow),
- (this_or_next|eq, ":type_no", itp_type_thrown),
- (this_or_next|eq, ":type_no", itp_type_pistol),
- (eq, ":type_no", itp_type_musket),
- (assign, ":battle_mode_no", ai_archer), #步射手
- (else_try),
- (lt, ":horse_no", 0),#步行
- (gt, ":weapon_no_1", 0),
- (item_get_type, ":type_no", ":weapon_no_1"),
- (neg|eq, ":type_no", itp_type_bow),#近战
- (neg|eq, ":type_no", itp_type_crossbow),
- (neg|eq, ":type_no", itp_type_thrown),
- (neg|eq, ":type_no", itp_type_pistol),
- (neg|eq, ":type_no", itp_type_musket),
- (le, ":weapon_no_2", 0),#不带盾
- (assign, ":battle_mode_no", ai_berserker), #双手豪杰
- (else_try),
- (lt, ":horse_no", 0),#步行
- (gt, ":weapon_no_1", 0),
- (item_get_type, ":type_no", ":weapon_no_1"),
- (eq, ":type_no", itp_type_polearm),#长杆
- (gt, ":weapon_no_2", 0),#带盾
- (assign, ":battle_mode_no", ai_pikeman), #长矛兵
- (else_try),
- (lt, ":horse_no", 0),#步行
- (gt, ":weapon_no_2", 0),#带盾
- (gt, ":weapon_no_1", 0),
- (item_get_type, ":type_no", ":weapon_no_1"),
- (this_or_next|eq, ":type_no", itp_type_one_handed_wpn),#单手武器
- (eq, ":type_no", itp_type_two_handed_wpn),#单双手武器
- (assign, ":battle_mode_no", ai_saber), #剑盾兵
- (try_end),
- (assign, reg1, ":battle_mode_no"),
- ]),
- #录入权重,将其储存进trp_temp_array_ai的slot里,便于统计与调用
- #输入数值,加权为正,减权为负。可以不填。
- #param输入录入数据的数量
- ("agent_ai_weight_input", [
- (store_script_param, ":total_num", 1),#录入数据的数量
- (try_for_range, ":slot_no", 0, ":total_num"),
- (store_add, ":param_no", ":slot_no", 2),
- (store_script_param, ":cur_weight", ":param_no"),
- (neq, ":cur_weight", 0),
- (troop_get_slot, ":weight_count", "trp_temp_array_ai", ":slot_no"),
- (val_add, ":weight_count", ":cur_weight"),
- (troop_set_slot, "trp_temp_array_ai", ":slot_no", ":weight_count"),
- (try_end),
- ]),
- #获取权重最高的一项,返回序号
- #权重最高的一项必须大于500才能执行,否则认定为所有项目都不应执行,不下指令,由原有AI自行普通攻击
- ("agent_ai_weight_output", [
- (assign, ":weight_range", 500),
- (assign, ":chosen_action", 0),
- (try_for_range, ":slot_no", 0, 10),
- (troop_get_slot, ":weight_count", "trp_temp_array_ai", ":slot_no"),
- (gt, ":weight_count", ":weight_range"),
- (assign, ":weight_range", ":weight_count"),
- (assign, ":chosen_action", ":slot_no"),
- (val_add, ":chosen_action", 1),
- (try_end),
- (assign, reg1, ":chosen_action"),
- ]),
- #清空权重
- ("agent_ai_weight_clear", [
- (store_script_param, ":total_num", 1),#录入数据的数量
- (try_for_range, ":slot_no", 0, ":total_num"),
- (troop_set_slot, "trp_temp_array_ai", ":slot_no", 0),
- (try_end),
- ]),
复制代码
这个系统的核心思想就是先把波士的可能行动都列出来,再把需要读取的条件都写一遍,像附图那样列一个excel,然后依次填入对应的权重。如果该条件促进该行动就加,反之就减,如果必不能做那就-1000(比如拿着远程不能近战攻击)。思路还是非常简单明了的。
不过,目前这个系统有个最大的问题是,会闪退。挺没道理的,我踏马连try for agent都省了,一共就两个人,模型也就是最朴素的那种,也没什么特别华丽的特效,怎么会闪退呢?怎么能给我闪退呢?请大佬们啃啃这个代码有没有什么问题?想当小白鼠的也可以自己用用看看,会不会出现同样的情况。
|