Yagababa
Regular
Hey everyone,
I'm proud to announce my first OSP! There's a lot of flaming arrow projects on the Forge, but I wasn't really satisfied w/ the results I was getting--so I went and made a new one.
I've created a solid system in WFaS with the new WSE build (shoutout @K700) that combines a couple particle systems and triggers to create a clean aesthetic, and a damage over time system that works great in MP (haven't tested in SP but it should work w/ very few alterations).
Before I get started, I should mention that while this will also work in Warband, it does require WSE and a reasonable knowledge of the module system. Let's get to it!
First things first, we're gonna need some particle systems, so chuck these in module_particle_systems:
Next, you're going to want to create a new arrow item in module_items, with a few triggers for our new particle effects. Be sure to declare your meshes, I just threw in some placeholders here--any native meshes will do.
Side note: I also don't have any imodbits because of my current project, but feel free to add/modify any of the base item stats to your liking.
Also, while we're here, go ahead and create a dummy weapon called FLAME_KILL, and make it a type of weapon you don't use anywhere in your mod. I don't use throwing stones, so this is perfect for me. I'll explain why in a bit:
Great, now let's add a couple of new agent slots in module_constants; you may have to change the numbers if these slots are already being used. In my case, 30+ were free:
Okay last step, onto the triggers. This is where the bulk of the magic happens. We're going to add six new triggers before the mission templates. If you already have a ti_on_agent_hit and/or ti_on_item_wielded check, you can just add the contents of these in your existing trigger. Or just add these new ones, whatever you're feeling.
Important to note here is that there's two places where it checks whether an agent is using a bow--I check this using is_between, and having all my bows in module_items appear consecutively. I recommend doing the same, and replacing BOWS_BEGIN w/ the first bow to appear and BOWS_END as one item after the last. You can also accomplish this by using constants, but for me this was simpler:
Make sure to call these:
in the appropriate mission templates.
Notice when to kill an agent via fire damage, I apply it using the FLAME_KILL dummy weapon:
Now you can replace the appropriate kill icon in mp_icon_fight.dds to a flame. If you used a throwing rock like me, here's an example I made. Feel free to use it.
...Okay I lied--there's one more step, but it's completely optional.
In module scripts, find the script "game_get_item_extra_text", and add this to the try block:
I should also mention it would be fairly simple to adapt this code to make normal, non-blue flaming arrows by editing the color keys in the particle systems.
And that should be just about everything! let me know if you have any questions or are having trouble getting this to work.
I'm proud to announce my first OSP! There's a lot of flaming arrow projects on the Forge, but I wasn't really satisfied w/ the results I was getting--so I went and made a new one.
I've created a solid system in WFaS with the new WSE build (shoutout @K700) that combines a couple particle systems and triggers to create a clean aesthetic, and a damage over time system that works great in MP (haven't tested in SP but it should work w/ very few alterations).
Before I get started, I should mention that while this will also work in Warband, it does require WSE and a reasonable knowledge of the module system. Let's get to it!
First things first, we're gonna need some particle systems, so chuck these in module_particle_systems:
Python:
################################################################################
# Soul arrows
################################################################################
# Soul arrows hit
("soul_fire_hit", psf_billboard_3d|psf_global_emit_dir|psf_always_emit|psf_randomize_size|psf_randomize_rotation, "prt_mesh_fire_1",
50, 0.2, 0.2, 0.03, 10.0, 0.0, #num_particles, life, damping, gravity_strength, turbulance_size, turbulance_strength
(0.5, 0., (1, 0), #alpha keys
(0.5, 0.6), (1, 0.9), #red keys
(0.5, 0.6),(1, 0.9), #green keys
(0.5, 0.9), (1, 0.9), #blue keys
(0, 0.15), (0.6, 0.5), #scale keys
(0.06, 0.06, 0.06), #emit box size
(0, 0, 0., #emit velocity
0.5, #emit dir randomness
200, #rotation speed
0.5 #rotation damping
),
# Soul arrow smoldering
("soul_smolder_smoke", psf_billboard_3d|psf_global_emit_dir|psf_always_emit, "prtcl_dust_a",
20, 0.5, 0.2, -0.2, 10.0, 0.5, #num_particles, life, damping, gravity_strength, turbulance_size, turbulance_strength
(0.5, 0.25), (1, 0), #alpha keys
(0.0, 0.2), (1, 0.1), #red keys
(0.0, 0.2),(1, 0.09), #green keys
(0.0, 0.2), (1, 0.0, #blue keys
(0, 0.5), (0.8, 2.5), #scale keys
(0.1, 0.1, 0.1), #emit box size
(0, 0, 1.5), #emit velocity
0.1 #emit dir randomness
),
("soul_smolder_sparks", psf_billboard_3d|psf_global_emit_dir|psf_always_emit|psf_randomize_size, "prt_sparks_mesh_1",
30, 1.5, 0.2, 0, 10.0, 0.2, #num_particles, life, damping, gravity_strength, turbulance_size, turbulance_strength
(0.66, 1), (1, 0), #alpha keys
(0.1, 0.3), (1, 0.7), #red keys
(0.1, 0.1),(1, 0.7), #green keys
(0.1, 0.7), (1, 0.9), #blue keys
(0.1, 0.05), (1, 0.05), #scale keys
(0.1, 0.1, 0.1), #emit box size
(0, 0, 0.9), #emit velocity
0.0, #emit dir randomness
0,
0,
),
# Soul arrow draw
("soul_draw_fire", psf_billboard_3d|psf_global_emit_dir|psf_always_emit|psf_randomize_size|psf_randomize_rotation, "prt_mesh_fire_1",
30, 0.1, 0.4, 0.03, 10.0, 0.3, #num_particles, life, damping, gravity_strength, turbulance_size, turbulance_strength
(0.5, 0., (1, 0), #alpha keys
(0.5, 0.5), (1, 0.9), #red keys
(0.5, 0.5),(1, 0.9), #green keys
(0.5, 0.9), (1, 0.9), #blue keys
(0, 0.15), (0.3, 0.2), #scale keys
(0.04, 0.04, 0.01), #emit box size
(0, 0, 0., #emit velocity
0.0, #emit dir randomness
200, #rotation speed
0.5 #rotation damping
),
("soul_draw_smoke", psf_billboard_3d|psf_global_emit_dir|psf_always_emit, "prtcl_dust_a",
1, 0.3, 0.2, -0.2, 10.0, 0.5, #num_particles, life, damping, gravity_strength, turbulance_size, turbulance_strength
(0.2, 0.1), (0.6, 0), #alpha keys
(0.0, 0.2), (1, 0.1), #red keys
(0.0, 0.2),(1, 0.09), #green keys
(0.0, 0.2), (1, 0.0, #blue keys
(0, 0.5), (0.8, 2.5), #scale keys
(0.1, 0.1, 0.1), #emit box size
(0, 0, 1.5), #emit velocity
0.1 #emit dir randomness
),
("soul_draw_sparks", psf_billboard_3d|psf_global_emit_dir|psf_always_emit|psf_randomize_size, "prt_sparks_mesh_1",
1, 0.3, 0.2, 0, 10.0, 0.2, #num_particles, life, damping, gravity_strength, turbulance_size, turbulance_strength
(0.3, 0.5), (0.6, 0), #alpha keys
(0.1, 0.3), (1, 0.7), #red keys
(0.1, 0.1),(1, 0.7), #green keys
(0.1, 0.7), (1, 0.9), #blue keys
(0.1, 0.05), (1, 0.05), #scale keys
(0.1, 0.1, 0.1), #emit box size
(0, 0, 0.9), #emit velocity
0.0, #emit dir randomness
0,
0,
),
# Soul arrow flying
("soul_missile_smoke", psf_billboard_3d|psf_global_emit_dir|psf_always_emit, "prtcl_dust_a",
50, 0.8, 0.2, -0.2, 10.0, 0.1, #num_particles, life, damping, gravity_strength, turbulance_size, turbulance_strength
(0.8, 0.5), (1, 0), #alpha keys
(0.0, 0.2), (1, 0.1), #red keys
(0.0, 0.2),(1, 0.09), #green keys
(0.0, 0.2), (1, 0.0, #blue keys
(0.1, 1), (1.5, 3), #scale keys
(0.1, 0.1, 0.1), #emit box size
(0, 0, 1.5), #emit velocity
0.1 #emit dir randomness
),
("soul_missile_sparks", psf_billboard_3d|psf_global_emit_dir|psf_always_emit|psf_randomize_size, "prt_sparks_mesh_1",
30, 0.8, 0.2, 0, 10.0, 0.05, #num_particles, life, damping, gravity_strength, turbulance_size, turbulance_strength
(0.66, 1), (1, 0), #alpha keys
(0.1, 0.3), (1, 0.7), #red keys
(0.1, 0.1),(1, 0.7), #green keys
(0.1, 0.7), (1, 0.9), #blue keys
(1, 0.1), (1.5, 0.15), #scale keys
(0.15, 0.15, 0.15), #emit box size
(0, 0, 0.9), #emit velocity
0.0, #emit dir randomness
0,
0,
),
Next, you're going to want to create a new arrow item in module_items, with a few triggers for our new particle effects. Be sure to declare your meshes, I just threw in some placeholders here--any native meshes will do.
Side note: I also don't have any imodbits because of my current project, but feel free to add/modify any of the base item stats to your liking.
Also, while we're here, go ahead and create a dummy weapon called FLAME_KILL, and make it a type of weapon you don't use anywhere in your mod. I don't use throwing stones, so this is perfect for me. I'll explain why in a bit:
Python:
["soulfire_arrows", "Soulfire Arrows", [("YOUR_MESH_HERE",0),("flying_missile", ixmesh_flying_ammo),("YOUR_CARRY_MESH_HERE", ixmesh_carry),("YOUR_QUIVER_MESH_HERE", ixmesh_inventory)], itp_type_arrows|itp_default_ammo, itcf_carry_quiver_back, 100, weight(3)|weapon_length(95)|thrust_damage(3, pierce)|max_ammo(30), 0,
[(ti_on_init_missile, [
(particle_system_add_new, "psys_soul_missile_smoke"),
(particle_system_add_new, "psys_soul_missile_sparks"),
]),
(ti_on_init_item, [
(set_position_delta, 0, 100, 0),
(particle_system_add_new, "psys_soul_smolder_smoke"),
(particle_system_add_new, "psys_soul_smolder_sparks"),
(set_current_color,150, 130, 70),
(add_point_light, 10, 30),
]),
(ti_on_missile_hit,
[
(particle_system_burst, "psys_soul_fire_hit", pos1, 15),
(set_current_color, 150, 130, 70),
(add_point_light, 10, 30),
]),
]],
["FLAME_KILL", "FLAME_KILL", [("bullet",0)], itp_type_thrown|itp_primary, itcf_throw_stone, 0, weight(0)|difficulty(0)|spd_rtng(0)|shoot_speed(0)|thrust_damage(0, blunt)|max_ammo(0)|weapon_length(0), 0],
Great, now let's add a couple of new agent slots in module_constants; you may have to change the numbers if these slots are already being used. In my case, 30+ were free:
Python:
slot_agent_on_fire = 30
slot_agent_fire_timer = 31
slot_agent_fire_bone = 32
slot_agent_fire_igniter = 33
slot_agent_wielding_soul_fire_arrows = 34
Okay last step, onto the triggers. This is where the bulk of the magic happens. We're going to add six new triggers before the mission templates. If you already have a ti_on_agent_hit and/or ti_on_item_wielded check, you can just add the contents of these in your existing trigger. Or just add these new ones, whatever you're feeling.
Important to note here is that there's two places where it checks whether an agent is using a bow--I check this using is_between, and having all my bows in module_items appear consecutively. I recommend doing the same, and replacing BOWS_BEGIN w/ the first bow to appear and BOWS_END as one item after the last. You can also accomplish this by using constants, but for me this was simpler:
Python:
# Make sure freshly spawned agents aren't on fire
reset_status_on_spawn = (ti_on_agent_spawn, 0, 0, [],
[
(store_trigger_param_1, ":agent_no"),
(agent_set_slot, ":agent_no", slot_agent_on_fire, 0),
])
# Apply fire status effect on hit
hit_checks = (ti_on_agent_hit, 0, 0, [(multiplayer_is_server),],
[
(store_trigger_param_1, ":agent_no"),
(store_trigger_param_2, ":attacker_no"),
(store_trigger_param_3, ":damage"),
(try_begin),
(is_between, reg0, "BOWS_BEGIN", "BOWS_END"), # Check if agent is using a bow
(assign, ":soul_arrows_check", 0),
(try_for_range, ":cur_slot", 0, 3), # Check if agent has soulfire arrows
(agent_get_item_slot, ":item_to_check", ":attacker_no", ":cur_slot"),
(eq, ":item_to_check", "itm_soulfire_arrows"),
(assign, ":soul_arrows_check", 1),
(try_end),
(try_begin),
(eq, ":soul_arrows_check", 1), # If so, add the status effect via the new slots
(agent_set_slot, ":agent_no", slot_agent_on_fire, 1),
(agent_set_slot, ":agent_no", slot_agent_fire_timer, 12), # Set timer to 12, you could make this random or adjust as you see fit
(agent_set_slot, ":agent_no", slot_agent_fire_igniter, ":attacker_no"),
(store_trigger_param, ":hit_bone", 4), # Store ignited 'bone' that was hit w/ arrow for smoldering particle effects
(agent_set_slot, ":agent_no", slot_agent_fire_bone, ":hit_bone"),
(try_end),
(try_end),
])
# Check for actively wielded flaming arrows
wielding_checks = (ti_on_item_wielded, 0, 0, [],[
(store_trigger_param_1, ":agent_no"),
(store_trigger_param_2, ":item_no"),
(try_begin),
(is_between, ":item_no", "BOWS_BEGIN", "BOWS_END"), # Check if agent is using a bow
(assign, ":soul_arrows_check", 0),
(try_for_range, ":cur_slot", 0, 3), # Check if agent has soulfire arrows
(agent_get_item_slot, ":item_to_check", ":agent_no", ":cur_slot"),
(eq, ":item_to_check", "itm_soulfire_arrows"),
(assign, ":soul_arrows_check", 1),
(try_end),
(try_begin),
(eq, ":soul_arrows_check", 1),
(agent_set_slot, ":agent_no", slot_agent_wielding_soul_fire_arrows, 1),
(else_try),
(agent_set_slot, ":agent_no", slot_agent_wielding_soul_fire_arrows, 0),
(try_end),
(else_try),
(agent_set_slot, ":agent_no", slot_agent_wielding_soul_fire_arrows, 0),
(try_end),
])
# Apply fire damage
fire_damage_check = (0.25, 0, 0, [(multiplayer_is_server)],
[
(try_for_agents, ":cur_agent"),
(agent_get_slot, "n_fire", ":cur_agent", slot_agent_on_fire), # Check if agent is on fire
(eq, "n_fire", 1),
(agent_get_slot, ":fire_timer", ":cur_agent", slot_agent_fire_timer),
(try_begin),
(gt, ":fire_timer", 0),
(val_sub, ":fire_timer", 1), # Tick down fire timer
(agent_set_slot, ":cur_agent", slot_agent_fire_timer, ":fire_timer"),
(store_agent_hit_points, ":agent_health", ":cur_agent", 1),
(val_sub, ":agent_health", 1),
(agent_set_hit_points, ":cur_agent", ":agent_health", 1), # Take away 1 HP from fire damage, feel free to change this value for balancing
(try_begin), # Check if we should kill the agent due to fire damage
(lt, ":agent_health", 2),
(agent_get_slot, ":igniter", ":cur_agent", slot_agent_fire_igniter),
(agent_deliver_damage_to_agent, ":igniter", ":cur_agent", 10, "itm_FLAME_KILL"), # Kill the agent using the dummy flame weapon, and give credit to the igniter
(try_end),
(else_try),
(agent_set_slot, ":cur_agent", slot_agent_on_fire, 0), # If the fire goes out, reset the slot status
(try_end),
(try_end),
])
# Add smoldering particle effect to burning agents
smolder = (0.25, 0, 0, [], [
(try_for_agents, ":cur_agent"),
(agent_is_alive, ":cur_agent"),
(agent_is_active, ":cur_agent"),
(agent_get_slot, ":on_fire", ":cur_agent", slot_agent_on_fire),
(eq, ":on_fire", 1),
(agent_get_slot, ":bone_no", ":cur_agent", slot_agent_fire_bone), # Using bone from ti_on_agent_hit
(agent_get_bone_position, pos2, ":cur_agent", ":bone_no", 1),
(particle_system_burst, "psys_soul_smolder_smoke", pos2, 40),
(particle_system_burst, "psys_soul_smolder_sparks", pos2, 40),
(try_end),
])
# Add flame particles to drawn bow
draw_flame = (0, 0, 0, [], [
(try_for_agents, ":cur_agent"),
(agent_get_slot, ":fire_arrow_check", ":cur_agent", slot_agent_wielding_soul_fire_arrows),
(eq, ":fire_arrow_check", 1),
(try_begin),
(agent_get_animation, ":animation", ":cur_agent", 1),
(eq, ":animation", "anim_ready_bow"),
# (this_or_next|game_key_is_down, gk_attack),
# (key_is_down, key_left_mouse_button),
(agent_get_bone_position, pos2, ":cur_agent", hb_item_l, 1),
(position_move_z, pos2, 10, 1),
(particle_system_burst, "psys_soul_draw_fire", pos2, 5), # total num particles
(particle_system_burst, "psys_soul_draw_smoke", pos2, 2),
(particle_system_burst, "psys_soul_draw_sparks", pos2, 2),
(set_current_color,150, 130, 70),
(add_point_light, 10, 30),
(try_end),
(try_end),
])
Make sure to call these:
Python:
reset_status_on_spawn,
fire_damage_check,
hit_checks,
wielding_checks,
smolder,
draw_flame,
Notice when to kill an agent via fire damage, I apply it using the FLAME_KILL dummy weapon:
Python:
(agent_deliver_damage_to_agent, ":igniter", ":cur_agent", 10, "itm_FLAME_KILL"),
Now you can replace the appropriate kill icon in mp_icon_fight.dds to a flame. If you used a throwing rock like me, here's an example I made. Feel free to use it.
...Okay I lied--there's one more step, but it's completely optional.
In module scripts, find the script "game_get_item_extra_text", and add this to the try block:
Python:
...
(else_try),
(eq, ":item_no", "itm_soulfire_arrows"),
(try_begin),
(eq, ":extra_text_id", 0),
(set_result_string, "@Fire Damage"), # Your flavor text here
(set_trigger_result, 0x7FC9FF), # Color of the text
(try_end),
(else_try),
...
I should also mention it would be fairly simple to adapt this code to make normal, non-blue flaming arrows by editing the color keys in the particle systems.
And that should be just about everything! let me know if you have any questions or are having trouble getting this to work.
10/5/2021: Attached smoldering effect to ignited agent's hit bone instead of calculating offset; this is simpler, more optimized, and looks way better.
10/6/2021: Flame particles on draw now triggered by animation rather than game_key for better multiplayer compatibility, per Veledentella's suggestion
10/6/2021: Flame particles on draw now triggered by animation rather than game_key for better multiplayer compatibility, per Veledentella's suggestion
Last edited: