mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-18 02:24:11 +01:00
Merge pull request #7672 from Fox-McCloud/syndicate-bomb-refactor
Refactors Syndicate Bombs and Adds Chemical Bombs
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/datum/wires/syndicatebomb
|
||||
random = 1
|
||||
random = TRUE
|
||||
holder_type = /obj/machinery/syndicatebomb
|
||||
wire_count = 5
|
||||
|
||||
@@ -13,83 +13,90 @@ var/const/WIRE_ACTIVATE = 16 // Will start a bombs timer if pulsed, will hint if
|
||||
switch(index)
|
||||
if(WIRE_BOOM)
|
||||
return "Explode"
|
||||
|
||||
|
||||
if(WIRE_UNBOLT)
|
||||
return "Unbolt"
|
||||
|
||||
|
||||
if(WIRE_DELAY)
|
||||
return "Delay"
|
||||
|
||||
|
||||
if(WIRE_PROCEED)
|
||||
return "Proceed"
|
||||
|
||||
|
||||
if(WIRE_ACTIVATE)
|
||||
return "Activate"
|
||||
|
||||
/datum/wires/syndicatebomb/CanUse(mob/living/L)
|
||||
var/obj/machinery/syndicatebomb/P = holder
|
||||
if(P.open_panel)
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/wires/syndicatebomb/UpdatePulsed(index)
|
||||
var/obj/machinery/syndicatebomb/P = holder
|
||||
var/obj/machinery/syndicatebomb/B = holder
|
||||
switch(index)
|
||||
if(WIRE_BOOM)
|
||||
if(P.active)
|
||||
P.loc.visible_message("<span class='danger'>[bicon(holder)] An alarm sounds! It's go-</span>")
|
||||
P.timer = 0
|
||||
if(B.active)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
|
||||
B.explode_now = TRUE
|
||||
if(WIRE_UNBOLT)
|
||||
P.loc.visible_message("<span class='notice'>[bicon(holder)] The bolts spin in place for a moment.</span>")
|
||||
holder.visible_message("<span class='notice'>[bicon(holder)] The bolts spin in place for a moment.</span>")
|
||||
if(WIRE_DELAY)
|
||||
playsound(P.loc, 'sound/machines/chime.ogg', 30, 1)
|
||||
P.loc.visible_message("<span class='notice'>[bicon(holder)] The bomb chirps.</span>")
|
||||
P.timer += 10
|
||||
if(WIRE_PROCEED)
|
||||
playsound(P.loc, 'sound/machines/buzz-sigh.ogg', 30, 1)
|
||||
P.loc.visible_message("<span class='danger'>[bicon(holder)] The bomb buzzes ominously!</span>")
|
||||
if(P.timer >= 61) //Long fuse bombs can suddenly become more dangerous if you tinker with them
|
||||
P.timer = 60
|
||||
if(P.timer >= 21)
|
||||
P.timer -= 10
|
||||
else if(P.timer >= 11) //both to prevent negative timers and to have a little mercy
|
||||
P.timer = 10
|
||||
if(WIRE_ACTIVATE)
|
||||
if(!P.active && !P.defused)
|
||||
playsound(P.loc, 'sound/machines/click.ogg', 30, 1)
|
||||
P.loc.visible_message("<span class='danger'>[bicon(holder)] You hear the bomb start ticking!</span>")
|
||||
P.active = 1
|
||||
P.icon_state = "[initial(P.icon_state)]-active[P.open_panel ? "-wires" : ""]"
|
||||
if(B.delayedbig)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bomb has already been delayed.</span>")
|
||||
else
|
||||
P.loc.visible_message("<span class='notice'>[bicon(holder)] The bomb seems to hesitate for a moment.</span>")
|
||||
P.timer += 5
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bomb chirps.</span>")
|
||||
playsound(B, 'sound/machines/chime.ogg', 30, 1)
|
||||
B.detonation_timer += 300
|
||||
B.delayedbig = TRUE
|
||||
if(WIRE_PROCEED)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] The bomb buzzes ominously!</span>")
|
||||
playsound(B, 'sound/machines/buzz-sigh.ogg', 30, 1)
|
||||
var/seconds = B.seconds_remaining()
|
||||
if(seconds >= 61) // Long fuse bombs can suddenly become more dangerous if you tinker with them.
|
||||
B.detonation_timer = world.time + 600
|
||||
else if(seconds >= 21)
|
||||
B.detonation_timer -= 100
|
||||
else if(seconds >= 11) // Both to prevent negative timers and to have a little mercy.
|
||||
B.detonation_timer = world.time + 100
|
||||
if(WIRE_ACTIVATE)
|
||||
if(!B.active && !B.defused)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] You hear the bomb start ticking!</span>")
|
||||
B.activate()
|
||||
B.update_icon()
|
||||
else if(B.delayedlittle)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] Nothing happens.</span>")
|
||||
else
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bomb seems to hesitate for a moment.</span>")
|
||||
B.detonation_timer += 100
|
||||
B.delayedlittle = TRUE
|
||||
..()
|
||||
|
||||
/datum/wires/syndicatebomb/UpdateCut(index, mended)
|
||||
var/obj/machinery/syndicatebomb/P = holder
|
||||
var/obj/machinery/syndicatebomb/B = holder
|
||||
switch(index)
|
||||
if(WIRE_EXPLODE)
|
||||
if(!mended)
|
||||
if(P.active)
|
||||
P.loc.visible_message("<span class='danger'>[bicon(holder)] An alarm sounds! It's go-</span>")
|
||||
P.timer = 0
|
||||
else
|
||||
P.defused = 1
|
||||
if(mended)
|
||||
B.defused = FALSE // Cutting and mending all the wires of an inactive bomb will thus cure any sabotage.
|
||||
else
|
||||
P.defused = 0 //cutting and mending all the wires of an inactive bomb will thus cure any sabotage
|
||||
if(B.active)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
|
||||
B.explode_now = TRUE
|
||||
else
|
||||
B.defused = TRUE
|
||||
if(WIRE_UNBOLT)
|
||||
if(!mended && P.anchored)
|
||||
playsound(P.loc, 'sound/effects/stealthoff.ogg', 30, 1)
|
||||
P.loc.visible_message("<span class='notice'>[bicon(holder)] The bolts lift out of the ground!</span>")
|
||||
P.anchored = 0
|
||||
if(!mended && B.anchored)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bolts lift out of the ground!</span>")
|
||||
playsound(B, 'sound/effects/stealthoff.ogg', 30, 1)
|
||||
B.anchored = FALSE
|
||||
if(WIRE_PROCEED)
|
||||
if(!mended && P.active)
|
||||
P.loc.visible_message("<span class='danger'>[bicon(holder)] An alarm sounds! It's go-</span>")
|
||||
P.timer = 0
|
||||
if(!mended && B.active)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
|
||||
B.explode_now = TRUE
|
||||
if(WIRE_ACTIVATE)
|
||||
if(!mended && P.active)
|
||||
P.loc.visible_message("<span class='notice'>[bicon(holder)] The timer stops! The bomb has been defused!</span>")
|
||||
P.icon_state = "[initial(P.icon_state)]-inactive[P.open_panel ? "-wires" : ""]"
|
||||
P.active = 0
|
||||
P.defused = 1
|
||||
if(!mended && B.active)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The timer stops! The bomb has been defused!</span>")
|
||||
B.active = FALSE
|
||||
B.defused = TRUE
|
||||
B.update_icon()
|
||||
..()
|
||||
@@ -1,3 +1,6 @@
|
||||
#define BUTTON_COOLDOWN 60 // cant delay the bomb forever
|
||||
#define BUTTON_DELAY 50 //five seconds
|
||||
|
||||
/obj/machinery/syndicatebomb
|
||||
icon = 'icons/obj/assemblies.dmi'
|
||||
name = "syndicate bomb"
|
||||
@@ -6,71 +9,119 @@
|
||||
|
||||
anchored = 0
|
||||
density = 0
|
||||
layer = MOB_LAYER - 0.1 //so people can't hide it and it's REALLY OBVIOUS
|
||||
layer = BELOW_MOB_LAYER //so people can't hide it and it's REALLY OBVIOUS
|
||||
unacidable = 1
|
||||
|
||||
var/datum/wires/syndicatebomb/wires = null
|
||||
var/timer = 120
|
||||
var/open_panel = 0 //are the wires exposed?
|
||||
var/active = 0 //is the bomb counting down?
|
||||
var/defused = 0 //is the bomb capable of exploding?
|
||||
var/obj/item/weapon/bombcore/payload = /obj/item/weapon/bombcore/
|
||||
var/minimum_timer = 90
|
||||
var/timer_set = 90
|
||||
var/maximum_timer = 60000
|
||||
|
||||
var/can_unanchor = TRUE
|
||||
|
||||
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?
|
||||
var/obj/item/weapon/bombcore/payload = /obj/item/weapon/bombcore
|
||||
var/beepsound = 'sound/items/timer.ogg'
|
||||
var/delayedbig = FALSE //delay wire pulsed?
|
||||
var/delayedlittle = FALSE //activation wire pulsed?
|
||||
var/obj/effect/countdown/syndicatebomb/countdown
|
||||
|
||||
var/next_beep
|
||||
var/detonation_timer
|
||||
var/explode_now = FALSE
|
||||
|
||||
/obj/machinery/syndicatebomb/proc/try_detonate(ignore_active = FALSE)
|
||||
. = (payload in src) && (active || ignore_active) && !defused
|
||||
if(.)
|
||||
payload.detonate()
|
||||
|
||||
/obj/machinery/syndicatebomb/process()
|
||||
if(active && !defused && (timer > 0)) //Tick Tock
|
||||
var/volume = (timer <= 20 ? 40 : 10) // Tick louder when the bomb is closer to being detonated.
|
||||
playsound(loc, beepsound, volume, 0)
|
||||
timer = max(timer - 2,0) // 2 seconds per process()
|
||||
if(active && !defused && (timer <= 0)) //Boom
|
||||
active = 0
|
||||
timer = 120
|
||||
update_icon()
|
||||
if(payload in src)
|
||||
payload.detonate()
|
||||
if(!active)
|
||||
fast_processing -= src
|
||||
detonation_timer = null
|
||||
next_beep = null
|
||||
countdown.stop()
|
||||
return
|
||||
if(!active || defused) //Counter terrorists win
|
||||
|
||||
if(!isnull(next_beep) && (next_beep <= world.time))
|
||||
var/volume
|
||||
switch(seconds_remaining())
|
||||
if(0 to 5)
|
||||
volume = 50
|
||||
if(5 to 10)
|
||||
volume = 40
|
||||
if(10 to 15)
|
||||
volume = 30
|
||||
if(15 to 20)
|
||||
volume = 20
|
||||
if(20 to 25)
|
||||
volume = 10
|
||||
else
|
||||
volume = 5
|
||||
playsound(loc, beepsound, volume, 0)
|
||||
next_beep = world.time + 10
|
||||
|
||||
if(active && !defused && ((detonation_timer <= world.time) || explode_now))
|
||||
active = FALSE
|
||||
timer_set = initial(timer_set)
|
||||
update_icon()
|
||||
try_detonate(TRUE)
|
||||
//Counter terrorists win
|
||||
else if(!active || defused)
|
||||
if(defused && payload in src)
|
||||
payload.defuse()
|
||||
return
|
||||
countdown.stop()
|
||||
fast_processing -= src
|
||||
|
||||
/obj/machinery/syndicatebomb/New()
|
||||
wires = new(src)
|
||||
payload = new payload(src)
|
||||
if(payload)
|
||||
payload = new payload(src)
|
||||
update_icon()
|
||||
countdown = new(src)
|
||||
..()
|
||||
|
||||
/obj/machinery/syndicatebomb/Destroy()
|
||||
QDEL_NULL(wires)
|
||||
QDEL_NULL(countdown)
|
||||
fast_processing -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/syndicatebomb/examine(mob/user)
|
||||
..(user)
|
||||
to_chat(user, "A digital display on it reads \"[timer]\".")
|
||||
to_chat(user, "A digital display on it reads \"[seconds_remaining()]\".")
|
||||
|
||||
/obj/machinery/syndicatebomb/update_icon()
|
||||
icon_state = "[initial(icon_state)][active ? "-active" : "-inactive"][open_panel ? "-wires" : ""]"
|
||||
|
||||
/obj/machinery/syndicatebomb/attackby(var/obj/item/I, var/mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/wrench))
|
||||
/obj/machinery/syndicatebomb/proc/seconds_remaining()
|
||||
if(active)
|
||||
. = max(0, round((detonation_timer - world.time) / 10))
|
||||
else
|
||||
. = timer_set
|
||||
|
||||
/obj/machinery/syndicatebomb/attackby(obj/item/I, mob/user, params)
|
||||
if(iswrench(I) && can_unanchor)
|
||||
if(!anchored)
|
||||
if(!isturf(src.loc) || istype(src.loc, /turf/space))
|
||||
to_chat(user, "<span class='notice'>The bomb must be placed on solid ground to attach it</span>")
|
||||
if(!isturf(loc) || isspaceturf(loc))
|
||||
to_chat(user, "<span class='notice'>The bomb must be placed on solid ground to attach it.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You firmly wrench the bomb to the floor</span>")
|
||||
to_chat(user, "<span class='notice'>You firmly wrench the bomb to the floor.</span>")
|
||||
playsound(loc, I.usesound, 50, 1)
|
||||
anchored = 1
|
||||
if(active)
|
||||
to_chat(user, "<span class='notice'>The bolts lock in place</span>")
|
||||
to_chat(user, "<span class='notice'>The bolts lock in place.</span>")
|
||||
else
|
||||
if(!active)
|
||||
to_chat(user, "<span class='notice'>You wrench the bomb from the floor</span>")
|
||||
to_chat(user, "<span class='notice'>You wrench the bomb from the floor.</span>")
|
||||
playsound(loc, I.usesound, 50, 1)
|
||||
anchored = 0
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The bolts are locked down!</span>")
|
||||
|
||||
else if(istype(I, /obj/item/weapon/screwdriver))
|
||||
else if(isscrewdriver(I))
|
||||
open_panel = !open_panel
|
||||
update_icon()
|
||||
to_chat(user, "<span class='notice'>You [open_panel ? "open" : "close"] the wire panel.</span>")
|
||||
@@ -79,28 +130,47 @@
|
||||
if(open_panel)
|
||||
wires.Interact(user)
|
||||
|
||||
else if(istype(I, /obj/item/weapon/crowbar))
|
||||
if(open_panel && isWireCut(WIRE_BOOM) && isWireCut(WIRE_UNBOLT) && isWireCut(WIRE_DELAY) && isWireCut(WIRE_PROCEED) && isWireCut(WIRE_ACTIVATE))
|
||||
else if(iscrowbar(I))
|
||||
if(open_panel && wires.IsAllCut())
|
||||
if(payload)
|
||||
to_chat(user, "<span class='notice'>You carefully pry out [payload].</span>")
|
||||
payload.loc = user.loc
|
||||
payload = null
|
||||
else
|
||||
to_chat(user, "<span class='notice'>There isn't anything in here to remove!</span>")
|
||||
to_chat(user, "<span class='warning'>There isn't anything in here to remove!</span>")
|
||||
else if(open_panel)
|
||||
to_chat(user, "<span class='notice'>The wires connecting the shell to the explosives are holding it down!</span>")
|
||||
to_chat(user, "<span class='warning'>The wires connecting the shell to the explosives are holding it down!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>The cover is screwed on, it won't pry off!</span>")
|
||||
to_chat(user, "<span class='warning'>The cover is screwed on, it won't pry off!</span>")
|
||||
else if(istype(I, /obj/item/weapon/bombcore))
|
||||
if(!payload)
|
||||
if(!user.drop_item())
|
||||
return
|
||||
payload = I
|
||||
to_chat(user, "<span class='notice'>You place [payload] into [src].</span>")
|
||||
user.drop_item()
|
||||
payload.loc = src
|
||||
payload.forceMove(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[payload] is already loaded into [src], you'll have to remove it first.</span>")
|
||||
else if(iswelder(I))
|
||||
if(payload || !wires.IsAllCut() || !open_panel)
|
||||
return
|
||||
var/obj/item/weapon/weldingtool/WT = I
|
||||
if(!WT.isOn())
|
||||
return
|
||||
if(WT.get_fuel() < 5) //uses up 5 fuel.
|
||||
to_chat(user, "<span class='warning'>You need more fuel to complete this task!</span>")
|
||||
return
|
||||
|
||||
playsound(loc, WT.usesound, 50, 1)
|
||||
to_chat(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
|
||||
to_chat(user, "<span class='notice'>You cut the [src] apart.</span>")
|
||||
new /obj/item/stack/sheet/plasteel(loc, 5)
|
||||
qdel(src)
|
||||
else
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/syndicatebomb/attack_ghost(mob/user)
|
||||
interact(user)
|
||||
@@ -133,21 +203,27 @@
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/syndicatebomb/proc/activate()
|
||||
active = TRUE
|
||||
fast_processing += src
|
||||
countdown.start()
|
||||
next_beep = world.time + 10
|
||||
detonation_timer = world.time + (timer_set * 10)
|
||||
playsound(loc, 'sound/machines/click.ogg', 30, 1)
|
||||
|
||||
/obj/machinery/syndicatebomb/proc/settings(mob/user)
|
||||
var/newtime = input(user, "Please set the timer.", "Timer", "[timer]") as num
|
||||
newtime = Clamp(newtime, 120, 60000)
|
||||
var/new_timer = input(user, "Please set the timer.", "Timer", "[timer_set]") as num
|
||||
if(can_interact(user)) //No running off and setting bombs from across the station
|
||||
timer = newtime
|
||||
loc.visible_message("<span class='notice'>[bicon(src)] timer set for [timer] seconds.</span>")
|
||||
timer_set = Clamp(new_timer, minimum_timer, maximum_timer)
|
||||
loc.visible_message("<span class='notice'>[bicon(src)] timer set for [timer_set] seconds.</span>")
|
||||
if(alert(user,"Would you like to start the countdown now?",,"Yes","No") == "Yes" && can_interact(user))
|
||||
if(defused || active)
|
||||
if(defused)
|
||||
loc.visible_message("<span class='notice'>[bicon(src)] Device error: User intervention required.</span>")
|
||||
return
|
||||
else
|
||||
loc.visible_message("<span class='danger'>[bicon(src)] [timer] seconds until detonation, please clear the area.</span>")
|
||||
playsound(loc, 'sound/machines/click.ogg', 30, 1)
|
||||
active = 1
|
||||
loc.visible_message("<span class='danger'>[bicon(src)] [timer_set] seconds until detonation, please clear the area.</span>")
|
||||
activate()
|
||||
update_icon()
|
||||
add_fingerprint(user)
|
||||
|
||||
@@ -167,12 +243,12 @@
|
||||
name = "training bomb"
|
||||
icon_state = "training-bomb"
|
||||
desc = "A salvaged syndicate device gutted of its explosives to be used as a training aid for aspiring bomb defusers."
|
||||
payload = /obj/item/weapon/bombcore/training/
|
||||
payload = /obj/item/weapon/bombcore/training
|
||||
|
||||
/obj/machinery/syndicatebomb/badmin
|
||||
name = "generic summoning badmin bomb"
|
||||
desc = "Oh god what is in this thing?"
|
||||
payload = /obj/item/weapon/bombcore/badmin/summon/
|
||||
payload = /obj/item/weapon/bombcore/badmin/summon
|
||||
|
||||
/obj/machinery/syndicatebomb/badmin/clown
|
||||
name = "clown bomb"
|
||||
@@ -181,8 +257,23 @@
|
||||
payload = /obj/item/weapon/bombcore/badmin/summon/clown
|
||||
beepsound = 'sound/items/bikehorn.ogg'
|
||||
|
||||
/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
|
||||
timer_set = 120
|
||||
|
||||
/obj/machinery/syndicatebomb/empty/New()
|
||||
..()
|
||||
wires.CutAll()
|
||||
|
||||
/obj/machinery/syndicatebomb/self_destruct
|
||||
name = "self destruct device"
|
||||
desc = "Do not taunt. Warranty invalid if exposed to high temperature. Not suitable for agents under 3 years of age."
|
||||
payload = /obj/item/weapon/bombcore/large
|
||||
can_unanchor = FALSE
|
||||
|
||||
///Bomb Cores///
|
||||
|
||||
@@ -196,17 +287,26 @@
|
||||
origin_tech = "syndicate=5;combat=6"
|
||||
burn_state = FLAMMABLE //Burnable (but the casing isn't)
|
||||
var/adminlog = null
|
||||
var/range_heavy = 3
|
||||
var/range_medium = 9
|
||||
var/range_light = 17
|
||||
var/range_flame = 17
|
||||
|
||||
/obj/item/weapon/bombcore/ex_act(severity) //Little boom can chain a big boom
|
||||
src.detonate()
|
||||
detonate()
|
||||
|
||||
|
||||
/obj/item/weapon/bombcore/burn()
|
||||
detonate()
|
||||
..()
|
||||
|
||||
/obj/item/weapon/bombcore/proc/detonate()
|
||||
if(adminlog)
|
||||
message_admins(adminlog)
|
||||
log_game(adminlog)
|
||||
explosion(get_turf(src),3,9,17, flame_range = 17)
|
||||
if(src.loc && istype(src.loc,/obj/machinery/syndicatebomb/))
|
||||
qdel(src.loc)
|
||||
explosion(get_turf(src), range_heavy, range_medium, range_light, flame_range = range_flame)
|
||||
if(loc && istype(loc, /obj/machinery/syndicatebomb))
|
||||
qdel(loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/bombcore/proc/defuse()
|
||||
@@ -223,17 +323,20 @@
|
||||
var/attempts = 0
|
||||
|
||||
/obj/item/weapon/bombcore/training/proc/reset()
|
||||
var/obj/machinery/syndicatebomb/holder = src.loc
|
||||
var/obj/machinery/syndicatebomb/holder = loc
|
||||
if(istype(holder))
|
||||
if(holder.wires)
|
||||
holder.wires.Shuffle()
|
||||
holder.defused = 0
|
||||
holder.open_panel = 0
|
||||
holder.delayedbig = FALSE
|
||||
holder.delayedlittle = FALSE
|
||||
holder.explode_now = FALSE
|
||||
holder.update_icon()
|
||||
holder.updateDialog()
|
||||
|
||||
/obj/item/weapon/bombcore/training/detonate()
|
||||
var/obj/machinery/syndicatebomb/holder = src.loc
|
||||
var/obj/machinery/syndicatebomb/holder = loc
|
||||
if(istype(holder))
|
||||
attempts++
|
||||
holder.loc.visible_message("<span class='danger'>[bicon(holder)] Alert: Bomb has detonated. Your score is now [defusals] for [attempts]. Resetting wires...</span>")
|
||||
@@ -242,7 +345,7 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/bombcore/training/defuse()
|
||||
var/obj/machinery/syndicatebomb/holder = src.loc
|
||||
var/obj/machinery/syndicatebomb/holder = loc
|
||||
if(istype(holder))
|
||||
attempts++
|
||||
defusals++
|
||||
@@ -257,11 +360,11 @@
|
||||
origin_tech = null
|
||||
|
||||
/obj/item/weapon/bombcore/badmin/defuse() //because we wouldn't want them being harvested by players
|
||||
var/obj/machinery/syndicatebomb/B = src.loc
|
||||
var/obj/machinery/syndicatebomb/B = loc
|
||||
qdel(B)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/bombcore/badmin/summon/
|
||||
/obj/item/weapon/bombcore/badmin/summon
|
||||
var/summon_path = /obj/item/weapon/reagent_containers/food/snacks/cookie
|
||||
var/amt_summon = 1
|
||||
|
||||
@@ -285,42 +388,165 @@
|
||||
playsound(src.loc, 'sound/misc/sadtrombone.ogg', 50)
|
||||
..()
|
||||
|
||||
/obj/item/weapon/bombcore/badmin/explosion/
|
||||
var/HeavyExplosion = 2
|
||||
var/MediumExplosion = 5
|
||||
var/LightExplosion = 11
|
||||
var/Flames = 11
|
||||
/obj/item/weapon/bombcore/large
|
||||
name = "large bomb payload"
|
||||
range_heavy = 5
|
||||
range_medium = 10
|
||||
range_light = 20
|
||||
range_flame = 20
|
||||
|
||||
/obj/item/weapon/bombcore/badmin/explosion/detonate()
|
||||
explosion(get_turf(src),HeavyExplosion,MediumExplosion,LightExplosion, flame_range = Flames)
|
||||
/obj/item/weapon/bombcore/large/underwall
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
|
||||
/obj/item/weapon/bombcore/miniature
|
||||
name = "small bomb core"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
range_heavy = 1
|
||||
range_medium = 2
|
||||
range_light = 4
|
||||
range_flame = 2
|
||||
|
||||
/obj/item/weapon/bombcore/miniature/detonate()
|
||||
explosion(src.loc,1,2,4,flame_range = 2) //Identical to a minibomb
|
||||
/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 = 1
|
||||
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)
|
||||
|
||||
// Detonate it again in one second, until it's out of juice.
|
||||
addtimer(src, "detonate", 10)
|
||||
|
||||
// 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(iscrowbar(I) && beakers.len > 0)
|
||||
playsound(loc, I.usesound, 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
|
||||
to_chat(user, "<span class='notice'>You load [src] with [I].</span>")
|
||||
I.loc = src
|
||||
else
|
||||
to_chat(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(list/parts_list)
|
||||
..()
|
||||
// Using different grenade casings, causes the payload to have different properties.
|
||||
var/obj/item/weapon/stock_parts/matter_bin/MB = locate(/obj/item/weapon/stock_parts/matter_bin) in src
|
||||
if(MB)
|
||||
max_beakers += MB.rating // max beakers = 2-5.
|
||||
qdel(MB)
|
||||
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 7 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 += 50 // 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)
|
||||
|
||||
///Syndicate Detonator (aka the big red button)///
|
||||
|
||||
/obj/item/device/syndicatedetonator
|
||||
name = "big red button"
|
||||
desc = "Nothing good can come of pressing a button this garish..."
|
||||
desc = "Your standard issue bomb synchronizing button. Five second safety delay to prevent 'accidents'."
|
||||
icon = 'icons/obj/assemblies.dmi'
|
||||
icon_state = "bigred"
|
||||
item_state = "electronic"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
origin_tech = "syndicate=3"
|
||||
var/cooldown = 0
|
||||
var/timer = 0
|
||||
var/detonated = 0
|
||||
var/existant = 0
|
||||
|
||||
/obj/item/device/syndicatedetonator/attack_self(mob/user as mob)
|
||||
if(!cooldown)
|
||||
/obj/item/device/syndicatedetonator/attack_self(mob/user)
|
||||
if(timer < world.time)
|
||||
for(var/obj/machinery/syndicatebomb/B in machines)
|
||||
if(B.active)
|
||||
B.timer = 0
|
||||
B.detonation_timer = world.time + BUTTON_DELAY
|
||||
detonated++
|
||||
existant++
|
||||
playsound(user, 'sound/machines/click.ogg', 20, 1)
|
||||
@@ -334,5 +560,7 @@
|
||||
log_game("[key_name(user)] has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using a [name] at [A.name] ([T.x],[T.y],[T.z])")
|
||||
detonated = 0
|
||||
existant = 0
|
||||
cooldown = 1
|
||||
spawn(30) cooldown = 0
|
||||
timer = world.time + BUTTON_COOLDOWN
|
||||
|
||||
#undef BUTTON_COOLDOWN
|
||||
#undef BUTTON_DELAY
|
||||
@@ -123,6 +123,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),
|
||||
new /datum/stack_recipe("Surgery Table", /obj/machinery/optable, 5, time = 50, one_per_turf = 1, on_floor = 1),
|
||||
new /datum/stack_recipe("Metal crate", /obj/structure/closet/crate, 10, time = 50, one_per_turf = 1),
|
||||
new /datum/stack_recipe("Mass Driver frame", /obj/machinery/mass_driver_frame, 3, time = 50, one_per_turf = 1)
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
var/obj/item/device/assembly_holder/nadeassembly = null
|
||||
var/label = 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.
|
||||
var/no_splash = FALSE //If the grenade deletes even if it has no reagents to splash with. Used for slime core reactions.
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/New()
|
||||
create_reagents(1000)
|
||||
@@ -99,6 +102,7 @@
|
||||
log_game("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])")
|
||||
bombers += "[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])"
|
||||
to_chat(user, "<span class='warning'>You prime the [name]! [det_time / 10] second\s!</span>")
|
||||
playsound(user.loc, 'sound/weapons/armbomb.ogg', 60, 1)
|
||||
active = 1
|
||||
update_icon()
|
||||
if(iscarbon(user))
|
||||
@@ -264,13 +268,18 @@
|
||||
if(stage != READY)
|
||||
return
|
||||
|
||||
var/has_reagents = 0
|
||||
var/list/datum/reagents/reactants = list()
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in beakers)
|
||||
if(G.reagents.total_volume)
|
||||
has_reagents = 1
|
||||
reactants += G.reagents
|
||||
|
||||
if(!has_reagents)
|
||||
playsound(loc, usesound, 50, 1)
|
||||
if(!chem_splash(get_turf(src), affected_area, reactants, ignition_temp, threatscale) && !no_splash)
|
||||
playsound(loc, 'sound/items/Screwdriver2.ogg', 50, 1)
|
||||
if(beakers.len)
|
||||
for(var/obj/O in beakers)
|
||||
O.forceMove(get_turf(src))
|
||||
beakers = list()
|
||||
stage = EMPTY
|
||||
update_icon()
|
||||
return
|
||||
|
||||
if(nadeassembly)
|
||||
@@ -281,31 +290,9 @@
|
||||
message_admins("grenade primed by an assembly, attached by [key_name_admin(M)]<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>(?)</A> ([admin_jump_link(M)]) and last touched by [key_name_admin(last)]<A HREF='?_src_=holder;adminmoreinfo=\ref[last]'>(?)</A> ([admin_jump_link(last)]) ([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)
|
||||
|
||||
update_mob()
|
||||
|
||||
invisibility = INVISIBILITY_MAXIMUM //kaboom
|
||||
qdel(nadeassembly) // do this now to stop infrared beams
|
||||
var/end_temp = 0
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in beakers)
|
||||
G.reagents.trans_to(src, G.reagents.total_volume)
|
||||
end_temp += G.reagents.chem_temp
|
||||
reagents.chem_temp = end_temp
|
||||
if(reagents.total_volume) //The possible reactions didnt use up all reagents.
|
||||
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()
|
||||
|
||||
for(var/atom/A in view(affected_area, loc))
|
||||
if(A == src)
|
||||
continue
|
||||
reagents.reaction(A, 1, 10)
|
||||
|
||||
|
||||
spawn(15) //Making sure all reagents can work
|
||||
qdel(src) //correctly before deleting the grenade.
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/proc/CreateDefaultTrigger(var/typekey)
|
||||
if(ispath(typekey,/obj/item/device/assembly))
|
||||
@@ -327,64 +314,37 @@
|
||||
//Large chem grenades accept slime cores and use the appropriately.
|
||||
/obj/item/weapon/grenade/chem_grenade/large
|
||||
name = "large grenade casing"
|
||||
desc = "For oversized grenades; fits additional contents and affects a greater area."
|
||||
desc = "A custom made large grenade. It affects a larger area."
|
||||
icon_state = "large_grenade"
|
||||
bomb_state = "largebomb"
|
||||
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;engineering=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
|
||||
|
||||
var/has_reagents = 0
|
||||
var/obj/item/slime_extract/valid_core = null
|
||||
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)
|
||||
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in beakers)
|
||||
if(!istype(G)) continue
|
||||
if(G.reagents.total_volume) has_reagents = 1
|
||||
for(var/obj/item/slime_extract/E in beakers)
|
||||
if(!istype(E)) continue
|
||||
if(E.Uses) valid_core = E
|
||||
if(E.reagents.total_volume) has_reagents = 1
|
||||
//If there is still a core (sometimes it's used up)
|
||||
//and there are reagents left, behave normally,
|
||||
//otherwise drop it on the ground for timed reactions like gold.
|
||||
|
||||
if(!has_reagents)
|
||||
playsound(loc, prime_sound, 50, 1)
|
||||
return
|
||||
|
||||
playsound(loc, 'sound/effects/bamf.ogg', 50, 1)
|
||||
|
||||
update_mob()
|
||||
|
||||
if(valid_core)
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in beakers)
|
||||
G.reagents.trans_to(valid_core, G.reagents.total_volume)
|
||||
|
||||
//If there is still a core (sometimes it's used up)
|
||||
//and there are reagents left, behave normally
|
||||
|
||||
if(valid_core && valid_core.reagents && valid_core.reagents.total_volume)
|
||||
valid_core.reagents.trans_to(src,valid_core.reagents.total_volume)
|
||||
else
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in beakers)
|
||||
G.reagents.trans_to(src, G.reagents.total_volume)
|
||||
|
||||
if(reagents.total_volume) //The possible reactions didnt use up all reagents.
|
||||
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()
|
||||
|
||||
for(var/atom/A in view(affected_area, loc))
|
||||
if( A == src ) continue
|
||||
reagents.reaction(A, 1, 10)
|
||||
|
||||
invisibility = INVISIBILITY_MAXIMUM //Why am i doing this?
|
||||
spawn(50) //To make sure all reagents can work
|
||||
qdel(src) //correctly before deleting the grenade.
|
||||
if(S)
|
||||
if(S.reagents && S.reagents.total_volume)
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in beakers)
|
||||
S.reagents.trans_to(G, S.reagents.total_volume)
|
||||
else
|
||||
S.forceMove(get_turf(src))
|
||||
no_splash = TRUE
|
||||
..()
|
||||
|
||||
|
||||
//I tried to just put it in the allowed_containers list but
|
||||
@@ -399,6 +359,71 @@
|
||||
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"
|
||||
origin_tech = "combat=4;engineering=4"
|
||||
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 detonated more than once. Can be configured using a multitool."
|
||||
icon_state = "timeg"
|
||||
origin_tech = "combat=3;engineering=4"
|
||||
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(ismultitool(I))
|
||||
switch(unit_spread)
|
||||
if(0 to 24)
|
||||
unit_spread += 5
|
||||
if(25 to 99)
|
||||
unit_spread += 25
|
||||
else
|
||||
unit_spread = 5
|
||||
to_chat(user, "<span class='notice'> You set the time release to [unit_spread] units per detonation.</span>")
|
||||
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
|
||||
if(!total_volume)
|
||||
qdel(src)
|
||||
qdel(nadeassembly)
|
||||
return
|
||||
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])")
|
||||
else
|
||||
addtimer(src, "prime", det_time)
|
||||
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])")
|
||||
|
||||
/obj/item/weapon/grenade/chem_grenade/metalfoam
|
||||
payload_name = "metal foam"
|
||||
|
||||
@@ -9,15 +9,19 @@
|
||||
var/atom/attached_to
|
||||
color = "#ff0000"
|
||||
var/text_size = 4
|
||||
var/started = 0
|
||||
var/started = FALSE
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
anchored = 1
|
||||
layer = 5
|
||||
anchored = TRUE
|
||||
layer = GHOST_LAYER
|
||||
|
||||
/obj/effect/countdown/New(atom/A)
|
||||
. = ..()
|
||||
attach(A)
|
||||
|
||||
/obj/effect/countdown/examine(mob/user)
|
||||
. = ..()
|
||||
to_chat(user, "This countdown is displaying: [displayed_text]")
|
||||
|
||||
/obj/effect/countdown/proc/attach(atom/A)
|
||||
attached_to = A
|
||||
loc = get_turf(A)
|
||||
@@ -25,13 +29,13 @@
|
||||
/obj/effect/countdown/proc/start()
|
||||
if(!started)
|
||||
fast_processing += src
|
||||
started = 1
|
||||
started = TRUE
|
||||
|
||||
/obj/effect/countdown/proc/stop()
|
||||
if(started)
|
||||
maptext = null
|
||||
fast_processing -= src
|
||||
started = 0
|
||||
started = FALSE
|
||||
|
||||
/obj/effect/countdown/proc/get_value()
|
||||
// Get the value from our atom
|
||||
@@ -56,6 +60,19 @@
|
||||
fast_processing -= src
|
||||
return ..()
|
||||
|
||||
/obj/effect/countdown/ex_act(severity) //immune to explosions
|
||||
return
|
||||
|
||||
/obj/effect/countdown/syndicatebomb
|
||||
name = "syndicate bomb countdown"
|
||||
|
||||
/obj/effect/countdown/syndicatebomb/get_value()
|
||||
var/obj/machinery/syndicatebomb/S = attached_to
|
||||
if(!istype(S))
|
||||
return
|
||||
else if(S.active)
|
||||
return S.seconds_remaining()
|
||||
|
||||
/obj/effect/countdown/clonepod
|
||||
name = "cloning pod countdown"
|
||||
text_size = 1
|
||||
|
||||
@@ -324,6 +324,30 @@
|
||||
/obj/item/stack/rods = 1)
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/chemical_payload
|
||||
name = "Chemical Payload (C4)"
|
||||
result = /obj/item/weapon/bombcore/chemical
|
||||
reqs = list(
|
||||
/obj/item/weapon/stock_parts/matter_bin = 1,
|
||||
/obj/item/weapon/grenade/plastic/c4 = 1,
|
||||
/obj/item/weapon/grenade/chem_grenade = 2
|
||||
)
|
||||
parts = list(/obj/item/weapon/stock_parts/matter_bin = 1, /obj/item/weapon/grenade/chem_grenade = 2)
|
||||
time = 30
|
||||
category = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/chemical_payload2
|
||||
name = "Chemical Payload (gibtonite)"
|
||||
result = /obj/item/weapon/bombcore/chemical
|
||||
reqs = list(
|
||||
/obj/item/weapon/stock_parts/matter_bin = 1,
|
||||
/obj/item/weapon/twohanded/required/gibtonite = 1,
|
||||
/obj/item/weapon/grenade/chem_grenade = 2
|
||||
)
|
||||
parts = list(/obj/item/weapon/stock_parts/matter_bin = 1, /obj/item/weapon/grenade/chem_grenade = 2)
|
||||
time = 50
|
||||
category = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/bonfire
|
||||
name = "Bonfire"
|
||||
time = 60
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
// 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(!isturf(epicenter) || !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(accessible[T])
|
||||
continue
|
||||
for(var/thing in T.GetAtmosAdjacentTurfs(alldir = TRUE))
|
||||
var/turf/NT = thing
|
||||
if(!(NT in accessible))
|
||||
continue
|
||||
if(!(get_dir(T,NT) in cardinal))
|
||||
continue
|
||||
accessible[T] = 1
|
||||
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
|
||||
for(var/thing in reactable)
|
||||
var/atom/A = thing
|
||||
var/distance = max(1,get_dist(A, epicenter))
|
||||
var/fraction = 0.5/(2 ** distance) //50/25/12/6... for a 200u splash, 25/12/6/3... for a 100u, 12/6/3/1 for a 50u
|
||||
splash_holder.reaction(A, TOUCH, fraction)
|
||||
|
||||
qdel(splash_holder)
|
||||
return 1
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ var/const/INGEST = 2
|
||||
|
||||
return the_id
|
||||
|
||||
/datum/reagents/proc/trans_to(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(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
|
||||
if(total_volume <= 0)
|
||||
@@ -143,13 +143,14 @@ var/const/INGEST = 2
|
||||
if(preserve_data)
|
||||
trans_data = copy_data(current_reagent)
|
||||
|
||||
R.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data, chem_temp)
|
||||
R.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data, chem_temp, no_react = 1)
|
||||
remove_reagent(current_reagent.id, current_reagent_transfer)
|
||||
|
||||
update_total()
|
||||
R.update_total()
|
||||
R.handle_reactions()
|
||||
handle_reactions()
|
||||
if(!no_react)
|
||||
R.handle_reactions()
|
||||
handle_reactions()
|
||||
return amount
|
||||
|
||||
/datum/reagents/proc/copy_to(obj/target, amount=1, multiplier=1, preserve_data=1, safety = 0)
|
||||
@@ -537,7 +538,7 @@ var/const/INGEST = 2
|
||||
var/amt = list_reagents[r_id]
|
||||
add_reagent(r_id, amt, data)
|
||||
|
||||
/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300)
|
||||
/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, no_react = 0)
|
||||
if(!isnum(amount))
|
||||
return 1
|
||||
update_total()
|
||||
@@ -554,7 +555,8 @@ var/const/INGEST = 2
|
||||
update_total()
|
||||
my_atom.on_reagent_change()
|
||||
R.on_merge(data)
|
||||
handle_reactions()
|
||||
if(!no_react)
|
||||
handle_reactions()
|
||||
return 0
|
||||
|
||||
var/datum/reagent/D = chemical_reagents_list[reagent]
|
||||
@@ -570,7 +572,8 @@ var/const/INGEST = 2
|
||||
|
||||
update_total()
|
||||
my_atom.on_reagent_change()
|
||||
handle_reactions()
|
||||
if(!no_react)
|
||||
handle_reactions()
|
||||
return 0
|
||||
else
|
||||
warning("[my_atom] attempted to add a reagent called '[reagent]' which doesn't exist. ([usr])")
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
/obj/machinery/biogenerator,
|
||||
/obj/machinery/hydroponics,
|
||||
/obj/machinery/constructable_frame,
|
||||
/obj/machinery/icemachine)
|
||||
/obj/machinery/icemachine,
|
||||
/obj/item/weapon/bombcore/chemical)
|
||||
|
||||
/obj/item/weapon/reagent_containers/glass/New()
|
||||
..()
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
/obj/structure/reagent_dispensers/proc/boom()
|
||||
visible_message("<span class='danger'>[src] ruptures!</span>")
|
||||
chem_splash(loc, 5, list(reagents))
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/reagent_dispensers/ex_act(severity)
|
||||
@@ -53,15 +54,6 @@
|
||||
desc = "A water tank."
|
||||
icon_state = "water"
|
||||
|
||||
/obj/structure/reagent_dispensers/watertank/boom()
|
||||
playsound(loc, 'sound/effects/spray2.ogg', 50, 1, -6)
|
||||
new /obj/effect/effect/water(loc)
|
||||
for(var/turf/simulated/T in view(5, loc))
|
||||
T.MakeSlippery()
|
||||
for(var/mob/living/L in T)
|
||||
L.adjust_fire_stacks(-20)
|
||||
..()
|
||||
|
||||
/obj/structure/reagent_dispensers/watertank/high
|
||||
name = "high-capacity water tank"
|
||||
desc = "A highly-pressurized water tank made to hold gargantuan amounts of water.."
|
||||
|
||||
@@ -80,6 +80,36 @@
|
||||
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" = 4, "engineering" = 4)
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 2000, MAT_PLASMA = 500)
|
||||
build_path = /obj/item/weapon/grenade/chem_grenade/pyro
|
||||
category = list("Weapons")
|
||||
|
||||
/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)
|
||||
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, "engineering" = 4)
|
||||
build_type = PROTOLATHE
|
||||
materials = list(MAT_METAL = 3000, MAT_GLASS = 500)
|
||||
build_path = /obj/item/weapon/grenade/chem_grenade/adv_release
|
||||
category = list("Weapons")
|
||||
|
||||
/datum/design/tele_shield
|
||||
name = "Telescopic Riot Shield"
|
||||
desc = "An advanced riot shield made of lightweight materials that collapses for easy storage."
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.8 KiB |
@@ -1949,6 +1949,7 @@
|
||||
#include "code\modules\projectiles\projectile\magic.dm"
|
||||
#include "code\modules\projectiles\projectile\reusable.dm"
|
||||
#include "code\modules\projectiles\projectile\special.dm"
|
||||
#include "code\modules\reagents\chem_splash.dm"
|
||||
#include "code\modules\reagents\reagent_containers.dm"
|
||||
#include "code\modules\reagents\reagent_dispenser.dm"
|
||||
#include "code\modules\reagents\chemistry\colors.dm"
|
||||
|
||||
Reference in New Issue
Block a user