骑马与砍杀中文站论坛

用户名  找回密码
 注册(Register!)

QQ登录

只需一步,快速开始

帖子
购买CDKEY 衣谷三国
查看: 2731|回复: 10

[功能与代码] 【战团代码示例】AI拾取弹药的实现

[复制链接]

23

主题

339

回帖

299

积分

见习骑士

Rank: 3

UID
3189500
第纳尔
2709
精华
0
互助
26
荣誉
6
贡献
20
魅力
437
注册时间
2020-6-13
鲜花(68) 鸡蛋(0)
发表于 2023-8-4 22:35:36 | 显示全部楼层 |阅读模式
本帖最后由 武安apk43 于 2023-9-29 00:01 编辑

首先声明,这个代码需要理解其原理根据需要做修改,因为一些代码关联到我的mod一些其他功能模块。
起因:我想实现骑砍2里的AI拾取弹药功能,看到R大曾经开源过非玩家角色捡地上武器的战场触发器 - MOD制作资料区 - 骑马与砍杀中文站论坛 - Powered by Discuz! (mountblade.com.cn)
但是R大这个有很大局限性,只能拾取dead(避免触发敏感词审核)角色手里的武器,而无法拾取弹药类,更别说单支的弹药了,所以就研究出了这个方案。
结果:
该方案可以实现拾取包括死亡掉落的弹药和单支类弹药,理论上还可以扩展到所有生成类场景item。
下面提供示例代码,添加了一些注解,包含核心实现方法和性能优化方案,仅供参考:
(点击展开 / 收起)

(点击展开 / 收起)

(点击展开 / 收起)

进一步优化
1. dead掉落弹药和射出去的弹药分开计算,并且触发时间错开来;
2.、把所有弹药类item物品放在一起,native排除教程和训练用的,就可以在module_constants.py里定义ammo_begin = "itm_arrows",ammo_end = "itm_pilgrim_disguise",然后循环的时候只循环弹药区间即可



















评分

参与人数 1第纳尔 +10 魅力 +2 收起 理由
agjib + 10 + 2 您的帖子很有价值!

查看全部评分

鲜花鸡蛋

我的长枪依在  在2023-8-16 17:00  送朵鲜花  并说:我非常同意你的观点,送朵鲜花鼓励一下
ggfgfgf  在2023-8-6 15:58  送朵鲜花  并说:我非常同意你的观点,送朵鲜花鼓励一下
B站个人空间:https://b23.tv/rZhCYpH

46

主题

630

回帖

493

积分

骑士

Rank: 4Rank: 4

UID
3398051
第纳尔
1850
精华
0
互助
48
荣誉
5
贡献
10
魅力
341
注册时间
2022-8-13
鲜花(58) 鸡蛋(0)
发表于 2023-8-6 18:20:22 | 显示全部楼层
这个可以,不过恕我直言,这个教程有点模糊,实现这个跟搞逆向一样,没有WSE的真实,令人发指,不过还是非常感谢您分享,请问可以用在mod中么

23

主题

339

回帖

299

积分

见习骑士

Rank: 3

UID
3189500
第纳尔
2709
精华
0
互助
26
荣誉
6
贡献
20
魅力
437
注册时间
2020-6-13
鲜花(68) 鸡蛋(0)
 楼主| 发表于 2023-8-6 20:20:48 | 显示全部楼层
ggfgfgf 发表于 2023-8-6 18:20
这个可以,不过恕我直言,这个教程有点模糊,实现这个跟搞逆向一样,没有WSE的真实,令人发指,不过还是非 ...

我的代码除了一个break_loop,退出循环操作,其他都没用到wse的op

发这个出来就是分享给大家,随便用。不过我还是希望credit里有我
B站个人空间:https://b23.tv/rZhCYpH

23

主题

339

回帖

299

积分

见习骑士

Rank: 3

UID
3189500
第纳尔
2709
精华
0
互助
26
荣誉
6
贡献
20
魅力
437
注册时间
2020-6-13
鲜花(68) 鸡蛋(0)
 楼主| 发表于 2023-8-6 20:24:17 | 显示全部楼层
本帖最后由 武安apk43 于 2023-8-6 20:27 编辑
ggfgfgf 发表于 2023-8-6 18:20
这个可以,不过恕我直言,这个教程有点模糊,实现这个跟搞逆向一样,没有WSE的真实,令人发指,不过还是非 ...

最核心的就是scene_spawned_item_get_num_instances,scene_spawned_item_get_instance还有try_for_prop_instances时用到的somt_XXX,还有性能优化也是非常重要,因为有三层循环。
判断agent的装备部分全部在其他的ti触发器上计算,然后try_for_agents用坐标限定循环距离范围。分类讨论判断agent装备情况也是很关键的
B站个人空间:https://b23.tv/rZhCYpH

46

主题

630

回帖

493

积分

骑士

Rank: 4Rank: 4

UID
3398051
第纳尔
1850
精华
0
互助
48
荣誉
5
贡献
10
魅力
341
注册时间
2022-8-13
鲜花(58) 鸡蛋(0)
发表于 2023-8-7 14:28:20 | 显示全部楼层
斗胆献丑了,补充了下,不完美啊,性能还需拆分操作优化,我写一起,做个备忘script.py部分

#script_cf_item_is_missile
#return if item is missile
#INPUT: param1 = item_id
#OUTPUT: boolean
        ("cf_item_is_missile",
        [
                (store_script_param, ":item_id", 1),
                (assign, ":result",1),
                (try_begin),
                        (item_get_type, ":item_type", ":item_id"),
                        (neq,":item_type",itp_type_thrown),
                        (neq,":item_type",itp_type_arrows),
                        (neq,":item_type",itp_type_bolts),
                        (neq,":item_type",itp_type_bullets),
                        (assign, ":result",0),
                (try_end),
                (eq, ":result", 1),
        ]),       
       
#script_cf_agent_has_ammo
#return if agent has right ammo
#INPUT: param1 = agent_no
#OUTPUT: false = have space without ammo,true = have ammo
        ("cf_agent_has_ammo",
        [
                (store_script_param, ":agent_no", 1),
                (agent_get_slot, ":ranged_weapon", ":agent_no", slot_agent_ranged_weapon),
                (assign, ":result", 1),
                (try_for_range, ":item", 0, 4),
                        (agent_get_item_slot, ":item_id", ":agent_no", ":item"),
                        (try_begin),
                                (eq, ":item_id", -1),
                                (assign, ":result", 0),
                        (else_try),
                                (item_get_type, ":item_type", ":item_id"),
                                (item_slot_eq, ":ranged_weapon", slot_ranged_weapon_ammo_type, ":item_type"),
                                (assign, ":result", 1),
                        (try_end),
                (try_end),
                (eq, ":result", 1),
        ]),       


game_start添加
#Items:
        (try_for_range, ":item_id", all_items_begin, all_items_end),
                (item_get_type, ":item_type", ":item_id"),
                        (try_begin),
                                (eq, ":item_type", itp_type_bow),
                                (item_set_slot, ":item_id", slot_ranged_weapon_ammo_type, itp_type_arrows),
                        (else_try),
                                (eq, ":item_type", itp_type_crossbow),
                                (item_set_slot, ":item_id", slot_ranged_weapon_ammo_type, itp_type_bolts),
                        (else_try),
                                (eq, ":item_type", itp_type_thrown),
                                (item_set_slot, ":item_id", slot_ranged_weapon_ammo_type, itp_type_thrown),
                        (try_end),
        (try_end),
       
# Troops:


# Assign banners and renown.

costants.py添加红色(部分已位于文件中,方便搜索)
slot_item_multiplayer_item_class   = 60 #temporary, can be moved to higher values
slot_item_multiplayer_availability_linked_list_begin = 61 #temporary, can be moved to higher value


slot_ranged_weapon_ammo_type =62#0 for non-ranged weapons


########################################################
##  AGENT SLOTS            #############################
########################################################

........
slot_agent_ranged_weapon = 28


########################################################
##  FACTION SLOTS          #############################
########################################################


heard_common.py添加
#object types for "try_for_prop_instances" operation
somt_object = 1   # Scene props (Edit mode placement)
somt_entry = 2   # Entry points
somt_item = 3  # Scene items (Edit mode placement)
somt_baggage = 4 # Containers like boxes?
somt_flora = 5 # Plants (trees, rocks, ...)
somt_passage = 6 # Passages
somt_spawned_item = 7 # Spawned items (Player discarded)
somt_spawned_single_ammo_item = 8 # Spawned items (Ammunition spawns when hit)
somt_spawned_unsheathed_item = 9 #   Spawned items Other dead agent drops
somt_shield = 10 # shield
somt_temporary_object = 11 # temp



missson_templates.py添加
ai_pick_up_ammo = (
        3, 0, 0, [(neg|all_enemies_defeated),],
        [
        (try_for_range, ":item_id", all_items_begin, all_items_end),
                (call_script, "script_cf_item_is_missile", ":item_id"),
                (try_begin),
                        (scene_spawned_item_get_num_instances, ":instance_number", ":item_id"),
                        (gt, ":instance_number", 0),
                        (item_get_type, ":item_type", ":item_id"),
                        (try_for_range, ":index", 0, ":instance_number"),
                                (scene_spawned_item_get_instance, ":instance", ":item_id", ":index"),
                                (prop_instance_get_position, pos10, ":instance"),
                                (position_set_z_to_ground_level, pos10),
                (assign,":run",1),
                                (try_for_agents, ":agent_no", pos10, 300),
                                        (eq,":run",1),
                                        (agent_is_alive, ":agent_no"),
                                        (agent_is_human, ":agent_no"),
                                        (agent_get_slot, ":ranged_weapon", ":agent_no", slot_agent_ranged_weapon),
                                        (gt, ":ranged_weapon", 0),
                                        (agent_is_non_player, ":agent_no"),
                                        (agent_slot_eq, ":agent_no", slot_agent_is_running_away, 0),
                                        (agent_get_horse, ":horse", ":agent_no"),
                                        (eq, reg1, ":horse"),
                                        # (agent_get_combat_state, reg1, ":agent_no"),#
                                        # (neq, reg1, 3),
                                        # (neq, reg1, 4),
                                        # (agent_get_slot, ":ranged_weapon", ":agent_no", slot_agent_ranged_weapon),#
                                        (agent_get_ammo, ":ammo", ":agent_no", 0),
                                        (item_slot_eq, ":ranged_weapon", slot_ranged_weapon_ammo_type, ":item_type"),
                                        (try_begin),
                                                (eq, ":item_type", itp_type_thrown),
                                                (agent_get_troop_id, ":troop_no", ":agent_no"),
                                                (store_skill_level, ":troop_skl", "skl_power_throw", ":troop_no"),
                                                (item_get_difficulty, ":item_skl", ":item_id"),
                                                # (this_or_next|le, ":ammo", 2),
                                                (lt, ":troop_skl", ":item_skl"),
                                        (else_try),
                                                (agent_set_crouch_mode, ":agent_no", 1),
                                                (try_begin),
                                                        (call_script, "script_cf_agent_has_ammo", ":agent_no"),
                                                        (agent_refill_ammo, ":agent_no"),
                                                (else_try),
                                                        (agent_equip_item, ":agent_no", ":item_id"),
                                                (try_end),
                                                (scene_prop_set_prune_time, ":instance", 0),
                                                (assign,":run",0),
                                        (try_end),
                                (try_end),
                        (try_end),
                (try_end),
       
                (try_for_prop_instances, ":instance", ":item_id", somt_spawned_single_ammo_item),#
                        (prop_instance_is_valid, ":instance"),
                        (prop_instance_get_position, pos10, ":instance"),
                        (position_move_y, pos10, 50, 0),
                        (position_set_z_to_ground_level, pos10),
                        (assign,":run",1),
                        (try_for_agents, ":agent_no", pos10, 300),
                                (eq,":run",1),
                                (agent_is_alive, ":agent_no"),
                                (agent_is_human, ":agent_no"),
                                (agent_get_slot, ":ranged_weapon", ":agent_no", slot_agent_ranged_weapon),
                                (gt, ":ranged_weapon", 0),
                                (agent_is_non_player, ":agent_no"),
                                (agent_slot_eq, ":agent_no", slot_agent_is_running_away, 0),


                                (agent_get_horse, ":horse", ":agent_no"),
                                (eq, ":horse", -1),
                                # (agent_get_combat_state, reg1, ":agent_no"),
                                # (neq, reg1, 3),
                                # (neq, reg1, 4),
                               
                                # (agent_get_ammo, ":ammo", ":agent_no", 0),
                                # (le, ":ammo", 10),
                                (item_slot_eq, ":ranged_weapon", slot_ranged_weapon_ammo_type, ":item_type"),
                                (try_begin),
                                        (eq, ":item_type", itp_type_thrown),
                                        (agent_get_troop_id, ":troop_no", ":agent_no"),
                                        (store_skill_level, ":troop_skl", "skl_power_throw", ":troop_no"),
                                        (item_get_difficulty, ":item_skl", ":item_id"),
                                                        # (this_or_next|le, ":ammo", 2),
                                        (lt, ":troop_skl", ":item_skl"),
                                (else_try),
                                        (agent_set_crouch_mode, ":agent_no", 1),
                                        (try_begin),
                                                (call_script, "script_cf_agent_has_ammo", ":agent_no"),
                                                (val_add, ":ammo", 1),
                                                (agent_set_ammo, ":agent_no", ":item_id", ":ammo"),
                                        (else_try),
                                                (agent_equip_item, ":agent_no", ":item_id"),
                                                (agent_set_ammo, ":agent_no", ":item_id", 1),
                                        (try_end),
                                        (scene_prop_set_prune_time, ":instance", 0),
                                        (assign,":run",0),
                                (try_end),
                        (try_end),
                (try_end),
        (try_end),
        ])


free_order_begin = (ti_once, 0, 0, [],
       [
           (try_for_agents, ":agent"),#get agent_ranged_weapon
                   (agent_set_slot,":agent",slot_agent_ranged_weapon,0),
                   (agent_get_wielded_item, ":item_id", ":agent"),
                   (item_get_type, ":item_type", ":item_id"),
                   (try_begin),
                           (eq,":item_type",itp_type_thrown),
                           (agent_set_slot,":agent",slot_agent_ranged_weapon,":item_id"),
                   (else_try),
                           (eq,":item_type",itp_type_bow),
                           (agent_set_slot,":agent",slot_agent_ranged_weapon,":item_id"),
                   (else_try),
                           (eq,":item_type",itp_type_crossbow),
                           (agent_set_slot,":agent",slot_agent_ranged_weapon,":item_id"),
                   (try_end),
           (try_end),
           ])



23

主题

339

回帖

299

积分

见习骑士

Rank: 3

UID
3189500
第纳尔
2709
精华
0
互助
26
荣誉
6
贡献
20
魅力
437
注册时间
2020-6-13
鲜花(68) 鸡蛋(0)
 楼主| 发表于 2023-8-7 16:32:22 | 显示全部楼层
本帖最后由 武安apk43 于 2023-8-7 16:45 编辑
ggfgfgf 发表于 2023-8-7 14:28
斗胆献丑了,补充了下,不完美啊,性能还需拆分操作优化,我写一起,做个备忘script.py部分

#script_cf_ ...

我发现有几个问题哈:
1. call_script, "script_cf_agent_has_ammo"只有agent有对应弹药装备才通过,所以后面的(else_try)包含了没有额外装备栏的情况,这可能会导致agent替换原有装备。你可以看看我最新修改的,在前面添加了一句(agent_slot_ge, ":agent_no", slot_agent_has_ammo_item, 1);
2. 完全可以把两个判断写一起,比如你的可以这样改:

                  (agent_get_slot, ":ranged_weapon", ":agent_no", slot_agent_ranged_weapon),
                (assign, ":has_space", 0),
                (assign, ":result", 0),
                (try_for_range, ":item", 0, 4),
                        (agent_get_item_slot, ":item_id", ":agent_no", ":item"),
                        (try_begin),
                                (eq, ":item_id", -1),
                                (assign, ":has_space", 1),
                        (else_try),
                                (item_get_type, ":item_type", ":item_id"),
                                (item_slot_eq, ":ranged_weapon", slot_ranged_weapon_ammo_type, ":item_type"),
                                (assign, ":result", 1),
                        (try_end),
                (try_end),

                (try_begin),
                        (eq, ":result", 0),

                        (eq, ":has_space", 1),
                        (assign, ":result", 2),
                (try_begin),

这样判断":result"大于0就排除了没有额外装备栏的情况。

3.这个其实完全可以写到ti_on_item_wielded里,节省大量计算。因为本质上这个是判断agent是否有ammo类装备,而不是判断是否有弹药。而且几乎所有兵种都是带近战武器的,AI弹药耗尽会自动换武器,包括AI拾取新的弹药装备之后也会触发。所以我用的slot储存这两种情况,而不是调用脚本计算。还有你看我最后新补充了优化方案,也可以节省很多计算量

4.你把slot_agent_ranged_weapon写在ti_once里,有没有考虑过增援生成的agent?可以写在ti_on_agent_spawn或者ti_on_item_wielded里;

其实我之所以不给全我的代码,是因为我的把判断装备部分全都和自动分组系统写在一起了,ti_on_item_wielded,ti_on_item_unwielded,ti_on_agent_mount和ti_on_agent_dismount四个触发器调用脚本。不过也正是因为如此我不清楚ti_on_agent_spawn里判断装备是否有效,没测。因为有可能agent的状态并未更新,比如在ti_on_agent_dismount里判断agent是否有马,就会得到之前骑的马


还有你粗心的写错了,一次性触发应该是(0, 0, ti_once, 而不是(ti_once, 0, 0,






鲜花鸡蛋

ggfgfgf  在2023-8-7 19:57  送朵鲜花  并说:
ggfgfgf  在2023-8-7 19:57  送朵鲜花  并说:我非常同意你的观点,送朵鲜花鼓励一下
ggfgfgf  在2023-8-7 19:57  送朵鲜花  并说:我非常同意你的观点,送朵鲜花鼓励一下
B站个人空间:https://b23.tv/rZhCYpH

46

主题

630

回帖

493

积分

骑士

Rank: 4Rank: 4

UID
3398051
第纳尔
1850
精华
0
互助
48
荣誉
5
贡献
10
魅力
341
注册时间
2022-8-13
鲜花(58) 鸡蛋(0)
发表于 2023-8-7 20:07:28 | 显示全部楼层
本帖最后由 ggfgfgf 于 2023-8-7 20:37 编辑
武安apk43 发表于 2023-8-7 16:32
我发现有几个问题哈:
1. call_script, "script_cf_agent_has_ammo"只有agent有对应弹药装备才通过,所 ...

感谢大佬回复,我的mod修改了增援,没有增援,一次全上,所以不用担心,哈哈,您的mod我玩了,厉害,着色器很优秀
ti_on_item_wielded调用这个脚本把reg0赋值给slot
#script_cf_agent_has_ammo
#return if agent has right ammo to slot_agent_has_ammo_item
#INPUT: param1 = agent_no
#OUTPUT:reg0:1 = have ammo,2 = have space without ammo
        ("cf_agent_has_ammo",
        [
                (store_script_param, ":agent_no", 1),
                (agent_get_slot, ":ranged_weapon", ":agent_no", slot_agent_ranged_weapon),
        (assign, ":has_space", 0),
        (assign, ":result", 0),
        (try_for_range, ":item", 0, 4),
                        (agent_get_item_slot, ":item_id", ":agent_no", ":item"),
                        (try_begin),
                                (eq, ":item_id", -1),
                                (assign, ":has_space", 1),
                        (else_try),
                                (item_get_type, ":item_type", ":item_id"),
                                (item_slot_eq, ":ranged_weapon", slot_ranged_weapon_ammo_type, ":item_type"),
                                (assign, ":result", 1),
                        (try_end),
        (try_end),


        (try_begin),
            (eq, ":result", 0),
            (eq, ":has_space", 1),
            (assign, ":result", 2),
        (try_begin),
                (assign,reg0,":result"),
        ]),        



46

主题

630

回帖

493

积分

骑士

Rank: 4Rank: 4

UID
3398051
第纳尔
1850
精华
0
互助
48
荣誉
5
贡献
10
魅力
341
注册时间
2022-8-13
鲜花(58) 鸡蛋(0)
发表于 2023-8-7 23:00:44 | 显示全部楼层
武安apk43 发表于 2023-8-7 16:32
我发现有几个问题哈:
1. call_script, "script_cf_agent_has_ammo"只有agent有对应弹药装备才通过,所 ...

大佬能问您个问题么?很好奇您mod仿砍2可以穿过人群挤开队友的功能是怎么实现的?跟WSE有关吗,感谢

23

主题

339

回帖

299

积分

见习骑士

Rank: 3

UID
3189500
第纳尔
2709
精华
0
互助
26
荣誉
6
贡献
20
魅力
437
注册时间
2020-6-13
鲜花(68) 鸡蛋(0)
 楼主| 发表于 2023-8-8 00:08:36 | 显示全部楼层
本帖最后由 武安apk43 于 2023-8-8 00:34 编辑
ggfgfgf 发表于 2023-8-7 23:00
大佬能问您个问题么?很好奇您mod仿砍2可以穿过人群挤开队友的功能是怎么实现的?跟WSE有关吗,感谢


我其实是受TW官网一个帖子启发的,你可以看看,没有用WSE。https://forums.taleworlds.com/index.php?threads/pierce-through-multiple-enemies-in-a-line.458998/#post-9872322


不好意思看错了,我以为你说的武器贯穿。那个挤过友军的实际原理很简单,就是以玩家为中心循环附近的agent,然后分类讨论各种情况,通过set position 让AI移动而已,有点用,但也不是非常有效果

鲜花鸡蛋

ggfgfgf  在2023-8-8 11:16  送朵鲜花  并说:我非常同意你的观点,送朵鲜花鼓励一下
B站个人空间:https://b23.tv/rZhCYpH

23

主题

339

回帖

299

积分

见习骑士

Rank: 3

UID
3189500
第纳尔
2709
精华
0
互助
26
荣誉
6
贡献
20
魅力
437
注册时间
2020-6-13
鲜花(68) 鸡蛋(0)
 楼主| 发表于 2023-9-20 18:27:48 | 显示全部楼层
补充一个:
(try_for_agents, <agent_no>[, <position_no>, <radius_fixed_point>]),, 这里的半径是浮点数,所以必须得set_fixed_point_multiplier
B站个人空间:https://b23.tv/rZhCYpH

23

主题

339

回帖

299

积分

见习骑士

Rank: 3

UID
3189500
第纳尔
2709
精华
0
互助
26
荣誉
6
贡献
20
魅力
437
注册时间
2020-6-13
鲜花(68) 鸡蛋(0)
 楼主| 发表于 2023-9-28 23:48:29 | 显示全部楼层
本帖最后由 武安apk43 于 2023-9-29 00:01 编辑

(try_for_agents, ":agent_no", pos10, 300),这里的半径是浮点数,所以必须得set_fixed_point_multiplier,WSE2和战团本体定点数在这里是不一样的
比如设置
定点数为1000,WSE2这里的范围单位就是CM,而战团这里的范围单位就是1/1000米
B站个人空间:https://b23.tv/rZhCYpH
您需要登录后才可以回帖 登录 | 注册(Register!)

本版积分规则

Archiver|手机版|小黑屋|骑马与砍杀中文站

GMT+8, 2025-3-29 11:54 , Processed in 0.114771 second(s), 22 queries , Gzip On, MemCached On.

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表