Skip to content

Commit

Permalink
Adds Chemical flamethrowers (#25091)
Browse files Browse the repository at this point in the history
* Initial work

* Good enough to open a PR out of draft

* Make these use the vars on the flamethrower

* Moar fixes

* Undefines define

* Update code/game/objects/items/weapons/chemical_flamethrower.dm

Co-authored-by: GDN <[email protected]>

* Update code/game/objects/items/weapons/chemical_flamethrower.dm

Co-authored-by: GDN <[email protected]>

* Update code/game/objects/items/weapons/chemical_flamethrower.dm

Co-authored-by: GDN <[email protected]>

* Update code/game/objects/items/weapons/chemical_flamethrower.dm

Co-authored-by: GDN <[email protected]>

* Update code/game/objects/items/weapons/chemical_flamethrower.dm

Co-authored-by: GDN <[email protected]>

* This won't compile

* GDN review

* Fixes CI

* Fixes CI even more

* 5 ammo per tile now

* Heavily nerfs adding multiple fires

* Adds phlogiston as a burnable reagent

* Fixes the fire name

* Placeholder sprite + ammo use fix

* Now in cargo partially

* Apply suggestions from code review

Co-authored-by: Henri215 <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* Update code/game/objects/items/weapons/chemical_flamethrower/chemical_flamethrower.dm

Co-authored-by: GDN <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* Update code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm

Co-authored-by: GDN <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* Update code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm

Co-authored-by: GDN <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* Lewc Review

* Adds nuclear variant

* Adds the chem flamethrower to the nukie uplink, alongside ammo

* More fire armor tweaks

* GDN review

* Update code/modules/reagents/chemistry/reagents/pyrotechnic.dm

Co-authored-by: 1080pCat <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* Update code/game/objects/items/weapons/chemical_flamethrower/chemical_flamethrower.dm

Co-authored-by: 1080pCat <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* Apply suggestions from code review

Co-authored-by: 1080pCat <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* Update code/game/objects/items/weapons/chemical_flamethrower/chemical_flamethrower.dm

Co-authored-by: Luc <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* Update code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm

Co-authored-by: Luc <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* TEMPORARY PUSH

* Adds inhands

* Update code/game/objects/items/weapons/chemical_flamethrower/chemical_flamethrower.dm

Co-authored-by: Luc <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* Update code/game/objects/items/weapons/chemical_flamethrower/chemical_flamethrower.dm

Co-authored-by: Luc <[email protected]>
Signed-off-by: DGamerL <[email protected]>

* Fixes inhands

* Makes air hot again

* Lewc review

* Audible messages and canister refilling

* Update code/game/objects/items/weapons/chemical_flamethrower/chemical_flamethrower.dm

Co-authored-by: Burzah <[email protected]>
Signed-off-by: DGamerL <[email protected]>

---------

Signed-off-by: DGamerL <[email protected]>
Co-authored-by: GDN <[email protected]>
Co-authored-by: Henri215 <[email protected]>
Co-authored-by: 1080pCat <[email protected]>
Co-authored-by: Luc <[email protected]>
Co-authored-by: Burzah <[email protected]>
  • Loading branch information
6 people authored Sep 5, 2024
1 parent 6ae5bfe commit e3c7311
Show file tree
Hide file tree
Showing 21 changed files with 523 additions and 10 deletions.
17 changes: 12 additions & 5 deletions code/datums/uplink_items/uplink_nuclear.dm
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,11 @@

/datum/uplink_item/dangerous/flamethrower
name = "Flamethrower"
desc = "A flamethrower, fuelled by a portion of highly flammable bio-toxins stolen previously from Nanotrasen stations. Make a statement by roasting the filth in their own greed. Use with caution."
reference = "FT"
item = /obj/item/flamethrower/full/tank
cost = 3
desc = "A chemical flamethrower, fueled by a volatile mix of fuel and napalm. Comes prefilled with two canisters. Do not use with caution."
reference = "CHEM_THROWER"
item = /obj/item/chemical_flamethrower/extended/nuclear
cost = 40 // In contrary to the gas flamethrower, this one is a very strong area denial tool that can't be countered by an AI
uplinktypes = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST)
surplus = 40

/datum/uplink_item/dangerous/combat_defib
name = "Combat Defibrillator Module"
Expand Down Expand Up @@ -278,6 +277,14 @@
cost = 30
uplinktypes = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST)

/datum/uplink_item/ammo/chemical_canister
name = "Box of chemical flamethrower canisters"
desc = "A box filled with 2 canisters of flamethrower fuel, exactly enough to fully refill your flamethrower once!"
reference = "CHEM_CAN"
item = /obj/item/storage/box/syndie_kit/chemical_canister
cost = 30
uplinktypes = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST)

/datum/uplink_item/ammo/machinegun
name = "L6 SAW - 5.56x45mm Box Magazine"
desc = "A 50-round magazine of 5.56x45mm ammunition for use in the L6 SAW machine gun. By the time you need to use this, you'll already be on a pile of corpses."
Expand Down
2 changes: 1 addition & 1 deletion code/game/atoms_movable.dm
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@

var/has_tried_to_move = FALSE

if(is_blocked_turf(target_turf, TRUE, excluded_objs=list(src)))
if(is_blocked_turf(target_turf, TRUE, excluded_objs = list(src)))
has_tried_to_move = TRUE
if(!Move(target_turf, crush_dir))
// we'll try to move, and if we didn't end up going anywhere, then we do nothing.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
/obj/item/chemical_flamethrower
name = "chemical flamethrower"
desc = "I love the smell of napalm in the morning."
icon = 'icons/obj/chemical_flamethrower.dmi'
icon_state = "chem_flame"
lefthand_file = 'icons/mob/inhands/flamethrower_lefthand.dmi'
righthand_file = 'icons/mob/inhands/flamethrower_righthand.dmi'
flags = CONDUCT
force = 5
throwforce = 10
throw_speed = 1
throw_range = 5
w_class = WEIGHT_CLASS_NORMAL
slot_flags = SLOT_FLAG_BACK
materials = list(MAT_METAL = 5000)
resistance_flags = FIRE_PROOF
origin_tech = "combat=1;plasmatech=2;engineering=2"

/// How many canisters fit in our flamethrower?
var/max_canisters = 1
/// All our loaded canisters in a list
var/list/canisters = list()
/// Is this a type of flamethrower that starts loaded?
var/should_start_with_canisters = FALSE

/// The burn temperature of our currently stored chemical in the canister
var/canister_burn_temp = T0C + 300
/// The burn duration of our currently stored chemical in the canister
var/canister_burn_duration = 10 SECONDS
/// How many firestacks will our reagent apply
var/canister_fire_applications = 1
/// Is this a syndicate flamethrower
var/syndicate = FALSE

/obj/item/chemical_flamethrower/Initialize(mapload)
. = ..()
if(should_start_with_canisters && !length(canisters))
canisters += new /obj/item/chemical_canister
update_canister_stats()
update_icon_state()

/obj/item/chemical_flamethrower/Destroy()
QDEL_LIST_CONTENTS(canisters)
return ..()

/obj/item/chemical_flamethrower/update_icon_state()
icon_state = "chem_flame[max_canisters == 2 ? "_2" : ""][syndicate ? "_s" : ""]"
item_state = icon_state

/obj/item/chemical_flamethrower/update_overlays()
. = ..()
var/iterator = 1
for(var/obj/item/chemical_canister as anything in canisters)
. += mutable_appearance('icons/obj/chemical_flamethrower.dmi', "[chemical_canister.icon_state]_[iterator]")
iterator++

/obj/item/chemical_flamethrower/attack_self(mob/user)
. = ..()
if(length(canisters))
unequip_canisters(user)

/obj/item/chemical_flamethrower/proc/unequip_canisters(mob/user)
if(!length(canisters))
return

var/obj/item/chemical_canister/canister_to_remove = canisters[length(canisters)]
canister_to_remove.forceMove(get_turf(src))
user.put_in_hands(canister_to_remove)
canisters -= canister_to_remove
update_icon(UPDATE_OVERLAYS)

/obj/item/chemical_flamethrower/attackby(obj/item/I, mob/user, params)
. = ..()
if(!istype(I, /obj/item/chemical_canister))
to_chat(user, "<span class='notice'>You can't fit [I] in there!</span>")
return
if(length(canisters) >= max_canisters)
to_chat(user, "<span class='notice'>[src] is already full!</span>")
return

if(!user.unEquip(I))
return

to_chat(user, "<span class='notice'>You put [I] into [src].</span>")
canisters += I
I.forceMove(src)
update_canister_stats()

/obj/item/chemical_flamethrower/proc/update_canister_stats()
if(!length(canisters))
canister_burn_temp = null
canister_burn_duration = null
canister_fire_applications = null
return

var/burn_temp
var/burn_duration
var/fire_applications
var/how_many_canisters = length(canisters)

for(var/obj/item/chemical_canister/canister as anything in canisters)
if(!canister.ammo)
continue
burn_temp += canister.chem_burn_temp
burn_duration += canister.chem_burn_duration
fire_applications += canister.fire_applications

canister_burn_temp = round(burn_temp / how_many_canisters, 1)
canister_burn_duration = round(burn_duration / how_many_canisters, 1)
canister_fire_applications = round(fire_applications / how_many_canisters, 1)
update_icon(UPDATE_OVERLAYS)

/obj/item/chemical_flamethrower/afterattack(atom/target, mob/user, flag)
. = ..()
if(flag || !user)
return

if(user.mind?.martial_art?.no_guns)
to_chat(user, "<span class='warning'>[user.mind.martial_art.no_guns_message]</span>")
return

if(HAS_TRAIT(user, TRAIT_CHUNKYFINGERS))
to_chat(user, "<span class='warning'>Your meaty finger is far too large for the trigger guard!</span>")
return

if(user.get_active_hand() == src) // Make sure our user is still holding us
var/turf/target_turf = get_turf(target)
if(target_turf)
var/turf_list = get_line(user, target_turf)
add_attack_logs(user, target, "Chemical Flamethrowered at [target.x], [target.y], [target.z]")
INVOKE_ASYNC(src, PROC_REF(flame_turf), turf_list, user)

/obj/item/chemical_flamethrower/proc/flame_turf(list/turflist = list(), mob/user)
if(!length(turflist))
return

var/turf/previousturf = get_turf(src)
for(var/turf/simulated/T in turflist)
if(iswallturf(T)) // No going through walls
break
if(!use_ammo(3))
to_chat(user, "<span class='warning'>You hear a click!</span>")
playsound(user, 'sound/weapons/empty.ogg', 100, TRUE)
break // Whoops! No ammo!

if(T == previousturf)
continue // So we don't burn the tile we be standin on

var/found_obstruction = FALSE
for(var/obj/thing in T)
if(thing.density && !istype(thing, /obj/structure/table))
found_obstruction = TRUE
break
if(found_obstruction)
break

make_flame(T)
update_canister_stats() // In case we ran out of some fuel this fire
sleep(1)
previousturf = T

/obj/item/chemical_flamethrower/proc/make_flame(turf/spawn_turf)
new /obj/effect/fire(spawn_turf, canister_burn_temp, (canister_burn_duration + rand(1, 3) SECONDS), canister_fire_applications) // For that spicy randomness (and to save your ears from all fires extinguishing at the same time)

/*
* Uses `amount` ammo from the flamethrower.
* Returns `TRUE` if ammo could be consumed, returns `FALSE` if it failed somehow
* It will use up ammo if it failed.
*/
/obj/item/chemical_flamethrower/proc/use_ammo(amount)
var/total_ammo
for(var/obj/item/chemical_canister/canister as anything in canisters)
total_ammo += canister.ammo
if(total_ammo - amount < 0)
return FALSE

var/length = length(canisters)
var/difference = amount
for(var/i in 0 to length)
var/obj/item/chemical_canister/canister = canisters[length - i]
if(canister.ammo - difference <= 0)
difference -= canister.ammo
canister.ammo = 0
else
canister.ammo -= difference
difference = 0

if(!difference)
break

return !difference

/obj/item/chemical_flamethrower/extended
name = "extended capacity chemical flamethrower"
desc = "A flamethrower that accepts two chemical canisters to create lasting fires."
max_canisters = 2

/obj/item/chemical_flamethrower/extended/nuclear
name = "\improper Syndicate extended capacity chemical flamethrower"
desc = "A flamethrower that accepts two chemical canisters to create lasting fires. As black as the ash of your enemies."
syndicate = TRUE

/obj/item/chemical_flamethrower/extended/nuclear/Initialize(mapload)
. = ..()
for(var/i in 1 to max_canisters)
canisters += new /obj/item/chemical_canister/extended/nuclear
update_canister_stats()

/obj/item/chemical_canister
name = "chemical canister"
desc = "A simple canister of fuel. Does not accept any pyrotechnics except for welding fuel."
icon = 'icons/obj/chemical_flamethrower.dmi'
icon_state = "normal"
container_type = OPENCONTAINER
/// How much ammo do we have? Empty at 0.
var/ammo = 100
/// Which reagent IDs do we accept
var/list/accepted_chemicals = list("fuel")
/// The burn temperature of our currently stored chemical
var/chem_burn_temp = T0C + 300
/// The burn duration of our currently stored chemical
var/chem_burn_duration = 10 SECONDS
/// How many firestacks will our reagent apply
var/fire_applications = 1
/// The currently stored reagent ID
var/current_reagent_id
/// How many units of the reagent do we need to have it's effects kick in?
var/required_volume = 10
/// Do we have a locked in reagent type?
var/has_filled_reagent = FALSE
/// Are we silent on the first change of reagents?
var/first_time_silent = FALSE // The reason for this is so we can have canisters that spawn with reagents but don't announce it on `Initialize()`

/obj/item/chemical_canister/Initialize(mapload)
. = ..()
create_reagents(50)

/obj/item/chemical_canister/on_reagent_change()
if(has_filled_reagent && ammo != 0)
audible_message("<span class='notice'>[src]'s speaker beeps: no new chemicals are accepted!</span>")
return

if(!reagents.get_master_reagent_id() || !(reagents.get_master_reagent_id() in accepted_chemicals))
reagents.clear_reagents()
audible_message("<span class='notice'>[src]'s speaker beeps: the most present chemical isn't accepted!</span>")
return

current_reagent_id = reagents.get_master_reagent_id()
reagents.isolate_reagent(current_reagent_id)
var/has_enough_reagents = reagents.total_volume >= required_volume

if(!first_time_silent)
audible_message("<span class='notice'>[src]'s speaker beeps: \
All reagents are removed except for [current_reagent_id]. \
The reservoir has [reagents.total_volume] out of [required_volume] units. \
Reagent effects are [has_enough_reagents ? "in effect" : "not active"].</span>")
first_time_silent = FALSE

if(has_enough_reagents)
var/datum/reagent/reagent_to_burn = reagents.reagent_list[1]
chem_burn_duration = reagent_to_burn.burn_duration
chem_burn_temp = reagent_to_burn.burn_temperature
fire_applications = reagent_to_burn.fire_stack_applications
ammo = initial(ammo)
has_filled_reagent = TRUE

/obj/item/chemical_canister/extended
name = "extended capacity chemical canister"
desc = "An extended version of the original design. Does not accept any pyrotechnics except for welding fuel."
icon_state = "extended"
ammo = 200
required_volume = 20 // Bigger canister? More reagents needed.

/obj/item/chemical_canister/extended/nuclear
icon_state = "pyro"
accepted_chemicals = list("napalm")
first_time_silent = TRUE

/obj/item/chemical_canister/extended/nuclear/Initialize(mapload)
..()
reagents.add_reagent("napalm", 30) // Overload it with napalm!

/obj/item/chemical_canister/pyrotechnics
name = "extended capacity chemical canister"
desc = "A specialized canister designed to accept certain pyrotechnics."
icon_state = "pyro"
ammo = 150
accepted_chemicals = list("phlogiston", "phlogiston_dust", "napalm", "fuel", "thermite", "clf3", "plasma")
Loading

0 comments on commit e3c7311

Please sign in to comment.