OSP Code Combat Universal Multishot Trigger

Users who are viewing this thread

Yes it was done before and yes I'm still posting this, you are right. Now let's get to the business. This version of multishot uses the same direction as your crosshair does, as it uses the default weapon origin position returned by attack trigger. Moreover, this version does not require you to set ANYTHING except the amount of additional missiles and their scatter range. You can copy-paste it as it is under any ranged weapon and it will automatically:
1) find what ammo you are currently using
2) add more instances of it with the same speed but not the same position on the line (so first missiles break the enemy shield and next ones actually do damage), the interval between positions is insignificant but it's enough for its purpose
3) reduce your ammo after each shot by the exact same amount as the number of missiles fired, to create the feeling of multishot and preserve the balance

Here is the code with explanations. This trigger is added to module_items.py (use the torch trigger for reference on how many brackets to set)

Code:
(ti_on_weapon_attack,

    (store_trigger_param_1, ":agent_no"),  # automatically take the agent for add_missile
    (set_fixed_point_multiplier, 1), # this is essential for missile speed, but it aslo increases difference in scatter range

    (agent_get_wielded_item, ":weapon", ":agent_no", 0),  # automatically take the weapon for add_missile
    (item_get_type, ":w_type", ":weapon"),
    (item_get_missile_speed, ":speed", ":weapon"),   # automatically take the speed for add_missile
    (assign, ":allow", 0),
    (assign, ":continue", 1),
    (assign, ":num_missiles", 5),  # the number you set here determines both the num of missiles and the ammount of ammo taken each time
    (try_for_range, ":slot", 0, 4), # automatically take the current ammo for add_missile
      (neq, ":continue", 0),
      (agent_get_item_slot, ":item_in_slot", ":agent_no", ":slot"),
      (neq, ":item_in_slot", -1),
      (item_get_type, ":m_type", ":item_in_slot"),
      (try_begin),
        (eq, ":w_type", itp_type_bow),
        (neq, ":item_in_slot", ":weapon"),
        (eq, ":m_type", itp_type_arrows), 
        (agent_get_ammo_for_slot, ":c_ammo", ":agent_no", ":slot"),
        (neq, ":c_ammo", 0),
        (assign, ":total_ammo_amount", ":c_ammo"),
        (assign, ":ammo", ":item_in_slot"),
        (assign, ":ammo_slot", ":slot"),         
        (assign, ":continue", 0),          
      (else_try),
        (eq, ":w_type", itp_type_crossbow),
        (neq, ":item_in_slot", ":weapon"),
        (eq, ":m_type", itp_type_bolts),      
        (agent_get_ammo_for_slot, ":c_ammo", ":agent_no", ":slot"),       
        (try_begin),
          (neq, ":c_ammo", 0),
          (assign, ":allow", 1),
        (else_try),
          (assign, ":num_quivers", 1),
          (try_for_range, ":s", 0, 4),
            (agent_get_item_slot, ":item", ":agent_no", ":s"),
            (neq, ":item", -1),
            (neq, ":item", ":item_in_slot"),
            (item_get_type, ":i_type", ":item"),
            (eq, ":i_type", itp_type_bolts),
            (val_add, ":num_quivers", 1),
          (try_end),
          (eq, ":num_quivers", 1),         
          (assign, ":allow", 1),          
        (try_end),
        (eq, ":allow", 1),
        (assign, ":total_ammo_amount", ":c_ammo"), 
        (assign, ":ammo", ":item_in_slot"),
        (assign, ":ammo_slot", ":slot"),         
        (assign, ":continue", 0),     
      (else_try),
        (this_or_next|eq, ":w_type", itp_type_pistol),
        (eq, ":w_type", itp_type_musket),
        (neq, ":item_in_slot", ":weapon"),
        (eq, ":m_type", itp_type_bullets),      
        (agent_get_ammo_for_slot, ":c_ammo", ":agent_no", ":slot"),       
        (try_begin),
          (neq, ":c_ammo", 0),
          (assign, ":allow", 1),
        (else_try),
          (assign, ":num_quivers", 1),
          (try_for_range, ":s", 0, 4),
            (agent_get_item_slot, ":item", ":agent_no", ":s"),
            (neq, ":item", -1),
            (neq, ":item", ":item_in_slot"),
            (item_get_type, ":i_type", ":item"),
            (eq, ":i_type", itp_type_bullets),
            (val_add, ":num_quivers", 1),
          (try_end),
          (eq, ":num_quivers", 1),         
          (assign, ":allow", 1),          
        (try_end),
        (eq, ":allow", 1),
        (assign, ":total_ammo_amount", ":c_ammo"), 
        (assign, ":ammo", ":item_in_slot"),
        (assign, ":ammo_slot", ":slot"),     
        (assign, ":continue", 0),         
      (else_try), 
        (eq, ":w_type", itp_type_thrown),
        (eq, ":m_type", itp_type_thrown),
        (eq, ":item_in_slot", ":weapon"),
        (agent_get_ammo_for_slot, ":c_ammo", ":agent_no", ":slot"),
        (neq, ":c_ammo", 0),
        (assign, ":total_ammo_amount", ":c_ammo"),             
        (assign, ":ammo", ":item_in_slot"),
        (assign, ":ammo_slot", ":slot"), 
        (assign, ":continue", 0),     
      (try_end),        
    (try_end),
    (try_for_range, ":num", 0, ":num_missiles"), # multishot
      (lt, ":num", ":num_missiles"), # this line prevents useless compiler warning
      (store_random_in_range, ":rnd_x", -1, 1), # X is vertical spread range, difference between (-1,1) and (-2,2) is more significant due to multiplier of 1
      (position_rotate_x, pos1, ":rnd_x"),
      (store_random_in_range, ":rnd_z", -1, 1),  # Z is horizontal spread range
      (position_rotate_z, pos1, ":rnd_z"),
      (store_random_in_range, ":rnd_y", -100, 100), # this is the line position shift, don't be afraid to adjust it if necessary
      (position_move_y, pos1, ":rnd_y"),
      (add_missile, ":agent_no", pos1, ":speed", ":weapon", 0, ":ammo", 0), # putting to use all the params we've taken above
    (try_end),
    (try_for_range, ":slot", 0, 4), # quick math for the amount of ammo to take. Starting with check if agent has more than 1 instance of his quiver
      (agent_get_item_slot, ":item_in_slot", ":agent_no", ":slot"),
      (neq, ":item_in_slot", -1),
      (neq, ":slot", ":ammo_slot"),
      (eq, ":item_in_slot", ":ammo"),
      (agent_get_ammo_for_slot, ":add_ammo", ":agent_no", ":slot"),
      (val_add, ":total_ammo_amount", ":add_ammo"),
    (try_end),
    (agent_get_ammo, ":cur_ammo", ":agent_no", 1), # total amount of ammo agent has for his wielded weapon
    (try_begin),
      (gt, ":cur_ammo", ":total_ammo_amount"), # if it is greater than the combined ammo of all instances of current quiver
      (assign, ":cur_ammo", ":total_ammo_amount"), # use that number instead
    (try_end), # otherwise do nothing
    (val_sub, ":num_missiles", 1), # after reload 1 ammo point will be taken by game engine in any case, so we subtract it
    (store_sub, ":new_ammo", ":cur_ammo", ":num_missiles"),
    (try_begin),
      (ge, ":new_ammo", 0),
      (agent_set_ammo, ":agent_no", ":ammo", ":new_ammo"),
    (else_try),
      (agent_set_ammo, ":agent_no", ":ammo", 0), # the ammo counter can't go below zero
    (try_end),
])

Another good news - the compiled version of this trigger will work in any mod without adaptaion. Just copy-paste using Morgh's editor or manually in item_kinds1.txt. This will bring some fresh experience in your favorite mods whether you have access to their source code or not.

Stay safe everyone.
 
Last edited:
Back
Top Bottom