• Please note that we've updated the Mount & Blade II: Bannerlord save file system which requires you to take certain steps in order for your save files to be compatible with e1.7.1 and any later updates. You can find the instructions here.

OSP Code Combat Leviathan Axe (from God of War) [WSE]

Users who are viewing this thread

Yagababa

Recruit
Hey everyone, I'm very proud to announce my new OSP--my attempt at recreating the Leviathan Axe from God of War!

The idea is to have a two-handed battle axe that can be used as a throwing weapon with the following features:
1. Melee cuts and a ranged splash AOE will cause a 'frost' status effect that slows down any enemies affected
2. After thrown, the axe can be called back to your hand by pressing the 'F' key
3. An enemy hit directly by a throw will be frozen in place, until hit by another attack or the axe is recalled
4. They'll take huge damage when shattered (w/ a nice particle effect)

Here's a quick demonstration:

Before I get into it, I should warn you the code to make this happen is pretty involved, and requires a fair amount of experience with the module system, as well as WSE to function. With that out of the way, let's make this happen!

First thing's first, we'll have to choose a mesh for the axe. Here's some example meshes, particles, and textures you can use as placeholders, I'm not really sure where I found them so I cannot take credit for any of those resources (except for the ice shard).

Speaking of particles, let's tackle those first--at the end of module_particle_systems (before the last ']'), add the following:
Python:
    # Axe Begin
    ("frost_emit", psf_billboard_3d|psf_global_emit_dir|psf_always_emit|psf_randomize_size,  "snowflake",
     30, 1.5, 0.1, 0.01, 2.0, 1,
     (0, 1), (1.5, 0),
     (0, 0.65), (1.5, 0.85),
     (0, 0.65), (1.5, 0.85),
     (0, 0.9), (1.5, 0.9),
     (0, 0.05), (1.5, 0),
     (0.5, 0.5, 0.5),
     (0, 0, 0),
     0.1,
     0,
     0,
    ),

    ("frost_axe_emit", psf_billboard_3d|psf_global_emit_dir|psf_always_emit|psf_randomize_size,  "snowflake",
     30, 1.5, 0.1, 0.01, 2.0, 1,
     (0, 0.8), (1.5, 0),
     (0, 0.65), (1.5, 0.85),
     (0, 0.65), (1.5, 0.85),
     (0, 0.9), (1.5, 0.9),
     (0, 0.025), (1.5, 0),
     (0.15, 0.15, 0.05),
     (0, 0, 0),
     0.002,
     0,
     0,
    ),

    ("frost_burst", psf_billboard_3d|psf_global_emit_dir|psf_always_emit|psf_randomize_size,  "snowflake",
     500, 1.5, 0.5, 0.2, 2.0, 1,
     (0, 1), (1.5, 0),
     (0, 0.65), (1.5, 0.85),
     (0, 0.65), (1.5, 0.85),
     (0, 0.9), (1.5, 0.9),
     (0, 0.05), (1.5, 0),
     (0.05, 0.05, 0.05),
     (0, 0, 1),
     1.5,
     0,
     0,
    ),

    ("ice_burst", psf_billboard_3d|psf_global_emit_dir|psf_always_emit|psf_randomize_size|psf_randomize_rotation,  "ice_shard",
     100, 1, 0.1, 0.5, 2.0, 1,
     (0, 1), (1, 0),
     (0, 0.9), (1, 0.9),
     (0, 0.9), (1, 0.9),
     (0, 0.9), (1, 0.9),
     (0, 0.2), (1, 0),
     (0.5, 0.5, 1.5),
     (0, 0, 0.5),
     0.5,
     0,
     0,
    ),
Just make sure to replace "snowflake" and "ice_shard" with whatever particle meshes you end up using. Those are just what I named mine, and you'll find them in the BRF linked above.

Okay next we'll define way too many constants. In module_constants, find the list of player slots (they should all start with slot_player_...). Add this at the end:
Python:
slot_player_axe_state = 53
And make sure to replace '53' with +1 whatever the last existing slot is (it might not be the same as mine). Next find the agent slots (slot_agent_...), and add these:
Python:
slot_agent_frozen = 35
slot_agent_freezer = 36

slot_agent_frosted = 37
slot_agent_frost_timer = 38
slot_agent_frost_bone = 39

slot_thrown_axe = 40
slot_axe_x = 41
slot_axe_y = 42
slot_axe_z = 43
slot_frozen_target = 44
Adjust the values similar to before to avoid overwriting old slots.

Then, go to header_common and find the list of server events (ctrl + F "server events" should find it. It's a list of lines that start with multiplayer_event_...). At the end of server events and before message types, add two new events:
Python:
multiplayer_event_axe_update = 120
multiplayer_event_play_animation = 121
Again, adjust the values. And that should be it for constants!

Let's head over to module_animations next and create a couple new ones. We'll need an animation for calling back the axe/catching it, and an animation for frozen enemies/horses. First, find the list of unused human animations, and replace the first two available ones with the following:
Python:
 ["call_axe", 0, amf_priority_striked|amf_play,
 [0.5, "attacks_single_righttoleft", 2, 5, arf_blend_in_0],],

 ["freeze", acf_enforce_all|acf_align_with_ground|acf_lock_rotation, amf_priority_die|amf_accurate_body|amf_play|amf_client_prediction,
 [0.5, "strikes_back", 405, 406, arf_blend_in_0],],

 ["unused_human_anim_46", ...
Then go to the unused horse animations and add this:
Python:
 ["horse_freeze", acf_enforce_all|acf_lock_rotation|acf_align_with_ground,  amf_priority_die|amf_accurate_body|amf_play|amf_client_prediction,
   [0.5, "anim_horse", 62, 63,  arf_blend_in_0],],
 
 ["unused_horse_anim_2", ...

Alright, next let's go to module_items and add our new axe:
Python:
["great_silver_axe", "Great Silver Axe", [("axe_ornate",0)], itp_type_thrown|itp_primary|itp_next_item_as_melee, itcf_throw_axe, 0, weight(2)|difficulty(0)|spd_rtng(80)|shoot_speed(18)|thrust_damage(0, cut)|max_ammo(1)|weapon_length(85), 0,
[(ti_on_init_item, [
    (set_position_delta, 20, 70, 0),
    (particle_system_add_new, "psys_frost_axe_emit"),
]),
(ti_on_missile_hit, [
    (try_begin),
        (multiplayer_is_server),
        (missile_remove_on_hit),
        (store_trigger_param_1, ":owner"),
        (set_spawn_position, pos1),
        (spawn_item, "itm_great_silver_axe", 0, 999),
        (position_rotate_x, pos1, -30, 0),
        (position_rotate_y, pos1, 90, 0),
        (set_position_delta, 0, -100, 0),
        (prop_instance_set_position, reg0, pos1, 0),
        (agent_set_slot, ":owner", slot_thrown_axe, reg0),
        (agent_unequip_item, ":owner", "itm_great_silver_axe"),

        (agent_get_player_id, ":player", ":owner"),
        (player_set_slot, ":player", slot_player_axe_state, 1),
        (multiplayer_send_int_to_player, ":player", multiplayer_event_axe_update, 1),

        # Frost AOE
        (particle_system_burst, "psys_frost_burst", pos1, 100),
        (agent_get_team, ":owner_team", ":owner"),
        (try_for_agents,":agent"),
          (agent_is_alive,":agent"),
          (neq, ":agent", ":owner"),
          (agent_get_team,":team", ":agent"),
          (neq,":team",":owner_team"),
          (agent_get_position, pos2, ":agent"),
          (get_distance_between_positions, ":dist", pos1, pos2),
          (lt, ":dist", 1000),
          (agent_set_slot, ":agent", slot_agent_frosted, 1),
          (agent_set_slot, ":agent", slot_agent_frost_timer, 10),
          (agent_set_slot, ":agent", slot_agent_frost_bone, hb_thorax),
        (try_end),
    (try_end),
]),
]],
["great_silver_axe_melee", "Great Silver Axe", [("axe_ornate",0)], itp_type_two_handed_wpn|itp_two_handed|itp_primary|itp_bonus_against_shield|itp_wooden_parry|itp_cant_use_on_horseback|itp_unbalanced|itp_crush_through, itc_nodachi|itcf_carry_spear, 100, weight(2)|difficulty(0)|spd_rtng(96)|weapon_length(85)|swing_damage(40, cut)|thrust_damage(0, pierce), 0,
[(ti_on_init_item, [
    (set_position_delta, 20, 70, 0),
    (particle_system_add_new, "psys_frost_axe_emit"),
]),
]],
["SHATTER", "SHATTER", [("bullet", 0)], itp_crush_through|itp_type_two_handed_wpn|itp_primary|itp_wooden_parry|itp_unbalanced, itc_morningstar|itcf_carry_mace_left_hip, 0, weight(0)|difficulty(0)|spd_rtng(0)|weapon_length(0)|swing_damage(0, pierce)|thrust_damage(0, pierce), 0],
The "SHATTER" item is what we'll use to deliver the shattering damage later. Similar to in my Soulfire Arrows OSP, you should make this a weapon type you don't currently use in your mod. I don't have any morningstars, so I went with that. The reason this is important is that we'll replace the multiplayer kill feed icon with a new frosty one for that particular weapon--you can find my example in the textures folder linked above (mp_icon_fight.dds).

Now let's go to module_scripts and add a new script anywhere you feel like:
Python:
    ("play_universal_animation", [
        (store_script_param, ":agent", 1),
        (store_script_param, ":animation", 2),
        (store_script_param, ":body_part", 3),
        (store_script_param, ":progress", 4),

        (agent_set_animation, ":agent", ":animation", ":body_part"),
        (agent_set_animation_progress, ":agent", ":progress", ":body_part"),

        (server_get_max_num_players, ":max_players"),
        (try_for_range, ":player", 0, ":max_players"),
            (player_is_active, ":player"),
            (multiplayer_send_4_int_to_player, ":player", multiplayer_event_play_animation, ":agent", ":animation", ":body_part", ":progress"),
        (try_end),

    ]),
This is crucial for synching animations across the server/clients for multiplayer. Gotta say, getting this to work in multiplayer was a nightmare.

Still in module_scripts, find the script "game_receive_network_message", and add these new entries to the try block:
Python:
game_receive_network_message",
    [
      (store_script_param, ":player_no", 1),
      (store_script_param, ":event_type", 2),

      (try_begin),
      # ANIMATION
        (eq, ":event_type", multiplayer_event_play_animation),
        (store_script_param, ":agent", 3),
        (store_script_param, ":animation", 4),
        (store_script_param, ":body_part", 5),
        (store_script_param, ":progress", 6),

        (agent_set_animation, ":agent", ":animation", ":body_part"),
        (agent_set_animation_progress, ":agent", ":progress", ":body_part"),
      (else_try),
      # GREAT SILVER AXE
        (eq, ":event_type", multiplayer_event_axe_update),
        (store_script_param, ":axe_state", 3),
        (try_begin),
            (neg|multiplayer_is_server),
            (multiplayer_get_my_player, ":player"),
            (player_set_slot, ":player", slot_player_axe_state, ":axe_state"),
        (else_try),
            (multiplayer_is_server),
            (player_set_slot, ":player_no", slot_player_axe_state, ":axe_state"),
            (try_begin),
                (player_get_slot, ":axe_state", ":player_no", slot_player_axe_state),
                (eq, ":axe_state", 2),

                # !!! ANIMATION
                (player_get_agent_id, ":agent", ":player_no"),
                (agent_get_animation, ":anim", ":agent", 1),
                (try_begin),
                    (neg|eq, ":anim", "anim_call_axe"),
                    (call_script, "script_play_universal_animation", ":agent", "anim_call_axe", 1, 0),
                (try_end),

                (agent_get_slot, ":frozen_target", ":agent", slot_frozen_target),
                (try_begin),
                    (gt, ":frozen_target", 0),
                    (agent_set_slot, ":frozen_target", slot_agent_frozen, 0),
                    (agent_get_position, pos1, ":frozen_target"),
                    (particle_system_burst, "psys_ice_burst", pos1, 50),
                    (agent_deliver_damage_to_agent, ":agent", ":frozen_target", 100, "itm_SHATTER"),
                (try_end),
                (agent_set_slot, ":agent", slot_frozen_target, -1),

                (agent_get_slot, ":axe", ":agent", slot_thrown_axe),
                (prop_instance_get_position, pos1, ":axe"),

                (scene_prop_set_prune_time, ":axe", 0),
                (position_get_x, ":x", pos1),
                (position_get_y, ":y", pos1),
                (position_get_z, ":z", pos1),
                (agent_set_slot, ":agent", slot_axe_x, ":x"),
                (agent_set_slot, ":agent", slot_axe_y, ":y"),
                (agent_set_slot, ":agent", slot_axe_z, ":z"),
                (agent_set_slot, ":agent", slot_thrown_axe, -2),

                (particle_system_burst, "psys_frost_burst", pos1, 100),

                (player_set_slot, ":player_no", slot_player_axe_state, 3),
                (multiplayer_send_int_to_player, ":player_no", multiplayer_event_axe_update, 3),
            (try_end),
        (try_end),
        ###############
        #SERVER EVENTS#
        ###############
      (else_try),
        (eq, ":event_type", multiplayer_event_set_item_selection), ...

And finally, module_mission_templates. This file has bulk of the code, so worst for last as they say. At the top of the file, we'll define a couple new triggers:
Python:
hit_checks = (ti_on_agent_hit, 0, 0, [(multiplayer_is_server),],
[
    (store_trigger_param_1, ":agent_no"),
    (store_trigger_param_2, ":attacker_no"),

    # Initiate frost
    (try_begin),
        (eq, reg0, "itm_great_silver_axe_melee"),
        (agent_set_slot, ":agent_no", slot_agent_frosted, 1),
        (agent_set_slot, ":agent_no", slot_agent_frost_timer, 10),
        (store_trigger_param, ":hit_bone", 4),
        (agent_set_slot, ":agent_no", slot_agent_frost_bone, ":hit_bone"),
    (try_end),

    # Freeze
    (agent_get_slot, ":is_frozen", ":agent_no", slot_agent_frozen),
    (try_begin),
        (eq, reg0, "itm_great_silver_axe"),
        (eq, ":is_frozen", 0),

        # If mounted, freeze horse instead
        (agent_get_horse, ":horse", ":agent_no"),
        (try_begin),
            (neq, ":horse", -1),
            (agent_get_slot, ":horse_is_frozen", ":horse", slot_agent_frozen),
            (eq, ":horse_is_frozen", 0),
            (assign, ":agent_no", ":horse"),
        (try_end),

        (agent_set_slot, ":agent_no", slot_agent_frozen, 1),
        (agent_set_slot, ":agent_no", slot_agent_freezer, ":attacker_no"),
        (agent_set_slot, ":attacker_no", slot_frozen_target, ":agent_no"),
    (else_try),
        # If they are already frozen, shatter them...
        (eq, ":is_frozen", 1),
        (agent_set_slot, ":agent_no", slot_agent_frozen, 0),
        (agent_get_slot, ":freezer", ":agent_no", slot_agent_freezer),
        (agent_deliver_damage_to_agent, ":freezer", ":agent_no", 100, "itm_SHATTER"),
        (agent_get_position, pos2, ":agent_no"),
        (particle_system_burst, "psys_ice_burst", pos2, 50),

        # Return axe
        (agent_get_slot, ":axe", ":freezer", slot_thrown_axe),
        (prop_instance_get_position, pos2, ":axe"),
        (scene_prop_set_prune_time, ":axe", 0),
        (position_get_x, ":x", pos2),
        (position_get_y, ":y", pos2),
        (position_get_z, ":z", pos2),
        (agent_set_slot, ":freezer", slot_axe_x, ":x"),
        (agent_set_slot, ":freezer", slot_axe_y, ":y"),
        (agent_set_slot, ":freezer", slot_axe_z, ":z"),
        (agent_set_slot, ":freezer", slot_thrown_axe, -2),

        (particle_system_burst, "psys_frost_burst", pos1, 100),

        (agent_get_player_id, ":player", ":freezer"),
        (call_script, "script_game_receive_network_message", ":player", multiplayer_event_axe_update, 2),
        (multiplayer_send_int_to_player, ":player", multiplayer_event_axe_update, 2),
    (try_end),
])

block_checks = (ti_on_agent_blocked, 0, 0, [(multiplayer_is_server),],
[
    (store_trigger_param_1, ":agent_no"),
    (store_trigger_param_2, ":attacker_no"),
    (store_trigger_param_3, ":weapon"),
    (store_trigger_param, ":missile", 4),

    # Freeze
    (agent_get_slot, ":is_frozen", ":agent_no", slot_agent_frozen),
    (try_begin),
        (this_or_next|eq, ":weapon", "itm_great_silver_axe"),
        (eq, ":missile", "itm_great_silver_axe"),
        (eq, ":is_frozen", 0),

        # If mounted, freeze horse instead
        (agent_get_horse, ":horse", ":agent_no"),
        (try_begin),
            (neq, ":horse", -1),
            (agent_get_slot, ":horse_is_frozen", ":horse", slot_agent_frozen),
            (eq, ":horse_is_frozen", 0),
            (assign, ":agent_no", ":horse"),
        (try_end),

        (agent_set_slot, ":agent_no", slot_agent_frozen, 1),
        (agent_set_slot, ":agent_no", slot_agent_freezer, ":attacker_no"),
        (agent_set_slot, ":attacker_no", slot_frozen_target, ":agent_no"),
    (else_try),
        # If they are already frozen, shatter them...
        (eq, ":is_frozen", 1),
        (agent_set_slot, ":agent_no", slot_agent_frozen, 0),
        (agent_get_slot, ":freezer", ":agent_no", slot_agent_freezer),
        (agent_deliver_damage_to_agent, ":freezer", ":agent_no", 100, "itm_SHATTER"),
        (agent_get_position, pos2, ":agent_no"),
        (particle_system_burst, "psys_ice_burst", pos2, 50),

        # Return axe
        (agent_get_slot, ":axe", ":freezer", slot_thrown_axe),
        (prop_instance_get_position, pos2, ":axe"),
        (scene_prop_set_prune_time, ":axe", 0),
        (position_get_x, ":x", pos2),
        (position_get_y, ":y", pos2),
        (position_get_z, ":z", pos2),
        (agent_set_slot, ":freezer", slot_axe_x, ":x"),
        (agent_set_slot, ":freezer", slot_axe_y, ":y"),
        (agent_set_slot, ":freezer", slot_axe_z, ":z"),
        (agent_set_slot, ":freezer", slot_thrown_axe, -2),

        (particle_system_burst, "psys_frost_burst", pos1, 100),

        (agent_get_player_id, ":player", ":freezer"),
        (call_script, "script_game_receive_network_message", ":player", multiplayer_event_axe_update, 2),
        (multiplayer_send_int_to_player, ":player", multiplayer_event_axe_update, 2),
    (try_end),
])

apply_status_effects = (1, 0, 0, [(multiplayer_is_server),],
[
    (try_for_agents, ":cur_agent"),
        (agent_get_slot, ":frosted", ":cur_agent", slot_agent_frosted),
        (eq, ":frosted", 1),

        # Apply frost speed penalty
        (try_begin),
            (eq, ":frosted", 1),
            (agent_get_slot, ":frost_timer", ":cur_agent", slot_agent_frost_timer),
            (gt, ":frost_timer", 0),
            (val_sub, ":frost_timer", 1),
            (agent_set_slot, ":cur_agent", slot_agent_frost_timer, ":frost_timer"),
            (agent_set_speed_modifier, ":cur_agent", 60),
        (else_try),
            (agent_set_speed_modifier, ":cur_agent", 100),
            (agent_set_slot, ":cur_agent", slot_agent_frosted, 0),
        (try_end),
    (try_end),
])

add_status_effect_particles = (0.25, 0, 0, [(multiplayer_is_server),], [
(try_for_agents, ":cur_agent"),
    (agent_is_alive, ":cur_agent"),
    (agent_is_active, ":cur_agent"),
    (agent_get_slot, ":frosted", ":cur_agent", slot_agent_frosted),
    (eq, ":frosted", 1),
    (try_begin),
        (eq, ":frosted", 1),
        (agent_get_slot, ":bone_no", ":cur_agent", slot_agent_frost_bone),
        (agent_get_bone_position, pos2, ":cur_agent", ":bone_no", 1),
        (particle_system_burst, "psys_frost_emit", pos2, 45),
    (try_end),
(try_end),
])

freeze = (0, 0, 0, [(multiplayer_is_server),],
[
(try_for_agents, ":cur_agent"),
    (agent_get_slot, ":frozen_check", ":cur_agent", slot_agent_frozen),
    (eq, ":frozen_check", 1),
    (agent_set_slot, ":cur_agent", slot_agent_frosted, 1),
    (agent_set_slot, ":cur_agent", slot_agent_frost_timer, 10),

    # Lock animation
    (try_begin),
        (agent_is_human, ":cur_agent"),
        (call_script, "script_play_universal_animation", ":cur_agent", "anim_freeze", 0, 0),
    (else_try),
        (call_script, "script_play_universal_animation", ":cur_agent", "anim_horse_freeze", 0, 0),
    (try_end),
(try_end),
])

# Call back axe (client side)
recall_axe = (0, 0, 0, [
    (game_key_is_down, gk_action),
    (multiplayer_get_my_player, ":player"),
    (player_slot_eq, ":player", slot_player_axe_state, 1),
    (player_get_agent_id, ":agent", ":player"),
    (neq, ":agent", -1),
    (agent_is_active, ":agent"),
    (agent_is_alive, ":agent"),
    (assign, ":count", 0),
    (try_for_range, ":cur", ek_item_0, ek_head),
        (agent_get_item_slot, ":iid", ":agent", ":cur"),
        (this_or_next|eq, ":iid", "itm_great_silver_axe"),
        (eq, ":iid", "itm_great_silver_axe_melee"),
        (val_add, ":count", 1),
        (player_set_slot, ":player", slot_player_axe_state, 0),
        (multiplayer_send_int_to_server, multiplayer_event_axe_update, 0),
    (try_end),
    (lt, ":count", 1),
],
[
    (multiplayer_get_my_player, ":player"),
    (player_set_slot, ":player", slot_player_axe_state, 2),
    (multiplayer_send_int_to_server, multiplayer_event_axe_update, 2),
])

# Axe has been called back, this handles the returning axe
axe_return = (0.1, 0, 0, [
    (multiplayer_is_server),
    (server_get_max_num_players, ":max_players"),
    (assign, ":check", 0),
    (try_for_range, ":player", 0, ":max_players"),
        (player_is_active, ":player"),
        (player_get_slot, ":axe_state", ":player", slot_player_axe_state),
        (eq, ":axe_state", 3),
        (assign, ":check", 1),

        (player_get_agent_id, ":agent", ":player"),
        (neq, ":agent", -1),
        (agent_is_active, ":agent"),
        (agent_is_alive, ":agent"),
        (try_for_range, ":cur", ek_item_0, ek_head),
            (agent_get_item_slot, ":iid", ":agent", ":cur"),
            (this_or_next|eq, ":iid", "itm_great_silver_axe"),
            (eq, ":iid", "itm_great_silver_axe_melee"),
            (player_set_slot, ":player", slot_player_axe_state, 0),
            (multiplayer_send_int_to_server, multiplayer_event_axe_update, 0),
        (try_end),
    (try_end),
    (eq, ":check", 1),
],
[
    (server_get_max_num_players, ":max_players"),
    (try_for_range, ":player", 0, ":max_players"),
        (player_is_active, ":player"),
        (player_get_slot, ":axe_state", ":player", slot_player_axe_state),
        (eq, ":axe_state", 3),

        # Get axe location
        (player_get_agent_id, ":agent", ":player"),
        (agent_get_slot, ":x", ":agent", slot_axe_x),
        (agent_get_slot, ":y", ":agent", slot_axe_y),
        (agent_get_slot, ":z", ":agent", slot_axe_z),
        (position_set_x, pos1, ":x"),
        (position_set_y, pos1, ":y"),
        (position_set_z, pos1, ":z"),

        # Add frost to catching hand
        (agent_get_bone_position, pos0, ":agent", hb_hand_r, 1),
        (particle_system_burst, "psys_frost_axe_emit", pos0, 2),


        (get_distance_between_positions, ":length", pos1, pos0),

        # Axe is close, drop current weapon and get ready to catch it
        (try_begin),
            (lt, ":length", 800),
            (agent_get_wielded_item, ":item", ":agent"),
            (try_begin),
                (neg|eq, ":item", -1),
                (agent_unequip_item, ":agent", ":item"),
                (agent_get_position, pos2, ":agent"),
                (position_set_z_to_ground_level, pos2),
                (set_spawn_position, pos2),
                (spawn_item, ":item", 0, 120),
            (try_end),
            # !!! ANIMATION
            (agent_get_animation, ":anim", ":agent", 1),
            (neg|eq, ":anim", "anim_call_axe"),
            #(agent_set_animation, ":agent", "anim_call_axe", 1),
            (call_script, "script_play_universal_animation", ":agent", "anim_call_axe", 1, 0),
        (try_end),


        # Catch Axe
        (try_begin),
            (lt, ":length", 200),
            (agent_set_slot, ":agent", slot_thrown_axe, -1),
            (agent_equip_item, ":agent", "itm_great_silver_axe"),
            (agent_set_wielded_item, ":agent", "itm_great_silver_axe"),

            # !!! ANIMATION
            #(agent_set_animation, ":agent", "anim_call_axe", 1),
            (call_script, "script_play_universal_animation", ":agent", "anim_call_axe", 1, 1),

            (particle_system_burst, "psys_frost_burst", pos0, 100),

            (player_set_slot, ":player", slot_player_axe_state, 0),
            (multiplayer_send_int_to_player, ":player", multiplayer_event_axe_update, 0),
        (else_try),
            # Fly axe closer to owner
            # Get Displacement
            (position_get_x, ":x_target", pos0),
            (position_get_y, ":y_target", pos0),
            (position_get_z, ":z_target", pos0),
            (val_sub, ":x_target", ":x"),
            (val_sub, ":y_target", ":y"),
            (val_sub, ":z_target", ":z"),

            # Scale Displacements
            (val_mul, ":x_target", 150),
            (val_mul, ":y_target", 150),
            (val_mul, ":z_target", 150),
            (val_div, ":x_target", ":length"),
            (val_div, ":y_target", ":length"),
            (val_div, ":z_target", ":length"),

            # Move 'axe'
            (position_move_x, pos1, ":x_target", 1),
            (position_move_y, pos1, ":y_target", 1),
            (position_move_z, pos1, ":z_target", 1),

            # Update position for next pass
            (position_get_x, ":x", pos1),
            (agent_set_slot, ":agent", slot_axe_x, ":x"),
            (position_get_y, ":y", pos1),
            (agent_set_slot, ":agent", slot_axe_y, ":y"),
            (position_get_z, ":z", pos1),
            (agent_set_slot, ":agent", slot_axe_z, ":z"),

            # Add particle burst
            (particle_system_burst, "psys_frost_axe_emit", pos1, 20),
        (try_end),
    (try_end),
])

Alright, now all that's left is to call these in the appropriate mission templates like so:
Python:
        ...

        hit_checks,
        block_checks,

        apply_status_effects,
        add_status_effect_particles,

        recall_axe,
        axe_return,
        freeze,
        ]
  ),
]

Wait I lied--all that's left is to find/make a ti_on_agent_spawn in the appropriate mission template that resets these slots:
Python:
            (agent_set_slot, ":agent_no", slot_agent_frozen, 0),
            (agent_set_slot, ":agent_no", slot_agent_frosted, 0),
            (agent_set_slot, ":agent_no", slot_thrown_axe, 0),
            (agent_get_player_id, ":player", ":agent_no"),
            (try_begin),
                (gt, ":player", -1),
                (player_set_slot, ":player", slot_player_axe_state, 0),
                (multiplayer_send_int_to_player, ":player", multiplayer_event_axe_update, 0),
            (try_end),
Not sure if it's totally necessary, but it can't hurt.

And that should be it! There's a lot of working parts here so if you're having trouble getting anything to work, feel free to post on this thread or message me. This weapon is probably too broken for PvP, but I designed it for Captain Coop/Invasion mode and it's a blast to play with; I highly recommend trying it out.

Also, if anyone is interested in a single player version for their mod, lmk and I could make it happen.
 
Last edited:
Thank you for yet another great OSP! I am also curious to see the bundle in action, so could you please share the video with us on another platform? MediaFire only allows to download the file, which is kind of not needed by me.
 

Yagababa

Recruit
Thank you for yet another great OSP! I am also curious to see the bundle in action, so could you please share the video with us on another platform? MediaFire only allows to download the file, which is kind of not needed by me.
Pretty impressive, nice work! Do you have a gameplay video showing it in action?
Just uploaded the video to YouTube for convenience--should be embedded in the original post now.
 
Top Bottom