diff --git a/code/datums/uplink_items/uplink_nuclear.dm b/code/datums/uplink_items/uplink_nuclear.dm
index d0386ad0c75f..342f4af31b71 100644
--- a/code/datums/uplink_items/uplink_nuclear.dm
+++ b/code/datums/uplink_items/uplink_nuclear.dm
@@ -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"
@@ -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."
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index c4ca156e5df5..749f88d4841d 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -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.
diff --git a/code/game/objects/items/weapons/chemical_flamethrower/chemical_flamethrower.dm b/code/game/objects/items/weapons/chemical_flamethrower/chemical_flamethrower.dm
new file mode 100644
index 000000000000..138a3d9309cd
--- /dev/null
+++ b/code/game/objects/items/weapons/chemical_flamethrower/chemical_flamethrower.dm
@@ -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, "You can't fit [I] in there!")
+ return
+ if(length(canisters) >= max_canisters)
+ to_chat(user, "[src] is already full!")
+ return
+
+ if(!user.unEquip(I))
+ return
+
+ to_chat(user, "You put [I] into [src].")
+ 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, "[user.mind.martial_art.no_guns_message]")
+ return
+
+ if(HAS_TRAIT(user, TRAIT_CHUNKYFINGERS))
+ to_chat(user, "Your meaty finger is far too large for the trigger guard!")
+ 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, "You hear a click!")
+ 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("[src]'s speaker beeps: no new chemicals are accepted!")
+ return
+
+ if(!reagents.get_master_reagent_id() || !(reagents.get_master_reagent_id() in accepted_chemicals))
+ reagents.clear_reagents()
+ audible_message("[src]'s speaker beeps: the most present chemical isn't accepted!")
+ 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("[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"].")
+ 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")
diff --git a/code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm b/code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm
new file mode 100644
index 000000000000..099f9eed56c7
--- /dev/null
+++ b/code/game/objects/items/weapons/chemical_flamethrower/fire_effect.dm
@@ -0,0 +1,116 @@
+GLOBAL_LIST_EMPTY(flame_effects)
+#define MAX_FIRE_EXIST_TIME 10 MINUTES // That's a lot of fuel, but you are not gonna make it last for longer
+
+/obj/effect/fire
+ name = "fire"
+ desc = "You don't think you should touch this."
+ icon = 'icons/effects/chemical_fire.dmi'
+ icon_state = "fire1"
+
+ /// How hot is our fire?
+ var/temperature
+ /// How long will our fire last
+ var/duration = 10 SECONDS
+ /// How many firestacks does the fire give to mobs
+ var/application_stacks = 1
+
+/obj/effect/fire/Initialize(mapload, reagent_temperature, reagent_duration, fire_applications)
+ . = ..()
+
+ if(reagent_duration < 0 || reagent_temperature <= 0) // There is no reason for this thing to exist
+ qdel(src)
+ return
+
+ duration = reagent_duration
+ temperature = reagent_temperature
+ application_stacks = max(application_stacks, fire_applications)
+
+ for(var/obj/effect/fire/flame in get_turf(src))
+ if(!istype(flame) || flame == src)
+ continue
+ merge_flames(flame)
+
+ GLOB.flame_effects += src
+ START_PROCESSING(SSprocessing, src)
+
+/obj/effect/fire/Destroy()
+ . = ..()
+ GLOB.flame_effects -= src
+ STOP_PROCESSING(SSprocessing, src)
+
+/obj/effect/fire/process()
+ if(duration <= 0)
+ fizzle()
+ return
+ duration -= 2 SECONDS
+
+ for(var/atom/movable/thing_to_burn in get_turf(src))
+ if(isliving(thing_to_burn))
+ damage_mob(thing_to_burn)
+ continue
+
+ if(isobj(thing_to_burn))
+ var/obj/obj_to_burn = thing_to_burn
+ obj_to_burn.fire_act(null, temperature)
+ continue
+
+ var/turf/location = get_turf(src)
+ if(!location)
+ return
+ var/datum/gas_mixture/air = location.private_unsafe_get_air()
+ if(!air)
+ return FALSE
+ var/datum/milla_safe/fire_heat_air/milla = new()
+ milla.invoke_async(src, location)
+
+/datum/milla_safe/fire_heat_air
+
+/datum/milla_safe/fire_heat_air/on_run(obj/effect/fire/fire, turf/T)
+ var/datum/gas_mixture/env = get_turf_air(T)
+ env.set_temperature(fire.temperature)
+
+/obj/effect/fire/water_act(volume, temperature, source, method)
+ . = ..()
+ duration -= 10 SECONDS
+ if(duration <= 0)
+ fizzle()
+
+/obj/effect/fire/Crossed(atom/movable/AM, oldloc)
+ . = ..()
+ if(isliving(AM))
+ damage_mob(AM)
+ to_chat(AM, "[src] burns you!")
+ return
+
+ if(isitem(AM))
+ var/obj/item/item_to_burn = AM
+ item_to_burn.fire_act(null, temperature)
+ return
+
+/obj/effect/fire/proc/fizzle()
+ playsound(src, 'sound/effects/fire_sizzle.ogg', 50, TRUE)
+ qdel(src)
+
+/obj/effect/fire/proc/merge_flames(obj/effect/fire/merging_flame)
+ duration = min((duration + (merging_flame.duration / 4)), MAX_FIRE_EXIST_TIME)
+ temperature = ((merging_flame.temperature + temperature) / 2) // No making a sun by just clicking 10 times on a turf
+ merging_flame.fizzle()
+
+/obj/effect/fire/proc/damage_mob(mob/living/mob_to_burn)
+ if(!istype(mob_to_burn))
+ return
+ var/fire_damage = temperature / 100
+ if(ishuman(mob_to_burn))
+ var/mob/living/carbon/human/human_to_burn = mob_to_burn
+ var/fire_armour = human_to_burn.get_thermal_protection()
+ if(fire_armour >= FIRE_IMMUNITY_MAX_TEMP_PROTECT)
+ return
+
+ if(fire_armour == FIRE_SUIT_MAX_TEMP_PROTECT) // Good protection but you won't survive infinitely in it
+ fire_damage /= 4
+
+ mob_to_burn.adjustFireLoss(fire_damage)
+ mob_to_burn.adjust_fire_stacks(application_stacks)
+ mob_to_burn.IgniteMob()
+
+#undef MAX_FIRE_EXIST_TIME
diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm
index 7e3157fec859..498e169fc6ed 100644
--- a/code/game/objects/items/weapons/storage/uplink_kits.dm
+++ b/code/game/objects/items/weapons/storage/uplink_kits.dm
@@ -557,6 +557,13 @@
/obj/item/storage/box/syndie_kit/pen_bomb/populate_contents()
new /obj/item/grenade/syndieminibomb/pen(src)
+/obj/item/storage/box/syndie_kit/chemical_canister
+ name = "\improper Chemical flamethrower canisters"
+
+/obj/item/storage/box/syndie_kit/chemical_canister/populate_contents()
+ new /obj/item/chemical_canister/extended/nuclear(src)
+ new /obj/item/chemical_canister/extended/nuclear(src)
+
/obj/item/storage/box/syndie_kit/decoy
name = "\improper Decoy Grenade kit"
diff --git a/code/modules/crafting/guncrafting.dm b/code/modules/crafting/guncrafting.dm
index 572854dfe284..d486b616db8e 100644
--- a/code/modules/crafting/guncrafting.dm
+++ b/code/modules/crafting/guncrafting.dm
@@ -105,6 +105,12 @@
origin_tech = "combat=6;magnets=6;syndicate=2"
outcome = /obj/item/gun/energy/disabler/silencer
+/obj/item/weaponcrafting/gunkit/chemical_flamethrower
+ name = "extended chemical flamethrower parts kit"
+ desc = "A suitcase containing the necessary gun parts to transform a standard chemical flamethrower into a version that can accept two cartridges instead of one."
+ origin_tech = "combat=5;engineering=6;plasmatech=4"
+ outcome = /obj/item/chemical_flamethrower/extended
+
/obj/item/weaponcrafting/gunkit/universal_gun_kit
name = "universal self assembling gun parts kit"
desc = "A suitcase containing the necessary gun parts to build a full gun, when combined with a gun kit. Use it directly on a gunkit to rapidly assemble it."
diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm
index 859ee38a7cde..22423ca2ddc0 100644
--- a/code/modules/crafting/recipes.dm
+++ b/code/modules/crafting/recipes.dm
@@ -296,6 +296,14 @@
..()
blacklist += subtypesof(/obj/item/gun/energy/disabler)
+/datum/crafting_recipe/flamethrower_extended
+ name = "Extended Chemical Flamethrower"
+ tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
+ result = list(/obj/item/chemical_flamethrower/extended)
+ reqs = list(/obj/item/chemical_flamethrower = 1,
+ /obj/item/stack/cable_coil = 5,
+ /obj/item/weaponcrafting/gunkit/chemical_flamethrower = 1)
+
/datum/crafting_recipe/ed209
name = "ED209"
result = list(/mob/living/simple_animal/bot/ed209)
diff --git a/code/modules/mob/living/carbon/human/human_life.dm b/code/modules/mob/living/carbon/human/human_life.dm
index b7297ef18a88..57c5cc8984b9 100644
--- a/code/modules/mob/living/carbon/human/human_life.dm
+++ b/code/modules/mob/living/carbon/human/human_life.dm
@@ -304,10 +304,10 @@
var/thermal_protection = 0 //Simple check to estimate how protected we are against multiple temperatures
if(wear_suit)
if(wear_suit.max_heat_protection_temperature >= FIRE_SUIT_MAX_TEMP_PROTECT)
- thermal_protection += (wear_suit.max_heat_protection_temperature*0.7)
+ thermal_protection += (wear_suit.max_heat_protection_temperature * 0.7)
if(head)
if(head.max_heat_protection_temperature >= FIRE_HELM_MAX_TEMP_PROTECT)
- thermal_protection += (head.max_heat_protection_temperature*THERMAL_PROTECTION_HEAD)
+ thermal_protection += (head.max_heat_protection_temperature * THERMAL_PROTECTION_HEAD)
thermal_protection = round(thermal_protection)
return thermal_protection
diff --git a/code/modules/projectiles/ammunition/ammo_boxes.dm b/code/modules/projectiles/ammunition/ammo_boxes.dm
index 9feb5d0bc375..336e25b5c184 100644
--- a/code/modules/projectiles/ammunition/ammo_boxes.dm
+++ b/code/modules/projectiles/ammunition/ammo_boxes.dm
@@ -196,7 +196,6 @@
ammo_type = /obj/item/ammo_casing/caseless/foam_dart/sniper/riot
materials = list(MAT_METAL = 90000)
-
/obj/item/ammo_box/caps
name = "speed loader (caps)"
desc = "A revolver speedloader for a cap gun. Cannot chamber live ammunition."
diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic.dm
index 63bd1d2ea9e8..f986e610d92c 100644
--- a/code/modules/reagents/chemistry/reagents/pyrotechnic.dm
+++ b/code/modules/reagents/chemistry/reagents/pyrotechnic.dm
@@ -6,6 +6,8 @@
color = "#FFAF00"
process_flags = ORGANIC | SYNTHETIC
taste_description = "burning"
+ burn_temperature = T0C + 500
+ burn_duration = 20 SECONDS
var/temp_fire = 4000
var/temp_deviance = 1000
var/size_divisor = 40
@@ -43,6 +45,7 @@
temp_deviance = 500
size_divisor = 80
mob_burning = 3 // 15
+ burn_temperature = T0C + 700
/datum/reagent/napalm
name = "Napalm"
@@ -52,6 +55,9 @@
process_flags = ORGANIC | SYNTHETIC
color = "#C86432"
taste_description = "burning"
+ burn_temperature = T0C + 500
+ burn_duration = 40 SECONDS
+ fire_stack_applications = 4 // BURN BABY BURN
/datum/reagent/napalm/reaction_temperature(exposed_temperature, exposed_volume)
if(exposed_temperature > T0C + 100)
@@ -91,6 +97,9 @@
drink_desc = "Unless you are an industrial tool, this is probably not safe for consumption."
taste_description = "mistakes"
process_flags = ORGANIC | SYNTHETIC
+ burn_temperature = T0C + 400
+ burn_duration = 15 SECONDS // Barely better than default
+
var/max_radius = 7
var/min_radius = 0
var/volume_radius_modifier = -0.15
@@ -139,7 +148,7 @@
T.create_reagents(50)
T.reagents.add_reagent("fuel", volume)
-/datum/reagent/fuel/reaction_mob(mob/living/M, method=REAGENT_TOUCH, volume)//Splashing people with welding fuel to make them easy to ignite!
+/datum/reagent/fuel/reaction_mob(mob/living/M, method = REAGENT_TOUCH, volume) // Splashing people with welding fuel to make them easy to ignite!
if(method == REAGENT_TOUCH)
if(M.on_fire)
M.adjust_fire_stacks(6)
@@ -152,6 +161,8 @@
color = "#7A2B94"
taste_description = "corporate assets going to waste"
taste_mult = 1.5
+ burn_temperature = T0C + 400
+ burn_duration = 20 SECONDS
/datum/reagent/plasma/reaction_temperature(exposed_temperature, exposed_volume)
if(exposed_temperature >= T0C + 100)
@@ -185,6 +196,8 @@
color = "#673910" // rgb: 103, 57, 16
process_flags = ORGANIC | SYNTHETIC
taste_description = "rust"
+ burn_temperature = T0C + 1500 // hahahahHAHAHAHAH LET IT BURN
+ burn_duration = 5 SECONDS // Not for long though
/datum/reagent/thermite/reaction_mob(mob/living/M, method= REAGENT_TOUCH, volume)
if(method == REAGENT_TOUCH)
@@ -237,6 +250,9 @@
metabolization_rate = 4
process_flags = ORGANIC | SYNTHETIC
taste_mult = 0
+ burn_temperature = T0C + 700
+ burn_duration = 15 SECONDS
+ fire_stack_applications = 3
/datum/reagent/clf3/on_mob_life(mob/living/M)
if(M.on_fire)
diff --git a/code/modules/reagents/chemistry/reagents_datum.dm b/code/modules/reagents/chemistry/reagents_datum.dm
index 2b4fbe56263d..e51056cbbea9 100644
--- a/code/modules/reagents/chemistry/reagents_datum.dm
+++ b/code/modules/reagents/chemistry/reagents_datum.dm
@@ -45,6 +45,13 @@
// Affects the quantity of the reagent that is requested by CC.
var/goal_difficulty = REAGENT_GOAL_SKIP
+ /// At what temperature does this reagent burn? Currently only used for chemical flamethrowers
+ var/burn_temperature = T0C
+ /// How long would a fire burn using this reagent? Currently only used for chemical flamethrowers
+ var/burn_duration = 30 SECONDS
+ /// How many firestacks will the reagent apply when it is burning? Currently only used for chemical flamethrowers
+ var/fire_stack_applications = 1
+
/datum/reagent/Destroy()
. = ..()
holder = null
diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm
index 1a94f7a7f872..bc6566a17e6d 100644
--- a/code/modules/research/designs/weapon_designs.dm
+++ b/code/modules/research/designs/weapon_designs.dm
@@ -354,3 +354,46 @@
materials = list(MAT_GOLD = 5000, MAT_METAL = 10000, MAT_TITANIUM = 3000, MAT_BLUESPACE = 2000)
build_path = /obj/item/organ/internal/cyberimp/arm/muscle
category = list("Weapons")
+
+/datum/design/upgraded_chemical_flamethrower
+ name = "Extended Capacity Chemical Flamethrower Parts"
+ desc = "Parts for a flamethrower that accepts two chemical cartridges to create lasting fires."
+ id = "chem_flamethrower_extended"
+ req_tech = list("combat" = 6, "engineering" = 7, "plasmatech" = 5)
+ materials = list(MAT_TITANIUM = 7000, MAT_METAL = 13000, MAT_GOLD = 1000)
+ build_path = /obj/item/weaponcrafting/gunkit/chemical_flamethrower
+ category = list("Weapons")
+
+// The normal and extended canisters can be obtained from cargo aswell, pyrotechnical ones are RnD exclusive
+/datum/design/chemical_canister
+ name = "Chemical Canister"
+ desc = "A plain chemical canister, designed for use with a chemical flamethrower."
+ id = "chemical_canister"
+ req_tech = list("materials" = 3, "plasmatech" = 4)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000)
+ reagents_list = list("fuel" = 20)
+ build_path = /obj/item/chemical_canister
+ category = list("Weapons")
+
+/datum/design/chemical_canister/extended
+ name = "Extended Capacity Chemical Canister"
+ desc = "A large chemical canister, designed for use with a chemical flamethrower."
+ id = "chemical_canister_extended"
+ req_tech = list("materials" = 5, "plasmatech" = 4)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 10000)
+ reagents_list = list("fuel" = 40)
+ build_path = /obj/item/chemical_canister/extended
+ category = list("Weapons")
+
+/datum/design/chemical_canister/pyrotechnics
+ name = "Chemical Canister (Pyrotechnics)"
+ desc = "A chemical canister designed to accept pyrotechnics."
+ id = "chemical_canister_pyro"
+ req_tech = list("materials" = 4, "plasmatech" = 6)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 7500)
+ reagents_list = list("fuel" = 30)
+ build_path = /obj/item/chemical_canister/pyrotechnics
+ category = list("Weapons")
diff --git a/code/modules/supply/supply_packs/pack_engineering.dm b/code/modules/supply/supply_packs/pack_engineering.dm
index 90def3798510..0c2d2df736e7 100644
--- a/code/modules/supply/supply_packs/pack_engineering.dm
+++ b/code/modules/supply/supply_packs/pack_engineering.dm
@@ -264,3 +264,17 @@
cost = 250
containertype = /obj/structure/largecrate
containername = "Plasma canister crate"
+
+/datum/supply_packs/engineering/chemical_flamethrower
+ name = "Chemical Flamethrower Starter Pack"
+ contains = list(/obj/item/chemical_flamethrower, /obj/item/chemical_canister, /obj/item/chemical_canister)
+ cost = 750
+ containertype = /obj/structure/closet/crate // Just a normal open crate, you can get a gas flamethrower from an autolathe
+ containername = "chemical flamethrower crate"
+
+/datum/supply_packs/engineering/chemical_canister
+ name = "Chemical Flamethrower Canister Pack"
+ contains = list(/obj/item/chemical_canister, /obj/item/chemical_canister, /obj/item/chemical_canister, /obj/item/chemical_canister, /obj/item/chemical_canister/extended) // One extended canister, as a treat
+ cost = 500
+ containertype = /obj/structure/closet/crate
+ containername = "chemical flamethrower canister crate"
diff --git a/icons/effects/chemical_fire.dmi b/icons/effects/chemical_fire.dmi
new file mode 100644
index 000000000000..9b9118cfc154
Binary files /dev/null and b/icons/effects/chemical_fire.dmi differ
diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi
index 44e2a2997afb..4b904d20be2f 100644
Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ
diff --git a/icons/mob/clothing/belt_mirror.dmi b/icons/mob/clothing/belt_mirror.dmi
index 6f8d91156a6b..33002364d190 100644
Binary files a/icons/mob/clothing/belt_mirror.dmi and b/icons/mob/clothing/belt_mirror.dmi differ
diff --git a/icons/mob/inhands/flamethrower_lefthand.dmi b/icons/mob/inhands/flamethrower_lefthand.dmi
new file mode 100644
index 000000000000..f68f114d8c94
Binary files /dev/null and b/icons/mob/inhands/flamethrower_lefthand.dmi differ
diff --git a/icons/mob/inhands/flamethrower_righthand.dmi b/icons/mob/inhands/flamethrower_righthand.dmi
new file mode 100644
index 000000000000..7c11f2a6b7dc
Binary files /dev/null and b/icons/mob/inhands/flamethrower_righthand.dmi differ
diff --git a/icons/obj/chemical_flamethrower.dmi b/icons/obj/chemical_flamethrower.dmi
new file mode 100644
index 000000000000..db4918663ec7
Binary files /dev/null and b/icons/obj/chemical_flamethrower.dmi differ
diff --git a/paradise.dme b/paradise.dme
index e45c0b1c98c6..9c247ecfd6a4 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -1229,6 +1229,8 @@
#include "code\game\objects\items\weapons\bio_chips\bio_chip_traitor.dm"
#include "code\game\objects\items\weapons\bio_chips\bio_chip_uplink.dm"
#include "code\game\objects\items\weapons\bio_chips\bio_chipper.dm"
+#include "code\game\objects\items\weapons\chemical_flamethrower\chemical_flamethrower.dm"
+#include "code\game\objects\items\weapons\chemical_flamethrower\fire_effect.dm"
#include "code\game\objects\items\weapons\grenades\atmosgrenade.dm"
#include "code\game\objects\items\weapons\grenades\bananade.dm"
#include "code\game\objects\items\weapons\grenades\chem_grenade.dm"
diff --git a/sound/effects/fire_sizzle.ogg b/sound/effects/fire_sizzle.ogg
new file mode 100644
index 000000000000..2c811d6ed45d
Binary files /dev/null and b/sound/effects/fire_sizzle.ogg differ