mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 12:41:09 +01:00
Adds Chemical Explosives
see changelog for details
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
|
||||
/obj/machinery/syndicatebomb
|
||||
icon = 'icons/obj/assemblies.dmi'
|
||||
name = "syndicate bomb"
|
||||
@@ -9,7 +10,7 @@
|
||||
layer = MOB_LAYER - 0.2 //so people can't hide it and it's REALLY OBVIOUS
|
||||
unacidable = 1
|
||||
|
||||
var/timer = 60
|
||||
var/timer = 120
|
||||
var/open_panel = FALSE //are the wires exposed?
|
||||
var/active = FALSE //is the bomb counting down?
|
||||
var/defused = FALSE //is the bomb capable of exploding?
|
||||
@@ -35,7 +36,8 @@
|
||||
|
||||
/obj/machinery/syndicatebomb/New()
|
||||
wires = new /datum/wires/syndicatebomb(src)
|
||||
payload = new payload(src)
|
||||
if(src.payload)
|
||||
payload = new payload(src)
|
||||
update_icon()
|
||||
..()
|
||||
|
||||
@@ -44,9 +46,21 @@
|
||||
wires = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/syndicatebomb/emag_act(mob/user)
|
||||
if(active && !emagged)
|
||||
emagged = 1
|
||||
timer = 60 // An emag can be used to reduce the timer, or give you more time, depending on when you use it.
|
||||
if(user)
|
||||
user.visible_message("<span class='warning'>Sparks fly out of the [src]!</span>",
|
||||
"<span class='notice'>You emag the [src], causing the timing mechanism to malfunction.</span>")
|
||||
playsound(src.loc, 'sound/effects/sparks4.ogg', 50, 1)
|
||||
|
||||
/obj/machinery/syndicatebomb/examine(mob/user)
|
||||
..()
|
||||
user << "A digital display on it reads \"[timer]\"."
|
||||
if(emagged)
|
||||
user << "A digital display on it reads \"[rand(-1, 60)]\"."
|
||||
else
|
||||
user << "A digital display on it reads \"[timer]\"."
|
||||
|
||||
/obj/machinery/syndicatebomb/update_icon()
|
||||
icon_state = "[initial(icon_state)][active ? "-active" : "-inactive"][open_panel ? "-wires" : ""]"
|
||||
@@ -99,6 +113,25 @@
|
||||
payload.loc = src
|
||||
else
|
||||
user << "<span class='warning'>[payload] is already loaded into [src]! You'll have to remove it first.</span>"
|
||||
else if(istype(I, /obj/item/weapon/weldingtool))
|
||||
if(payload || !wires.is_all_cut() || !open_panel)
|
||||
return
|
||||
var/obj/item/weapon/weldingtool/WT = I
|
||||
if(!WT.isOn())
|
||||
return
|
||||
if(WT.get_fuel() < 5) //uses up 5 fuel.
|
||||
user << "<span class='warning'>You need more fuel to complete this task!</span>"
|
||||
return
|
||||
|
||||
playsound(loc, pick('sound/items/Welder.ogg', 'sound/items/Welder2.ogg'), 50, 1)
|
||||
user << "<span class='notice'>You start to cut the [src] apart...</span>"
|
||||
if(do_after(user, 20/I.toolspeed, target = src))
|
||||
if(!WT.isOn() || !WT.remove_fuel(5, user))
|
||||
return
|
||||
user << "<span class='notice'>You cut the [src] apart.</span>"
|
||||
new /obj/item/stack/sheet/plasteel( loc, 5)
|
||||
qdel(src)
|
||||
return
|
||||
else
|
||||
..()
|
||||
|
||||
@@ -120,7 +153,7 @@
|
||||
|
||||
/obj/machinery/syndicatebomb/proc/settings(mob/user)
|
||||
var/newtime = input(user, "Please set the timer.", "Timer", "[timer]") as num
|
||||
newtime = Clamp(newtime, 60, 60000)
|
||||
newtime = Clamp(newtime, 120, 60000)
|
||||
if(in_range(src, user) && isliving(user)) //No running off and setting bombs from across the station
|
||||
timer = newtime
|
||||
src.loc.visible_message("<span class='notice'>\icon[src] timer set for [timer] seconds.</span>")
|
||||
@@ -166,6 +199,17 @@
|
||||
/obj/machinery/syndicatebomb/badmin/varplosion
|
||||
payload = /obj/item/weapon/bombcore/badmin/explosion/
|
||||
|
||||
/obj/machinery/syndicatebomb/empty
|
||||
name = "bomb"
|
||||
icon_state = "base-bomb"
|
||||
desc = "An ominous looking device designed to detonate an explosive payload. Can be bolted down using a wrench."
|
||||
payload = null
|
||||
open_panel = TRUE
|
||||
|
||||
/obj/machinery/syndicatebomb/empty/New()
|
||||
..()
|
||||
wires.cut_all()
|
||||
|
||||
///Bomb Cores///
|
||||
|
||||
/obj/item/weapon/bombcore
|
||||
@@ -180,11 +224,18 @@
|
||||
var/adminlog = null
|
||||
|
||||
/obj/item/weapon/bombcore/ex_act(severity, target) // Little boom can chain a big boom.
|
||||
detonate()
|
||||
if(prob(50))
|
||||
detonate()
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/bombcore/burn()
|
||||
detonate()
|
||||
..()
|
||||
if(prob(25))
|
||||
detonate()
|
||||
..()
|
||||
else
|
||||
..()
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/bombcore/proc/detonate()
|
||||
if(adminlog)
|
||||
@@ -292,6 +343,127 @@
|
||||
explosion(src.loc, 1, 2, 4, flame_range = 2) //Identical to a minibomb
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/bombcore/chemical
|
||||
name = "chemical payload"
|
||||
desc = "An explosive payload designed to spread chemicals, dangerous or otherwise, across a large area. It is able to hold up to four chemical containers, and must be loaded before use."
|
||||
origin_tech = "combat=4;materials=3"
|
||||
icon_state = "chemcore"
|
||||
var/list/beakers = list()
|
||||
var/max_beakers = 4
|
||||
var/spread_range = 5
|
||||
var/temp_boost = 50
|
||||
var/time_release = 0
|
||||
|
||||
/obj/item/weapon/bombcore/chemical/detonate()
|
||||
|
||||
if(time_release > 0)
|
||||
var/total_volume = 0
|
||||
for(var/obj/item/weapon/reagent_containers/RC in beakers)
|
||||
total_volume += RC.reagents.total_volume
|
||||
|
||||
if(total_volume < time_release) // If it's empty, the detonation is complete.
|
||||
if(loc && istype(loc,/obj/machinery/syndicatebomb/))
|
||||
qdel(loc)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
var/fraction = time_release/total_volume
|
||||
var/datum/reagents/reactants = new(time_release)
|
||||
reactants.my_atom = src
|
||||
for(var/obj/item/weapon/reagent_containers/RC in beakers)
|
||||
RC.reagents.trans_to(reactants, RC.reagents.total_volume*fraction, 1, 1, 1)
|
||||
chem_splash(get_turf(src), spread_range, list(reactants), temp_boost)
|
||||
|
||||
spawn(10)
|
||||
detonate() // Detonate it again in one second, until it's out of juice.
|
||||
|
||||
|
||||
// If it's not a time release bomb, do normal explosion
|
||||
|
||||
var/list/reactants = list()
|
||||
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in beakers)
|
||||
reactants += G.reagents
|
||||
|
||||
for(var/obj/item/slime_extract/S in beakers)
|
||||
if(S.Uses)
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in beakers)
|
||||
G.reagents.trans_to(S, G.reagents.total_volume)
|
||||
|
||||
if(S && S.reagents && S.reagents.total_volume)
|
||||
reactants += S.reagents
|
||||
|
||||
if(!chem_splash(get_turf(src), spread_range, reactants, temp_boost))
|
||||
playsound(loc, 'sound/items/Screwdriver2.ogg', 50, 1)
|
||||
return // The Explosion didn't do anything. No need to log, or disappear.
|
||||
|
||||
if(adminlog)
|
||||
message_admins(adminlog)
|
||||
log_game(adminlog)
|
||||
|
||||
playsound(loc, 'sound/effects/bamf.ogg', 75, 1, 5)
|
||||
|
||||
if(loc && istype(loc,/obj/machinery/syndicatebomb/))
|
||||
qdel(loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/bombcore/chemical/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/crowbar) && beakers.len > 0)
|
||||
playsound(loc, 'sound/items/Crowbar.ogg', 50, 1)
|
||||
for (var/obj/item/B in beakers)
|
||||
B.loc = get_turf(src)
|
||||
beakers -= B
|
||||
return
|
||||
else if(istype(I, /obj/item/weapon/reagent_containers/glass/beaker) || istype(I, /obj/item/weapon/reagent_containers/glass/bottle))
|
||||
if(beakers.len < max_beakers)
|
||||
if(!user.drop_item())
|
||||
return
|
||||
beakers += I
|
||||
user << "<span class='notice'>You load [src] with [I].</span>"
|
||||
I.loc = src
|
||||
else
|
||||
user << "<span class='warning'>The [I] wont fit! The [src] can only hold up to [max_beakers] containers.</span>"
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/weapon/bombcore/chemical/CheckParts()
|
||||
// Using different grenade casings, causes the payload to have different properties.
|
||||
for(var/obj/item/weapon/grenade/chem_grenade/G in src)
|
||||
|
||||
if(istype(G, /obj/item/weapon/grenade/chem_grenade/large))
|
||||
var/obj/item/weapon/grenade/chem_grenade/large/LG = G
|
||||
max_beakers += 1 // Adding two large grenades only allows for a maximum of 6 beakers.
|
||||
spread_range += 2 // Extra range, reduced density.
|
||||
temp_boost += 50 // maximum of +150K blast using only large beakers. Not enough to self ignite.
|
||||
for(var/obj/item/slime_extract/S in LG.beakers) // And slime cores.
|
||||
if(beakers.len < max_beakers)
|
||||
beakers += S
|
||||
S.loc = src
|
||||
else
|
||||
S.loc = get_turf(src)
|
||||
|
||||
if(istype(G, /obj/item/weapon/grenade/chem_grenade/cryo))
|
||||
spread_range -= 1 // Reduced range, but increased density.
|
||||
temp_boost -= 100 // minimum of -150K blast.
|
||||
|
||||
if(istype(G, /obj/item/weapon/grenade/chem_grenade/pyro))
|
||||
temp_boost += 150 // maximum of +350K blast, which is enough to self ignite. Which means a self igniting bomb can't take advantage of other grenade casing properties. Sorry?
|
||||
|
||||
if(istype(G, /obj/item/weapon/grenade/chem_grenade/adv_release))
|
||||
time_release += 25 // A typical bomb, using basic beakers, will explode over 2-4 seconds. Using two will make the reaction last for less time, but it will be more dangerous overall.
|
||||
|
||||
for(var/obj/item/weapon/reagent_containers/glass/B in G)
|
||||
if(beakers.len < max_beakers)
|
||||
beakers += B
|
||||
B.loc = src
|
||||
else
|
||||
B.loc = get_turf(src)
|
||||
|
||||
qdel(G)
|
||||
return
|
||||
|
||||
|
||||
|
||||
///Syndicate Detonator (aka the big red button)///
|
||||
|
||||
/obj/item/device/syndicatedetonator
|
||||
@@ -326,7 +498,4 @@
|
||||
detonated = 0
|
||||
existant = 0
|
||||
cooldown = 1
|
||||
spawn(30) cooldown = 0
|
||||
|
||||
|
||||
|
||||
spawn(30) cooldown = 0
|
||||
@@ -79,6 +79,7 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \
|
||||
*/
|
||||
var/global/list/datum/stack_recipe/plasteel_recipes = list ( \
|
||||
new/datum/stack_recipe("AI core", /obj/structure/AIcore, 4, time = 50, one_per_turf = 1), \
|
||||
new/datum/stack_recipe("bomb assembly", /obj/machinery/syndicatebomb/empty, 10, time = 50), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/plasteel
|
||||
@@ -110,7 +111,6 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \
|
||||
new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20), \
|
||||
new/datum/stack_recipe("wood table frame", /obj/structure/table_frame/wood, 2, time = 10), \
|
||||
new/datum/stack_recipe("rifle stock", /obj/item/weaponcrafting/stock, 10, time = 40), \
|
||||
new/datum/stack_recipe("rolling pin", /obj/item/weapon/kitchen/rollingpin, 2, time = 30), \
|
||||
new/datum/stack_recipe("wooden chair", /obj/structure/chair/wood/normal, 3, time = 10, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("wooden barricade", /obj/structure/barricade/wooden, 5, time = 50, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("wooden door", /obj/structure/mineral_door/wood, 10, time = 20, one_per_turf = 1, on_floor = 1), \
|
||||
@@ -223,4 +223,4 @@ var/global/list/datum/stack_recipe/runed_metal_recipes = list ( \
|
||||
desc = "Rare kind of gems which are only gained by blood sacrifice to minor deities. They are needed in crafting powerful objects."
|
||||
singular_name = "greater gem"
|
||||
icon_state = "sheet-greatergem"
|
||||
origin_tech = "materials=8"
|
||||
origin_tech = "materials=8"
|
||||
@@ -15,6 +15,8 @@
|
||||
var/affected_area = 3
|
||||
var/obj/item/device/assembly_holder/nadeassembly = null
|
||||
var/assemblyattacher
|
||||
var/ignition_temp = 10 // The amount of heat added to the reagents when this grenade goes off.
|
||||
var/threatscale = 1 // Used by advanced grenades to make them slightly more worthy.
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/New()
|
||||
create_reagents(1000)
|
||||
@@ -153,15 +155,14 @@
|
||||
nadeassembly.on_found(finder)
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/prime()
|
||||
if(stage != READY || !reagents)
|
||||
if(stage != READY)
|
||||
return
|
||||
|
||||
var/has_reagents
|
||||
for(var/obj/item/I in beakers)
|
||||
if(I.reagents.total_volume)
|
||||
has_reagents = 1
|
||||
var/list/datum/reagents/reactants = list()
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in beakers)
|
||||
reactants += G.reagents
|
||||
|
||||
if(!has_reagents)
|
||||
if(!chem_splash(get_turf(src), affected_area, reactants, ignition_temp, threatscale))
|
||||
playsound(loc, 'sound/items/Screwdriver2.ogg', 50, 1)
|
||||
return
|
||||
|
||||
@@ -173,79 +174,30 @@
|
||||
message_admins("grenade primed by an assembly, attached by [key_name_admin(M)]<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>(?)</A> (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[M]'>FLW</A>) and last touched by [key_name_admin(last)]<A HREF='?_src_=holder;adminmoreinfo=\ref[last]'>(?)</A> (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[last]'>FLW</A>) ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[T.x];Y=[T.y];Z=[T.z]'>[A.name] (JMP)</a>.")
|
||||
log_game("grenade primed by an assembly, attached by [key_name(M)] and last touched by [key_name(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at [A.name] ([T.x], [T.y], [T.z])")
|
||||
|
||||
playsound(loc, 'sound/effects/bamf.ogg', 50, 1)
|
||||
|
||||
var/turf/DT = get_turf(src)
|
||||
var/area/DA = get_area(DT)
|
||||
log_game("A grenade detonated at [DA.name] ([DT.x], [DT.y], [DT.z])")
|
||||
|
||||
update_mob()
|
||||
|
||||
mix_reagents()
|
||||
|
||||
if(reagents.total_volume) //The possible reactions didnt use up all reagents, so we spread it around.
|
||||
var/datum/effect_system/steam_spread/steam = new /datum/effect_system/steam_spread()
|
||||
steam.set_up(10, 0, get_turf(src))
|
||||
steam.attach(src)
|
||||
steam.start()
|
||||
|
||||
var/list/viewable = view(affected_area, loc)
|
||||
var/list/accessible = can_flood_from(loc, affected_area)
|
||||
var/list/reactable = accessible
|
||||
var/mycontents = GetAllContents()
|
||||
for(var/turf/T in accessible)
|
||||
for(var/atom/A in T.GetAllContents())
|
||||
if(A in mycontents) continue
|
||||
if(!(A in viewable)) continue
|
||||
reactable |= A
|
||||
if(!reactable.len) //Nothing to react with. Probably means we're in nullspace.
|
||||
qdel(src)
|
||||
return
|
||||
var/fraction = 1/reactable.len
|
||||
for(var/atom/A in reactable)
|
||||
reagents.reaction(A, TOUCH, fraction)
|
||||
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/proc/mix_reagents()
|
||||
var/total_temp
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in beakers)
|
||||
G.reagents.trans_to(src, G.reagents.total_volume)
|
||||
total_temp += G.reagents.chem_temp
|
||||
reagents.chem_temp = total_temp
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/proc/can_flood_from(myloc, maxrange)
|
||||
var/turf/myturf = get_turf(myloc)
|
||||
var/list/reachable = list(myloc)
|
||||
for(var/i=1; i<=maxrange; i++)
|
||||
var/list/turflist = list()
|
||||
for(var/turf/T in (orange(i, myloc) - orange(i-1, myloc)))
|
||||
turflist |= T
|
||||
for(var/turf/T in turflist)
|
||||
if( !(get_dir(T,myloc) in cardinal) && (abs(T.x - myturf.x) == abs(T.y - myturf.y) ))
|
||||
turflist.Remove(T)
|
||||
turflist.Add(T) // we move the purely diagonal turfs to the end of the list.
|
||||
for(var/turf/T in turflist)
|
||||
if(T in reachable) continue
|
||||
for(var/turf/NT in orange(1, T))
|
||||
if(!(NT in reachable)) continue
|
||||
if(!(get_dir(T,NT) in cardinal)) continue
|
||||
if(!NT.CanAtmosPass(T)) continue
|
||||
reachable |= T
|
||||
break
|
||||
return reachable
|
||||
|
||||
//Large chem grenades accept slime cores and use the appropriately.
|
||||
/obj/item/weapon/grenade/chem_grenade/large
|
||||
name = "large grenade"
|
||||
desc = "A custom made large grenade."
|
||||
desc = "A custom made large grenade. It affects a larger area."
|
||||
icon_state = "large_grenade"
|
||||
allowed_containers = list(/obj/item/weapon/reagent_containers/glass,/obj/item/weapon/reagent_containers/food/condiment,
|
||||
/obj/item/weapon/reagent_containers/food/drinks)
|
||||
origin_tech = "combat=3;materials=3"
|
||||
affected_area = 4
|
||||
affected_area = 5
|
||||
ignition_temp = 25 // Large grenades are slightly more effective at setting off heat-sensitive mixtures than smaller grenades.
|
||||
threatscale = 1.1 // 10% more effective.
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/large/prime()
|
||||
if(stage != READY)
|
||||
return
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/large/mix_reagents()
|
||||
for(var/obj/item/slime_extract/S in beakers)
|
||||
if(S.Uses)
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in beakers)
|
||||
@@ -272,6 +224,76 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/cryo // Intended for rare cryogenic mixes. Cools the area moderately upon detonation.
|
||||
name = "cryo grenade"
|
||||
desc = "A custom made cryogenic grenade. It rapidly cools its contents upon detonation."
|
||||
icon_state = "cryog"
|
||||
affected_area = 2
|
||||
ignition_temp = -100
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/pyro // Intended for pyrotechnical mixes. Produces a small fire upon detonation, igniting potentially flammable mixtures.
|
||||
name = "pyro grenade"
|
||||
desc = "A custom made pyrotechnical grenade. It heats up and ignites its contents upon detonation."
|
||||
icon_state = "pyrog"
|
||||
affected_area = 3
|
||||
ignition_temp = 500 // This is enough to expose a hotspot.
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/adv_release // Intended for weaker, but longer lasting effects. Could have some interesting uses.
|
||||
name = "advanced release grenade"
|
||||
desc = "A custom made advanced release grenade. It is able to be triggered more than once. Can be configured using a multitool."
|
||||
icon_state = "timeg"
|
||||
var/unit_spread = 10 // Amount of units per repeat. Can be altered with a multitool.
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/adv_release/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/device/multitool))
|
||||
if(unit_spread < 100)
|
||||
unit_spread += 5
|
||||
else
|
||||
unit_spread = 5
|
||||
user << "<span class='notice'> You set the time release to [unit_spread] units per detonation.</span>"
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/adv_release/prime()
|
||||
if(stage != READY)
|
||||
return
|
||||
|
||||
var/total_volume = 0
|
||||
for(var/obj/item/weapon/reagent_containers/RC in beakers)
|
||||
total_volume += RC.reagents.total_volume
|
||||
|
||||
var/fraction = unit_spread/total_volume
|
||||
var/datum/reagents/reactants = new(unit_spread)
|
||||
reactants.my_atom = src
|
||||
for(var/obj/item/weapon/reagent_containers/RC in beakers)
|
||||
RC.reagents.trans_to(reactants, RC.reagents.total_volume*fraction, threatscale, 1, 1)
|
||||
|
||||
chem_splash(get_turf(src), affected_area, list(reactants), ignition_temp, threatscale)
|
||||
|
||||
if(nadeassembly)
|
||||
var/mob/M = get_mob_by_ckey(assemblyattacher)
|
||||
var/mob/last = get_mob_by_ckey(nadeassembly.fingerprintslast)
|
||||
var/turf/T = get_turf(src)
|
||||
var/area/A = get_area(T)
|
||||
message_admins("grenade primed by an assembly, attached by [key_name_admin(M)]<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>(?)</A> (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[M]'>FLW</A>) and last touched by [key_name_admin(last)]<A HREF='?_src_=holder;adminmoreinfo=\ref[last]'>(?)</A> (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[last]'>FLW</A>) ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[T.x];Y=[T.y];Z=[T.z]'>[A.name] (JMP)</a>.")
|
||||
log_game("grenade primed by an assembly, attached by [key_name(M)] and last touched by [key_name(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at [A.name] ([T.x], [T.y], [T.z])")
|
||||
|
||||
var/turf/DT = get_turf(src)
|
||||
var/area/DA = get_area(DT)
|
||||
log_game("A grenade detonated at [DA.name] ([DT.x], [DT.y], [DT.z])")
|
||||
|
||||
if(total_volume < unit_spread) // If that was the last detonation, delete the grenade to prevent reusing it. Keep in mind, an explosion might destroy the grenade before it can detonate again anyways.
|
||||
update_mob()
|
||||
qdel(src)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
////// PREMADE GRENADES //////
|
||||
//////////////////////////////
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/metalfoam
|
||||
name = "metal foam grenade"
|
||||
|
||||
@@ -327,3 +327,27 @@
|
||||
time = 10
|
||||
reqs = list(/obj/item/weapon/paper = 5)
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/table_recipe/chemical_payload
|
||||
name = "Chemical Bomb Core (C4)"
|
||||
result = /obj/item/weapon/bombcore/chemical
|
||||
reqs = list(
|
||||
/obj/item/weapon/stock_parts/matter_bin/super = 1,
|
||||
/obj/item/weapon/c4 = 1,
|
||||
/obj/item/weapon/grenade/chem_grenade = 2
|
||||
)
|
||||
parts = list(/obj/item/weapon/grenade/chem_grenade = 2)
|
||||
time = 30
|
||||
category = CAT_WEAPON
|
||||
|
||||
/datum/table_recipe/chemical_payload2
|
||||
name = "Chemical Bomb Core (gibtonite)"
|
||||
result = /obj/item/weapon/bombcore/chemical
|
||||
reqs = list(
|
||||
/obj/item/weapon/stock_parts/matter_bin/super = 1,
|
||||
/obj/item/weapon/twohanded/required/gibtonite = 1,
|
||||
/obj/item/weapon/grenade/chem_grenade = 2
|
||||
)
|
||||
parts = list(/obj/item/weapon/grenade/chem_grenade = 2)
|
||||
time = 50
|
||||
category = CAT_WEAPON
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// Replaces chemgrenade stuff, allowing reagent explosions to be called from anywhere.
|
||||
// It should be called using a location, the range, and a list of reagents involved.
|
||||
|
||||
// Threatscale is a multiplier for the 'threat' of the grenade. If you're increasing the affected range drastically, you might want to improve this.
|
||||
// Extra heat affects the temperature of the mixture, and may cause it to react in different ways.
|
||||
|
||||
|
||||
proc/chem_splash(turf/epicenter, affected_range = 3, list/datum/reagents/reactants = list(), extra_heat = 0, threatscale = 1, adminlog = 1)
|
||||
if(!istype(epicenter, /turf) || !reactants.len || threatscale <= 0)
|
||||
return
|
||||
var/has_reagents
|
||||
var/total_reagents
|
||||
for(var/datum/reagents/R in reactants)
|
||||
if(R.total_volume)
|
||||
has_reagents = 1
|
||||
total_reagents += R.total_volume
|
||||
|
||||
if(!has_reagents)
|
||||
return
|
||||
|
||||
var/datum/reagents/splash_holder = new/datum/reagents(total_reagents*threatscale)
|
||||
splash_holder.my_atom = epicenter // For some reason this is setting my_atom to null, and causing runtime errors.
|
||||
var/total_temp = 0
|
||||
|
||||
for(var/datum/reagents/R in reactants)
|
||||
R.trans_to(splash_holder, R.total_volume, threatscale, 1, 1)
|
||||
total_temp += R.chem_temp
|
||||
splash_holder.chem_temp = (total_temp/reactants.len) + extra_heat // Average temperature of reagents + extra heat.
|
||||
splash_holder.handle_reactions() // React them now.
|
||||
|
||||
if(splash_holder.total_volume && affected_range >= 0) //The possible reactions didnt use up all reagents, so we spread it around.
|
||||
var/datum/effect_system/steam_spread/steam = new /datum/effect_system/steam_spread()
|
||||
steam.set_up(10, 0, epicenter)
|
||||
steam.attach(epicenter)
|
||||
steam.start()
|
||||
|
||||
var/list/viewable = view(affected_range, epicenter)
|
||||
|
||||
var/list/accessible = list(epicenter)
|
||||
for(var/i=1; i<=affected_range; i++)
|
||||
var/list/turflist = list()
|
||||
for(var/turf/T in (orange(i, epicenter) - orange(i-1, epicenter)))
|
||||
turflist |= T
|
||||
for(var/turf/T in turflist)
|
||||
if( !(get_dir(T,epicenter) in cardinal) && (abs(T.x - epicenter.x) == abs(T.y - epicenter.y) ))
|
||||
turflist.Remove(T)
|
||||
turflist.Add(T) // we move the purely diagonal turfs to the end of the list.
|
||||
for(var/turf/T in turflist)
|
||||
if(T in accessible) continue
|
||||
for(var/turf/NT in orange(1, T))
|
||||
if(!(NT in accessible)) continue
|
||||
if(!(get_dir(T,NT) in cardinal)) continue
|
||||
if(!NT.CanAtmosPass(T)) continue
|
||||
accessible |= T
|
||||
break
|
||||
var/list/reactable = accessible
|
||||
for(var/turf/T in accessible)
|
||||
for(var/atom/A in T.GetAllContents())
|
||||
if(!(A in viewable)) continue
|
||||
reactable |= A
|
||||
if(extra_heat >= 300)
|
||||
T.hotspot_expose(extra_heat*2, 5)
|
||||
if(!reactable.len) //Nothing to react with. Probably means we're in nullspace.
|
||||
return
|
||||
var/fraction = 0.5/accessible.len // In a 100u mix. A small grenade spreads ~1.5u units per affected tile. A large grenade spreads ~0.75u, and a bomb spreads ~0.4u
|
||||
for(var/atom/A in reactable)
|
||||
splash_holder.reaction(A, TOUCH, fraction)
|
||||
|
||||
qdel(splash_holder)
|
||||
return 1
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ var/const/INJECT = 5 //injection
|
||||
|
||||
return id
|
||||
|
||||
/datum/reagents/proc/trans_to(obj/target, amount=1, multiplier=1, preserve_data=1)//if preserve_data=0, the reagents data will be lost. Usefull if you use data for some strange stuff and don't want it to be transferred.
|
||||
/datum/reagents/proc/trans_to(obj/target, amount=1, multiplier=1, preserve_data=1, no_react = 0)//if preserve_data=0, the reagents data will be lost. Usefull if you use data for some strange stuff and don't want it to be transferred.
|
||||
if(!target )
|
||||
return
|
||||
var/datum/reagents/R
|
||||
@@ -150,8 +150,9 @@ var/const/INJECT = 5 //injection
|
||||
|
||||
update_total()
|
||||
R.update_total()
|
||||
R.handle_reactions()
|
||||
src.handle_reactions()
|
||||
if(!no_react)
|
||||
R.handle_reactions()
|
||||
src.handle_reactions()
|
||||
return amount
|
||||
|
||||
/datum/reagents/proc/copy_to(obj/target, amount=1, multiplier=1, preserve_data=1)
|
||||
|
||||
@@ -127,6 +127,42 @@
|
||||
build_path = /obj/item/weapon/grenade/chem_grenade/large
|
||||
category = list("Weapons")
|
||||
|
||||
/datum/design/pyro_grenade
|
||||
name = "Pyro Grenade"
|
||||
desc = "An advanced grenade that is able to self ignite its mixture."
|
||||
id = "pyro_Grenade"
|
||||
req_tech = list("combat" = 3, "materials" = 3)
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 2000, MAT_PLASMA = 500)
|
||||
reliability = 79
|
||||
build_path = /obj/item/weapon/grenade/chem_grenade/pyro
|
||||
category = list("Weapons")
|
||||
|
||||
/* // Currently commented out, because it has no worthwhile useage yet.
|
||||
|
||||
/datum/design/cryo_grenade
|
||||
name = "Cryo Grenade"
|
||||
desc = "An advanced grenade that rapidly cools its contents upon detonation."
|
||||
id = "cryo_Grenade"
|
||||
req_tech = list("combat" = 3, "materials" = 3)
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 2000, MAT_SILVER = 500)
|
||||
reliability = 79
|
||||
build_path = /obj/item/weapon/grenade/chem_grenade/cryo
|
||||
category = list("Weapons")
|
||||
*/
|
||||
|
||||
/datum/design/adv_grenade
|
||||
name = "Advanced Release Grenade"
|
||||
desc = "An advanced grenade that can be detonated several times, best used with a repeating igniter."
|
||||
id = "adv_Grenade"
|
||||
req_tech = list("combat" = 3, "materials" = 3)
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 3000, MAT_GLASS = 500)
|
||||
reliability = 79
|
||||
build_path = /obj/item/weapon/grenade/chem_grenade/adv_release
|
||||
category = list("Weapons")
|
||||
|
||||
/datum/design/smg
|
||||
name = "NanoTrasen Saber SMG"
|
||||
desc = "A prototype advancment over the WT-550 auto rifle made using lightweight materials on a traditional frame, designed to fire standard 9mm rounds."
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
author: "nullbear"
|
||||
|
||||
delete-after: True
|
||||
|
||||
changes:
|
||||
- rscadd: "Added several craftable explosive chemical weapons."
|
||||
- rscadd: "Made it possible to craft bomb assemblies using plasteel. Note: they will need a payload, and to have their wires set, before it can be detonated."
|
||||
- rscadd: "Made it possible to emag bombs in order to cause the timer to malfunction and reset itself to 60 seconds. This can be used to give yourself more time, or to shorten the timer."
|
||||
- tweak: "Large Grenades are now 10% larger and more effective."
|
||||
- tweak: "Grenades now typically heat up their contents when they explode."
|
||||
- tweak: "Non-typical grenades are slightly more potent than they were before."
|
||||
- tweak: "Reduces metagaming potential for bypassing the timer and setting off bombs with c4 or fire."
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.0 KiB |
Reference in New Issue
Block a user