Bomb and Radioactivity Behaviors (#21593)

changes:
- balance: "Dirty bomb cleanable 'greenglow' decal left behind is now
actually radioactive to make it more persistently hazardous."
- balance: "'Radioactive waste' rare Warehouse spawn submap now uses
low-radioactivity variants for some of its contents and also been given
a radioactive gear crate."
- balance: "Adds increased taste_mult values to radioactive waste,
napalm, and nitroglycerin; it should be noticeable if your drink is
spiked with any of them."
- balance: "Both uranium and radioactive waste reagents will create
radioactive pools on the floor if spilled (uranium weak, radioactive
waste medium/strong)."
- balance: "Bombs are now allowed to be planted on any mob type except
for carbons."
- balance: "Increases the numbers of assemblies (signalers, igniters,
etc.) stocked in vending machines."
- rscadd: "Adds a radioactive waste chemical canister to the Uplink (5
tc)."
- code_imp: "Adds additional variants of greenglow/radioactive decal and
radioactive_waste/hazardous obj that are more or less radioactive for
mapping and ST use."
  - code_imp: "Cleans up bomb timer setting code and admin logging."
  - qol: "Adds more examine hints to reagent dispensers."
  - qol: "Adds more examine hints to bombs."
  
The 'radioactive waste chemical canister' item cost was set to 5 tc to
match the other 'hazardous chemical' antag item, the Chlorine Tank.
This commit is contained in:
Batrachophreno
2025-12-19 20:21:10 +00:00
committed by GitHub
parent 1c786f16c6
commit 55045bc606
17 changed files with 286 additions and 115 deletions
@@ -64,12 +64,57 @@
H.apply_radiation(5)
STOP_PROCESSING(SSprocessing, src)
ABSTRACT_TYPE(/obj/effect/decal/cleanable/greenglow/radioactive)
/// Radiation generated by SSradiation.radiate each process() tick.
var/radioactivity
light_range = 2
light_power = 0.6
light_color = "#64C864"
/obj/effect/decal/cleanable/greenglow/radioactive/antagonist_hints(mob/user, distance, is_adjacent)
. += ..()
. += "Characters directly adjacent to or on top of this object will be exposed to <b>[radioactivity] IU/s</b> of radiation. Radiation falls off (approximately) by 75% for every tile away you move."
/obj/effect/decal/cleanable/greenglow/radioactive/low
radioactivity = 20
/obj/effect/decal/cleanable/greenglow/radioactive/low/antagonist_hints(mob/user, distance, is_adjacent)
. += ..()
. += "Geiger counters will start clicking at ~5 tiles away from this object."
. += "Almost all voidsuits, including softsuits, provide sufficient protection to move safely adjacent to it."
/obj/effect/decal/cleanable/greenglow/radioactive/medium
radioactivity = 40
/obj/effect/decal/cleanable/greenglow/radioactive/medium/antagonist_hints(mob/user, distance, is_adjacent)
. += ..()
. += "Geiger counters will start clicking at ~8 tiles away from this object."
. += "An engineering or atmos voidsuit is necessary to move safely adjacent to it."
/obj/effect/decal/cleanable/greenglow/radioactive/high
radioactivity = 80
/obj/effect/decal/cleanable/greenglow/radioactive/high/antagonist_hints(mob/user, distance, is_adjacent)
. += ..()
. += "Geiger counters will start clicking at ~10 tiles away from this object."
. += "A radsuit is necessary to move safely adjacent to it."
/obj/effect/decal/cleanable/greenglow/radioactive/extreme
/// This is higher than radsuits can absorb! Use with caution.
radioactivity = 120
/obj/effect/decal/cleanable/greenglow/radioactive/extreme/antagonist_hints(mob/user, distance, is_adjacent)
. += ..()
. += "Geiger counters will start clicking at ~12 tiles away from this object."
. += "No living thing can safely stand next to this object! Borgs or IPCs only!"
/obj/effect/decal/cleanable/greenglow/radioactive/Initialize()
. = ..()
START_PROCESSING(SSprocessing, src)
/obj/effect/decal/cleanable/greenglow/radioactive/process()
SSradiation.radiate(src, 25)
SSradiation.radiate(src, radioactivity)
/obj/effect/decal/cleanable/cobweb
name = "cobweb"
+60 -32
View File
@@ -11,11 +11,28 @@
origin_tech = list(TECH_ILLEGAL = 2)
var/datum/wires/explosive/c4/wires = null
var/detonate_time = 0
var/timer = 10
/// Default timer is 30 seconds, but can be configured for anything from 10s to 20m.
var/timer = 300
var/atom/target = null
var/open_panel = 0
var/obj/effect/plastic_explosive/effect_overlay
/obj/item/plastique/mechanics_hints()
. += ..()
. += "This can be planted on ANY type of target except for open turfs (floors), and items with built-in storage (boxes, jackets, webbings, etc.)."
. += "This cannot be planted on playable characters (carbons), but any other mob type (department pets, maint drones, schlorrgos, borgs, rats, cleanbots, etc.) are fair game."
. += "Use this on yourself to set the timer."
. += "There is a wiring panel on it affixed by <b>screws</b>."
/obj/item/plastique/antagonist_hints()
. += ..()
. += "This can easily be converted into a remote-triggered bomb by attaching a signaller to all 5 wires on the same frequency. Pulse that frequency with another signaller to immediately detonate the bomb."
. += "Everyone loves an exploding cake or pizza."
. += "Everyone loves an exploding hat."
. += "Everyone loves an exploding coffeemaker."
. += "Everyone loves an exploding beer keg."
. += "Everyone loves an exploding object you just dropped in the disposals."
/obj/item/plastique/Initialize()
. = ..()
wires = new(src)
@@ -37,39 +54,57 @@
return ..()
/obj/item/plastique/attack_self(mob/user as mob)
var/newtime = input(usr, "Please set the timer.", "Timer", 10) as num
if(user.get_active_hand() == src)
newtime = clamp(newtime, 10, 60000)
timer = newtime
to_chat(user, SPAN_NOTICE("Timer set for [timer] seconds."))
timer = setTimer(user)
if(timer)
to_chat(user, SPAN_NOTICE("Timer set for [DisplayTimeText(timer)] seconds."))
/obj/item/plastique/proc/setTimer(mob/user as mob)
var/newtime = tgui_input_number(
user = user,
message = "Please set the timer (in seconds).",
title = "Timer",
default = 30, // 30 second default
max_value = 300, // 5 minute maximum
min_value = 10, // 10 second minimum
timeout = 30 SECONDS
)
if(!newtime)
return FALSE
// Convert player input to deciseconds.
return newtime * 10
/obj/item/plastique/afterattack(atom/movable/target, mob/user, flag)
if (!flag)
return
if(ismob(target) || istype(target, /turf/unsimulated) || isopenturf(target) || istype(target, /obj/item/storage/) || istype(target, /obj/item/clothing/accessory/storage/) || istype(target, /obj/item/clothing/under))
return
if(deploy_check(user))
return
return FALSE
if(iscarbon(target) || istype(target, /turf/unsimulated) || isopenturf(target) || istype(target, /obj/item/storage/) || istype(target, /obj/item/clothing/accessory/storage/) || istype(target, /obj/item/clothing/under))
return FALSE
if(!deploy_check(user))
return FALSE
to_chat(user, SPAN_NOTICE("Planting explosives..."))
if(do_after(user, 5 SECONDS, target, DO_UNIQUE))
user.do_attack_animation(target)
deploy_c4(target, user)
return TRUE
return FALSE
/obj/item/plastique/proc/deploy_check(var/mob/user)
return FALSE
return TRUE
/obj/item/plastique/proc/deploy_c4(var/atom/movable/explode_target, mob/user)
user.drop_from_inventory(src, get_turf(user))
src.target = explode_target
var/timetext = DisplayTimeText(timer)
log_and_message_admins("planted [src.name] on [target.name] with [src.timer] second fuse", user, get_turf(target))
log_and_message_admins("planted [src.name] on [target.name] with [timetext] fuse", user, get_turf(target))
new /obj/effect/plastic_explosive(get_turf(user), target, src)
to_chat(user, "Bomb has been planted. Timer counting down from [timer].")
to_chat(user, SPAN_WARNING("Bomb has been planted. Timer counting down from [timetext]."))
detonate_time = world.time + (timer * 10)
addtimer(CALLBACK(src, PROC_REF(explode), get_turf(target)), timer * 10)
detonate_time = world.time + (timer)
addtimer(CALLBACK(src, PROC_REF(explode), get_turf(target)), timer)
/obj/item/plastique/proc/explode(turf/location)
if(!target)
@@ -104,7 +139,7 @@
/obj/item/plastique/cyborg/antagonist_hints(mob/user, distance, is_adjacent)
. += ..()
. += "When used, this dispenser will deploy C4 on a target, upon which it will enter a charging state. After two minutes, it will restock a new C4 bundle."
. += "When used, this dispenser will deploy C4 on a target, upon which it will enter a charging state. After five minutes, it will restock a new C4 bundle."
/obj/item/plastique/cyborg/Initialize()
. = ..()
@@ -116,24 +151,24 @@
/obj/item/plastique/cyborg/deploy_check(mob/user)
if(!can_deploy)
to_chat(user, SPAN_WARNING("\The [src] hasn't recharged yet!"))
return TRUE
return FALSE
..()
/obj/item/plastique/cyborg/deploy_c4(atom/movable/target, mob/user)
var/obj/item/plastique/C4 = new /obj/item/plastique(target)
C4.timer = src.timer
var/timetext = DisplayTimeText(timer)
C4.target = target
log_and_message_admins("planted [C4.name] on [target.name] with [C4.timer] second fuse", user, get_turf(target))
log_and_message_admins("planted [C4.name] on [target.name] with [timetext] fuse", user, get_turf(target))
new /obj/effect/plastic_explosive(get_turf(user), target, C4)
to_chat(user, SPAN_NOTICE("Bomb has been planted. Timer counting down from [C4.timer]."))
to_chat(user, SPAN_NOTICE("Bomb has been planted. Timer counting down from [timetext].."))
C4.detonate_time = world.time + (timer * 10)
addtimer(CALLBACK(C4, PROC_REF(explode), get_turf(target)), timer * 10)
C4.detonate_time = world.time + (timer)
addtimer(CALLBACK(C4, PROC_REF(explode), get_turf(target)), timer)
addtimer(CALLBACK(src, PROC_REF(recharge)), recharge_time)
can_deploy = FALSE
maptext = "<span style=\"font-family: 'Small Fonts'; -dm-text-outline: 1 black; font-size: 6px;\">Charge</span>"
maptext = "<span style=\"font-family: 'Small Fonts'; -dm-text-outline: 1 black; font-size: 6px;\">Charging</span>"
/obj/item/plastique/cyborg/proc/recharge()
if(isrobot(loc))
@@ -146,17 +181,10 @@
/obj/item/plastique/dirty
name = "dirty bomb"
desc = "A small explosive laced with radium. The explosion is small, but the radioactive material will remain for a fair while."
timer = 300
/obj/item/plastique/dirty/attack_self(mob/user as mob)
var/newtime = input(usr, "Please set the timer.", "Timer", 10) as num
if(user.get_active_hand() == src)
newtime = clamp(newtime, 300, 60000)
timer = newtime
to_chat(user, SPAN_NOTICE("Timer set for [timer] seconds."))
timer = 30 SECONDS
/obj/item/plastique/dirty/explode(turf/location)
if(location)
SSradiation.radiate(src, 250)
new /obj/effect/decal/cleanable/greenglow(get_turf(src))
new /obj/effect/decal/cleanable/greenglow/radioactive/medium(get_turf(src))
..()