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