diff --git a/_maps/map_files/Delta/delta.dmm b/_maps/map_files/Delta/delta.dmm
index df6f6e8fa68..4656c571e48 100644
--- a/_maps/map_files/Delta/delta.dmm
+++ b/_maps/map_files/Delta/delta.dmm
@@ -62882,8 +62882,8 @@
/obj/structure/rack,
/obj/item/clothing/gloves/color/black,
/obj/item/wrench,
-/obj/item/clothing/glasses/meson,
/obj/effect/decal/warning_stripes/yellow/hollow,
+/obj/item/clothing/glasses/meson/engine,
/turf/simulated/floor/plasteel,
/area/engine/engineering)
"cjT" = (
@@ -70613,8 +70613,8 @@
/obj/structure/rack,
/obj/item/clothing/gloves/color/black,
/obj/item/wrench,
-/obj/item/clothing/glasses/meson,
/obj/effect/decal/warning_stripes/yellow/hollow,
+/obj/item/clothing/glasses/meson/engine,
/turf/simulated/floor/plasteel,
/area/engine/engine_smes)
"cxI" = (
diff --git a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm
index d5b8ea22469..acf99d0d6f6 100644
--- a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm
@@ -23621,6 +23621,7 @@
pixel_y = 5
},
/obj/effect/decal/warning_stripes/yellow,
+/obj/item/clothing/glasses/meson/engine,
/turf/simulated/floor/plasteel,
/area/engine/engineering)
"aQS" = (
@@ -31850,6 +31851,7 @@
},
/obj/structure/closet/radiation,
/obj/effect/decal/warning_stripes/yellow,
+/obj/item/clothing/glasses/meson/engine,
/turf/simulated/floor/plasteel,
/area/engine/engineering)
"bfz" = (
@@ -32918,6 +32920,7 @@
pixel_x = 29
},
/obj/effect/decal/warning_stripes/yellow,
+/obj/item/clothing/glasses/meson/engine,
/turf/simulated/floor/plasteel,
/area/engine/engineering)
"bhp" = (
@@ -34940,6 +34943,7 @@
"bkT" = (
/obj/structure/closet/toolcloset,
/obj/effect/decal/warning_stripes/yellow,
+/obj/item/clothing/glasses/meson/engine,
/turf/simulated/floor/plasteel,
/area/engine/engineering)
"bkU" = (
diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm
index 18bf30f7715..514ea41a456 100644
--- a/_maps/map_files/cyberiad/cyberiad.dmm
+++ b/_maps/map_files/cyberiad/cyberiad.dmm
@@ -54034,6 +54034,12 @@
/area/hallway/primary/central/sw)
"bWT" = (
/obj/machinery/computer/arcade,
+/obj/machinery/status_display{
+ density = 0;
+ layer = 4;
+ pixel_x = 0;
+ pixel_y = 32
+ },
/turf/simulated/floor/plasteel,
/area/engine/break_room)
"bWU" = (
@@ -54518,14 +54524,16 @@
},
/area/medical/sleeper)
"bXK" = (
-/obj/item/twohanded/required/kirbyplants,
/obj/machinery/firealarm{
dir = 8;
pixel_x = -24
},
-/turf/simulated/floor/plasteel{
- icon_state = "freezerfloor"
+/obj/machinery/shower{
+ icon_state = "shower";
+ dir = 4
},
+/obj/effect/decal/warning_stripes/blue/hollow,
+/turf/simulated/floor/plasteel/dark,
/area/medical/cryo)
"bXL" = (
/obj/structure/table/glass,
@@ -54552,7 +54560,6 @@
/turf/simulated/floor/plating,
/area/medical/genetics)
"bXO" = (
-/obj/item/twohanded/required/kirbyplants,
/obj/machinery/power/apc{
cell_type = 15000;
dir = 4;
@@ -54563,9 +54570,11 @@
icon_state = "0-2";
d2 = 2
},
-/turf/simulated/floor/plasteel{
- icon_state = "freezerfloor"
+/obj/machinery/shower{
+ dir = 8
},
+/obj/effect/decal/warning_stripes/blue/hollow,
+/turf/simulated/floor/plasteel/dark,
/area/medical/cryo)
"bXP" = (
/obj/structure/disposalpipe/segment,
@@ -55477,6 +55486,7 @@
dir = 2;
icon_state = "pipe-c"
},
+/obj/effect/decal/warning_stripes/blue/partial,
/turf/simulated/floor/plasteel{
icon_state = "freezerfloor"
},
@@ -55514,6 +55524,7 @@
d2 = 2;
icon_state = "1-2"
},
+/obj/effect/decal/warning_stripes/blue/partial,
/turf/simulated/floor/plasteel{
icon_state = "freezerfloor"
},
@@ -58525,13 +58536,10 @@
name = "Research Division"
})
"cdG" = (
-/obj/structure/table,
-/obj/machinery/status_display{
- density = 0;
- layer = 4;
- pixel_x = 0;
- pixel_y = 32
+/obj/machinery/shower{
+ pixel_y = 8
},
+/obj/effect/decal/warning_stripes/yellow/hollow,
/turf/simulated/floor/plasteel,
/area/engine/break_room)
"cdH" = (
@@ -73786,6 +73794,10 @@
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 9
},
+/obj/item/radio/intercom{
+ name = "station intercom (General)";
+ pixel_y = -28
+ },
/turf/simulated/floor/plasteel,
/area/engine/controlroom)
"cDB" = (
@@ -73859,10 +73871,6 @@
},
/area/toxins/misc_lab)
"cDI" = (
-/obj/item/radio/intercom{
- name = "station intercom (General)";
- pixel_y = -28
- },
/obj/machinery/computer/drone_control,
/turf/simulated/floor/plasteel,
/area/engine/controlroom)
@@ -75401,7 +75409,10 @@
dir = 4;
icon_state = "tube1"
},
-/obj/structure/table,
+/obj/machinery/shower{
+ pixel_y = 8
+ },
+/obj/effect/decal/warning_stripes/yellow/hollow,
/turf/simulated/floor/plasteel,
/area/engine/break_room)
"cGv" = (
@@ -80828,7 +80839,7 @@
/obj/structure/table/reinforced,
/obj/item/tank/emergency_oxygen/engi,
/obj/item/clothing/gloves/color/black,
-/obj/item/clothing/glasses/meson,
+/obj/item/clothing/glasses/meson/engine,
/turf/simulated/floor/engine,
/area/engine/engineering)
"cQG" = (
@@ -84506,9 +84517,11 @@
/turf/simulated/floor/plasteel,
/area/engine/engineering)
"cXO" = (
-/obj/machinery/light{
- dir = 8
+/obj/machinery/shower{
+ icon_state = "shower";
+ dir = 4
},
+/obj/effect/decal/warning_stripes/yellow/hollow,
/turf/simulated/floor/plasteel,
/area/atmos)
"cXP" = (
@@ -86239,6 +86252,7 @@
network = list("SS13")
},
/obj/structure/reagent_dispensers/fueltank,
+/obj/effect/decal/warning_stripes/yellow/partial,
/turf/simulated/floor/plasteel,
/area/atmos)
"dbL" = (
@@ -86516,6 +86530,9 @@
/area/maintenance/asmaint)
"dct" = (
/obj/machinery/portable_atmospherics/scrubber,
+/obj/machinery/light{
+ dir = 8
+ },
/turf/simulated/floor/plasteel,
/area/atmos)
"dcu" = (
@@ -89643,7 +89660,7 @@
d2 = 8;
icon_state = "4-8"
},
-/obj/machinery/door/poddoor/shutters/preopen{
+/obj/machinery/door/poddoor/shutters/radiation/preopen{
dir = 2;
id_tag = "engsm";
name = "Radiation Chamber Shutters"
@@ -93728,6 +93745,9 @@
dir = 4
},
/obj/structure/closet/wardrobe/atmospherics_yellow,
+/obj/machinery/light{
+ dir = 8
+ },
/turf/simulated/floor/plasteel,
/area/atmos)
"dtk" = (
@@ -94021,7 +94041,7 @@
icon_state = "4-8"
},
/obj/effect/decal/cleanable/dirt,
-/obj/machinery/door/poddoor/shutters/preopen{
+/obj/machinery/door/poddoor/shutters/radiation/preopen{
dir = 2;
id_tag = "engsm";
name = "Radiation Chamber Shutters"
@@ -94084,7 +94104,7 @@
},
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/blood/oil,
-/obj/machinery/door/poddoor/shutters/preopen{
+/obj/machinery/door/poddoor/shutters/radiation/preopen{
dir = 2;
id_tag = "engsm";
name = "Radiation Chamber Shutters"
@@ -95092,6 +95112,10 @@
icon_state = "cmo"
},
/area/shuttle/escape)
+"lnQ" = (
+/obj/effect/decal/warning_stripes/yellow/partial,
+/turf/simulated/floor/plasteel,
+/area/engine/break_room)
"lop" = (
/obj/structure/chair{
dir = 8
@@ -95171,6 +95195,10 @@
icon_state = "alarm0";
pixel_x = -22
},
+/obj/effect/decal/warning_stripes/yellow/partial{
+ dir = 1;
+ icon_state = "3"
+ },
/turf/simulated/floor/plasteel,
/area/atmos)
"lLQ" = (
@@ -95683,7 +95711,7 @@
},
/obj/item/tank/plasma,
/obj/effect/decal/cleanable/dirt,
-/obj/machinery/door/poddoor/shutters/preopen{
+/obj/machinery/door/poddoor/shutters/radiation/preopen{
dir = 2;
id_tag = "engsm";
name = "Radiation Chamber Shutters"
@@ -95909,7 +95937,7 @@
d2 = 8;
icon_state = "4-8"
},
-/obj/machinery/door/poddoor/shutters/preopen{
+/obj/machinery/door/poddoor/shutters/radiation/preopen{
dir = 2;
id_tag = "engsm";
name = "Radiation Chamber Shutters"
@@ -95993,6 +96021,19 @@
},
/turf/simulated/floor/engine,
/area/engine/engineering)
+"rzU" = (
+/obj/structure/cable{
+ d1 = 1;
+ d2 = 2;
+ icon_state = "1-2";
+ tag = ""
+ },
+/obj/effect/decal/warning_stripes/yellow/partial{
+ icon_state = "3";
+ dir = 4
+ },
+/turf/simulated/floor/plasteel,
+/area/atmos)
"rAt" = (
/obj/structure/extinguisher_cabinet,
/turf/simulated/shuttle/wall{
@@ -96307,6 +96348,21 @@
},
/turf/simulated/floor/plating,
/area/engine/engineering)
+"tQJ" = (
+/obj/effect/decal/warning_stripes/north,
+/obj/structure/cable/yellow{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
+/obj/structure/table/reinforced,
+/obj/item/clothing/suit/radiation,
+/obj/item/clothing/head/radiation,
+/obj/item/clothing/glasses/meson,
+/obj/item/geiger_counter,
+/obj/item/geiger_counter,
+/turf/simulated/floor/engine,
+/area/engine/engineering)
"ubz" = (
/obj/structure/table,
/obj/item/rpd,
@@ -96487,7 +96543,7 @@
icon_state = "4-8"
},
/obj/effect/decal/cleanable/dirt,
-/obj/machinery/door/poddoor/shutters/preopen{
+/obj/machinery/door/poddoor/shutters/radiation/preopen{
dir = 2;
id_tag = "engsm";
name = "Radiation Chamber Shutters"
@@ -126441,7 +126497,7 @@ cZP
cXx
cVj
cSU
-cQG
+tQJ
cSx
cVy
omz
@@ -128221,7 +128277,7 @@ cCJ
cvI
cHQ
cdG
-dcj
+lnQ
cHX
dcj
dcj
@@ -128478,7 +128534,7 @@ cCa
cDR
cHQ
cGu
-dcj
+lnQ
cIh
cIX
cJq
@@ -129779,7 +129835,7 @@ cWU
cXV
cVI
cVI
-cVI
+rzU
dbL
dcL
dds
diff --git a/code/ATMOSPHERICS/atmospherics.dm b/code/ATMOSPHERICS/atmospherics.dm
index 07174d6f38b..d5e6176ca22 100644
--- a/code/ATMOSPHERICS/atmospherics.dm
+++ b/code/ATMOSPHERICS/atmospherics.dm
@@ -28,7 +28,6 @@ Pipelines + Other Objects -> Pipe network
var/initialize_directions = 0
var/pipe_color
- var/obj/item/pipe/stored
var/image/pipe_image
/obj/machinery/atmospherics/New()
@@ -48,13 +47,10 @@ Pipelines + Other Objects -> Pipe network
SSair.atmos_machinery += src
/obj/machinery/atmospherics/proc/atmos_init()
- if(can_unwrench)
- stored = new(src, make_from = src)
// Updates all pipe overlays and underlays
update_underlays()
/obj/machinery/atmospherics/Destroy()
- QDEL_NULL(stored)
SSair.atmos_machinery -= src
SSair.deferred_pipenet_rebuilds -= src
for(var/mob/living/L in src) //ventcrawling is serious business
@@ -229,12 +225,10 @@ Pipelines + Other Objects -> Pipe network
/obj/machinery/atmospherics/deconstruct(disassembled = TRUE)
if(!(flags & NODECONSTRUCT))
if(can_unwrench)
- if(stored)
- stored.forceMove(get_turf(src))
- if(!disassembled)
- stored.obj_integrity = stored.max_integrity * 0.5
- transfer_fingerprints_to(stored)
- stored = null
+ var/obj/item/pipe/stored = new(loc, make_from = src)
+ if(!disassembled)
+ stored.obj_integrity = stored.max_integrity * 0.5
+ transfer_fingerprints_to(stored)
..()
/obj/machinery/atmospherics/on_construction(D, P, C)
diff --git a/code/ATMOSPHERICS/pipes/cap.dm b/code/ATMOSPHERICS/pipes/cap.dm
index bc85edb7c44..94ba0b5429c 100644
--- a/code/ATMOSPHERICS/pipes/cap.dm
+++ b/code/ATMOSPHERICS/pipes/cap.dm
@@ -18,7 +18,7 @@
/obj/machinery/atmospherics/pipe/cap/hide(var/i)
if(level == 1 && istype(loc, /turf/simulated))
- invisibility = i ? 101 : 0
+ invisibility = i ? INVISIBILITY_MAXIMUM : 0
update_icon()
/obj/machinery/atmospherics/pipe/cap/pipeline_expansion()
diff --git a/code/ATMOSPHERICS/pipes/manifold.dm b/code/ATMOSPHERICS/pipes/manifold.dm
index f166ddd9a6a..17f93dd7a23 100644
--- a/code/ATMOSPHERICS/pipes/manifold.dm
+++ b/code/ATMOSPHERICS/pipes/manifold.dm
@@ -60,7 +60,7 @@
/obj/machinery/atmospherics/pipe/manifold/hide(var/i)
if(level == 1 && istype(loc, /turf/simulated))
- invisibility = i ? 101 : 0
+ invisibility = i ? INVISIBILITY_MAXIMUM : 0
/obj/machinery/atmospherics/pipe/manifold/pipeline_expansion()
return list(node1, node2, node3)
diff --git a/code/ATMOSPHERICS/pipes/manifold4w.dm b/code/ATMOSPHERICS/pipes/manifold4w.dm
index 688f9564ac8..a5e32eb6f69 100644
--- a/code/ATMOSPHERICS/pipes/manifold4w.dm
+++ b/code/ATMOSPHERICS/pipes/manifold4w.dm
@@ -133,7 +133,7 @@
/obj/machinery/atmospherics/pipe/manifold4w/hide(var/i)
if(level == 1 && istype(loc, /turf/simulated))
- invisibility = i ? 101 : 0
+ invisibility = i ? INVISIBILITY_MAXIMUM : 0
/obj/machinery/atmospherics/pipe/manifold4w/atmos_init()
..()
diff --git a/code/ATMOSPHERICS/pipes/simple/pipe_simple.dm b/code/ATMOSPHERICS/pipes/simple/pipe_simple.dm
index 3874e01c742..70abc375ca2 100644
--- a/code/ATMOSPHERICS/pipes/simple/pipe_simple.dm
+++ b/code/ATMOSPHERICS/pipes/simple/pipe_simple.dm
@@ -164,4 +164,4 @@
/obj/machinery/atmospherics/pipe/simple/hide(var/i)
if(level == 1 && istype(loc, /turf/simulated))
- invisibility = i ? 101 : 0
+ invisibility = i ? INVISIBILITY_MAXIMUM : 0
diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm
index d379817e4b4..fc67f448526 100644
--- a/code/__DEFINES/colors.dm
+++ b/code/__DEFINES/colors.dm
@@ -11,6 +11,7 @@
#define COLOR_WHITE "#FFFFFF"
#define COLOR_GRAY "#808080"
#define COLOR_BLACK "#000000"
+#define COLOR_HALF_TRANSPARENT_BLACK "#0000007A"
#define COLOR_NAVY_BLUE "#000080"
#define COLOR_LIGHT_GREEN "#008000"
#define COLOR_DARK_GRAY "#404040"
diff --git a/code/__DEFINES/dcs/helpers.dm b/code/__DEFINES/dcs/helpers.dm
index 144e94f1fe0..ba2b9a704a3 100644
--- a/code/__DEFINES/dcs/helpers.dm
+++ b/code/__DEFINES/dcs/helpers.dm
@@ -6,6 +6,14 @@
#define SEND_GLOBAL_SIGNAL(sigtype, arguments...) ( SEND_SIGNAL(SSdcs, sigtype, ##arguments) )
+/// Signifies that this proc is used to handle signals.
+/// Every proc you pass to RegisterSignal must have this.
+#define SIGNAL_HANDLER SHOULD_NOT_SLEEP(TRUE)
+
+/// Signifies that this proc is used to handle signals, but also sleeps.
+/// Do not use this for new work.
+#define SIGNAL_HANDLER_DOES_SLEEP
+
/// A wrapper for _AddElement that allows us to pretend we're using normal named arguments
#define AddElement(arguments...) _AddElement(list(##arguments))
/// A wrapper for _RemoveElement that allows us to pretend we're using normal named arguments
diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm
index 485e5cd2656..cdcfba077b3 100644
--- a/code/__DEFINES/flags.dm
+++ b/code/__DEFINES/flags.dm
@@ -58,6 +58,11 @@
#define CHECK_RICOCHET_2 8192
+/// should the contents of this atom be acted upon
+#define RAD_PROTECT_CONTENTS_2 16384
+/// should this object be allowed to be contaminated
+#define RAD_NO_CONTAMINATE_2 32768
+
//Reagent flags
#define REAGENT_NOREACT 1
diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm
index 6e677b02e49..9286ea2726d 100644
--- a/code/__DEFINES/layers.dm
+++ b/code/__DEFINES/layers.dm
@@ -86,6 +86,8 @@
#define LIGHTING_PLANE 15
#define LIGHTING_LAYER 15
+#define RAD_TEXT_LAYER 15.1
+
#define ABOVE_LIGHTING_PLANE 16
#define ABOVE_LIGHTING_LAYER 16
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index c37a1943046..1c6eff17b7b 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -429,6 +429,9 @@
//Explosive wall groups
#define EXPLOSIVE_WALL_GROUP_SYNDICATE_BASE "syndicate_base"
+/// Prepares a text to be used for maptext. Use this so it doesn't look hideous.
+#define MAPTEXT(text) {"[##text]"}
+
// Filters
#define FILTER_AMBIENT_OCCLUSION filter(type="drop_shadow", x=0, y=-2, size=4, color="#04080FAA")
diff --git a/code/__DEFINES/radiation.dm b/code/__DEFINES/radiation.dm
new file mode 100644
index 00000000000..9f7ea16f7b2
--- /dev/null
+++ b/code/__DEFINES/radiation.dm
@@ -0,0 +1,55 @@
+/*
+These defines are the balancing points of various parts of the radiation system.
+Changes here can have widespread effects: make sure you test well.
+Ask ninjanomnom if they're around
+*/
+
+#define RAD_BACKGROUND_RADIATION 9 // How much radiation is harmless to a mob, this is also when radiation waves stop spreading
+ // WARNING: Lowering this value significantly increases SSradiation load
+
+// apply_effect((amount * RAD_MOB_COEFFICIENT) / max(1, (radiation ** 2) * RAD_OVERDOSE_REDUCTION), IRRADIATE, blocked)
+#define RAD_MOB_COEFFICIENT 0.20 // Radiation applied is multiplied by this
+#define RAD_MOB_SKIN_PROTECTION ((1 / RAD_MOB_COEFFICIENT) + RAD_BACKGROUND_RADIATION)
+
+#define RAD_LOSS_PER_TICK 0.5
+#define RAD_TOX_COEFFICIENT 0.08 // Toxin damage per tick coefficient
+#define RAD_OVERDOSE_REDUCTION 0.000001 // Coefficient to the reduction in applied rads once the thing, usualy mob, has too much radiation
+ // WARNING: This number is highly sensitive to change, graph is first for best results
+#define RAD_BURN_THRESHOLD 1000 // Applied radiation must be over this to burn
+//Holy shit test after you tweak anything it's said like 6 times in here
+//You probably want to plot any tweaks you make so you can see the curves visually
+#define RAD_BURN_LOG_BASE 1.1
+#define RAD_BURN_LOG_GRADIENT 10000
+#define RAD_BURN_CURVE(X) log(1 + ((X - RAD_BURN_THRESHOLD) / RAD_BURN_LOG_GRADIENT)) / log(RAD_BURN_LOG_BASE)
+
+#define RAD_MOB_SAFE 500 // How much stored radiation in a mob with no ill effects
+
+#define RAD_MOB_HAIRLOSS 800 // How much stored radiation to check for hair loss
+
+#define RAD_MOB_MUTATE 1250 // How much stored radiation to check for mutation
+
+#define RAD_MOB_VOMIT 2000 // The amount of radiation to check for vomitting
+#define RAD_MOB_VOMIT_PROB 1 // Chance per tick of vomitting
+
+#define RAD_MOB_KNOCKDOWN 2000 // How much stored radiation to check for stunning
+#define RAD_MOB_KNOCKDOWN_PROB 1 // Chance of knockdown per tick when over threshold
+#define RAD_MOB_KNOCKDOWN_AMOUNT 3 // Amount of knockdown when it occurs
+
+#define RAD_NO_INSULATION 1.0 // For things that shouldn't become irradiated for whatever reason
+#define RAD_VERY_LIGHT_INSULATION 0.9 // What girders have
+#define RAD_LIGHT_INSULATION 0.8
+#define RAD_MEDIUM_INSULATION 0.7 // What common walls have
+#define RAD_HEAVY_INSULATION 0.6 // What reinforced walls have
+#define RAD_EXTREME_INSULATION 0.5 // What rad collectors have
+#define RAD_FULL_INSULATION 0 // Unused
+
+// WARNING: The defines below could have disastrous consequences if tweaked incorrectly. See: The great SM purge of Oct.6.2017
+// contamination_strength = (strength - RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_STR_COEFFICIENT
+#define RAD_MINIMUM_CONTAMINATION 350 // How strong does a radiation wave have to be to contaminate objects
+#define RAD_CONTAMINATION_STR_COEFFICIENT 0.25 // Higher means higher strength scaling contamination strength
+#define RAD_DISTANCE_COEFFICIENT 1 // Lower means further rad spread
+
+#define RAD_HALF_LIFE 90 // The half-life of contaminated objects
+
+#define RAD_GEIGER_MEASURE_SMOOTHING 5
+#define RAD_GEIGER_GRACE_PERIOD 2
diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm
index 6a5ba2d22ca..80afcc6819a 100644
--- a/code/__HELPERS/_logging.dm
+++ b/code/__HELPERS/_logging.dm
@@ -189,3 +189,16 @@ GLOBAL_PROTECT(log_end)
/client/proc/simple_info_line()
return "[key_name(src)] ([mob.x],[mob.y],[mob.z])"
+
+/proc/loc_name(atom/A)
+ if(!istype(A))
+ return "(INVALID LOCATION)"
+
+ var/turf/T = A
+ if(!istype(T))
+ T = get_turf(A)
+
+ if(istype(T))
+ return "([AREACOORD(T)])"
+ else if(A.loc)
+ return "(UNKNOWN (?, ?, ?))"
diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm
index afb70cb81e6..612f7b5abef 100644
--- a/code/__HELPERS/cmp.dm
+++ b/code/__HELPERS/cmp.dm
@@ -31,6 +31,9 @@
/proc/cmp_subsystem_priority(datum/controller/subsystem/a, datum/controller/subsystem/b)
return a.priority - b.priority
+/proc/cmp_filter_data_priority(list/A, list/B)
+ return A["priority"] - B["priority"]
+
/proc/cmp_timer(datum/timedevent/a, datum/timedevent/b)
return a.timeToRun - b.timeToRun
diff --git a/code/__HELPERS/filters.dm b/code/__HELPERS/filters.dm
new file mode 100644
index 00000000000..5121e4955ff
--- /dev/null
+++ b/code/__HELPERS/filters.dm
@@ -0,0 +1,320 @@
+#define ICON_NOT_SET "Not Set"
+
+//This is stored as a nested list instead of datums or whatever because it json encodes nicely for usage in tgui
+GLOBAL_LIST_INIT(master_filter_info, list(
+ "alpha" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "icon" = ICON_NOT_SET,
+ "render_source" = "",
+ "flags" = 0
+ ),
+ "flags" = list(
+ "MASK_INVERSE" = MASK_INVERSE,
+ "MASK_SWAP" = MASK_SWAP
+ )
+ ),
+ "angular_blur" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "size" = 1
+ )
+ ),
+ /* Not supported because making a proper matrix editor on the frontend would be a huge dick pain.
+ Uncomment if you ever implement it
+ "color" = list(
+ "defaults" = list(
+ "color" = matrix(),
+ "space" = FILTER_COLOR_RGB
+ )
+ ),
+ */
+ "displace" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "size" = null,
+ "icon" = ICON_NOT_SET,
+ "render_source" = ""
+ )
+ ),
+ "drop_shadow" = list(
+ "defaults" = list(
+ "x" = 1,
+ "y" = -1,
+ "size" = 1,
+ "offset" = 0,
+ "color" = COLOR_HALF_TRANSPARENT_BLACK
+ )
+ ),
+ "blur" = list(
+ "defaults" = list(
+ "size" = 1
+ )
+ ),
+ "layer" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "icon" = ICON_NOT_SET,
+ "render_source" = "",
+ "flags" = FILTER_OVERLAY,
+ "color" = "",
+ "transform" = null,
+ "blend_mode" = BLEND_DEFAULT
+ )
+ ),
+ "motion_blur" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0
+ )
+ ),
+ "outline" = list(
+ "defaults" = list(
+ "size" = 0,
+ "color" = COLOR_BLACK,
+ "flags" = NONE
+ ),
+ "flags" = list(
+ "OUTLINE_SHARP" = OUTLINE_SHARP,
+ "OUTLINE_SQUARE" = OUTLINE_SQUARE
+ )
+ ),
+ "radial_blur" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "size" = 0.01
+ )
+ ),
+ "rays" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "size" = 16,
+ "color" = COLOR_WHITE,
+ "offset" = 0,
+ "density" = 10,
+ "threshold" = 0.5,
+ "factor" = 0,
+ "flags" = FILTER_OVERLAY | FILTER_UNDERLAY
+ ),
+ "flags" = list(
+ "FILTER_OVERLAY" = FILTER_OVERLAY,
+ "FILTER_UNDERLAY" = FILTER_UNDERLAY
+ )
+ ),
+ "ripple" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "size" = 1,
+ "repeat" = 2,
+ "radius" = 0,
+ "falloff" = 1,
+ "flags" = NONE
+ ),
+ "flags" = list(
+ "WAVE_BOUNDED" = WAVE_BOUNDED
+ )
+ ),
+ "wave" = list(
+ "defaults" = list(
+ "x" = 0,
+ "y" = 0,
+ "size" = 1,
+ "offset" = 0,
+ "flags" = NONE
+ ),
+ "flags" = list(
+ "WAVE_SIDEWAYS" = WAVE_SIDEWAYS,
+ "WAVE_BOUNDED" = WAVE_BOUNDED
+ )
+ )
+))
+
+#undef ICON_NOT_SET
+/*
+ * Helpers to generate lists for filter helpers
+ * This is the only practical way of writing these that actually produces sane lists
+ */
+/proc/alpha_mask_filter(x, y, icon/icon, render_source, flags)
+ . = list("type" = "alpha")
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(icon))
+ .["icon"] = icon
+ if(!isnull(render_source))
+ .["render_source"] = render_source
+ if(!isnull(flags))
+ .["flags"] = flags
+
+/proc/angular_blur_filter(x, y, size)
+ . = list("type" = "angular_blur")
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(size))
+ .["size"] = size
+
+/proc/color_matrix_filter(matrix/in_matrix, space)
+ . = list("type" = "color")
+ .["color"] = in_matrix
+ if(!isnull(space))
+ .["space"] = space
+
+/proc/displacement_map_filter(icon, render_source, x, y, size = 32)
+ . = list("type" = "displace")
+ if(!isnull(icon))
+ .["icon"] = icon
+ if(!isnull(render_source))
+ .["render_source"] = render_source
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(size))
+ .["size"] = size
+
+/proc/drop_shadow_filter(x, y, size, offset, color)
+ . = list("type" = "drop_shadow")
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(size))
+ .["size"] = size
+ if(!isnull(offset))
+ .["offset"] = offset
+ if(!isnull(color))
+ .["color"] = color
+
+/proc/gauss_blur_filter(size)
+ . = list("type" = "blur")
+ if(!isnull(size))
+ .["size"] = size
+
+/proc/layering_filter(icon, render_source, x, y, flags, color, transform, blend_mode)
+ . = list("type" = "layer")
+ if(!isnull(icon))
+ .["icon"] = icon
+ if(!isnull(render_source))
+ .["render_source"] = render_source
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(color))
+ .["color"] = color
+ if(!isnull(flags))
+ .["flags"] = flags
+ if(!isnull(transform))
+ .["transform"] = transform
+ if(!isnull(blend_mode))
+ .["blend_mode"] = blend_mode
+
+/proc/motion_blur_filter(x, y)
+ . = list("type" = "motion_blur")
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+
+/proc/outline_filter(size, color, flags)
+ . = list("type" = "outline")
+ if(!isnull(size))
+ .["size"] = size
+ if(!isnull(color))
+ .["color"] = color
+ if(!isnull(flags))
+ .["flags"] = flags
+
+/proc/radial_blur_filter(size, x, y)
+ . = list("type" = "radial_blur")
+ if(!isnull(size))
+ .["size"] = size
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+
+/proc/rays_filter(size, color, offset, density, threshold, factor, x, y, flags)
+ . = list("type" = "rays")
+ if(!isnull(size))
+ .["size"] = size
+ if(!isnull(color))
+ .["color"] = color
+ if(!isnull(offset))
+ .["offset"] = offset
+ if(!isnull(density))
+ .["density"] = density
+ if(!isnull(threshold))
+ .["threshold"] = threshold
+ if(!isnull(factor))
+ .["factor"] = factor
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(flags))
+ .["flags"] = flags
+
+/proc/ripple_filter(radius, size, falloff, repeat, x, y, flags)
+ . = list("type" = "ripple")
+ if(!isnull(radius))
+ .["radius"] = radius
+ if(!isnull(size))
+ .["size"] = size
+ if(!isnull(falloff))
+ .["falloff"] = falloff
+ if(!isnull(repeat))
+ .["repeat"] = repeat
+ if(!isnull(flags))
+ .["flags"] = flags
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+
+/proc/wave_filter(x, y, size, offset, flags)
+ . = list("type" = "wave")
+ if(!isnull(size))
+ .["size"] = size
+ if(!isnull(x))
+ .["x"] = x
+ if(!isnull(y))
+ .["y"] = y
+ if(!isnull(offset))
+ .["offset"] = offset
+ if(!isnull(flags))
+ .["flags"] = flags
+
+/proc/apply_wibbly_filters(atom/in_atom, length)
+ for(var/i in 1 to 7)
+ //This is a very baffling and strange way of doing this but I am just preserving old functionality
+ var/X
+ var/Y
+ var/rsq
+ do
+ X = 60 * rand() - 30
+ Y = 60 * rand() - 30
+ rsq = X * X + Y * Y
+ while(rsq < 100 || rsq > 900) // Yeah let's just loop infinitely due to bad luck what's the worst that could happen?
+ var/random_roll = rand()
+ in_atom.add_filter("wibbly-[i]", 5, wave_filter(x = X, y = Y, size = rand() * 2.5 + 0.5, offset = random_roll))
+ var/filter = in_atom.get_filter("wibbly-[i]")
+ animate(filter, offset = random_roll, time = 0, loop = -1, flags = ANIMATION_PARALLEL)
+ animate(offset = random_roll - 1, time = rand() * 20 + 10)
+
+/proc/remove_wibbly_filters(atom/in_atom)
+ var/filter
+ for(var/i in 1 to 7)
+ filter = in_atom.get_filter("wibbly-[i]")
+ animate(filter)
+ in_atom.remove_filter("wibbly-[i]")
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index bd99ca2ec62..d76ffc005a0 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -349,12 +349,22 @@
for(var/client/C in group)
C.screen -= O
+/proc/remove_images_from_clients(image/I, list/show_to)
+ for(var/client/C in show_to)
+ C.images -= I
+
/proc/flick_overlay(image/I, list/show_to, duration)
for(var/client/C in show_to)
C.images += I
- spawn(duration)
- for(var/client/C in show_to)
- C.images -= I
+ addtimer(CALLBACK(GLOBAL_PROC, /proc/remove_images_from_clients, I, show_to), duration, TIMER_CLIENT_TIME)
+
+/proc/flick_overlay_view(image/I, atom/target, duration) //wrapper for the above, flicks to everyone who can see the target atom
+ var/list/viewing = list()
+ for(var/m in viewers(target))
+ var/mob/M = m
+ if(M.client)
+ viewing += M.client
+ flick_overlay(I, viewing, duration)
/proc/get_active_player_count()
// Get active players who are playing in the round
diff --git a/code/__HELPERS/radiation.dm b/code/__HELPERS/radiation.dm
new file mode 100644
index 00000000000..79a6194dc80
--- /dev/null
+++ b/code/__HELPERS/radiation.dm
@@ -0,0 +1,57 @@
+/**
+ * A special GetAllContents that doesn't search past things with rad insulation
+ * Components which return COMPONENT_BLOCK_RADIATION prevent further searching into that object's contents. The object itself will get returned still.
+ * The ignore list makes those objects never return at all
+ */
+/proc/get_rad_contents(atom/location)
+ var/static/list/ignored_things = typecacheof(list(
+ /mob/dead,
+ /mob/camera,
+ /obj/effect,
+ /obj/docking_port,
+ /atom/movable/lighting_object,
+ /obj/item/projectile))
+ var/list/processing_list = list(location)
+ . = list()
+ while(length(processing_list))
+ var/atom/thing = processing_list[1]
+ processing_list -= thing
+ if(ignored_things[thing.type])
+ continue
+ . += thing
+ if((thing.flags_2 & RAD_PROTECT_CONTENTS_2) || (SEND_SIGNAL(thing, COMSIG_ATOM_RAD_PROBE) & COMPONENT_BLOCK_RADIATION))
+ continue
+ processing_list += thing.contents
+
+/proc/radiation_pulse(atom/source, intensity, range_modifier, log = FALSE, can_contaminate = TRUE)
+ if(!SSradiation.can_fire)
+ return
+ for(var/dir in GLOB.cardinal)
+ new /datum/radiation_wave(source, dir, intensity, range_modifier, can_contaminate)
+
+ var/list/things = get_rad_contents(source) //copypasta because I don't want to put special code in waves to handle their origin
+ for(var/k in 1 to length(things))
+ var/atom/thing = things[k]
+ if(!thing)
+ continue
+ thing.rad_act(intensity)
+
+ var/static/last_huge_pulse = 0
+ if(intensity > 3000 && world.time > last_huge_pulse + 200)
+ last_huge_pulse = world.time
+ log = TRUE
+ if(log)
+ var/turf/_source_T = isturf(source) ? source : get_turf(source)
+ log_game("Radiation pulse with intensity: [intensity] and range modifier: [range_modifier] in [loc_name(_source_T)] ")
+ return TRUE
+
+/proc/get_rad_contamination(atom/location)
+ var/rad_strength = 0
+ for(var/i in get_rad_contents(location)) // Yes it's intentional that you can't detect radioactive things under rad protection. Gives traitors a way to hide their glowing green rocks.
+ var/atom/thing = i
+ if(!thing)
+ continue
+ var/datum/component/radioactive/radiation = thing.GetComponent(/datum/component/radioactive)
+ if(radiation && rad_strength < radiation.strength)
+ rad_strength = radiation.strength
+ return rad_strength
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 33582212c1f..55f5cae7535 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -419,6 +419,24 @@ Turf and target are seperate in case you want to teleport some distance from a t
return "[round((powerused * 0.000001), 0.001)] MW"
return "[round((powerused * 0.000000001), 0.0001)] GW"
+// Format an energy value in J, kJ, MJ, or GJ. 1W = 1J/s.
+/proc/DisplayJoules(units)
+ if (units < 1000) // Less than a kJ
+ return "[round(units, 0.1)] J"
+ else if (units < 1000000) // Less than a MJ
+ return "[round(units * 0.001, 0.01)] kJ"
+ else if (units < 1000000000) // Less than a GJ
+ return "[round(units * 0.000001, 0.001)] MJ"
+ return "[round(units * 0.000000001, 0.0001)] GJ"
+
+// Format an energy value measured in Power Cell units.
+/proc/DisplayEnergy(units)
+ // APCs process every (SSmachines.wait * 0.1) seconds, and turn 1 W of
+ // excess power into GLOB.CELLRATE energy units when charging cells.
+ // With the current configuration of wait=20 and CELLRATE=0.002, this
+ // means that one unit is 1 kJ.
+ return DisplayJoules(units * SSmachines.wait * 0.1 / GLOB.CELLRATE)
+
//Forces a variable to be posative
/proc/modulus(var/M)
if(M >= 0)
diff --git a/code/_onclick/hud/plane_master.dm b/code/_onclick/hud/plane_master.dm
index d372da7c681..d49722e79ee 100644
--- a/code/_onclick/hud/plane_master.dm
+++ b/code/_onclick/hud/plane_master.dm
@@ -12,15 +12,6 @@
/obj/screen/plane_master/proc/Hide(override)
alpha = override || hide_alpha
-/obj/screen/plane_master/proc/outline(_size, _color)
- filters += filter(type = "outline", size = _size, color = _color)
-
-/obj/screen/plane_master/proc/shadow(_size, _border, _offset = 0, _x = 0, _y = 0, _color = "#04080FAA")
- filters += filter(type = "drop_shadow", x = _x, y = _y, color = _color, size = _size, offset = _offset)
-
-/obj/screen/plane_master/proc/clear_filters()
- filters = list()
-
//Why do plane masters need a backdrop sometimes? Read http://www.byond.com/forum/?post=2141928
//Trust me, you need one. Period. If you don't think you do, you're doing something extremely wrong.
/obj/screen/plane_master/proc/backdrop(mob/mymob)
@@ -40,7 +31,7 @@
/obj/screen/plane_master/game_world/backdrop(mob/mymob)
clear_filters()
if(istype(mymob) && mymob.client && mymob.client.prefs && (mymob.client.prefs.toggles & PREFTOGGLE_AMBIENT_OCCLUSION))
- filters += FILTER_AMBIENT_OCCLUSION
+ add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA"))
/obj/screen/plane_master/lighting
name = "lighting plane master"
diff --git a/code/controllers/subsystem/radiation.dm b/code/controllers/subsystem/radiation.dm
new file mode 100644
index 00000000000..fb86110a5f5
--- /dev/null
+++ b/code/controllers/subsystem/radiation.dm
@@ -0,0 +1,18 @@
+PROCESSING_SUBSYSTEM_DEF(radiation)
+ name = "Radiation"
+ flags = SS_NO_INIT | SS_BACKGROUND
+ wait = 1 SECONDS
+ offline_implications = "Radiation will no longer function; power generation may not happen. A restart may or may not be required, depending on the situation."
+ var/list/warned_atoms = list()
+
+/datum/controller/subsystem/processing/radiation/proc/warn(datum/component/radioactive/contamination)
+ if(!contamination || QDELETED(contamination))
+ return
+ var/ref = contamination.parent.UID()
+ if(warned_atoms[ref])
+ return
+ warned_atoms[ref] = TRUE
+ var/atom/master = contamination.parent
+ SSblackbox.record_feedback("tally", "contaminated", 1, master.type)
+ var/msg = "has become contaminated with enough radiation to contaminate other objects. || Source: [contamination.source] || Strength: [contamination.strength]"
+ master.investigate_log(msg, "radiation")
diff --git a/code/datums/components/radioactive.dm b/code/datums/components/radioactive.dm
new file mode 100644
index 00000000000..cb707b71cd7
--- /dev/null
+++ b/code/datums/components/radioactive.dm
@@ -0,0 +1,104 @@
+#define RAD_AMOUNT_LOW 50
+#define RAD_AMOUNT_MEDIUM 200
+#define RAD_AMOUNT_HIGH 500
+#define RAD_AMOUNT_EXTREME 1000
+
+/datum/component/radioactive
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
+
+ var/source
+ ///the half-life measured in ticks
+ var/hl3_release_date
+ var/strength
+ var/can_contaminate
+
+/datum/component/radioactive/Initialize(_strength = 0, _source, _half_life = RAD_HALF_LIFE, _can_contaminate = TRUE)
+ strength = _strength
+ source = _source
+ hl3_release_date = _half_life
+ can_contaminate = _can_contaminate
+ if(istype(parent, /atom))
+ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/rad_examine)
+ if(istype(parent, /obj/item))
+ RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/rad_attack)
+ RegisterSignal(parent, COMSIG_ITEM_ATTACK_OBJ, .proc/rad_attack)
+ else
+ return COMPONENT_INCOMPATIBLE
+ if(strength > RAD_MINIMUM_CONTAMINATION)
+ SSradiation.warn(src)
+ //Let's make er glow
+ //This relies on parent not being a turf or something. IF YOU CHANGE THAT, CHANGE THIS
+ var/atom/movable/master = parent
+ master.add_filter("rad_glow", 2, list("type" = "outline", "color" = "#39ff1430", "size" = 2))
+ addtimer(CALLBACK(src, .proc/glow_loop, master), rand(1, 19)) //Things should look uneven
+ START_PROCESSING(SSradiation, src)
+
+/datum/component/radioactive/Destroy()
+ STOP_PROCESSING(SSradiation, src)
+ var/atom/movable/master = parent
+ master.remove_filter("rad_glow")
+ return ..()
+
+/datum/component/radioactive/process()
+ if(!prob(50))
+ return
+ radiation_pulse(parent, strength, RAD_DISTANCE_COEFFICIENT * 2, FALSE, can_contaminate)
+ if(!hl3_release_date)
+ return
+ strength -= strength / hl3_release_date
+ if(strength <= RAD_BACKGROUND_RADIATION)
+ qdel(src)
+ return PROCESS_KILL
+
+/datum/component/radioactive/proc/glow_loop(atom/movable/master)
+ var/filter = master.get_filter("rad_glow")
+ if(filter)
+ animate(filter, alpha = 110, time = 15, loop = -1)
+ animate(alpha = 40, time = 25)
+
+/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original, _strength, _source, _half_life, _can_contaminate)
+ if(!i_am_original)
+ return
+ if(!hl3_release_date) // Permanently radioactive things don't get to grow stronger
+ return
+ if(C)
+ var/datum/component/radioactive/other = C
+ strength = max(strength, other.strength)
+ else
+ strength = max(strength, _strength)
+
+/datum/component/radioactive/proc/rad_examine(datum/source, mob/user, list/out)
+ SIGNAL_HANDLER
+
+ var/atom/master = parent
+
+ var/list/fragments = list()
+ if(get_dist(master, user) <= 1)
+ fragments += "The air around [master] feels warm"
+ switch(strength)
+ if(0 to RAD_AMOUNT_LOW)
+ if(length(fragments))
+ fragments += "."
+ if(RAD_AMOUNT_LOW to RAD_AMOUNT_MEDIUM)
+ fragments += "[length(fragments) ? " and [master.p_they()] " : "[master] "]feel[master.p_s()] weird to look at."
+ if(RAD_AMOUNT_MEDIUM to RAD_AMOUNT_HIGH)
+ fragments += "[length(fragments) ? " and [master.p_they()] " : "[master] "]seem[master.p_s()] to be glowing a bit."
+ if(RAD_AMOUNT_HIGH to INFINITY) //At this level the object can contaminate other objects
+ fragments += "[length(fragments) ? " and [master.p_they()] " : "[master] "]hurt[master.p_s()] to look at."
+
+ if(length(fragments))
+ out += "[fragments.Join()]"
+
+/datum/component/radioactive/proc/rad_attack(datum/source, atom/movable/target, mob/living/user)
+ SIGNAL_HANDLER
+
+ radiation_pulse(parent, strength / 20)
+ target.rad_act(strength / 2)
+ if(!hl3_release_date)
+ return
+ strength -= strength / hl3_release_date
+
+#undef RAD_AMOUNT_LOW
+#undef RAD_AMOUNT_MEDIUM
+#undef RAD_AMOUNT_HIGH
+#undef RAD_AMOUNT_EXTREME
diff --git a/code/datums/elements/rad_insulation.dm b/code/datums/elements/rad_insulation.dm
new file mode 100644
index 00000000000..a0c9812820f
--- /dev/null
+++ b/code/datums/elements/rad_insulation.dm
@@ -0,0 +1,34 @@
+/datum/element/rad_insulation
+ element_flags = ELEMENT_DETACH | ELEMENT_BESPOKE
+ id_arg_index = 2
+ var/amount // Multiplier for radiation strength passing through
+
+/datum/element/rad_insulation/Attach(datum/target, _amount = RAD_MEDIUM_INSULATION, protects = TRUE, contamination_proof = TRUE)
+ . = ..()
+ if(!isatom(target))
+ return COMPONENT_INCOMPATIBLE
+
+ if(protects) // Does this protect things in its contents from being affected?
+ RegisterSignal(target, COMSIG_ATOM_RAD_PROBE, .proc/rad_probe_react)
+ if(contamination_proof) // Can this object be contaminated?
+ RegisterSignal(target, COMSIG_ATOM_RAD_CONTAMINATING, .proc/rad_contaminating)
+ if(_amount != 1) // If it's 1 it won't have any impact on radiation passing through anyway
+ RegisterSignal(target, COMSIG_ATOM_RAD_WAVE_PASSING, .proc/rad_pass)
+
+ amount = _amount
+
+/datum/element/rad_insulation/proc/rad_probe_react(datum/source)
+ SIGNAL_HANDLER
+
+ return COMPONENT_BLOCK_RADIATION
+
+/datum/element/rad_insulation/proc/rad_contaminating(datum/source, strength)
+ SIGNAL_HANDLER
+
+ return COMPONENT_BLOCK_CONTAMINATION
+
+/datum/element/rad_insulation/proc/rad_pass(datum/source, datum/radiation_wave/wave, width)
+ SIGNAL_HANDLER
+
+ wave.intensity = wave.intensity * (1 - ((1 - amount) / width)) // The further out the rad wave goes the less it's affected by insulation (larger width)
+ return COMPONENT_RAD_WAVE_HANDLED
diff --git a/code/datums/looping_sounds/item_sounds.dm b/code/datums/looping_sounds/item_sounds.dm
new file mode 100644
index 00000000000..ba174c706b6
--- /dev/null
+++ b/code/datums/looping_sounds/item_sounds.dm
@@ -0,0 +1,37 @@
+#define RAD_GEIGER_LOW 100 // Geiger counter sound thresholds
+#define RAD_GEIGER_MEDIUM 500
+#define RAD_GEIGER_HIGH 1000
+
+/datum/looping_sound/geiger
+ mid_sounds = list(
+ list('sound/items/geiger/low1.ogg' = 1, 'sound/items/geiger/low2.ogg' = 1, 'sound/items/geiger/low3.ogg' = 1, 'sound/items/geiger/low4.ogg' = 1),
+ list('sound/items/geiger/med1.ogg' = 1, 'sound/items/geiger/med2.ogg' = 1, 'sound/items/geiger/med3.ogg' = 1, 'sound/items/geiger/med4.ogg' = 1),
+ list('sound/items/geiger/high1.ogg' = 1, 'sound/items/geiger/high2.ogg' = 1, 'sound/items/geiger/high3.ogg' = 1, 'sound/items/geiger/high4.ogg' = 1),
+ list('sound/items/geiger/ext1.ogg' = 1, 'sound/items/geiger/ext2.ogg' = 1, 'sound/items/geiger/ext3.ogg' = 1, 'sound/items/geiger/ext4.ogg' = 1)
+ )
+ mid_length = 2
+ volume = 25
+ var/last_radiation
+
+/datum/looping_sound/geiger/get_sound(starttime)
+ var/danger
+ switch(last_radiation)
+ if(RAD_BACKGROUND_RADIATION to RAD_GEIGER_LOW)
+ danger = 1
+ if(RAD_GEIGER_LOW to RAD_GEIGER_MEDIUM)
+ danger = 2
+ if(RAD_GEIGER_MEDIUM to RAD_GEIGER_HIGH)
+ danger = 3
+ if(RAD_GEIGER_HIGH to INFINITY)
+ danger = 4
+ else
+ return null
+ return ..(starttime, mid_sounds[danger])
+
+/datum/looping_sound/geiger/stop()
+ . = ..()
+ last_radiation = 0
+
+#undef RAD_GEIGER_LOW
+#undef RAD_GEIGER_MEDIUM
+#undef RAD_GEIGER_HIGH
diff --git a/code/datums/radiation_wave.dm b/code/datums/radiation_wave.dm
new file mode 100644
index 00000000000..8cc0f7dc136
--- /dev/null
+++ b/code/datums/radiation_wave.dm
@@ -0,0 +1,139 @@
+/datum/radiation_wave
+ /// The thing that spawned this radiation wave
+ var/source
+ /// The center of the wave
+ var/turf/master_turf
+ /// How far we've moved
+ var/steps=0
+ /// How strong it was originaly
+ var/intensity
+ /// How much contaminated material it still has
+ var/remaining_contam
+ /// Higher than 1 makes it drop off faster, 0.5 makes it drop off half etc
+ var/range_modifier
+ /// The direction of movement
+ var/move_dir
+ /// The directions to the side of the wave, stored for easy looping
+ var/list/__dirs
+ /// Whether or not this radiation wave can create contaminated objects
+ var/can_contaminate
+
+/datum/radiation_wave/New(atom/_source, dir, _intensity = 0, _range_modifier = RAD_DISTANCE_COEFFICIENT, _can_contaminate = TRUE)
+
+ source = "[_source] \[[_source.UID()]\]"
+
+ master_turf = get_turf(_source)
+
+ move_dir = dir
+ __dirs = list()
+ __dirs += turn(dir, 90)
+ __dirs += turn(dir, -90)
+
+ intensity = _intensity
+ remaining_contam = intensity
+ range_modifier = _range_modifier
+ can_contaminate = _can_contaminate
+
+ START_PROCESSING(SSradiation, src)
+
+/datum/radiation_wave/Destroy()
+ . = QDEL_HINT_IWILLGC
+ STOP_PROCESSING(SSradiation, src)
+ ..()
+
+/datum/radiation_wave/process()
+ master_turf = get_step(master_turf, move_dir)
+ if(!master_turf)
+ qdel(src)
+ return
+ steps++
+ var/list/atoms = get_rad_atoms()
+
+ var/strength
+ if(steps > 1)
+ strength = INVERSE_SQUARE(intensity, max(range_modifier * steps, 1), 1)
+ else
+ strength = intensity
+
+ if(strength < RAD_BACKGROUND_RADIATION)
+ qdel(src)
+ return
+ radiate(atoms, strength)
+ check_obstructions(atoms) // reduce our overall strength if there are radiation insulators
+
+/datum/radiation_wave/proc/get_rad_atoms()
+ var/list/atoms = list()
+ var/distance = steps
+ var/cmove_dir = move_dir
+ var/cmaster_turf = master_turf
+
+ if(cmove_dir == NORTH || cmove_dir == SOUTH)
+ distance-- //otherwise corners overlap
+
+ atoms += get_rad_contents(cmaster_turf)
+
+ var/turf/place
+ for(var/dir in __dirs) //There should be just 2 dirs in here, left and right of the direction of movement
+ place = cmaster_turf
+ for(var/i in 1 to distance)
+ place = get_step(place, dir)
+ if(!place)
+ break
+ atoms += get_rad_contents(place)
+
+ return atoms
+
+/datum/radiation_wave/proc/check_obstructions(list/atoms)
+ var/width = steps
+ var/cmove_dir = move_dir
+ if(cmove_dir == NORTH || cmove_dir == SOUTH)
+ width--
+ width = 1 + (2 * width)
+
+ for(var/k in 1 to atoms.len)
+ var/atom/thing = atoms[k]
+ if(!thing)
+ continue
+ if(SEND_SIGNAL(thing, COMSIG_ATOM_RAD_WAVE_PASSING, src, width) & COMPONENT_RAD_WAVE_HANDLED)
+ continue
+ if(thing.rad_insulation != RAD_NO_INSULATION)
+ intensity *= (1 - ((1 - thing.rad_insulation) / width))
+
+/datum/radiation_wave/proc/radiate(list/atoms, strength)
+ var/can_contam = strength >= RAD_MINIMUM_CONTAMINATION
+ var/contamination_strength = (strength-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_STR_COEFFICIENT
+ contamination_strength = max(contamination_strength, RAD_BACKGROUND_RADIATION)
+ // It'll never reach 100% chance but the further out it gets the more likely it'll contaminate
+ var/contamination_chance = 100 - (90 / (1 + steps * 0.1))
+ for(var/k in atoms)
+ var/atom/thing = k
+ if(QDELETED(thing))
+ continue
+ thing.rad_act(strength)
+
+ // This list should only be for types which don't get contaminated but you want to look in their contents
+ // If you don't want to look in their contents and you don't want to rad_act them:
+ // modify the ignored_things list in __HELPERS/radiation.dm instead
+ var/static/list/blacklisted = typecacheof(list(
+ /turf,
+ /obj/structure/cable,
+ /obj/machinery/atmospherics,
+ /obj/item/ammo_casing,
+ /obj/item/implant,
+ /obj/singularity,
+ ))
+ if(!can_contaminate || !can_contam || blacklisted[thing.type])
+ continue
+ if(thing.flags_2 & RAD_NO_CONTAMINATE_2 || SEND_SIGNAL(thing, COMSIG_ATOM_RAD_CONTAMINATING, strength) & COMPONENT_BLOCK_CONTAMINATION)
+ continue
+
+ if(contamination_strength > remaining_contam)
+ contamination_strength = remaining_contam
+ if(!prob(contamination_chance))
+ continue
+ if(SEND_SIGNAL(thing, COMSIG_ATOM_RAD_CONTAMINATING, strength) & COMPONENT_BLOCK_CONTAMINATION)
+ continue
+ remaining_contam -= contamination_strength
+ if(remaining_contam < RAD_BACKGROUND_RADIATION)
+ can_contaminate = FALSE
+ thing.AddComponent(/datum/component/radioactive, contamination_strength, source)
diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm
index 2ee5eea17ff..659d44e2faf 100644
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -608,7 +608,9 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY
/obj/item/clothing/head/welding,
/obj/item/clothing/head/hardhat,
/obj/item/clothing/head/hardhat,
- /obj/item/clothing/head/hardhat)
+ /obj/item/clothing/head/hardhat,
+ /obj/item/clothing/glasses/meson/engine,
+ /obj/item/clothing/glasses/meson/engine)
cost = 10
containername = "engineering gear crate"
@@ -705,6 +707,18 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY
cost = 25
containername = "particle accelerator crate"
+/datum/supply_packs/engineering/radiation
+ name = "Radiation Protection Crate"
+ cost = 20
+ contains = list(/obj/item/clothing/head/radiation,
+ /obj/item/clothing/head/radiation,
+ /obj/item/clothing/suit/radiation,
+ /obj/item/clothing/suit/radiation,
+ /obj/item/geiger_counter,
+ /obj/item/geiger_counter)
+ containername = "radiation protection crate"
+ containertype = /obj/structure/closet/crate/radiation
+
/datum/supply_packs/engineering/engine/spacesuit
name = "Space Suit Crate"
contains = list(/obj/item/clothing/suit/space,
diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm
index 2bfefa5624e..09d6f67323e 100644
--- a/code/datums/weather/weather_types/radiation_storm.dm
+++ b/code/datums/weather/weather_types/radiation_storm.dm
@@ -46,7 +46,7 @@
randmutg(H)
domutcheck(H, null, 1)
- L.apply_effect(20, IRRADIATE, resist)
+ L.rad_act(20)
/datum/weather/rad_storm/end()
if(..())
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 2ab953e5fc3..63c5f838548 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -7,6 +7,9 @@
var/list/fingerprints
var/list/fingerprintshidden
var/fingerprintslast = null
+ ///For handling persistent filters
+ var/list/filter_data
+
var/list/blood_DNA
var/blood_color
var/last_bumped = 0
@@ -48,6 +51,9 @@
var/list/atom_colours //used to store the different colors on an atom
//its inherent color, the colored paint applied on it, special color effect etc...
+ /// Radiation insulation types
+ var/rad_insulation = RAD_NO_INSULATION
+
/// Last name used to calculate a color for the chatmessage overlays. Used for caching.
var/chat_color_name
/// Last color calculated for the the chatmessage overlays. Used for caching.
@@ -270,6 +276,9 @@
/atom/proc/emp_act(severity)
return
+/atom/proc/water_act(volume, temperature, source, method = REAGENT_TOUCH) //amount of water acting : temperature of water in kelvin : object that called it (for shennagins)
+ return TRUE
+
/atom/proc/bullet_act(obj/item/projectile/P, def_zone)
SEND_SIGNAL(src, COMSIG_ATOM_BULLET_ACT, P, def_zone)
. = P.on_hit(src, 0, def_zone)
@@ -404,6 +413,14 @@
/atom/proc/emag_act()
return
+/**
+ * Respond to a radioactive wave hitting this atom
+ *
+ * Default behaviour is to send [COMSIG_ATOM_RAD_ACT] and return
+ */
+/atom/proc/rad_act(amount)
+ SEND_SIGNAL(src, COMSIG_ATOM_RAD_ACT, amount)
+
/atom/proc/fart_act(mob/living/M)
return FALSE
@@ -422,6 +439,71 @@
if(AM && isturf(AM.loc))
step(AM, turn(AM.dir, 180))
+
+/atom/proc/add_filter(name, priority, list/params)
+ LAZYINITLIST(filter_data)
+ var/list/p = params.Copy()
+ p["priority"] = priority
+ filter_data[name] = p
+ update_filters()
+
+/atom/proc/update_filters()
+ filters = null
+ filter_data = sortTim(filter_data, /proc/cmp_filter_data_priority, TRUE)
+ for(var/f in filter_data)
+ var/list/data = filter_data[f]
+ var/list/arguments = data.Copy()
+ arguments -= "priority"
+ filters += filter(arglist(arguments))
+ UNSETEMPTY(filter_data)
+
+/atom/proc/transition_filter(name, time, list/new_params, easing, loop)
+ var/filter = get_filter(name)
+ if(!filter)
+ return
+
+ var/list/old_filter_data = filter_data[name]
+
+ var/list/params = old_filter_data.Copy()
+ for(var/thing in new_params)
+ params[thing] = new_params[thing]
+
+ animate(filter, new_params, time = time, easing = easing, loop = loop)
+ for(var/param in params)
+ filter_data[name][param] = params[param]
+
+/atom/proc/change_filter_priority(name, new_priority)
+ if(!filter_data || !filter_data[name])
+ return
+
+ filter_data[name]["priority"] = new_priority
+ update_filters()
+
+/obj/item/update_filters()
+ . = ..()
+ for(var/X in actions)
+ var/datum/action/A = X
+ A.UpdateButtonIcon()
+
+/atom/proc/get_filter(name)
+ if(filter_data && filter_data[name])
+ return filters[filter_data.Find(name)]
+
+/atom/proc/remove_filter(name_or_names)
+ if(!filter_data)
+ return
+
+ var/list/names = islist(name_or_names) ? name_or_names : list(name_or_names)
+
+ for(var/name in names)
+ if(filter_data[name])
+ filter_data -= name
+ update_filters()
+
+/atom/proc/clear_filters()
+ filter_data = null
+ filters = null
+
/*
* Base proc, terribly named but it's all over the code so who cares I guess right?
*
@@ -708,27 +790,33 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
blood_overlay.color = color
overlays += blood_overlay
-/atom/proc/clean_blood()
+/atom/proc/clean_blood(radiation_clean = FALSE)
germ_level = 0
+ if(radiation_clean)
+ var/datum/component/radioactive/healthy_green_glow = GetComponent(/datum/component/radioactive)
+ if(!QDELETED(healthy_green_glow))
+ healthy_green_glow.strength = max(0, (healthy_green_glow.strength - (RAD_BACKGROUND_RADIATION * 2)))
+ if(healthy_green_glow.strength <= RAD_BACKGROUND_RADIATION)
+ qdel(healthy_green_glow)
if(islist(blood_DNA))
blood_DNA = null
return TRUE
-/obj/effect/decal/cleanable/blood/clean_blood()
+/obj/effect/decal/cleanable/blood/clean_blood(radiation_clean = FALSE)
return // While this seems nonsensical, clean_blood isn't supposed to be used like this on a blood decal.
-/obj/item/clean_blood()
+/obj/item/clean_blood(radiation_clean = FALSE)
. = ..()
if(.)
if(blood_overlay)
overlays -= blood_overlay
-/obj/item/clothing/gloves/clean_blood()
+/obj/item/clothing/gloves/clean_blood(radiation_clean = FALSE)
. = ..()
if(.)
transfer_blood = 0
-/obj/item/clothing/shoes/clean_blood()
+/obj/item/clothing/shoes/clean_blood(radiation_clean = FALSE)
..()
bloody_shoes = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_NOT_BLOODY = 0)
blood_state = BLOOD_STATE_NOT_BLOODY
@@ -736,36 +824,36 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
var/mob/M = loc
M.update_inv_shoes()
-/mob/living/carbon/human/clean_blood(clean_hands = TRUE, clean_mask = TRUE, clean_feet = TRUE)
+/mob/living/carbon/human/clean_blood(radiation_clean = FALSE, clean_hands = TRUE, clean_mask = TRUE, clean_feet = TRUE)
if(w_uniform && !(wear_suit && wear_suit.flags_inv & HIDEJUMPSUIT))
- if(w_uniform.clean_blood())
+ if(w_uniform.clean_blood(radiation_clean))
update_inv_w_uniform()
if(gloves && !(wear_suit && wear_suit.flags_inv & HIDEGLOVES))
- if(gloves.clean_blood())
+ if(gloves.clean_blood(radiation_clean))
update_inv_gloves()
gloves.germ_level = 0
clean_hands = FALSE
if(shoes && !(wear_suit && wear_suit.flags_inv & HIDESHOES))
- if(shoes.clean_blood())
+ if(shoes.clean_blood(radiation_clean))
update_inv_shoes()
clean_feet = FALSE
if(s_store && !(wear_suit && wear_suit.flags_inv & HIDESUITSTORAGE))
- if(s_store.clean_blood())
+ if(s_store.clean_blood(radiation_clean))
update_inv_s_store()
if(lip_style && !(head && head.flags_inv & HIDEMASK))
lip_style = null
update_body()
if(glasses && !(wear_mask && wear_mask.flags_inv & HIDEEYES))
- if(glasses.clean_blood())
+ if(glasses.clean_blood(radiation_clean))
update_inv_glasses()
if(l_ear && !(wear_mask && wear_mask.flags_inv & HIDEEARS))
- if(l_ear.clean_blood())
+ if(l_ear.clean_blood(radiation_clean))
update_inv_ears()
if(r_ear && !(wear_mask && wear_mask.flags_inv & HIDEEARS))
- if(r_ear.clean_blood())
+ if(r_ear.clean_blood(radiation_clean))
update_inv_ears()
if(belt)
- if(belt.clean_blood())
+ if(belt.clean_blood(radiation_clean))
update_inv_belt()
..(clean_hands, clean_mask, clean_feet)
update_icons() //apply the now updated overlays to the mob
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index d5b3443cc01..6837a1a564e 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -441,9 +441,6 @@
if(master)
return master.attack_hand(a, b, c)
-/atom/movable/proc/water_act(volume, temperature, source, method = REAGENT_TOUCH) //amount of water acting : temperature of water in kelvin : object that called it (for shennagins)
- return TRUE
-
/atom/movable/proc/handle_buckled_mob_movement(newloc,direct,movetime)
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm
index 5b1a14bba1f..1b3fb461f39 100644
--- a/code/game/dna/dna_modifier.dm
+++ b/code/game/dna/dna_modifier.dm
@@ -317,7 +317,7 @@
if(NO_DNA in H.dna.species.species_traits)
return TRUE
- var/radiation_protection = occupant.run_armor_check(null, "rad", "Your clothes feel warm.", "Your clothes feel warm.")
+ var/radiation_protection = occupant.run_armor_check(null, "rad")
if(radiation_protection > NEGATE_MUTATION_THRESHOLD)
return TRUE
return FALSE
@@ -540,7 +540,7 @@
return
var/radiation = (((radiation_intensity * 3) + radiation_duration * 3) / connected.damage_coeff)
- connected.occupant.apply_effect(radiation, IRRADIATE, 0)
+ connected.occupant.apply_effect(radiation, IRRADIATE)
if(connected.radiation_check())
return
@@ -588,7 +588,7 @@
if(prob((80 + (radiation_duration / 2))))
var/radiation = (radiation_intensity + radiation_duration)
- connected.occupant.apply_effect(radiation,IRRADIATE,0)
+ connected.occupant.apply_effect(radiation, IRRADIATE)
if(connected.radiation_check())
return
@@ -598,7 +598,7 @@
connected.occupant.UpdateAppearance()
else
var/radiation = ((radiation_intensity * 2) + radiation_duration)
- connected.occupant.apply_effect(radiation, IRRADIATE, 0)
+ connected.occupant.apply_effect(radiation, IRRADIATE)
if(connected.radiation_check())
return
@@ -644,7 +644,7 @@
if(connected.occupant)
if(prob((80 + ((radiation_duration / 2) + (connected.precision_coeff ** 3)))))
var/radiation = ((radiation_intensity + radiation_duration) / connected.damage_coeff)
- connected.occupant.apply_effect(radiation, IRRADIATE, 0)
+ connected.occupant.apply_effect(radiation, IRRADIATE)
if(connected.radiation_check())
return 1
@@ -662,7 +662,7 @@
domutcheck(connected.occupant, connected)
else
var/radiation = (((radiation_intensity * 2) + radiation_duration) / connected.damage_coeff)
- connected.occupant.apply_effect(radiation, IRRADIATE, 0)
+ connected.occupant.apply_effect(radiation, IRRADIATE)
if(connected.radiation_check())
return
@@ -737,7 +737,7 @@
connected.locked = lock_state
var/radiation = (rand(20,50) / connected.damage_coeff)
- connected.occupant.apply_effect(radiation, IRRADIATE, 0)
+ connected.occupant.apply_effect(radiation, IRRADIATE)
if(connected.radiation_check())
return
diff --git a/code/game/dna/genes/goon_disabilities.dm b/code/game/dna/genes/goon_disabilities.dm
index 2d2d19cc3bb..362271b8504 100644
--- a/code/game/dna/genes/goon_disabilities.dm
+++ b/code/game/dna/genes/goon_disabilities.dm
@@ -49,13 +49,7 @@
return TRUE
/datum/dna/gene/disability/radioactive/OnMobLife(mob/living/carbon/human/H)
- var/radiation_amount = abs(min(H.radiation - 20,0))
- H.apply_effect(radiation_amount, IRRADIATE)
- for(var/mob/living/L in range(1, H))
- if(L == H)
- continue
- to_chat(L, "You are enveloped by a soft green glow emanating from [H].")
- L.apply_effect(5, IRRADIATE)
+ radiation_pulse(H, 20)
/datum/dna/gene/disability/radioactive/OnDrawUnderlays(mob/M, g)
return "rads_s"
@@ -152,14 +146,14 @@
/datum/dna/gene/disability/speech/chav/New()
..()
block = GLOB.chavblock
-
+
/datum/dna/gene/disability/speech/chav/OnSay(mob/M, message)
var/static/regex/R = regex("\\b([chavlinks.Join("|")])\\b", "g")
message = R.Replace(message, /datum/dna/gene/disability/speech/chav/proc/replace_speech)
return message
/datum/dna/gene/disability/speech/chav/proc/replace_speech(matched)
return chavlinks[matched]
-
+
// WAS: /datum/bioEffect/swedish
/datum/dna/gene/disability/speech/swedish
name = "Swedish"
diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm
index 0743a6f686d..f0f0fbda5fa 100644
--- a/code/game/gamemodes/meteor/meteors.dm
+++ b/code/game/gamemodes/meteor/meteors.dm
@@ -245,8 +245,7 @@ GLOBAL_LIST_INIT(meteors_ops, list(/obj/effect/meteor/goreops)) //Meaty Ops
..(heavy)
explosion(src.loc, 0, 0, 4, 3, 0)
new /obj/effect/decal/cleanable/greenglow(get_turf(src))
- for(var/mob/living/L in view(5, src))
- L.apply_effect(40, IRRADIATE)
+ radiation_pulse(src, 500)
//Station buster Tunguska
/obj/effect/meteor/tunguska
diff --git a/code/game/gamemodes/miniantags/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm
index 62739b030e1..993542a3b36 100644
--- a/code/game/gamemodes/miniantags/revenant/revenant.dm
+++ b/code/game/gamemodes/miniantags/revenant/revenant.dm
@@ -118,7 +118,7 @@
/mob/living/simple_animal/revenant/New()
..()
-
+ flags_2 |= RAD_NO_CONTAMINATE_2
remove_from_all_data_huds()
random_revenant_name()
diff --git a/code/game/machinery/Beacon.dm b/code/game/machinery/Beacon.dm
index d3b2114f801..1f626f0656b 100644
--- a/code/game/machinery/Beacon.dm
+++ b/code/game/machinery/Beacon.dm
@@ -40,7 +40,7 @@
return ..()
/obj/machinery/bluespace_beacon/hide(var/intact)
- invisibility = intact ? 101 : 0
+ invisibility = intact ? INVISIBILITY_MAXIMUM : 0
update_icon()
// update the icon_state
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index d670c42e5a8..dea6cd510cd 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -57,6 +57,8 @@ GLOBAL_LIST_EMPTY(airlock_overlays)
explosion_block = 1
assemblytype = /obj/structure/door_assembly
siemens_strength = 1
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
+ rad_insulation = RAD_MEDIUM_INSULATION
var/security_level = 0 //How much are wires secured
var/aiControlDisabled = AICONTROLDISABLED_OFF
var/hackProof = FALSE // if TRUE, this door can't be hacked by the AI
diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm
index 9f99b45afa4..6eaa6a3ae12 100644
--- a/code/game/machinery/doors/airlock_types.dm
+++ b/code/game/machinery/doors/airlock_types.dm
@@ -150,18 +150,17 @@
icon = 'icons/obj/doors/airlocks/station/uranium.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_uranium
paintable = FALSE
- var/event_step = 20
+ var/last_event = 0
-/obj/machinery/door/airlock/uranium/New()
+/obj/machinery/door/airlock/uranium/process()
+ if(world.time > last_event + 20)
+ if(prob(50))
+ radiate()
+ last_event = world.time
..()
- addtimer(CALLBACK(src, .proc/radiate), event_step)
-
/obj/machinery/door/airlock/uranium/proc/radiate()
- if(prob(50))
- for(var/mob/living/L in range (3,src))
- L.apply_effect(15,IRRADIATE,0)
- addtimer(CALLBACK(src, .proc/radiate), event_step)
+ radiation_pulse(get_turf(src), 150)
/obj/machinery/door/airlock/uranium/glass
diff --git a/code/game/machinery/doors/shutters.dm b/code/game/machinery/doors/shutters.dm
index 457b056b7f9..c2914262d15 100644
--- a/code/game/machinery/doors/shutters.dm
+++ b/code/game/machinery/doors/shutters.dm
@@ -12,3 +12,24 @@
icon_state = "open"
density = FALSE
opacity = 0
+
+/obj/machinery/door/poddoor/shutters/radiation
+ name = "radiation shutters"
+ desc = "Lead-lined shutters with a radiation hazard symbol. Whilst this won't stop you getting irradiated, especially by a supermatter crystal, it will stop radiation travelling as far."
+ icon = 'icons/obj/doors/shutters_radiation.dmi'
+ icon_state = "closed"
+ rad_insulation = RAD_EXTREME_INSULATION
+
+/obj/machinery/door/poddoor/shutters/radiation/preopen
+ icon_state = "open"
+ density = FALSE
+ opacity = FALSE
+ rad_insulation = RAD_NO_INSULATION
+
+/obj/machinery/door/poddoor/shutters/radiation/open()
+ . = ..()
+ rad_insulation = RAD_NO_INSULATION
+
+/obj/machinery/door/poddoor/shutters/radiation/close()
+ . = ..()
+ rad_insulation = RAD_EXTREME_INSULATION
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 5358a1206b8..7420c366c3d 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -102,7 +102,6 @@ Class Procs:
max_integrity = 200
layer = BELOW_OBJ_LAYER
var/stat = 0
- var/emagged = 0
var/use_power = IDLE_POWER_USE
//0 = dont run the auto
//1 = run auto, use idle
diff --git a/code/game/machinery/magnet.dm b/code/game/machinery/magnet.dm
index dd2ef029d57..9963cfbda93 100644
--- a/code/game/machinery/magnet.dm
+++ b/code/game/machinery/magnet.dm
@@ -44,7 +44,7 @@
// update the invisibility and icon
/obj/machinery/magnetic_module/hide(intact)
- invisibility = intact ? 101 : 0
+ invisibility = intact ? INVISIBILITY_MAXIMUM : 0
updateicon()
// update the icon_state
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index b307c91b5df..f7efcd7733d 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -207,6 +207,7 @@
name = "radiation suit storage unit"
suit_type = /obj/item/clothing/suit/radiation
helmet_type = /obj/item/clothing/head/radiation
+ storage_type = /obj/item/geiger_counter
//copied from /obj/effect/nasavoidsuitspawner
/obj/machinery/suit_storage_unit/telecoms/Initialize()
diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm
index 18abeba7400..3b26877e4b2 100644
--- a/code/game/machinery/transformer.dm
+++ b/code/game/machinery/transformer.dm
@@ -201,7 +201,7 @@
flick("separator-AO0",src)
playsound(loc, 'sound/effects/alert.ogg', 50, 0)
sleep(5)
- H.apply_effect((rand(150,200)),IRRADIATE,0)
+ H.rad_act(rand(150, 200))
if(prob(5))
if(prob(75))
randmutb(H) // Applies bad mutation
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index e42b8a1460b..62c3583bb4e 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -1638,7 +1638,7 @@
icon_state = "engivend"
icon_deny = "engivend-deny"
req_one_access_txt = "11;24" // Engineers and atmos techs can use this
- products = list(/obj/item/clothing/glasses/meson = 2,/obj/item/multitool = 4,/obj/item/airlock_electronics = 10,/obj/item/firelock_electronics = 10,/obj/item/firealarm_electronics = 10,/obj/item/apc_electronics = 10,/obj/item/airalarm_electronics = 10,/obj/item/stock_parts/cell/high = 10,/obj/item/camera_assembly = 10)
+ products = list(/obj/item/clothing/glasses/meson/engine = 2,/obj/item/multitool = 4, /obj/item/geiger_counter = 5, /obj/item/airlock_electronics = 10,/obj/item/firelock_electronics = 10,/obj/item/firealarm_electronics = 10,/obj/item/apc_electronics = 10,/obj/item/airalarm_electronics = 10,/obj/item/stock_parts/cell/high = 10,/obj/item/camera_assembly = 10)
contraband = list(/obj/item/stock_parts/cell/potato = 3)
premium = list(/obj/item/storage/belt/utility = 3)
refill_canister = /obj/item/vending_refill/engivend
@@ -1659,7 +1659,7 @@
icon_deny = "engi-deny"
req_access_txt = "11"
products = list(/obj/item/clothing/under/rank/chief_engineer = 4,/obj/item/clothing/under/rank/engineer = 4,/obj/item/clothing/shoes/workboots = 4,/obj/item/clothing/head/hardhat = 4,
- /obj/item/storage/belt/utility = 4,/obj/item/clothing/glasses/meson = 4,/obj/item/clothing/gloves/color/yellow = 4, /obj/item/screwdriver = 12,
+ /obj/item/storage/belt/utility = 4,/obj/item/clothing/glasses/meson/engine = 4,/obj/item/clothing/gloves/color/yellow = 4, /obj/item/screwdriver = 12,
/obj/item/crowbar = 12,/obj/item/wirecutters = 12,/obj/item/multitool = 12,/obj/item/wrench = 12,/obj/item/t_scanner = 12,
/obj/item/stack/cable_coil/heavyduty = 8, /obj/item/stock_parts/cell = 8, /obj/item/weldingtool = 8,/obj/item/clothing/head/welding = 8,
/obj/item/light/tube = 10,/obj/item/clothing/suit/fire = 4, /obj/item/stock_parts/scanning_module = 5,/obj/item/stock_parts/micro_laser = 5,
diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm
index 8fdbf0880df..e33a748354c 100644
--- a/code/game/mecha/equipment/tools/other_tools.dm
+++ b/code/game/mecha/equipment/tools/other_tools.dm
@@ -489,12 +489,11 @@
fuel_per_cycle_idle = 10
fuel_per_cycle_active = 30
power_per_cycle = 50
- var/rad_per_cycle = 0.3
+ var/rad_per_cycle = 30
/obj/item/mecha_parts/mecha_equipment/generator/nuclear/critfail()
return
/obj/item/mecha_parts/mecha_equipment/generator/nuclear/process()
if(..())
- for(var/mob/living/carbon/M in view(chassis))
- M.apply_effect((rad_per_cycle * 3),IRRADIATE,0)
+ radiation_pulse(get_turf(src), rad_per_cycle)
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index d01f8fd856b..594b318750c 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -37,7 +37,6 @@
var/datum/effect_system/spark_spread/spark_system = new
var/lights = 0
var/lights_power = 6
- var/emagged = FALSE
var/frozen = FALSE
var/repairing = FALSE
diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm
index f671fcfcf23..f1c3ae63c1f 100644
--- a/code/game/objects/effects/mines.dm
+++ b/code/game/objects/effects/mines.dm
@@ -67,7 +67,7 @@
var/radiation_amount
/obj/effect/mine/dnascramble/mineEffect(mob/living/victim)
- victim.apply_effect(radiation_amount, IRRADIATE, 0)
+ victim.rad_act(radiation_amount)
if(ishuman(victim))
var/mob/living/carbon/human/V = victim
if(NO_DNA in V.dna.species.species_traits)
diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm
index dcdcff81313..76f80e0b02a 100644
--- a/code/game/objects/effects/spawners/lootdrop.dm
+++ b/code/game/objects/effects/spawners/lootdrop.dm
@@ -94,6 +94,7 @@
/obj/item/book/manual/engineering_construction = 10,
/obj/item/book/manual/engineering_hacking = 10,
/obj/item/clothing/head/cone = 10,
+ /obj/item/geiger_counter = 30,
/obj/item/coin/silver = 10,
/obj/item/coin/twoheaded = 10,
/obj/item/poster/random_contraband = 10,
diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm
index 95b36194f56..abb86e2cd14 100644
--- a/code/game/objects/items/devices/chameleonproj.dm
+++ b/code/game/objects/items/devices/chameleonproj.dm
@@ -199,23 +199,7 @@
deactivate(user)
else
to_chat(user, "You activate [src].")
- var/start = user.filters.len
- var/X
- var/Y
- var/rsq
- var/i
- var/f
- for(i in 1 to 7)
- do
- X = 60 * rand() - 30
- Y = 60 * rand() - 30
- rsq = X * X + Y * Y
- while(rsq < 100 || rsq > 900)
- user.filters += filter(type = "wave", x = X, y = Y, size = rand() * 2.5 + 0.5, offset = rand())
- for(i in 1 to 7)
- f = user.filters[start+i]
- animate(f, offset = f:offset, time = 0, loop = 3, flags = ANIMATION_PARALLEL)
- animate(offset = f:offset - 1, time = rand() * 20 + 10)
+ apply_wibbly_filters(user)
if(do_after(user, 50, target = user) && user.cell.use(activationCost))
playsound(src, 'sound/effects/bamf.ogg', 100, 1, -6)
to_chat(user, "You are now disguised as a Nanotrasen engineering cyborg.")
@@ -223,10 +207,7 @@
else
to_chat(user, "The chameleon field fizzles.")
do_sparks(3, FALSE, user)
- for(i in 1 to min(7, user.filters.len)) // removing filters that are animating does nothing, we gotta stop the animations first
- f = user.filters[start + i]
- animate(f)
- user.filters = null
+ remove_wibbly_filters(user)
/obj/item/borg_chameleon/process()
if(S)
diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm
new file mode 100644
index 00000000000..e9539fdafd7
--- /dev/null
+++ b/code/game/objects/items/devices/geiger_counter.dm
@@ -0,0 +1,216 @@
+#define RAD_LEVEL_NORMAL 9
+#define RAD_LEVEL_MODERATE 100
+#define RAD_LEVEL_HIGH 400
+#define RAD_LEVEL_VERY_HIGH 800
+#define RAD_LEVEL_CRITICAL 1500
+
+/obj/item/geiger_counter //DISCLAIMER: I know nothing about how real-life Geiger counters work. This will not be realistic. ~Xhuis
+ name = "\improper Geiger counter"
+ desc = "A handheld device used for detecting and measuring radiation pulses."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "geiger_off"
+ item_state = "multitool"
+ w_class = WEIGHT_CLASS_SMALL
+ slot_flags = SLOT_BELT
+ flags = NOBLUDGEON
+ materials = list(MAT_METAL = 150, MAT_GLASS = 150)
+
+ var/grace = RAD_GEIGER_GRACE_PERIOD
+ var/datum/looping_sound/geiger/soundloop
+
+ var/scanning = FALSE
+ var/radiation_count = 0
+ var/current_tick_amount = 0
+ var/last_tick_amount = 0
+ var/fail_to_receive = 0
+ var/current_warning = 1
+
+/obj/item/geiger_counter/Initialize(mapload)
+ . = ..()
+ START_PROCESSING(SSobj, src)
+
+ soundloop = new(list(src), FALSE)
+
+/obj/item/geiger_counter/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+
+/obj/item/geiger_counter/process()
+ update_icon()
+ update_sound()
+
+ if(!scanning)
+ current_tick_amount = 0
+ return
+
+ radiation_count -= radiation_count / RAD_GEIGER_MEASURE_SMOOTHING
+ radiation_count += current_tick_amount / RAD_GEIGER_MEASURE_SMOOTHING
+
+ if(current_tick_amount)
+ grace = RAD_GEIGER_GRACE_PERIOD
+ last_tick_amount = current_tick_amount
+
+ else if(!emagged)
+ grace--
+ if(grace <= 0)
+ radiation_count = 0
+
+ current_tick_amount = 0
+
+/obj/item/geiger_counter/examine(mob/user)
+ . = ..()
+ if(!scanning)
+ return
+ . += "Alt-click it to clear stored radiation levels."
+ if(emagged)
+ . += "The display seems to be incomprehensible."
+ return
+ switch(radiation_count)
+ if(-INFINITY to RAD_LEVEL_NORMAL)
+ . += "Ambient radiation level count reports that all is well."
+ if(RAD_LEVEL_NORMAL + 1 to RAD_LEVEL_MODERATE)
+ . += "Ambient radiation levels slightly above average."
+ if(RAD_LEVEL_MODERATE + 1 to RAD_LEVEL_HIGH)
+ . += "Ambient radiation levels above average."
+ if(RAD_LEVEL_HIGH + 1 to RAD_LEVEL_VERY_HIGH)
+ . += "Ambient radiation levels highly above average."
+ if(RAD_LEVEL_VERY_HIGH + 1 to RAD_LEVEL_CRITICAL)
+ . += "Ambient radiation levels nearing critical level."
+ if(RAD_LEVEL_CRITICAL + 1 to INFINITY)
+ . += "Ambient radiation levels above critical level!"
+
+ . += "The last radiation amount detected was [last_tick_amount]"
+
+/obj/item/geiger_counter/update_icon()
+ if(!scanning)
+ icon_state = "geiger_off"
+ else if(emagged)
+ icon_state = "geiger_on_emag"
+ else
+ switch(radiation_count)
+ if(-INFINITY to RAD_LEVEL_NORMAL)
+ icon_state = "geiger_on_1"
+ if(RAD_LEVEL_NORMAL + 1 to RAD_LEVEL_MODERATE)
+ icon_state = "geiger_on_2"
+ if(RAD_LEVEL_MODERATE + 1 to RAD_LEVEL_HIGH)
+ icon_state = "geiger_on_3"
+ if(RAD_LEVEL_HIGH + 1 to RAD_LEVEL_VERY_HIGH)
+ icon_state = "geiger_on_4"
+ if(RAD_LEVEL_VERY_HIGH + 1 to RAD_LEVEL_CRITICAL)
+ icon_state = "geiger_on_4"
+ if(RAD_LEVEL_CRITICAL + 1 to INFINITY)
+ icon_state = "geiger_on_5"
+
+/obj/item/geiger_counter/proc/update_sound()
+ var/datum/looping_sound/geiger/loop = soundloop
+ if(!scanning)
+ loop.stop()
+ return
+ if(!radiation_count)
+ loop.stop()
+ return
+ loop.last_radiation = radiation_count
+ loop.start()
+
+/obj/item/geiger_counter/rad_act(amount)
+ . = ..()
+ if(amount <= RAD_BACKGROUND_RADIATION || !scanning)
+ return
+ current_tick_amount += amount
+ update_icon()
+
+/obj/item/geiger_counter/attack_self(mob/user)
+ scanning = !scanning
+ update_icon()
+ to_chat(user, "[bicon(src)] You switch [scanning ? "on" : "off"] [src].")
+
+/obj/item/geiger_counter/afterattack(atom/target, mob/user)
+ . = ..()
+ if(user.a_intent == INTENT_HELP)
+ if(!emagged)
+ user.visible_message("[user] scans [target] with [src].", "You scan [target]'s radiation levels with [src]...")
+ addtimer(CALLBACK(src, .proc/scan, target, user), 20, TIMER_UNIQUE) // Let's not have spamming GetAllContents
+ else
+ user.visible_message("[user] scans [target] with [src].", "You project [src]'s stored radiation into [target]!")
+ target.rad_act(radiation_count)
+ radiation_count = 0
+ return TRUE
+
+/obj/item/geiger_counter/proc/scan(atom/A, mob/user)
+ var/rad_strength = get_rad_contamination(A)
+
+ if(isliving(A))
+ var/mob/living/M = A
+ if(!M.radiation)
+ to_chat(user, "[bicon(src)] Radiation levels within normal boundaries.")
+ else
+ to_chat(user, "[bicon(src)] Subject is irradiated. Radiation levels: [M.radiation].")
+
+ if(rad_strength)
+ to_chat(user, "[bicon(src)] Target contains radioactive contamination. Radioactive strength: [rad_strength]")
+ else
+ to_chat(user, "[bicon(src)] Target is free of radioactive contamination.")
+
+/obj/item/geiger_counter/attackby(obj/item/I, mob/user, params)
+ if(I.tool_behaviour == TOOL_SCREWDRIVER && emagged)
+ if(scanning)
+ to_chat(user, "Turn off [src] before you perform this action!")
+ return FALSE
+ user.visible_message("[user] unscrews [src]'s maintenance panel and begins fiddling with its innards...", "You begin resetting [src]...")
+ if(!I.use_tool(src, user, 40, volume = 50))
+ return FALSE
+ user.visible_message("[user] refastens [src]'s maintenance panel!", "You reset [src] to its factory settings!")
+ emagged = FALSE
+ radiation_count = 0
+ update_icon()
+ return TRUE
+ else
+ return ..()
+
+/obj/item/geiger_counter/AltClick(mob/living/user)
+ if(!istype(user) || !!user.Adjacent(src))
+ return ..()
+ if(!scanning)
+ to_chat(usr, "[src] must be on to reset its radiation level!")
+ return
+ radiation_count = 0
+ to_chat(usr, "You flush [src]'s radiation counts, resetting it to normal.")
+ update_icon()
+
+/obj/item/geiger_counter/emag_act(mob/user)
+ if(emagged)
+ return
+ if(scanning)
+ to_chat(user, "Turn off [src] before you perform this action!")
+ return
+ to_chat(user, "You override [src]'s radiation storing protocols. It will now generate small doses of radiation, and stored rads are now projected into creatures you scan.")
+ emagged = TRUE
+
+
+
+/obj/item/geiger_counter/cyborg
+ var/mob/listeningTo
+
+/obj/item/geiger_counter/cyborg/equipped(mob/user)
+ . = ..()
+ if(listeningTo == user)
+ return
+ if(listeningTo)
+ UnregisterSignal(listeningTo, COMSIG_ATOM_RAD_ACT)
+ RegisterSignal(user, COMSIG_ATOM_RAD_ACT, .proc/redirect_rad_act)
+ listeningTo = user
+
+/obj/item/geiger_counter/cyborg/proc/redirect_rad_act(datum/source, amount)
+ rad_act(amount)
+
+/obj/item/geiger_counter/cyborg/dropped()
+ . = ..()
+ if(listeningTo)
+ UnregisterSignal(listeningTo, COMSIG_ATOM_RAD_ACT)
+
+#undef RAD_LEVEL_NORMAL
+#undef RAD_LEVEL_MODERATE
+#undef RAD_LEVEL_HIGH
+#undef RAD_LEVEL_VERY_HIGH
+#undef RAD_LEVEL_CRITICAL
diff --git a/code/game/objects/items/devices/handheld_defib.dm b/code/game/objects/items/devices/handheld_defib.dm
index 9dd159ca91b..ed05732d760 100644
--- a/code/game/objects/items/devices/handheld_defib.dm
+++ b/code/game/objects/items/devices/handheld_defib.dm
@@ -10,7 +10,6 @@
var/icon_base = "defib"
var/cooldown = FALSE
var/charge_time = 100
- var/emagged = FALSE
/obj/item/handheld_defibrillator/emag_act(mob/user)
if(!emagged)
diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm
index e96fceb8b6c..63058d9442b 100644
--- a/code/game/objects/items/devices/lightreplacer.dm
+++ b/code/game/objects/items/devices/lightreplacer.dm
@@ -52,7 +52,6 @@
origin_tech = "magnets=3;engineering=4"
force = 8
- var/emagged = FALSE
var/max_uses = 20
var/uses = 10
// How much to increase per each glass?
diff --git a/code/game/objects/items/devices/megaphone.dm b/code/game/objects/items/devices/megaphone.dm
index 5bc16ac2838..9e2e8a085f7 100644
--- a/code/game/objects/items/devices/megaphone.dm
+++ b/code/game/objects/items/devices/megaphone.dm
@@ -8,7 +8,6 @@
flags = CONDUCT
var/spamcheck = 0
- var/emagged = 0
var/insults = 0
var/span = ""
var/list/insultmsg = list("FUCK EVERYONE!", "I'M A TATER!", "ALL SECURITY TO SHOOT ME ON SIGHT!", "I HAVE A BOMB!", "CAPTAIN IS A COMDOM!", "FOR THE SYNDICATE!")
diff --git a/code/game/objects/items/devices/radio/beacon.dm b/code/game/objects/items/devices/radio/beacon.dm
index 487a582a3ab..5027676e1d3 100644
--- a/code/game/objects/items/devices/radio/beacon.dm
+++ b/code/game/objects/items/devices/radio/beacon.dm
@@ -5,7 +5,6 @@
item_state = "signaler"
var/code = "Beacon"
origin_tech = "bluespace=1"
- var/emagged = 0
var/syndicate = 0
var/area_bypass = FALSE
var/cc_beacon = FALSE //set if allowed to teleport to even if on zlevel2
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index a41d6a8b51b..7872120b96c 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -12,39 +12,28 @@ REAGENT SCANNER
desc = "A terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes."
icon = 'icons/obj/device.dmi'
icon_state = "t-ray0"
- var/on = 0
+ var/on = FALSE
slot_flags = SLOT_BELT
- w_class = 2
w_class = WEIGHT_CLASS_SMALL
item_state = "electronic"
materials = list(MAT_METAL=150)
origin_tech = "magnets=1;engineering=1"
- var/scan_range = 1
- var/pulse_duration = 10
-
-/obj/item/t_scanner/longer_pulse
- pulse_duration = 50
-
-/obj/item/t_scanner/extended_range
- scan_range = 3
-
-/obj/item/t_scanner/extended_range/longer_pulse
- scan_range = 3
- pulse_duration = 50
/obj/item/t_scanner/Destroy()
if(on)
STOP_PROCESSING(SSobj, src)
return ..()
-/obj/item/t_scanner/attack_self(mob/user)
-
+/obj/item/t_scanner/proc/toggle_on()
on = !on
- icon_state = copytext(icon_state, 1, length(icon_state))+"[on]"
-
+ icon_state = copytext_char(icon_state, 1, -1) + "[on]"
if(on)
START_PROCESSING(SSobj, src)
+ else
+ STOP_PROCESSING(SSobj, src)
+/obj/item/t_scanner/attack_self(mob/user)
+ toggle_on()
/obj/item/t_scanner/process()
if(!on)
@@ -53,41 +42,25 @@ REAGENT SCANNER
scan()
/obj/item/t_scanner/proc/scan()
+ t_ray_scan(loc)
- for(var/turf/T in range(scan_range, src.loc) )
-
- if(!T.intact)
+/proc/t_ray_scan(mob/viewer, flick_time = 8, distance = 3)
+ if(!ismob(viewer) || !viewer.client)
+ return
+ var/list/t_ray_images = list()
+ for(var/obj/O in orange(distance, viewer))
+ if(O.level != 1)
continue
- for(var/obj/O in T.contents)
-
- if(O.level != 1)
- continue
-
- if(O.invisibility == 101)
- O.invisibility = 0
- O.alpha = 128
- spawn(pulse_duration)
- if(O)
- var/turf/U = O.loc
- if(U && U.intact)
- O.invisibility = 101
- O.alpha = 255
- for(var/mob/living/M in T.contents)
- var/oldalpha = M.alpha
- if(M.alpha < 255 && istype(M))
- M.alpha = 255
- spawn(10)
- if(M)
- M.alpha = oldalpha
-
- var/mob/living/M = locate() in T
-
- if(M && M.invisibility == 2)
- M.invisibility = 0
- spawn(2)
- if(M)
- M.invisibility = INVISIBILITY_LEVEL_TWO
+ if(O.invisibility == INVISIBILITY_MAXIMUM)
+ var/image/I = new(loc = get_turf(O))
+ var/mutable_appearance/MA = new(O)
+ MA.alpha = 128
+ MA.dir = O.dir
+ I.appearance = MA
+ t_ray_images += I
+ if(length(t_ray_images))
+ flick_overlay(t_ray_images, list(viewer.client), flick_time)
/proc/chemscan(mob/living/user, mob/living/M)
diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm
index d6c73461e76..9a33dc3a3b1 100644
--- a/code/game/objects/items/devices/traitordevices.dm
+++ b/code/game/objects/items/devices/traitordevices.dm
@@ -102,7 +102,7 @@ effective or pretty fucking useless.
if(M)
if(intensity >= 5)
M.apply_effect(round(intensity/1.5), PARALYZE)
- M.apply_effect(intensity*10, IRRADIATE)
+ M.rad_act(intensity * 10)
else
to_chat(user, "The radioactive microlaser is still recharging.")
diff --git a/code/game/objects/items/devices/whistle.dm b/code/game/objects/items/devices/whistle.dm
index b4ebe4465fd..754c0676b71 100644
--- a/code/game/objects/items/devices/whistle.dm
+++ b/code/game/objects/items/devices/whistle.dm
@@ -8,7 +8,6 @@
flags = CONDUCT
var/spamcheck = 0
- var/emagged = 0
/obj/item/hailer/attack_self(mob/living/carbon/user as mob)
if(spamcheck)
diff --git a/code/game/objects/items/weapons/dna_injector.dm b/code/game/objects/items/weapons/dna_injector.dm
index 45047e97156..5f635b1eb73 100644
--- a/code/game/objects/items/weapons/dna_injector.dm
+++ b/code/game/objects/items/weapons/dna_injector.dm
@@ -70,7 +70,7 @@
if(used)
return
if(istype(M,/mob/living))
- M.apply_effect(rand(20 / (damage_coeff ** 2), 50 / (damage_coeff ** 2)), IRRADIATE, 0, 1)
+ M.apply_effect(rand(20 / (damage_coeff ** 2), 50 / (damage_coeff ** 2)), IRRADIATE)
var/mob/living/carbon/human/H
if(istype(M, /mob/living/carbon/human))
H = M
diff --git a/code/game/objects/items/weapons/grenades/atmosgrenade.dm b/code/game/objects/items/weapons/grenades/atmosgrenade.dm
index 6ba46d3442e..536e1ddd1b0 100644
--- a/code/game/objects/items/weapons/grenades/atmosgrenade.dm
+++ b/code/game/objects/items/weapons/grenades/atmosgrenade.dm
@@ -36,19 +36,19 @@
icon = 'icons/obj/grenade.dmi'
icon_state = "gluon"
item_state = "flashbang"
- var/range = 4
- var/rad_damage = 60
+ var/freeze_range = 4
+ var/rad_damage = 350
var/stamina_damage = 30
/obj/item/grenade/gluon/prime()
update_mob()
playsound(loc, 'sound/effects/empulse.ogg', 50, 1)
- for(var/turf/T in view(range, loc))
+ radiation_pulse(src, rad_damage)
+ for(var/turf/T in view(freeze_range, loc))
if(isfloorturf(T))
var/turf/simulated/F = T
F.MakeSlippery(TURF_WET_PERMAFROST)
for(var/mob/living/carbon/L in T)
L.adjustStaminaLoss(stamina_damage)
- L.apply_effect(rad_damage, IRRADIATE)
L.adjust_bodytemperature(-230)
qdel(src)
diff --git a/code/game/objects/items/weapons/storage/backpack.dm b/code/game/objects/items/weapons/storage/backpack.dm
index 5f668316126..9caa87d8a4b 100644
--- a/code/game/objects/items/weapons/storage/backpack.dm
+++ b/code/game/objects/items/weapons/storage/backpack.dm
@@ -315,7 +315,7 @@
/obj/item/storage/backpack/satchel_flat/hide(var/intact)
if(intact)
- invisibility = 101
+ invisibility = INVISIBILITY_MAXIMUM
anchored = 1 //otherwise you can start pulling, cover it, and drag around an invisible backpack.
icon_state = "[initial(icon_state)]2"
else
diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm
index 172a95d3cd0..ab52435ffcb 100644
--- a/code/game/objects/items/weapons/storage/belt.dm
+++ b/code/game/objects/items/weapons/storage/belt.dm
@@ -58,6 +58,7 @@
/obj/item/stack/cable_coil,
/obj/item/t_scanner,
/obj/item/analyzer,
+ /obj/item/geiger_counter,
/obj/item/extinguisher/mini,
/obj/item/holosign_creator)
@@ -135,7 +136,8 @@
/obj/item/sensor_device,
/obj/item/wrench/medical,
/obj/item/handheld_defibrillator,
- /obj/item/reagent_containers/applicator
+ /obj/item/reagent_containers/applicator,
+ /obj/item/geiger_counter
)
/obj/item/storage/belt/medical/surgery
diff --git a/code/game/objects/items/weapons/storage/secure.dm b/code/game/objects/items/weapons/storage/secure.dm
index 357cb043ca4..57ddb8b78ad 100644
--- a/code/game/objects/items/weapons/storage/secure.dm
+++ b/code/game/objects/items/weapons/storage/secure.dm
@@ -21,7 +21,6 @@
var/l_set = 0
var/l_setshort = 0
var/l_hacking = 0
- var/emagged = 0
var/open = 0
w_class = WEIGHT_CLASS_NORMAL
max_w_class = WEIGHT_CLASS_SMALL
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index e07c651924d..1023ffd73c8 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -29,6 +29,8 @@
var/on_blueprints = FALSE //Are we visible on the station blueprints at roundstart?
var/force_blueprints = FALSE //forces the obj to be on the blueprints, regardless of when it was created.
var/suicidal_hands = FALSE // Does it requires you to hold it to commit suicide with it?
+ /// Is it emagged or not?
+ var/emagged = FALSE
/obj/New()
..()
diff --git a/code/game/objects/structures/barsign.dm b/code/game/objects/structures/barsign.dm
index e50456bc03d..83d03263571 100644
--- a/code/game/objects/structures/barsign.dm
+++ b/code/game/objects/structures/barsign.dm
@@ -9,7 +9,6 @@
armor = list("melee" = 20, "bullet" = 20, "laser" = 20, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
var/list/barsigns=list()
var/list/hiddensigns
- var/emagged = 0
var/state = 0
var/prev_sign = ""
var/panel_open = 0
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
index 39b6a0a0096..3200cf3a7ad 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
@@ -34,6 +34,7 @@
new /obj/item/holosign_creator/engineering(src)
new /obj/item/flash(src)
new /obj/item/clothing/head/beret/eng(src)
+ new /obj/item/clothing/glasses/meson/engine(src)
new /obj/item/door_remote/chief_engineer(src)
new /obj/item/rpd(src)
new /obj/item/reagent_containers/food/drinks/mug/ce(src)
@@ -109,7 +110,7 @@
new /obj/item/clothing/under/rank/engineer/skirt(src)
new /obj/item/clothing/suit/storage/hazardvest(src)
new /obj/item/clothing/mask/gas(src)
- new /obj/item/clothing/glasses/meson(src)
+ new /obj/item/clothing/glasses/meson/engine(src)
new /obj/item/cartridge/engineering(src)
new /obj/item/clothing/head/beret/eng(src)
@@ -143,5 +144,6 @@
new /obj/item/watertank/atmos(src)
new /obj/item/clothing/suit/fire/atmos(src)
new /obj/item/clothing/head/hardhat/atmos(src)
+ new /obj/item/clothing/glasses/meson/engine/tray(src)
new /obj/item/rpd(src)
new /obj/item/destTagger(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
index 75dde9a7e9f..39375adb0e1 100644
--- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
@@ -140,6 +140,7 @@
icon_closed = "radsuitcloset"
/obj/structure/closet/radiation/populate_contents()
+ new /obj/item/geiger_counter(src)
new /obj/item/clothing/suit/radiation(src)
new /obj/item/clothing/head/radiation(src)
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index 353262d123d..ef533637cc2 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -385,16 +385,6 @@
icon_opened = "radiationopen"
icon_closed = "radiation"
-/obj/structure/closet/crate/radiation/populate_contents()
- new /obj/item/clothing/suit/radiation(src)
- new /obj/item/clothing/head/radiation(src)
- new /obj/item/clothing/suit/radiation(src)
- new /obj/item/clothing/head/radiation(src)
- new /obj/item/clothing/suit/radiation(src)
- new /obj/item/clothing/head/radiation(src)
- new /obj/item/clothing/suit/radiation(src)
- new /obj/item/clothing/head/radiation(src)
-
/obj/structure/closet/crate/secure/weapon
desc = "A secure weapons crate."
name = "weapons crate"
diff --git a/code/game/objects/structures/depot.dm b/code/game/objects/structures/depot.dm
index 096ffa9e33b..29ba8882bd7 100644
--- a/code/game/objects/structures/depot.dm
+++ b/code/game/objects/structures/depot.dm
@@ -44,8 +44,7 @@
if(prob(50))
empulse(src, 4, 10)
else
- for(var/mob/living/M in range(10, loc))
- M.apply_effect(rand(5, 25), IRRADIATE)
+ radiation_pulse(get_turf(src), 500, 2)
/obj/structure/fusionreactor/wrench_act(mob/user, obj/item/I)
. = TRUE
diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm
index 452450d31c8..0fe5d37c95d 100644
--- a/code/game/objects/structures/false_walls.dm
+++ b/code/game/objects/structures/false_walls.dm
@@ -12,6 +12,8 @@
anchored = TRUE
icon = 'icons/turf/walls/wall.dmi'
icon_state = "wall"
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
+ rad_insulation = RAD_MEDIUM_INSULATION
var/mineral = /obj/item/stack/sheet/metal
var/mineral_amount = 2
@@ -191,16 +193,13 @@
/obj/structure/falsewall/uranium/proc/radiate()
if(!active)
- if(world.time > last_event+15)
+ if(world.time > last_event + 15)
active = 1
- for(var/mob/living/L in range(3,src))
- L.apply_effect(12,IRRADIATE,0)
- for(var/turf/simulated/wall/mineral/uranium/T in range(3,src))
+ radiation_pulse(src, 150)
+ for(var/turf/simulated/wall/mineral/uranium/T in orange(1, src))
T.radiate()
last_event = world.time
active = null
- return
- return
/*
* Other misc falsewall types
*/
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index 47dbf7456c1..fb145958ed7 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -4,6 +4,8 @@
anchored = 1
density = 1
layer = BELOW_OBJ_LAYER
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
+ rad_insulation = RAD_VERY_LIGHT_INSULATION
var/state = GIRDER_NORMAL
var/girderpasschance = 20 // percentage chance that a projectile passes through the girder.
max_integrity = 200
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index b1e0f40b8d9..b4747d1c67f 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -6,6 +6,7 @@
density = TRUE
anchored = TRUE
flags = CONDUCT
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
pressure_resistance = 5*ONE_ATMOSPHERE
layer = BELOW_OBJ_LAYER
level = 3
diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm
index 91f88b34913..06bd8237cda 100644
--- a/code/game/objects/structures/holosign.dm
+++ b/code/game/objects/structures/holosign.dm
@@ -62,6 +62,8 @@
/obj/structure/holosign/barrier/engineering
icon_state = "holosign_engi"
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
+ rad_insulation = RAD_LIGHT_INSULATION
/obj/structure/holosign/barrier/atmos
name = "holo firelock"
@@ -72,6 +74,8 @@
anchored = TRUE
layer = ABOVE_MOB_LAYER
alpha = 150
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
+ rad_insulation = RAD_LIGHT_INSULATION
/obj/structure/holosign/barrier/atmos/Initialize(mapload)
. = ..()
diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm
index 29f2337c22e..bde75bb489d 100644
--- a/code/game/objects/structures/mineral_doors.dm
+++ b/code/game/objects/structures/mineral_doors.dm
@@ -9,6 +9,8 @@
icon_state = "metal"
max_integrity = 200
armor = list("melee" = 10, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 50, "acid" = 50)
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
+ rad_insulation = RAD_MEDIUM_INSULATION
var/initial_state
var/state = 0 //closed, 1 == open
var/isSwitchingStates = 0
@@ -153,11 +155,13 @@
icon_state = "silver"
sheetType = /obj/item/stack/sheet/mineral/silver
max_integrity = 300
+ rad_insulation = RAD_HEAVY_INSULATION
/obj/structure/mineral_door/gold
name = "gold door"
icon_state = "gold"
sheetType = /obj/item/stack/sheet/mineral/gold
+ rad_insulation = RAD_HEAVY_INSULATION
/obj/structure/mineral_door/uranium
name = "uranium door"
@@ -174,6 +178,7 @@
/obj/structure/mineral_door/transparent
opacity = 0
+ rad_insulation = RAD_VERY_LIGHT_INSULATION
/obj/structure/mineral_door/transparent/Close()
..()
@@ -207,6 +212,7 @@
icon_state = "diamond"
sheetType = /obj/item/stack/sheet/mineral/diamond
max_integrity = 1000
+ rad_insulation = RAD_EXTREME_INSULATION
/obj/structure/mineral_door/wood
name = "wood door"
@@ -217,6 +223,7 @@
hardness = 1
resistance_flags = FLAMMABLE
max_integrity = 200
+ rad_insulation = RAD_VERY_LIGHT_INSULATION
/obj/structure/mineral_door/resin
name = "resin door"
diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm
index 5a8a122be21..e1303b90b43 100644
--- a/code/game/objects/structures/signs.dm
+++ b/code/game/objects/structures/signs.dm
@@ -6,6 +6,7 @@
layer = 3.5
max_integrity = 100
armor = list("melee" = 50, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
/obj/structure/sign/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
switch(damage_type)
diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm
index 22449bb547b..2c7ffbe2e90 100644
--- a/code/game/objects/structures/statues.dm
+++ b/code/game/objects/structures/statues.dm
@@ -90,10 +90,9 @@
/obj/structure/statue/uranium/proc/radiate()
if(!active)
- if(world.time > last_event+15)
+ if(world.time > last_event + 15)
active = 1
- for(var/mob/living/L in range(3,src))
- L.apply_effect(12,IRRADIATE,0)
+ radiation_pulse(src, 30)
last_event = world.time
active = null
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index b54e6f40434..6feb3255822 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -240,6 +240,10 @@
pixel_x = 0
pixel_y = 32
+#define SHOWER_FREEZING "freezing"
+#define SHOWER_NORMAL "normal"
+#define SHOWER_BOILING "boiling"
+
/obj/machinery/shower
name = "shower"
desc = "The HS-451. Installed in the 2550s by the Nanotrasen Hygiene Division."
@@ -248,11 +252,11 @@
density = 0
anchored = 1
use_power = NO_POWER_USE
- var/on = 0
- var/obj/effect/mist/mymist = null
- var/ismist = 0 //needs a var so we can make it linger~
- var/watertemp = "normal" //freezing, normal, or boiling
- var/mobpresent = 0 //true if there is a mob on the shower's loc, this is to ease process()
+ ///Is the shower on or off?
+ var/on = FALSE
+ ///What temperature the shower reagents are set to.
+ var/current_temperature = SHOWER_NORMAL
+ ///What sound will be played on loop when the shower is on and pouring water.
var/datum/looping_sound/showering/soundloop
/obj/machinery/shower/New(turf/T, newdir = SOUTH, building = FALSE)
@@ -270,7 +274,6 @@
layer = FLY_LAYER
/obj/machinery/shower/Destroy()
- QDEL_NULL(mymist)
QDEL_NULL(soundloop)
return ..()
@@ -280,47 +283,45 @@
name = "mist"
icon = 'icons/obj/watercloset.dmi'
icon_state = "mist"
- layer = MOB_LAYER + 1
- anchored = 1
+ layer = FLY_LAYER
+ anchored = TRUE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
-/obj/machinery/shower/attack_hand(mob/M as mob)
+/obj/machinery/shower/attack_hand(mob/M)
on = !on
update_icon()
+ handle_mist()
+ add_fingerprint(M)
if(on)
+ START_PROCESSING(SSmachines, src)
+ process()
soundloop.start()
- if(M.loc == loc)
- wash(M)
- check_heat(M)
- M.water_act(100, convertHeat(), src)
- for(var/atom/movable/G in src.loc)
- G.clean_blood()
- G.water_act(100, convertHeat(), src)
else
soundloop.stop()
+ var/turf/simulated/T = loc
+ if(istype(T) && !T.density)
+ T.MakeSlippery(TURF_WET_WATER, 5 SECONDS)
-/obj/machinery/shower/attackby(obj/item/I as obj, mob/user as mob, params)
+/obj/machinery/shower/attackby(obj/item/I, mob/user, params)
if(I.type == /obj/item/analyzer)
- to_chat(user, "The water temperature seems to be [watertemp].")
- if(on)
- I.water_act(100, convertHeat(), src)
+ to_chat(user, "The water temperature seems to be [current_temperature].")
return ..()
/obj/machinery/shower/wrench_act(mob/user, obj/item/I)
- . = TRUE
- if(!I.tool_use_check(user, 0))
- return
- to_chat(user, "You begin to adjust the temperature valve with the [I].")
- if(I.use_tool(src, user, 50, volume = I.tool_volume))
- switch(watertemp)
- if("normal")
- watertemp = "freezing"
- if("freezing")
- watertemp = "boiling"
- if("boiling")
- watertemp = "normal"
- user.visible_message("[user] adjusts the shower with the [I].", "You adjust [src] to [watertemp].")
- update_icon() //letsa update whenever we change the temperature, since the mist might need to change
+ ..()
+ to_chat(user, "You begin to adjust the temperature valve with [I].")
+ if(I.use_tool(src, user, 50))
+ switch(current_temperature)
+ if(SHOWER_NORMAL)
+ current_temperature = SHOWER_FREEZING
+ if(SHOWER_FREEZING)
+ current_temperature = SHOWER_BOILING
+ if(SHOWER_BOILING)
+ current_temperature = SHOWER_NORMAL
+ user.visible_message("[user] adjusts the shower with \the [I].", "You adjust the shower with \the [I] to [current_temperature] temperature.")
+ add_hiddenprint(user)
+ handle_mist()
+ return TRUE
/obj/machinery/shower/welder_act(mob/user, obj/item/I)
. = TRUE
@@ -331,111 +332,103 @@
return
visible_message("[user] begins slicing [src] free...", "You begin slicing [src] free...", "You hear welding.")
if(I.use_tool(src, user, 40, volume = I.tool_volume))
- if(mymist)
- qdel(mymist)
user.visible_message("[user] cuts [src] loose!", "You cut [src] loose!")
var/obj/item/mounted/shower/S = new /obj/item/mounted/shower(get_turf(user))
transfer_prints_to(S, TRUE)
qdel(src)
-/obj/machinery/shower/update_icon() //this makes the shower mist up or clear mist (depending on water temperature)
- overlays.Cut() //once it's been on for a while, in addition to handling the water overlay.
+/obj/machinery/shower/update_icon()
+ cut_overlays()
if(on)
- overlays += image('icons/obj/watercloset.dmi', src, "water", MOB_LAYER + 1, dir)
- var/mist_time = 50 //5 seconds at normal temperature to build up mist
- if(watertemp == "freezing")
- mist_time = 70 //7 seconds on freezing temperature to disperse existing mist
- if(watertemp == "boiling")
- mist_time = 20 //2 seconds on boiling temperature to build up mist
- addtimer(CALLBACK(src, .proc/update_mist), mist_time)
- else
- addtimer(CALLBACK(src, .proc/update_mist), 250) //25 seconds for mist to disperse after being turned off
+ var/mutable_appearance/water_falling = mutable_appearance('icons/obj/watercloset.dmi', "water", ABOVE_MOB_LAYER)
+ add_overlay(water_falling)
-/obj/machinery/shower/proc/update_mist()
+/obj/machinery/shower/proc/handle_mist()
+ // If there is no mist, and the shower was turned on (on a non-freezing temp): make mist in 5 seconds
+ // If there was already mist, and the shower was turned off (or made cold): remove the existing mist in 25 sec
+ var/obj/effect/mist/mist = locate() in loc
+ if(!mist && on && current_temperature != SHOWER_FREEZING)
+ addtimer(CALLBACK(src, .proc/make_mist), 5 SECONDS)
+
+ if(mist && (!on || current_temperature == SHOWER_FREEZING))
+ addtimer(CALLBACK(src, .proc/clear_mist), 25 SECONDS)
+
+
+/obj/machinery/shower/proc/make_mist()
+ var/obj/effect/mist/mist = locate() in loc
+ if(!mist && on && current_temperature != SHOWER_FREEZING)
+ new /obj/effect/mist(loc)
+
+/obj/machinery/shower/proc/clear_mist()
+ var/obj/effect/mist/mist = locate() in loc
+ if(mist && (!on || current_temperature == SHOWER_FREEZING))
+ qdel(mist)
+
+/obj/machinery/shower/Crossed(atom/movable/AM)
+ ..()
if(on)
- if(watertemp == "freezing")
- if(mymist)
- qdel(mymist)
- ismist = 0
- return
- if(mymist)
- return
- ismist = 1
- mymist = new /obj/effect/mist(loc)
- else
- if(mymist)
- qdel(mymist)
- ismist = 0
-
-/obj/machinery/shower/Crossed(atom/movable/O, oldloc)
- ..()
- wash(O)
- if(ismob(O))
- mobpresent += 1
- check_heat(O)
-
-/obj/machinery/shower/Uncrossed(atom/movable/O)
- if(ismob(O))
- mobpresent -= 1
- ..()
+ wash(AM)
/obj/machinery/shower/proc/convertHeat()
- switch(watertemp)
- if("boiling")
+ switch(current_temperature)
+ if(SHOWER_BOILING)
return 340.15
- if("normal")
+ if(SHOWER_NORMAL)
return 310.15
- if("freezing")
+ if(SHOWER_FREEZING)
return 230.15
//Yes, showers are super powerful as far as washing goes.
-/obj/machinery/shower/proc/wash(atom/movable/O as obj|mob)
- if(!on) return
-
- if(istype(O, /obj/item))
- var/obj/item/I = O
+/obj/machinery/shower/proc/wash(atom/A)
+ if(isitem(A))
+ var/obj/item/I = A
I.extinguish()
- O.water_act(100, convertHeat(), src)
+ A.water_act(100, convertHeat(), src)
- if(isliving(O))
- var/mob/living/L = O
+ if(isliving(A))
+ var/mob/living/L = A
+ check_heat(L)
L.ExtinguishMob()
L.adjust_fire_stacks(-20) //Douse ourselves with water to avoid fire more easily
- to_chat(L, "You've been drenched in water!")
- L.clean_blood()
- if(isturf(loc))
- var/turf/tile = loc
- loc.clean_blood()
- for(var/obj/effect/E in tile)
- if(is_cleanable(E))
- qdel(E)
+ A.clean_blood(radiation_clean = TRUE)
/obj/machinery/shower/process()
- if(!on || !mobpresent)
- return
- for(var/mob/living/carbon/C in loc)
- if(prob(33))
- wash(C) //re-applies water and re-cleans mob while they remain under the shower, 33% chance per process to avoid message spam/quick death
- check_heat(C)
+ if(on)
+ if(isturf(loc))
+ var/turf/tile = loc
+ tile.water_act(100, convertHeat(), src)
+ tile.clean_blood(radiation_clean = TRUE)
+ for(var/obj/effect/E in tile)
+ if(is_cleanable(E))
+ qdel(E)
+ for(var/A in loc)
+ wash(A)
+ else
+ on = FALSE
+ soundloop.stop()
+ handle_mist()
+ update_icon()
-/obj/machinery/shower/proc/check_heat(mob/M as mob)
- if(!on || watertemp == "normal")
+/obj/machinery/shower/proc/check_heat(mob/M)
+ if(current_temperature == SHOWER_NORMAL)
return
if(iscarbon(M))
var/mob/living/carbon/C = M
- if(watertemp == "freezing")
+ if(current_temperature == SHOWER_FREEZING)
//C.bodytemperature = max(80, C.bodytemperature - 80)
to_chat(C, "The water is freezing!")
- return
- if(watertemp == "boiling")
+
+ else if(current_temperature == SHOWER_BOILING)
//C.bodytemperature = min(500, C.bodytemperature + 35)
C.adjustFireLoss(5)
to_chat(C, "The water is searing!")
- return
+#undef SHOWER_FREEZING
+#undef SHOWER_NORMAL
+#undef SHOWER_BOILING
/obj/item/bikehorn/rubberducky
name = "rubber ducky"
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 65c212af723..2382688232b 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -30,10 +30,12 @@ GLOBAL_LIST_INIT(wcCommon, pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e",
pressure_resistance = 4*ONE_ATMOSPHERE
anchored = TRUE
flags = ON_BORDER
+ flags_2 = RAD_PROTECT_CONTENTS_2
can_be_unanchored = TRUE
max_integrity = 25
resistance_flags = ACID_PROOF
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 100)
+ rad_insulation = RAD_VERY_LIGHT_INSULATION
var/ini_dir = null
var/state = WINDOW_OUT_OF_FRAME
var/reinf = FALSE
@@ -505,6 +507,7 @@ GLOBAL_LIST_INIT(wcCommon, pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e",
cancolor = TRUE
heat_resistance = 1600
armor = list("melee" = 50, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 25, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 100)
+ rad_insulation = RAD_HEAVY_INSULATION
max_integrity = 50
explosion_block = 1
glass_type = /obj/item/stack/sheet/rglass
@@ -579,6 +582,7 @@ GLOBAL_LIST_INIT(wcCommon, pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e",
max_integrity = 150
explosion_block = 1
armor = list("melee" = 75, "bullet" = 5, "laser" = 0, "energy" = 0, "bomb" = 45, "bio" = 100, "rad" = 100, "fire" = 99, "acid" = 100)
+ rad_insulation = RAD_NO_INSULATION
/obj/structure/window/plasmabasic/BlockSuperconductivity()
return 1
@@ -593,6 +597,7 @@ GLOBAL_LIST_INIT(wcCommon, pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e",
max_integrity = 500
explosion_block = 2
armor = list("melee" = 85, "bullet" = 20, "laser" = 0, "energy" = 0, "bomb" = 60, "bio" = 100, "rad" = 100, "fire" = 99, "acid" = 100)
+ rad_insulation = RAD_NO_INSULATION
damage_deflection = 21
/obj/structure/window/plasmareinforced/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
@@ -630,6 +635,7 @@ GLOBAL_LIST_INIT(wcCommon, pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e",
canSmoothWith = list(/obj/structure/window/full/basic, /obj/structure/window/full/reinforced, /obj/structure/window/full/reinforced/tinted, /obj/structure/window/full/plasmabasic, /obj/structure/window/full/plasmareinforced)
explosion_block = 1
armor = list("melee" = 75, "bullet" = 5, "laser" = 0, "energy" = 0, "bomb" = 45, "bio" = 100, "rad" = 100, "fire" = 99, "acid" = 100)
+ rad_insulation = RAD_NO_INSULATION
/obj/structure/window/full/plasmareinforced
name = "reinforced plasma window"
@@ -643,6 +649,7 @@ GLOBAL_LIST_INIT(wcCommon, pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e",
max_integrity = 1000
explosion_block = 2
armor = list("melee" = 85, "bullet" = 20, "laser" = 0, "energy" = 0, "bomb" = 60, "bio" = 100, "rad" = 100, "fire" = 99, "acid" = 100)
+ rad_insulation = RAD_NO_INSULATION
/obj/structure/window/full/plasmareinforced/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
return
@@ -658,6 +665,7 @@ GLOBAL_LIST_INIT(wcCommon, pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e",
reinf = TRUE
heat_resistance = 1600
armor = list("melee" = 50, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 25, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 100)
+ rad_insulation = RAD_HEAVY_INSULATION
explosion_block = 1
glass_type = /obj/item/stack/sheet/rglass
cancolor = TRUE
@@ -707,6 +715,7 @@ GLOBAL_LIST_INIT(wcCommon, pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e",
reinf = TRUE
heat_resistance = 1600
armor = list("melee" = 50, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 100)
+ rad_insulation = RAD_HEAVY_INSULATION
smooth = SMOOTH_TRUE
canSmoothWith = null
explosion_block = 3
diff --git a/code/game/turfs/simulated/floor/mineral.dm b/code/game/turfs/simulated/floor/mineral.dm
index dd975dc80d9..6749783c68d 100644
--- a/code/game/turfs/simulated/floor/mineral.dm
+++ b/code/game/turfs/simulated/floor/mineral.dm
@@ -237,15 +237,13 @@
/turf/simulated/floor/mineral/uranium/proc/radiate()
if(!active)
- if(world.time > last_event+15)
- active = 1
- for(var/mob/living/L in range(3,src))
- L.apply_effect(1,IRRADIATE,0)
- for(var/turf/simulated/floor/mineral/uranium/T in orange(1,src))
+ if(world.time > last_event + 15)
+ active = TRUE
+ radiation_pulse(src, 10)
+ for(var/turf/simulated/floor/mineral/uranium/T in orange(1, src))
T.radiate()
last_event = world.time
- active = 0
- return
+ active = FALSE
// ALIEN ALLOY
/turf/simulated/floor/mineral/abductor
diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm
index f528483db5c..538c1599069 100644
--- a/code/game/turfs/simulated/minerals.dm
+++ b/code/game/turfs/simulated/minerals.dm
@@ -11,6 +11,8 @@
opacity = 1
density = TRUE
blocks_air = TRUE
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
+ rad_insulation = RAD_MEDIUM_INSULATION
layer = EDGED_TURF_LAYER
temperature = TCMB
var/environment_type = "asteroid"
diff --git a/code/game/turfs/simulated/shuttle.dm b/code/game/turfs/simulated/shuttle.dm
index 7a781679173..acbe2cdf9d8 100644
--- a/code/game/turfs/simulated/shuttle.dm
+++ b/code/game/turfs/simulated/shuttle.dm
@@ -11,6 +11,8 @@
opacity = 1
density = 1
blocks_air = 1
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
+ rad_insulation = RAD_MEDIUM_INSULATION
/turf/simulated/shuttle/rpd_act(mob/user, obj/item/rpd/our_rpd)
if(our_rpd.mode == RPD_DELETE_MODE)//No pipes on shuttles
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index 23d0c9789bd..36cf112886f 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -22,6 +22,9 @@
blocks_air = 1
explosion_block = 1
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
+ rad_insulation = RAD_MEDIUM_INSULATION
+
thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall
diff --git a/code/game/turfs/simulated/walls_mineral.dm b/code/game/turfs/simulated/walls_mineral.dm
index 8b60be916c3..9719c5cc731 100644
--- a/code/game/turfs/simulated/walls_mineral.dm
+++ b/code/game/turfs/simulated/walls_mineral.dm
@@ -60,16 +60,13 @@
/turf/simulated/wall/mineral/uranium/proc/radiate()
if(!active)
- if(world.time > last_event+15)
+ if(world.time > last_event + 15)
active = 1
- for(var/mob/living/L in range(3,src))
- L.apply_effect(12,IRRADIATE,0)
- for(var/turf/simulated/wall/mineral/uranium/T in range(3,src))
+ radiation_pulse(src, 40)
+ for(var/turf/simulated/wall/mineral/uranium/T in orange(1, src))
T.radiate()
last_event = world.time
active = null
- return
- return
/turf/simulated/wall/mineral/uranium/attack_hand(mob/user as mob)
radiate()
diff --git a/code/game/turfs/simulated/walls_reinforced.dm b/code/game/turfs/simulated/walls_reinforced.dm
index a3e9c9ae0f2..953a8ade1b8 100644
--- a/code/game/turfs/simulated/walls_reinforced.dm
+++ b/code/game/turfs/simulated/walls_reinforced.dm
@@ -6,6 +6,7 @@
opacity = 1
density = 1
explosion_block = 2
+ rad_insulation = RAD_HEAVY_INSULATION
damage_cap = 600
max_temperature = 6000
hardness = 10
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 3aaf12cd5fc..52125e9fd41 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -560,6 +560,3 @@
/turf/AllowDrop()
return TRUE
-
-/turf/proc/water_act(volume, temperature, source)
- return FALSE
diff --git a/code/game/turfs/unsimulated/walls.dm b/code/game/turfs/unsimulated/walls.dm
index c5688c31323..44cf5c669ea 100644
--- a/code/game/turfs/unsimulated/walls.dm
+++ b/code/game/turfs/unsimulated/walls.dm
@@ -4,6 +4,8 @@
icon_state = "riveted"
opacity = 1
density = 1
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
+ rad_insulation = RAD_MEDIUM_INSULATION
explosion_block = 2
/turf/unsimulated/wall/fakeglass
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 32a416b34ce..b1629bf01eb 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -743,11 +743,11 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
for(var/obj/machinery/power/rad_collector/Rad in GLOB.machines)
if(Rad.anchored)
- if(!Rad.P)
+ if(!Rad.loaded_tank)
var/obj/item/tank/plasma/Plasma = new/obj/item/tank/plasma(Rad)
Plasma.air_contents.toxins = 70
Rad.drainratio = 0
- Rad.P = Plasma
+ Rad.loaded_tank = Plasma
Plasma.loc = Rad
if(!Rad.active)
diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm
index 5648f21d3e2..56184f1daf6 100644
--- a/code/modules/client/preference/preferences.dm
+++ b/code/modules/client/preference/preferences.dm
@@ -2114,11 +2114,9 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
if("ambientocclusion")
toggles ^= PREFTOGGLE_AMBIENT_OCCLUSION
- if(parent && parent.screen && parent.screen.len)
+ if(length(parent?.screen))
var/obj/screen/plane_master/game_world/PM = locate(/obj/screen/plane_master/game_world) in parent.screen
- PM.filters -= FILTER_AMBIENT_OCCLUSION
- if(toggles & PREFTOGGLE_AMBIENT_OCCLUSION)
- PM.filters += FILTER_AMBIENT_OCCLUSION
+ PM.backdrop(parent.mob)
if("parallax")
var/parallax_styles = list(
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 6a9dd763a05..15d409b92b2 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -204,7 +204,6 @@
var/invis_override = 0
var/lighting_alpha
- var/emagged = 0
var/list/color_view = null//overrides client.color while worn
var/prescription = 0
var/prescription_upgradable = 0
diff --git a/code/modules/clothing/glasses/engine_goggles.dm b/code/modules/clothing/glasses/engine_goggles.dm
new file mode 100644
index 00000000000..acdce6a78ed
--- /dev/null
+++ b/code/modules/clothing/glasses/engine_goggles.dm
@@ -0,0 +1,120 @@
+//Engineering Mesons
+
+#define MODE_NONE ""
+#define MODE_MESON "meson"
+#define MODE_TRAY "t-ray"
+#define MODE_RAD "radiation"
+
+/obj/item/clothing/glasses/meson/engine
+ name = "engineering scanner goggles"
+ desc = "Goggles used by engineers. The Meson Scanner mode lets you see basic structural and terrain layouts through walls, the T-ray Scanner mode lets you see underfloor objects such as cables and pipes, and the Radiation Scanner mode lets you see objects contaminated by radiation."
+ icon_state = "trayson-meson"
+ item_state = "trayson-meson"
+ actions_types = list(/datum/action/item_action/toggle_mode)
+ origin_tech = "materials=3;magnets=3;engineering=3;plasmatech=3"
+ vision_flags = NONE
+ invis_view = SEE_INVISIBLE_LIVING
+
+ var/list/modes = list(MODE_NONE = MODE_MESON, MODE_MESON = MODE_TRAY, MODE_TRAY = MODE_RAD, MODE_RAD = MODE_NONE)
+ var/mode = MODE_NONE
+ var/range = 1
+
+/obj/item/clothing/glasses/meson/engine/Initialize(mapload)
+ . = ..()
+ START_PROCESSING(SSobj, src)
+ update_icon()
+
+/obj/item/clothing/glasses/meson/engine/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/item/clothing/glasses/meson/engine/proc/toggle_mode(mob/user, voluntary)
+ mode = modes[mode]
+ to_chat(user, "[voluntary ? "You turn the goggles" : "The goggles turn"] [mode ? "to [mode] mode" : "off"][voluntary ? "." : "!"]")
+
+ switch(mode)
+ if(MODE_MESON)
+ vision_flags = SEE_TURFS
+ lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
+
+ if(MODE_TRAY) //undoes the last mode, meson
+ vision_flags = NONE
+ lighting_alpha = null
+
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.glasses == src)
+ H.update_sight()
+
+ update_icon()
+ for(var/X in actions)
+ var/datum/action/A = X
+ A.UpdateButtonIcon()
+
+/obj/item/clothing/glasses/meson/engine/attack_self(mob/user)
+ toggle_mode(user, TRUE)
+
+/obj/item/clothing/glasses/meson/engine/process()
+ if(!ishuman(loc))
+ return
+ var/mob/living/carbon/human/user = loc
+ if(user.glasses != src || !user.client)
+ return
+ switch(mode)
+ if(MODE_TRAY)
+ t_ray_scan(user, 8, range)
+ if(MODE_RAD)
+ show_rads()
+
+/obj/item/clothing/glasses/meson/engine/proc/show_rads()
+ var/mob/living/carbon/human/user = loc
+ var/list/rad_places = list()
+ for(var/datum/component/radioactive/thing in SSradiation.processing)
+ var/atom/owner = thing.parent
+ var/turf/place = get_turf(owner)
+ if(rad_places[place])
+ rad_places[place] += thing.strength
+ else
+ rad_places[place] = thing.strength
+
+ for(var/i in rad_places)
+ var/turf/place = i
+ if(get_dist(user, place) >= range * 5) //Rads are easier to see than wires under the floor
+ continue
+ var/strength = round(rad_places[i] / 1000, 0.1)
+ var/image/pic = image(loc = place)
+ var/mutable_appearance/MA = new()
+ MA.maptext = MAPTEXT("[strength]k")
+ MA.color = "#04e604"
+ MA.layer = RAD_TEXT_LAYER
+ MA.plane = GAME_PLANE
+ pic.appearance = MA
+ flick_overlay(pic, list(user.client), 10)
+
+/obj/item/clothing/glasses/meson/engine/update_icon()
+ icon_state = "trayson-[mode]"
+ update_mob()
+
+/obj/item/clothing/glasses/meson/engine/proc/update_mob()
+ item_state = icon_state
+ if(isliving(loc))
+ var/mob/living/user = loc
+ if(user.get_item_by_slot(slot_glasses) == src)
+ user.update_inv_glasses()
+ else
+ user.update_inv_l_hand()
+ user.update_inv_r_hand()
+
+/obj/item/clothing/glasses/meson/engine/tray //atmos techs have lived far too long without tray goggles while those damned engineers get their dual-purpose gogles all to themselves
+ name = "optical t-ray scanner"
+ icon_state = "trayson-t-ray"
+ item_state = "trayson-t-ray"
+ desc = "Used by engineering staff to see underfloor objects such as cables and pipes."
+ range = 2
+ origin_tech = "materials=3;magnets=2;engineering=2"
+ modes = list(MODE_NONE = MODE_TRAY, MODE_TRAY = MODE_NONE)
+
+#undef MODE_NONE
+#undef MODE_MESON
+#undef MODE_TRAY
+#undef MODE_RAD
diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm
index 011bc60cdc4..cc63f0a6e40 100644
--- a/code/modules/clothing/glasses/glasses.dm
+++ b/code/modules/clothing/glasses/glasses.dm
@@ -49,7 +49,7 @@
name = "Optical Meson Scanner"
desc = "Used for seeing walls, floors, and stuff through anything."
icon_state = "meson"
- item_state = "glasses"
+ item_state = "meson"
origin_tech = "magnets=1;engineering=2"
vision_flags = SEE_TURFS
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
@@ -66,7 +66,6 @@
name = "Night Vision Optical Meson Scanner"
desc = "An Optical Meson Scanner fitted with an amplified visible light spectrum overlay, providing greater visual clarity in darkness."
icon_state = "nvgmeson"
- item_state = "glasses"
origin_tech = "magnets=4;engineering=5;plasmatech=4"
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index 283a71bcbd0..64ca479175f 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -14,6 +14,11 @@
item_color = "engineering" //Determines used sprites: hardsuit[on]-[color] and hardsuit[on]-[color]2 (lying down sprite)
actions_types = list(/datum/action/item_action/toggle_helmet_light)
+ var/current_tick_amount = 0
+ var/radiation_count = 0
+ var/grace = RAD_GEIGER_GRACE_PERIOD
+ var/datum/looping_sound/geiger/soundloop
+
//Species-specific stuff.
species_restricted = list("exclude","Wryn")
sprite_sheets = list(
@@ -33,6 +38,16 @@
"Vulpkanin" = 'icons/obj/clothing/species/vulpkanin/hats.dmi'
)
+/obj/item/clothing/head/helmet/space/hardsuit/Initialize(mapload)
+ . = ..()
+ soundloop = new(list(), FALSE, TRUE)
+ soundloop.volume = 5
+ START_PROCESSING(SSobj, src)
+
+/obj/item/clothing/head/helmet/space/hardsuit/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
/obj/item/clothing/head/helmet/space/hardsuit/attack_self(mob/user)
toggle_light(user)
@@ -61,6 +76,7 @@
..()
if(suit)
suit.RemoveHelmet()
+ soundloop.stop(user)
/obj/item/clothing/head/helmet/space/hardsuit/item_action_slot_check(slot)
if(slot == slot_head)
@@ -71,14 +87,38 @@
if(slot != slot_head)
if(suit)
suit.RemoveHelmet()
+ soundloop.stop(user)
else
qdel(src)
+ else
+ soundloop.start(user)
/obj/item/clothing/head/helmet/space/hardsuit/proc/display_visor_message(var/msg)
var/mob/wearer = loc
if(msg && ishuman(wearer))
wearer.show_message("[msg]", 1)
+/obj/item/clothing/head/helmet/space/hardsuit/rad_act(amount)
+ . = ..()
+ if(amount <= RAD_BACKGROUND_RADIATION)
+ return
+ current_tick_amount += amount
+
+/obj/item/clothing/head/helmet/space/hardsuit/process()
+ radiation_count -= radiation_count / RAD_GEIGER_MEASURE_SMOOTHING
+ radiation_count += current_tick_amount / RAD_GEIGER_MEASURE_SMOOTHING
+
+ if(current_tick_amount)
+ grace = RAD_GEIGER_GRACE_PERIOD
+
+ grace--
+ if(grace <= 0)
+ radiation_count = 0
+
+ current_tick_amount = 0
+
+ soundloop.last_radiation = radiation_count
+
/obj/item/clothing/head/helmet/space/hardsuit/emp_act(severity)
..()
display_visor_message("[severity > 1 ? "Light" : "Strong"] electromagnetic pulse detected!")
diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm
index e77bcb7478a..52182e1cf1f 100644
--- a/code/modules/clothing/suits/utility.dm
+++ b/code/modules/clothing/suits/utility.dm
@@ -131,7 +131,7 @@
strip_delay = 60
put_on_delay = 60
resistance_flags = NONE
-
+ flags_2 = RAD_PROTECT_CONTENTS_2
sprite_sheets = list(
"Vox" = 'icons/mob/species/vox/head.dmi',
"Grey" = 'icons/mob/species/grey/head.dmi'
@@ -147,14 +147,14 @@
permeability_coefficient = 0.50
flags = THICKMATERIAL
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
- allowed = list(/obj/item/flashlight,/obj/item/tank/emergency_oxygen)
+ allowed = list(/obj/item/flashlight,/obj/item/tank/emergency_oxygen, /obj/item/geiger_counter)
slowdown = 1.5
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 60, "rad" = 100, "fire" = 30, "acid" = 30)
flags_inv = HIDEJUMPSUIT|HIDETAIL
strip_delay = 60
put_on_delay = 60
resistance_flags = NONE
-
+ flags_2 = RAD_PROTECT_CONTENTS_2
sprite_sheets = list(
"Vox" = 'icons/mob/species/vox/suit.dmi'
)
diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm
index 497277e16e8..a80289686ff 100644
--- a/code/modules/clothing/under/accessories/accessory.dm
+++ b/code/modules/clothing/under/accessories/accessory.dm
@@ -270,7 +270,6 @@
item_color = "holobadge"
slot_flags = SLOT_BELT | SLOT_TIE
- var/emagged = FALSE //Emagging removes Sec check.
var/stored_name = null
/obj/item/clothing/accessory/holobadge/cord
diff --git a/code/modules/mining/equipment/wormhole_jaunter.dm b/code/modules/mining/equipment/wormhole_jaunter.dm
index f9a98b01483..c791c5d58b7 100644
--- a/code/modules/mining/equipment/wormhole_jaunter.dm
+++ b/code/modules/mining/equipment/wormhole_jaunter.dm
@@ -11,7 +11,6 @@
throw_range = 5
origin_tech = "bluespace=2"
slot_flags = SLOT_BELT
- var/emagged = FALSE
/obj/item/wormhole_jaunter/attack_self(mob/user)
user.visible_message("[user.name] activates the [name]!")
@@ -73,7 +72,6 @@
icon_state = "bhole3"
desc = "A stable hole in the universe made by a wormhole jaunter. Turbulent doesn't even begin to describe how rough passage through one of these is, but at least it will always get you somewhere near a beacon."
failchance = 0
- var/emagged = FALSE
/obj/effect/portal/jaunt_tunnel/can_teleport(atom/movable/M)
if(!emagged && ismegafauna(M))
diff --git a/code/modules/mob/living/carbon/brain/life.dm b/code/modules/mob/living/carbon/brain/life.dm
index 0faa238190e..b188c7bac72 100644
--- a/code/modules/mob/living/carbon/brain/life.dm
+++ b/code/modules/mob/living/carbon/brain/life.dm
@@ -1,21 +1,3 @@
-/mob/living/carbon/brain/handle_mutations_and_radiation()
- if(radiation)
- if(radiation > 100)
- if(!container)
- to_chat(src, "You feel weak.")
- else
- to_chat(src, "STATUS: CRITICAL AMOUNTS OF RADIATION DETECTED.")
-
- switch(radiation)
-
- if(50 to 75)
- if(prob(5))
- if(!container)
- to_chat(src, "You feel weak.")
- else
- to_chat(src, "STATUS: DANGEROUS AMOUNTS OF RADIATION DETECTED.")
- ..()
-
/mob/living/carbon/brain/proc/handle_temperature_damage(body_part, exposed_temperature, exposed_intensity)
if(status_flags & GODMODE)
return
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 02035a31520..cb00e02dd12 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -1225,14 +1225,14 @@ so that different stomachs can handle things in different ways VB*/
I.extinguish() //extinguishes our clothes
..()
-/mob/living/carbon/clean_blood(clean_hands = TRUE, clean_mask = TRUE, clean_feet = TRUE)
+/mob/living/carbon/clean_blood(radiation_clean = FALSE, clean_hands = TRUE, clean_mask = TRUE, clean_feet = TRUE)
if(head)
- if(head.clean_blood())
+ if(head.clean_blood(radiation_clean))
update_inv_head()
if(head.flags_inv & HIDEMASK)
clean_mask = FALSE
if(wear_suit)
- if(wear_suit.clean_blood())
+ if(wear_suit.clean_blood(radiation_clean))
update_inv_wear_suit()
if(wear_suit.flags_inv & HIDESHOES)
clean_feet = FALSE
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 78489251ca1..2ec78381536 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -412,6 +412,8 @@
. = list(msg)
+ SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .)
+
//Helper procedure. Called by /mob/living/carbon/human/examine() and /mob/living/carbon/human/Topic() to determine HUD access to security and medical records.
/proc/hasHUD(mob/M, hudtype)
if(istype(M, /mob/living/carbon/human))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index e5ad4790701..5e37c1b49b4 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -4,6 +4,7 @@
voice_name = "unknown"
icon = 'icons/mob/human.dmi'
icon_state = "body_m_s"
+ appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE|LONG_GLIDE
deathgasp_on_death = TRUE
/mob/living/carbon/human/New(loc)
@@ -1601,13 +1602,18 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
if(prob(current_size * 5) && hand.w_class >= ((11-current_size)/2) && unEquip(hand))
step_towards(hand, src)
to_chat(src, "\The [S] pulls \the [hand] from your grip!")
- apply_effect(current_size * 3, IRRADIATE)
+ rad_act(current_size * 3)
/mob/living/carbon/human/narsie_act()
if(iswizard(src) && iscultist(src)) //Wizard cultists are immune to narsie because it would prematurely end the wiz round that's about to end by the automated shuttle call anyway
return
..()
+/mob/living/carbon/human/rad_act(amount)
+ if(RADIMMUNE in dna.species.species_traits)
+ return SEND_SIGNAL(src, COMSIG_ATOM_RAD_ACT, amount)
+ . = ..()
+
/mob/living/carbon/human/proc/do_cpr(mob/living/carbon/human/H)
if(H == src)
to_chat(src, "You cannot perform CPR on yourself!")
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 950089bf011..94459fb2624 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -193,64 +193,8 @@
if(gene_stability < GENETIC_DAMAGE_STAGE_3)
gib()
- if(!(RADIMMUNE in dna.species.species_traits))
- if(radiation)
- radiation = clamp(radiation, 0, 200)
-
- var/autopsy_damage = 0
- switch(radiation)
- if(1 to 49)
- radiation = max(radiation-1, 0)
- if(prob(25))
- adjustToxLoss(1)
- adjustFireLoss(1)
- autopsy_damage = 2
-
- if(50 to 74)
- radiation = max(radiation-2, 0)
- adjustToxLoss(1)
- adjustFireLoss(1)
- autopsy_damage = 2
- if(prob(5))
- radiation = max(radiation-5, 0)
- Weaken(3)
- to_chat(src, "You feel weak.")
- emote("collapse")
-
- if(75 to 100)
- radiation = max(radiation-2, 0)
- adjustToxLoss(2)
- adjustFireLoss(2)
- autopsy_damage = 4
- if(prob(2))
- to_chat(src, "You mutate!")
- randmutb(src)
- domutcheck(src, null)
-
- if(101 to 150)
- radiation = max(radiation-3, 0)
- adjustToxLoss(2)
- adjustFireLoss(3)
- autopsy_damage = 5
- if(prob(4))
- to_chat(src, "You mutate!")
- randmutb(src)
- domutcheck(src, null)
-
- if(151 to INFINITY)
- radiation = max(radiation-3, 0)
- adjustToxLoss(2)
- adjustFireLoss(3)
- autopsy_damage = 5
- if(prob(6))
- to_chat(src, "You mutate!")
- randmutb(src)
- domutcheck(src, null)
-
- if(autopsy_damage)
- var/obj/item/organ/external/chest/chest = get_organ("chest")
- if(chest)
- chest.add_autopsy_data("Radiation Poisoning", autopsy_damage)
+ if(!dna || !dna.species.handle_mutations_and_radiation(src))
+ ..()
/mob/living/carbon/human/breathe()
if(!dna.species.breathe(src))
diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm
index 42680f9f807..e47514b1094 100644
--- a/code/modules/mob/living/carbon/human/species/_species.dm
+++ b/code/modules/mob/living/carbon/human/species/_species.dm
@@ -749,6 +749,49 @@
/datum/species/proc/update_health_hud(mob/living/carbon/human/H)
return FALSE
+/datum/species/proc/handle_mutations_and_radiation(mob/living/carbon/human/H)
+ if(RADIMMUNE in species_traits)
+ H.radiation = 0
+ return TRUE
+
+ . = FALSE
+ var/radiation = H.radiation
+
+ if(radiation > RAD_MOB_KNOCKDOWN && prob(RAD_MOB_KNOCKDOWN_PROB))
+ if(!H.IsWeakened())
+ H.emote("collapse")
+ H.Weaken(RAD_MOB_KNOCKDOWN_AMOUNT)
+ to_chat(H, "You feel weak.")
+
+ if(radiation > RAD_MOB_VOMIT && prob(RAD_MOB_VOMIT_PROB))
+ H.vomit(10, TRUE)
+
+ if(radiation > RAD_MOB_MUTATE)
+ if(prob(1))
+ to_chat(H, "You mutate!")
+ randmutb(H)
+ H.emote("gasp")
+ domutcheck(H, null)
+
+ if(radiation > RAD_MOB_HAIRLOSS)
+ var/obj/item/organ/external/head/head_organ = H.get_organ("head")
+ if(!head_organ)
+ return
+ if(prob(15) && head_organ.h_style != "Bald")
+ to_chat(H, "Your hair starts to fall out in clumps...")
+ addtimer(CALLBACK(src, .proc/go_bald, H), 5 SECONDS)
+
+/datum/species/proc/go_bald(mob/living/carbon/human/H)
+ if(QDELETED(H)) //may be called from a timer
+ return
+ var/obj/item/organ/external/head/head_organ = H.get_organ("head")
+ if(!head_organ)
+ return
+ head_organ.f_style = "Shaved"
+ head_organ.h_style = "Bald"
+ H.update_hair()
+ H.update_fhair()
+
/*
Returns the path corresponding to the corresponding organ
It'll return null if the organ doesn't correspond, so include null checks when using this!
diff --git a/code/modules/mob/living/carbon/human/species/golem.dm b/code/modules/mob/living/carbon/human/species/golem.dm
index 7ff32e38644..cde56de264b 100644
--- a/code/modules/mob/living/carbon/human/species/golem.dm
+++ b/code/modules/mob/living/carbon/human/species/golem.dm
@@ -389,13 +389,7 @@
special_names = list("Oxide", "Rod", "Meltdown")
/datum/species/golem/uranium/handle_life(mob/living/carbon/human/H)
- for(var/mob/living/L in range(2, H))
- if(ishuman(L))
- var/mob/living/carbon/human/I = L
- if(!(RADIMMUNE in I.dna.species.species_traits))
- L.apply_effect(10, IRRADIATE)
- if(prob(25)) //reduce spam
- to_chat(L, "You are enveloped by a soft green glow emanating from [H].")
+ radiation_pulse(H, 20)
..()
//Ventcrawler
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index c11eaca5293..b20ac4588b0 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -226,29 +226,9 @@
return
/mob/living/carbon/handle_mutations_and_radiation()
- if(radiation)
-
- switch(radiation)
- if(0 to 50)
- radiation--
- if(prob(25))
- adjustToxLoss(1)
- updatehealth("handle mutations and radiation(0-50)")
-
- if(50 to 75)
- radiation -= 2
- adjustToxLoss(1)
- if(prob(5))
- radiation -= 5
- updatehealth("handle mutations and radiation(50-75)")
-
- if(75 to 100)
- radiation -= 3
- adjustToxLoss(3)
- updatehealth("handle mutations and radiation(75-100)")
-
- radiation = clamp(radiation, 0, 100)
-
+ radiation -= min(radiation, RAD_LOSS_PER_TICK)
+ if(radiation > RAD_MOB_SAFE)
+ adjustToxLoss(log(radiation - RAD_MOB_SAFE) * RAD_TOX_COEFFICIENT)
/mob/living/carbon/handle_chemicals_in_body()
reagents.metabolize(src)
diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm
index 60f186631b7..c0f667e9d31 100644
--- a/code/modules/mob/living/damage_procs.dm
+++ b/code/modules/mob/living/damage_procs.dm
@@ -72,10 +72,10 @@
-/mob/living/proc/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0, var/negate_armor = 0)
- blocked = (100-blocked)/100
+/mob/living/proc/apply_effect(effect = 0, effecttype = STUN, blocked = 0)
+ blocked = (100 - blocked) / 100
if(!effect || (blocked <= 0))
- return 0
+ return FALSE
switch(effecttype)
if(STUN)
Stun(effect * blocked)
@@ -84,10 +84,7 @@
if(PARALYZE)
Paralyse(effect * blocked)
if(IRRADIATE)
- var/rad_damage = effect
- if(!negate_armor) // Setting negate_armor overrides radiation armor checks, which are automatic otherwise
- rad_damage = max(effect * ((100-run_armor_check(null, "rad", "Your clothes feel warm.", "Your clothes feel warm."))/100),0)
- radiation += rad_damage
+ radiation += max(effect * blocked, 0)
if(SLUR)
Slur(effect * blocked)
if(STUTTER)
@@ -100,21 +97,32 @@
if(status_flags & CANSTUN)
Jitter(effect * blocked)
updatehealth("apply effect")
- return 1
+ return TRUE
-/mob/living/proc/apply_effects(var/stun = 0, var/weaken = 0, var/paralyze = 0, var/irradiate = 0, var/slur = 0, var/stutter = 0, var/eyeblur = 0, var/drowsy = 0, var/blocked = 0, var/stamina = 0, var/jitter = 0)
- if(blocked >= 100) return 0
- if(stun) apply_effect(stun, STUN, blocked)
- if(weaken) apply_effect(weaken, WEAKEN, blocked)
- if(paralyze) apply_effect(paralyze, PARALYZE, blocked)
- if(irradiate) apply_effect(irradiate, IRRADIATE, blocked)
- if(slur) apply_effect(slur, SLUR, blocked)
- if(stutter) apply_effect(stutter, STUTTER, blocked)
- if(eyeblur) apply_effect(eyeblur, EYE_BLUR, blocked)
- if(drowsy) apply_effect(drowsy, DROWSY, blocked)
- if(stamina) apply_damage(stamina, STAMINA, null, blocked)
- if(jitter) apply_effect(jitter, JITTER, blocked)
- return 1
+/mob/living/proc/apply_effects(stun = 0, weaken = 0, paralyze = 0, irradiate = 0, slur = 0, stutter = 0, eyeblur = 0, drowsy = 0, blocked = 0, stamina = 0, jitter = 0)
+ if(blocked >= 100)
+ return FALSE
+ if(stun)
+ apply_effect(stun, STUN, blocked)
+ if(weaken)
+ apply_effect(weaken, WEAKEN, blocked)
+ if(paralyze)
+ apply_effect(paralyze, PARALYZE, blocked)
+ if(irradiate)
+ apply_effect(irradiate, IRRADIATE, blocked)
+ if(slur)
+ apply_effect(slur, SLUR, blocked)
+ if(stutter)
+ apply_effect(stutter, STUTTER, blocked)
+ if(eyeblur)
+ apply_effect(eyeblur, EYE_BLUR, blocked)
+ if(drowsy)
+ apply_effect(drowsy, DROWSY, blocked)
+ if(stamina)
+ apply_damage(stamina, STAMINA, null, blocked)
+ if(jitter)
+ apply_effect(jitter, JITTER, blocked)
+ return TRUE
/mob/living/proc/getBruteLoss()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index bb76b436ad0..05b29d20545 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1033,6 +1033,21 @@
return 1
return 0
+/mob/living/rad_act(amount)
+ . = ..()
+
+ if(!amount || (amount < RAD_MOB_SKIN_PROTECTION))
+ return
+
+ amount -= RAD_BACKGROUND_RADIATION // This will always be at least 1 because of how skin protection is calculated
+
+ var/blocked = getarmor(null, "rad")
+
+ if(amount > RAD_BURN_THRESHOLD)
+ apply_damage(RAD_BURN_CURVE(amount), BURN, null, blocked)
+
+ apply_effect((amount * RAD_MOB_COEFFICIENT) / max(1, (radiation ** 2) * RAD_OVERDOSE_REDUCTION), IRRADIATE, blocked)
+
/mob/living/proc/fakefireextinguish()
return
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 006573b018f..7dcdd3387fc 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -241,6 +241,7 @@
modules += new /obj/item/multitool/cyborg(src)
modules += new /obj/item/t_scanner(src)
modules += new /obj/item/analyzer(src)
+ modules += new /obj/item/geiger_counter/cyborg(src)
modules += new /obj/item/holosign_creator/engineering(src)
modules += new /obj/item/gripper(src)
modules += new /obj/item/matter_decompiler(src)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 70fc688607a..cfecbdae193 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -5,6 +5,7 @@
bubble_icon = "machine"
has_unlimited_silicon_privilege = 1
weather_immunities = list("ash")
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
var/syndicate = 0
var/const/MAIN_CHANNEL = "Main Frequency"
var/lawchannel = MAIN_CHANNEL // Default channel on which to state laws
@@ -222,27 +223,9 @@
return 2
-/mob/living/silicon/apply_effect(var/effect = 0,var/effecttype = STUN, var/blocked = 0, var/negate_armor = 0)
- return 0//The only effect that can hit them atm is flashes and they still directly edit so this works for now
-/*
- if(!effect || (blocked >= 2)) return 0
- switch(effecttype)
- if(STUN)
- Stun(effect / (blocked + 1))
- if(WEAKEN)
- Weaken(effect / (blocked + 1))
- if(PARALYZE)
- Paralyse(effect / (blocked + 1))
- if(IRRADIATE)
- radiation += min((effect - (effect*getarmor(null, "rad"))), 0)//Rads auto check armor
- if(STUTTER)
- stuttering = max(stuttering,(effect/(blocked+1)))
- if(EYE_BLUR)
- eye_blurry = max(eye_blurry,(effect/(blocked+1)))
- if(DROWSY)
- drowsyness = max(drowsyness,(effect/(blocked+1)))
- updatehealth()
- return 1*/
+/mob/living/silicon/apply_effect(effect = 0, effecttype = STUN, blocked = 0)
+ return FALSE //The only effect that can hit them atm is flashes and they still directly edit so this works for now
+
/proc/islinked(var/mob/living/silicon/robot/bot, var/mob/living/silicon/ai/ai)
if(!istype(bot) || !istype(ai))
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 7d700ce309d..fcf94d746eb 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1426,22 +1426,22 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
/mob/proc/set_nutrition(change)
nutrition = max(0, change)
-/mob/clean_blood(clean_hands = TRUE, clean_mask = TRUE, clean_feet = TRUE)
+/mob/clean_blood(radiation_clean = FALSE, clean_hands = TRUE, clean_mask = TRUE, clean_feet = TRUE)
. = ..()
if(bloody_hands && clean_hands)
bloody_hands = 0
update_inv_gloves()
if(l_hand)
- if(l_hand.clean_blood())
+ if(l_hand.clean_blood(radiation_clean))
update_inv_l_hand()
if(r_hand)
- if(r_hand.clean_blood())
+ if(r_hand.clean_blood(radiation_clean))
update_inv_r_hand()
if(back)
- if(back.clean_blood())
+ if(back.clean_blood(radiation_clean))
update_inv_back()
if(wear_mask && clean_mask)
- if(wear_mask.clean_blood())
+ if(wear_mask.clean_blood(radiation_clean))
update_inv_wear_mask()
if(clean_feet)
feet_blood_color = null
diff --git a/code/modules/pda/cart.dm b/code/modules/pda/cart.dm
index d4845926786..bd6994d21c3 100644
--- a/code/modules/pda/cart.dm
+++ b/code/modules/pda/cart.dm
@@ -299,7 +299,6 @@
desc = "The hit new PDA game that lets you track down and capture your favorite Nano-Mobs living in your world!"
icon_state = "cart-eye"
programs = list(new/datum/data/pda/app/mob_hunter_game)
- var/emagged = 0
/obj/item/cartridge/mob_hunt_game/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/nanomob_card))
diff --git a/code/modules/pda/utilities.dm b/code/modules/pda/utilities.dm
index 81a2271db04..3f3f8303469 100644
--- a/code/modules/pda/utilities.dm
+++ b/code/modules/pda/utilities.dm
@@ -125,8 +125,8 @@
pda.atmosanalyzer_scan(T.parent.air, user, T)
else if(istype(A, /obj/machinery/power/rad_collector))
var/obj/machinery/power/rad_collector/T = A
- if(T.P)
- pda.atmosanalyzer_scan(T.P.air_contents, user, T)
+ if(T.loaded_tank)
+ pda.atmosanalyzer_scan(T.loaded_tank.air_contents, user, T)
else if(istype(A, /obj/item/flamethrower))
var/obj/item/flamethrower/T = A
if(T.ptank)
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 40969d7e677..3c8db1f50df 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -97,7 +97,7 @@ By design, d1 is the smallest direction and d2 is the highest
/obj/structure/cable/hide(i)
if(level == 1 && isturf(loc))
- invisibility = i ? 101 : 0
+ invisibility = i ? INVISIBILITY_MAXIMUM : 0
updateicon()
/obj/structure/cable/proc/updateicon()
diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm
index cf04c8a66f8..9332085c48c 100644
--- a/code/modules/power/gravitygenerator.dm
+++ b/code/modules/power/gravitygenerator.dm
@@ -367,8 +367,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne
/obj/machinery/gravity_generator/main/proc/pulse_radiation()
- for(var/mob/living/L in view(7, src))
- L.apply_effect(20, IRRADIATE)
+ radiation_pulse(src, 200)
// Shake everyone on the z level to let them know that gravity was enagaged/disenagaged.
/obj/machinery/gravity_generator/main/proc/shake_everyone()
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index 08af8a3df17..067589f959d 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -401,19 +401,13 @@
/obj/machinery/power/port_gen/pacman/super/UseFuel()
//produces a tiny amount of radiation when in use
- if(prob(2*power_output))
- for(var/mob/living/L in range(src, 5))
- L.apply_effect(1, IRRADIATE) //should amount to ~5 rads per minute at max safe power
+ if(prob(2 * power_output))
+ radiation_pulse(get_turf(src), 50)
..()
/obj/machinery/power/port_gen/pacman/super/explode()
//a nice burst of radiation
- var/rads = 50 + (sheets + sheet_left)*1.5
- for(var/mob/living/L in range(src, 10))
- //should really fall with the square of the distance, but that makes the rads value drop too fast
- //I dunno, maybe physics works different when you live in 2D -- SM radiation also works like this, apparently
- L.apply_effect(max(20, round(rads/get_dist(L,src))), IRRADIATE)
-
+ radiation_pulse(get_turf(src), 500, 2)
explosion(src.loc, 3, 3, 5, 3)
qdel(src)
diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm
index e6a933c4458..14059c63ea7 100644
--- a/code/modules/power/singularity/collector.dm
+++ b/code/modules/power/singularity/collector.dm
@@ -1,21 +1,28 @@
+// stored_energy += (pulse_strength - RAD_COLLECTOR_EFFICIENCY) * RAD_COLLECTOR_COEFFICIENT
+#define RAD_COLLECTOR_EFFICIENCY 80 // radiation needs to be over this amount to get power
+#define RAD_COLLECTOR_COEFFICIENT 100
+#define RAD_COLLECTOR_STORED_OUT 0.04 // (this * 100)% of stored power outputted per tick. Doesn't actualy change output total, lower numbers just means collectors output for longer in absence of a source
+#define RAD_COLLECTOR_OUTPUT min(stored_energy, (stored_energy * RAD_COLLECTOR_STORED_OUT) + 1000) //Produces at least 1000 watts if it has more than that stored
+
GLOBAL_LIST_EMPTY(rad_collectors)
/obj/machinery/power/rad_collector
- name = "Radiation Collector Array"
+ name = "\improper radiation collector array"
desc = "A device which uses Hawking Radiation and plasma to produce power."
icon = 'icons/obj/singularity.dmi'
icon_state = "ca"
- anchored = 0
- density = 1
+ anchored = FALSE
+ density = TRUE
req_access = list(ACCESS_ENGINE_EQUIP)
-// use_power = NO_POWER_USE
max_integrity = 350
integrity_failure = 80
- var/obj/item/tank/plasma/P = null
- var/last_power = 0
- var/active = 0
- var/locked = 0
+ rad_insulation = RAD_EXTREME_INSULATION
+ var/obj/item/tank/plasma/loaded_tank = null
+ var/stored_energy = 0
+ var/active = FALSE
+ var/locked = FALSE
var/drainratio = 1
+ var/powerproduction_drain = 0.001
/obj/machinery/power/rad_collector/Initialize(mapload)
. = ..()
@@ -26,114 +33,118 @@ GLOBAL_LIST_EMPTY(rad_collectors)
return ..()
/obj/machinery/power/rad_collector/process()
- if(P)
- if(P.air_contents.toxins <= 0)
- investigate_log("out of fuel.","singulo")
- P.air_contents.toxins = 0
- eject()
- else
- P.air_contents.toxins -= 0.001*drainratio
- return
+ if(!loaded_tank)
+ return
+ if(!loaded_tank.air_contents.toxins)
+ investigate_log("out of fuel.", "singulo")
+ playsound(src, 'sound/machines/ding.ogg', 50, TRUE)
+ eject()
+ else
+ var/gasdrained = min(powerproduction_drain * drainratio, loaded_tank.air_contents.toxins)
+ loaded_tank.air_contents.toxins -= gasdrained
+
+ var/power_produced = RAD_COLLECTOR_OUTPUT
+ add_avail(power_produced)
+ stored_energy -= power_produced
-/obj/machinery/power/rad_collector/attack_hand(mob/user as mob)
+/obj/machinery/power/rad_collector/attack_hand(mob/user)
if(anchored)
- if(!src.locked)
+ if(!locked)
toggle_power()
- user.visible_message("[user.name] turns the [src.name] [active? "on":"off"].", \
- "You turn the [src.name] [active? "on":"off"].")
- investigate_log("turned [active?"on":"off"] by [user.key]. [P?"Fuel: [round(P.air_contents.toxins/0.29)]%":"It is empty"].","singulo")
- return
+ user.visible_message("[user.name] turns the [name] [active ? "on" : "off"].", "You turn the [name] [active ? "on" : "off"].")
+ investigate_log("turned [active ? "on" : "off"] by [user.key]. [loaded_tank ? "Fuel: [round(loaded_tank.air_contents.toxins / 0.29)]%" : "It is empty"].", "singulo")
else
to_chat(user, "The controls are locked!")
- return
-/obj/machinery/power/rad_collector/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/multitool))
- to_chat(user, "The [W.name] detects that [last_power]W were recently produced.")
- return 1
- else if(istype(W, /obj/item/analyzer) && P)
- atmosanalyzer_scan(P.air_contents, user)
- else if(istype(W, /obj/item/tank/plasma))
- if(!src.anchored)
- to_chat(user, "The [src] needs to be secured to the floor first.")
- return 1
- if(src.P)
+/obj/machinery/power/rad_collector/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/analyzer) && loaded_tank)
+ atmosanalyzer_scan(loaded_tank.air_contents, user)
+ else if(istype(I, /obj/item/tank/plasma))
+ if(!anchored)
+ to_chat(user, "[src] needs to be secured to the floor first.")
+ return TRUE
+ if(loaded_tank)
to_chat(user, "There's already a plasma tank loaded.")
- return 1
- user.drop_item()
- src.P = W
- W.loc = src
- update_icons()
- else if(istype(W, /obj/item/crowbar))
- if(P && !src.locked)
+ return TRUE
+ if(user.drop_item())
+ loaded_tank = I
+ I.forceMove(src)
+ update_icons()
+ else if(iscrowbar(I))
+ if(loaded_tank && !locked)
eject()
- return 1
- else if(istype(W, /obj/item/wrench))
- if(P)
+ return TRUE
+ else if(iswrench(I))
+ if(loaded_tank)
to_chat(user, "Remove the plasma tank first.")
- return 1
- playsound(src.loc, W.usesound, 75, 1)
- src.anchored = !src.anchored
- user.visible_message("[user.name] [anchored? "secures":"unsecures"] the [src.name].", \
- "You [anchored? "secure":"undo"] the external bolts.", \
- "You hear a ratchet")
+ return TRUE
+ playsound(loc, I.usesound, 75, TRUE)
+ anchored = !anchored
+ user.visible_message("[user.name] [anchored ? "secures" : "unsecures"] the [name].", "You [anchored ? "secure" : "undo"] the external bolts.", "You hear a ratchet")
if(anchored)
connect_to_network()
else
disconnect_from_network()
- else if(istype(W, /obj/item/card/id)||istype(W, /obj/item/pda))
- if(src.allowed(user))
+ else if(istype(I, /obj/item/card/id) || istype(I, /obj/item/pda))
+ if(allowed(user))
if(active)
- src.locked = !src.locked
- to_chat(user, "The controls are now [src.locked ? "locked." : "unlocked."]")
+ locked = !locked
+ to_chat(user, "The controls are now [locked ? "locked." : "unlocked."]")
else
- src.locked = 0 //just in case it somehow gets locked
- to_chat(user, "The controls can only be locked when the [src] is active")
+ locked = FALSE //just in case it somehow gets locked
+ to_chat(user, "The controls can only be locked when [src] is active")
else
to_chat(user, "Access denied!")
- return 1
+ return TRUE
else
return ..()
+/obj/machinery/power/rad_collector/examine(mob/user)
+ . = ..()
+ if(active)
+ // stored_energy is converted directly to watts every SSmachines.wait * 0.1 seconds.
+ // Therefore, its units are joules per SSmachines.wait * 0.1 seconds.
+ // So joules = stored_energy * SSmachines.wait * 0.1
+ var/joules = stored_energy * SSmachines.wait * 0.1
+ . += "[src]'s display states that it has stored [DisplayJoules(joules)], and is processing [DisplayPower(RAD_COLLECTOR_OUTPUT)]."
+ else
+ . += "[src]'s display displays the words: \"Power production mode. Please insert Plasma.\""
+
/obj/machinery/power/rad_collector/obj_break(damage_flag)
if(!(stat & BROKEN) && !(flags & NODECONSTRUCT))
eject()
stat |= BROKEN
/obj/machinery/power/rad_collector/proc/eject()
- locked = 0
- var/obj/item/tank/plasma/Z = src.P
+ locked = FALSE
+ var/obj/item/tank/plasma/Z = loaded_tank
if(!Z)
return
- Z.loc = get_turf(src)
+ Z.forceMove(drop_location())
Z.layer = initial(Z.layer)
Z.plane = initial(Z.plane)
- src.P = null
+ loaded_tank = null
if(active)
toggle_power()
else
update_icons()
-/obj/machinery/power/rad_collector/proc/receive_pulse(var/pulse_strength)
- if(P && active)
- var/power_produced = 0
- power_produced = P.air_contents.toxins*pulse_strength*20
- add_avail(power_produced)
- last_power = power_produced
- return
- return
+/obj/machinery/power/rad_collector/rad_act(amount)
+ . = ..()
+ if(loaded_tank && active && amount > RAD_COLLECTOR_EFFICIENCY)
+ stored_energy += (amount - RAD_COLLECTOR_EFFICIENCY) * RAD_COLLECTOR_COEFFICIENT
/obj/machinery/power/rad_collector/proc/update_icons()
- overlays.Cut()
- if(P)
- overlays += image('icons/obj/singularity.dmi', "ptank")
+ cut_overlays()
+ if(loaded_tank)
+ add_overlay("ptank")
if(stat & (NOPOWER|BROKEN))
return
if(active)
- overlays += image('icons/obj/singularity.dmi', "on")
+ add_overlay("on")
/obj/machinery/power/rad_collector/proc/toggle_power()
@@ -145,4 +156,8 @@ GLOBAL_LIST_EMPTY(rad_collectors)
icon_state = "ca"
flick("ca_deactive", src)
update_icons()
- return
+
+#undef RAD_COLLECTOR_EFFICIENCY
+#undef RAD_COLLECTOR_COEFFICIENT
+#undef RAD_COLLECTOR_STORED_OUT
+#undef RAD_COLLECTOR_OUTPUT
diff --git a/code/modules/power/singularity/particle_accelerator/particle.dm b/code/modules/power/singularity/particle_accelerator/particle.dm
index 93eb3fa18c6..621bc34964a 100644
--- a/code/modules/power/singularity/particle_accelerator/particle.dm
+++ b/code/modules/power/singularity/particle_accelerator/particle.dm
@@ -31,7 +31,7 @@
/obj/effect/accelerated_particle/proc/try_irradiate(src, atom/A)
if(isliving(A))
var/mob/living/L = A
- L.apply_effect((energy * 6), IRRADIATE, 0)
+ L.rad_act(energy * 6)
else if(istype(A, /obj/machinery/the_singularitygen))
var/obj/machinery/the_singularitygen/S = A
S.energy += energy
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index 002fcefab93..b1d69257484 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -116,7 +116,7 @@
// it might mean we are stuck in a corner somewere. So move around to try to expand.
move()
if(current_size >= STAGE_TWO)
- pulse()
+ radiation_pulse(src, min(5000, (energy * 4.5) + 1000), RAD_DISTANCE_COEFFICIENT * 0.5)
if(prob(event_chance))//Chance for it to run a special event TODO:Come up with one or two more that fit
event()
eat()
@@ -377,15 +377,13 @@
/obj/singularity/proc/event()
- var/numb = pick(1,2,3,4,5,6)
+ var/numb = rand(1, 4)
switch(numb)
- if(1)//EMP
+ if(1) //EMP
emp_area()
- if(2,3)//tox damage all carbon mobs in area
- toxmob()
- if(4)//Stun mobs who lack optic scanners
+ if(2) //Stun mobs who lack optic scanners
mezzer()
- if(5,6) //Sets all nearby mobs on fire
+ if(3, 4) //Sets all nearby mobs on fire
if(current_size < STAGE_SIX)
return 0
combust_mobs()
@@ -394,17 +392,6 @@
return 1
-/obj/singularity/proc/toxmob()
- var/toxrange = 10
- var/radiation = 15
- var/radiationmin = 3
- if(energy>200)
- radiation += round((energy-150)/10,1)
- radiationmin = round((radiation/5),1)
- for(var/mob/living/M in view(toxrange, src.loc))
- M.apply_effect(rand(radiationmin,radiation), IRRADIATE)
-
-
/obj/singularity/proc/combust_mobs()
for(var/mob/living/carbon/C in urange(20, src, 1))
C.visible_message("[C]'s skin bursts into flame!", \
@@ -438,12 +425,6 @@
empulse(src, 8, 10)
return
-
-/obj/singularity/proc/pulse()
- for(var/obj/machinery/power/rad_collector/R in GLOB.rad_collectors)
- if(R.z == z && get_dist(R, src) <= 15) // Better than using orange() every process
- R.receive_pulse(energy)
-
/obj/singularity/singularity_act()
var/gain = (energy/2)
var/dist = max((current_size - 2),1)
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index a6f29506da3..38feb897ab4 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -76,6 +76,7 @@
icon_state = "darkmatter"
density = TRUE
anchored = TRUE
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
light_range = 4
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
var/base_icon_state = "darkmatter"
@@ -291,7 +292,7 @@
var/mob/living/carbon/human/H = mob
H.hallucination += max(50, min(300, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(mob, src) + 1))))
var/rads = DETONATION_RADS * sqrt(1 / (get_dist(L, src) + 1))
- L.apply_effect(rads, IRRADIATE)
+ L.rad_act(rads)
var/turf/T = get_turf(src)
for(var/mob/M in GLOB.player_list)
@@ -463,9 +464,8 @@
power = max((removed.temperature * temp_factor / T0C) * gasmix_power_ratio + power, 0)
if(prob(50))
- for(var/obj/machinery/power/rad_collector/R in GLOB.rad_collectors)
- if(atoms_share_level(R, src) && get_dist(R, src) <= 15) //Better than using orange() every process
- R.receive_pulse(power * (1 + power_transmission_bonus / 10))
+
+ radiation_pulse(src, power * max(0, (1 + (power_transmission_bonus / 10))))
//Power * 0.55 * a value between 1 and 0.8
var/device_energy = power * REACTION_POWER_MODIFIER
@@ -500,7 +500,7 @@
l.hallucination = clamp(l.hallucination, 0, 200)
for(var/mob/living/l in range(src, round((power / 100) ** 0.25)))
var/rads = (power / 10) * sqrt( 1 / max(get_dist(l, src), 1) )
- l.apply_effect(rads, IRRADIATE)
+ l.rad_act(rads)
//Transitions between one function and another, one we use for the fast inital startup, the other is used to prevent errors with fusion temperatures.
//Use of the second function improves the power gain imparted by using co2
@@ -676,7 +676,7 @@
Consume(I)
playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, TRUE)
- user.apply_effect(150, IRRADIATE)
+ radiation_pulse(src, 150, 4)
/obj/machinery/power/supermatter_crystal/Bumped(atom/movable/AM)
if(isliving(AM))
@@ -716,9 +716,8 @@
matter_power += 200
//Some poor sod got eaten, go ahead and irradiate people nearby.
+ radiation_pulse(src, 3000, 2, TRUE)
for(var/mob/living/L in range(10))
- var/rads = 500 * sqrt( 1 / (get_dist(L, src) + 1))
- L.apply_effect(rads, IRRADIATE)
investigate_log("has irradiated [key_name(L)] after consuming [AM].", "supermatter")
if(L in view())
L.show_message("As [src] slowly stops resonating, you find your skin covered in new radiation burns.", 1,
diff --git a/code/modules/power/terminal.dm b/code/modules/power/terminal.dm
index e66128ba724..584079b3c45 100644
--- a/code/modules/power/terminal.dm
+++ b/code/modules/power/terminal.dm
@@ -27,7 +27,7 @@
/obj/machinery/power/terminal/hide(i)
if(i)
- invisibility = 101
+ invisibility = INVISIBILITY_MAXIMUM
icon_state = "term-f"
else
invisibility = 0
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 5742e2d34bb..5bd4c4eb283 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -336,8 +336,6 @@
var/powercost = ""
var/powercostcolor = ""
-
- var/emagged = 0 //ups the temperature cap from 500 to 1000, targets hit by beams over 500 Kelvin will burst into flames
var/dat = ""
/obj/item/gun/energy/temperature/Initialize(mapload, ...)
diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm
index b78339e8ef7..71258e4fc0b 100644
--- a/code/modules/projectiles/projectile/special.dm
+++ b/code/modules/projectiles/projectile/special.dm
@@ -140,18 +140,18 @@
var/mob/living/carbon/human/H = M
if(IS_PLANT in H.dna.species.species_traits)
if(prob(15))
- M.apply_effect((rand(30,80)),IRRADIATE)
- M.Weaken(5)
- M.visible_message("[M] writhes in pain as [M.p_their()] vacuoles boil.", "You writhe in pain as your vacuoles boil!", "You hear the crunching of leaves.")
+ H.rad_act(rand(30, 80))
+ H.Weaken(5)
+ H.visible_message("[H] writhes in pain as [M.p_their()] vacuoles boil.", "You writhe in pain as your vacuoles boil!", "You hear the crunching of leaves.")
if(prob(80))
- randmutb(M)
- domutcheck(M,null)
+ randmutb(H)
+ domutcheck(H, null)
else
- randmutg(M)
- domutcheck(M,null)
+ randmutg(H)
+ domutcheck(H, null)
else
- M.adjustFireLoss(rand(5,15))
- M.show_message("The radiation beam singes you!")
+ H.adjustFireLoss(rand(5, 15))
+ H.show_message("The radiation beam singes you!")
else if(iscarbon(target))
M.show_message("The radiation beam dissipates harmlessly through your body.")
else
diff --git a/code/modules/reagents/chemistry/reagents/drugs.dm b/code/modules/reagents/chemistry/reagents/drugs.dm
index ea110581083..893d6c30837 100644
--- a/code/modules/reagents/chemistry/reagents/drugs.dm
+++ b/code/modules/reagents/chemistry/reagents/drugs.dm
@@ -409,7 +409,7 @@
to_chat(M, "You feel FUCKED UP!!!!!!")
M << 'sound/effects/singlebeat.ogg'
M.emote("faint")
- M.apply_effect(5, IRRADIATE, negate_armor = 1)
+ M.apply_effect(5, IRRADIATE)
M.adjustToxLoss(5)
M.adjustBrainLoss(10)
else
diff --git a/code/modules/reagents/chemistry/reagents/toxins.dm b/code/modules/reagents/chemistry/reagents/toxins.dm
index 33092629a49..49a462b4d86 100644
--- a/code/modules/reagents/chemistry/reagents/toxins.dm
+++ b/code/modules/reagents/chemistry/reagents/toxins.dm
@@ -160,7 +160,7 @@
/datum/reagent/radium/on_mob_life(mob/living/M)
if(M.radiation < 80)
- M.apply_effect(4, IRRADIATE, negate_armor = 1)
+ M.apply_effect(4, IRRADIATE)
return ..()
/datum/reagent/radium/reaction_turf(turf/T, volume)
@@ -190,7 +190,7 @@
/datum/reagent/mutagen/on_mob_life(mob/living/M)
if(!M.dna)
return //No robots, AIs, aliens, Ians or other mobs should be affected by this.
- M.apply_effect(2*REAGENTS_EFFECT_MULTIPLIER, IRRADIATE, negate_armor = 1)
+ M.apply_effect(2 * REAGENTS_EFFECT_MULTIPLIER, IRRADIATE)
if(prob(4))
randmutb(M)
return ..()
@@ -215,7 +215,7 @@
/datum/reagent/stable_mutagen/on_mob_life(mob/living/M)
if(!ishuman(M) || !M.dna)
return
- M.apply_effect(2*REAGENTS_EFFECT_MULTIPLIER, IRRADIATE, negate_armor = 1)
+ M.apply_effect(2 * REAGENTS_EFFECT_MULTIPLIER, IRRADIATE)
if(current_cycle == 10 && islist(data))
if(istype(data["dna"], /datum/dna))
var/mob/living/carbon/human/H = M
@@ -241,7 +241,7 @@
taste_description = "the inside of a reactor"
/datum/reagent/uranium/on_mob_life(mob/living/M)
- M.apply_effect(2, IRRADIATE, negate_armor = 1)
+ M.apply_effect(2, IRRADIATE)
return ..()
/datum/reagent/uranium/reaction_turf(turf/T, volume)
@@ -472,7 +472,7 @@
taste_mult = 0
/datum/reagent/polonium/on_mob_life(mob/living/M)
- M.apply_effect(8, IRRADIATE, negate_armor = 1)
+ M.apply_effect(8, IRRADIATE)
return ..()
/datum/reagent/histamine
@@ -1182,7 +1182,7 @@
M.UpdateAppearance()
/datum/reagent/glowing_slurry/on_mob_life(mob/living/M)
- M.apply_effect(2, IRRADIATE, 0, negate_armor = 1)
+ M.apply_effect(2, IRRADIATE)
if(!M.dna)
return
var/did_mutation = FALSE
diff --git a/code/modules/reagents/reagent_containers/applicator.dm b/code/modules/reagents/reagent_containers/applicator.dm
index 42f001d3de7..d7c53f1f5a3 100644
--- a/code/modules/reagents/reagent_containers/applicator.dm
+++ b/code/modules/reagents/reagent_containers/applicator.dm
@@ -11,7 +11,6 @@
temperature_min = 270
temperature_max = 350
var/ignore_flags = FALSE
- var/emagged = FALSE
var/applied_amount = 8 // How much it applies
var/applying = FALSE // So it can't be spammed.
var/measured_health = 0 // Used for measuring health; we don't want this to stop applying once the person's health isn't changing.
diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm
index 965717a4d77..d9929bfa51d 100644
--- a/code/modules/reagents/reagent_containers/hypospray.dm
+++ b/code/modules/reagents/reagent_containers/hypospray.dm
@@ -15,7 +15,6 @@
container_type = OPENCONTAINER
slot_flags = SLOT_BELT
var/ignore_flags = FALSE
- var/emagged = FALSE
var/safety_hypo = FALSE
/obj/item/reagent_containers/hypospray/attack(mob/living/M, mob/user)
diff --git a/code/modules/recycling/disposal-construction.dm b/code/modules/recycling/disposal-construction.dm
index 44366341678..18820c4c703 100644
--- a/code/modules/recycling/disposal-construction.dm
+++ b/code/modules/recycling/disposal-construction.dm
@@ -69,7 +69,7 @@
// hide called by levelupdate if turf intact status changes
// change visibility status and force update of icon
/obj/structure/disposalconstruct/hide(var/intact)
- invisibility = (intact && level==1) ? 101: 0 // hide if floor is intact
+ invisibility = (intact && level == 1) ? INVISIBILITY_MAXIMUM : 0 // hide if floor is intact
update()
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index 3df56d94ef0..7ca4ba37de4 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -17,6 +17,7 @@
on_blueprints = TRUE
armor = list("melee" = 25, "bullet" = 10, "laser" = 10, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30)
max_integrity = 200
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
resistance_flags = FIRE_PROOF
var/datum/gas_mixture/air_contents // internal reservoir
var/mode = 1 // item mode 0=off 1=charging 2=charged
@@ -510,8 +511,9 @@
// this allows the gas flushed to be tracked
/obj/structure/disposalholder
- invisibility = 101
+ invisibility = INVISIBILITY_MAXIMUM
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
var/datum/gas_mixture/gas = null // gas used to flush, will appear at exit point
var/active = 0 // true if the holder is moving, otherwise inactive
dir = 0
@@ -688,6 +690,7 @@
max_integrity = 200
armor = list("melee" = 25, "bullet" = 10, "laser" = 10, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30)
damage_deflection = 10
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
layer = DISPOSAL_PIPE_LAYER // slightly lower than wires and other pipes
var/base_icon_state // initial icon state on map
@@ -760,7 +763,7 @@
// hide called by levelupdate if turf intact status changes
// change visibility status and force update of icon
/obj/structure/disposalpipe/hide(var/intact)
- invisibility = intact ? 101: 0 // hide if floor is intact
+ invisibility = intact ? INVISIBILITY_MAXIMUM: 0 // hide if floor is intact
update_icon()
// update actual icon_state depending on visibility
@@ -1263,6 +1266,7 @@
icon_state = "outlet"
density = 1
anchored = 1
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2
var/active = 0
var/turf/target // this will be where the output objects are 'thrown' to.
var/obj/structure/disposalpipe/trunk/linkedtrunk
diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm
index 6d274a47ed3..fd0a434e087 100644
--- a/code/modules/research/designs/autolathe_designs.dm
+++ b/code/modules/research/designs/autolathe_designs.dm
@@ -840,6 +840,14 @@
build_path = /obj/item/toy/crayon/spraycan
category = list("initial", "Tools")
+/datum/design/geiger
+ name = "Geiger Counter"
+ id = "geigercounter"
+ build_type = AUTOLATHE
+ materials = list(MAT_METAL = 150, MAT_GLASS = 150)
+ build_path = /obj/item/geiger_counter
+ category = list("initial", "Tools")
+
/datum/design/desttagger
name = "Destination tagger"
id = "desttagger"
diff --git a/code/modules/research/designs/equipment_designs.dm b/code/modules/research/designs/equipment_designs.dm
index af6fc828ad3..a2527ca6d64 100644
--- a/code/modules/research/designs/equipment_designs.dm
+++ b/code/modules/research/designs/equipment_designs.dm
@@ -91,6 +91,27 @@
build_path = /obj/item/clothing/glasses/meson
category = list("Equipment")
+
+/datum/design/engine_goggles
+ name = "Engineering Scanner Goggles"
+ desc = "Goggles used by engineers. The Meson Scanner mode lets you see basic structural and terrain layouts through walls, regardless of lighting condition. The T-ray Scanner mode lets you see underfloor objects such as cables and pipes."
+ id = "engine_goggles"
+ req_tech = list("materials" = 4, "magnets" = 3, "engineering" = 4, "plasmatech" = 3)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_PLASMA = 100)
+ build_path = /obj/item/clothing/glasses/meson/engine
+ category = list("Equipment")
+
+/datum/design/tray_goggles
+ name = "Optical T-Ray Scanners"
+ desc = "Used by engineering staff to see underfloor objects such as cables and pipes."
+ id = "tray_goggles"
+ req_tech = list("materials" = 3, "magnets" = 2, "engineering" = 2)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500)
+ build_path = /obj/item/clothing/glasses/meson/engine/tray
+ category = list("Equipment")
+
/datum/design/nvgmesons
name = "Night Vision Optical Meson Scanners"
desc = "Prototype meson scanners fitted with an extra sensor which amplifies the visible light spectrum and overlays it to the UHD display."
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index 43cc010ac1c..76e9f4b4119 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -282,9 +282,7 @@
ejectItem()
if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
visible_message("[src] malfunctions, melting [exp_on] and leaking radiation!")
- for(var/mob/living/m in oview(1, src))
- m.apply_effect(25,IRRADIATE)
- investigate_log("Experimentor has irradiated [m]", "experimentor") //One entry per person so we know what was irradiated.
+ radiation_pulse(src, 500)
ejectItem(TRUE)
if(prob(EFFECT_PROB_LOW-badThingCoeff))
visible_message("[src] malfunctions, spewing toxic waste!")
diff --git a/code/modules/response_team/ert_outfits.dm b/code/modules/response_team/ert_outfits.dm
index f7463b6d8be..4ee48dcbfd9 100644
--- a/code/modules/response_team/ert_outfits.dm
+++ b/code/modules/response_team/ert_outfits.dm
@@ -232,7 +232,7 @@
gloves = /obj/item/clothing/gloves/color/yellow
suit = /obj/item/clothing/suit/space/hardsuit/ert/engineer
suit_store = /obj/item/tank/emergency_oxygen/engi
- glasses = /obj/item/clothing/glasses/meson
+ glasses = /obj/item/clothing/glasses/meson/engine
mask = /obj/item/clothing/mask/gas
l_pocket = /obj/item/gun/energy/gun/mini
@@ -252,13 +252,13 @@
belt = /obj/item/storage/belt/utility/chief/full
suit = /obj/item/clothing/suit/space/hardsuit/ert/engineer/gamma
suit_store = /obj/item/tank/emergency_oxygen/engi
- glasses = /obj/item/clothing/glasses/meson
+ glasses = /obj/item/clothing/glasses/meson/engine
mask = /obj/item/clothing/mask/gas
cybernetic_implants = list(
/obj/item/organ/internal/cyberimp/eyes/shield,
/obj/item/organ/internal/cyberimp/chest/nutriment
)
- l_pocket = /obj/item/t_scanner/extended_range
+ l_pocket = /obj/item/t_scanner
r_pocket = /obj/item/melee/classic_baton/telescopic
backpack_contents = list(
@@ -281,7 +281,7 @@
glasses = /obj/item/clothing/glasses/meson/night
mask = /obj/item/clothing/mask/gas/sechailer/swat
- l_pocket = /obj/item/t_scanner/extended_range
+ l_pocket = /obj/item/t_scanner
r_pocket = /obj/item/melee/classic_baton/telescopic
backpack_contents = list(
diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm
index 8308a793ca9..e6afe6054cf 100644
--- a/code/modules/surgery/organs/heart.dm
+++ b/code/modules/surgery/organs/heart.dm
@@ -153,7 +153,6 @@
icon_state = "heart-c-u-on"
icon_base = "heart-c-u"
dead_icon = "heart-c-u-off"
- var/emagged = FALSE
var/attempted_restart = FALSE
/obj/item/organ/internal/heart/cybernetic/upgraded/on_life()
diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm
index 10c47f1eae6..21ac34a16c6 100644
--- a/code/modules/surgery/organs/organ_external.dm
+++ b/code/modules/surgery/organs/organ_external.dm
@@ -7,7 +7,7 @@
max_damage = 0
dir = SOUTH
organ_tag = "limb"
-
+ flags_2 = RAD_PROTECT_CONTENTS_2 | RAD_NO_CONTAMINATE_2 // On Para, external organs have a loc, ergo they need this.
var/brute_mod = 1
var/burn_mod = 1
diff --git a/code/modules/telesci/rcs.dm b/code/modules/telesci/rcs.dm
index 13d0383b145..28475ce55d8 100644
--- a/code/modules/telesci/rcs.dm
+++ b/code/modules/telesci/rcs.dm
@@ -27,8 +27,6 @@
var/teleporting = FALSE
/// How much power does each teleport use?
var/chargecost = 1000
- /// Is emagged?
- var/emagged = FALSE
/obj/item/rcs/get_cell()
return rcell
diff --git a/icons/mob/eyes.dmi b/icons/mob/eyes.dmi
index 8620822ca5d..5ff3a9b0fb2 100644
Binary files a/icons/mob/eyes.dmi and b/icons/mob/eyes.dmi differ
diff --git a/icons/mob/inhands/clothing_lefthand.dmi b/icons/mob/inhands/clothing_lefthand.dmi
index b1f406da718..c01be54b995 100644
Binary files a/icons/mob/inhands/clothing_lefthand.dmi and b/icons/mob/inhands/clothing_lefthand.dmi differ
diff --git a/icons/mob/inhands/clothing_righthand.dmi b/icons/mob/inhands/clothing_righthand.dmi
index 8e9bdfc6200..5b0e3fc17fd 100644
Binary files a/icons/mob/inhands/clothing_righthand.dmi and b/icons/mob/inhands/clothing_righthand.dmi differ
diff --git a/icons/obj/clothing/glasses.dmi b/icons/obj/clothing/glasses.dmi
index c17502604fe..03bcddbd266 100644
Binary files a/icons/obj/clothing/glasses.dmi and b/icons/obj/clothing/glasses.dmi differ
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index 912f1d12a84..ebf6021fd21 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/icons/obj/doors/shutters_radiation.dmi b/icons/obj/doors/shutters_radiation.dmi
new file mode 100644
index 00000000000..657b613b0cc
Binary files /dev/null and b/icons/obj/doors/shutters_radiation.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 1a7844d3ab6..973c1ae44af 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -67,6 +67,7 @@
#include "code\__DEFINES\pipes.dm"
#include "code\__DEFINES\preferences.dm"
#include "code\__DEFINES\qdel.dm"
+#include "code\__DEFINES\radiation.dm"
#include "code\__DEFINES\radio.dm"
#include "code\__DEFINES\reagents.dm"
#include "code\__DEFINES\role_preferences.dm"
@@ -97,6 +98,7 @@
#include "code\__HELPERS\debugger.dm"
#include "code\__HELPERS\experimental.dm"
#include "code\__HELPERS\files.dm"
+#include "code\__HELPERS\filters.dm"
#include "code\__HELPERS\game.dm"
#include "code\__HELPERS\global_lists.dm"
#include "code\__HELPERS\heap.dm"
@@ -108,6 +110,7 @@
#include "code\__HELPERS\names.dm"
#include "code\__HELPERS\pronouns.dm"
#include "code\__HELPERS\qdel.dm"
+#include "code\__HELPERS\radiation.dm"
#include "code\__HELPERS\sanitize_values.dm"
#include "code\__HELPERS\text.dm"
#include "code\__HELPERS\time.dm"
@@ -250,6 +253,7 @@
#include "code\controllers\subsystem\overlays.dm"
#include "code\controllers\subsystem\parallax.dm"
#include "code\controllers\subsystem\persistent_data.dm"
+#include "code\controllers\subsystem\radiation.dm"
#include "code\controllers\subsystem\radio.dm"
#include "code\controllers\subsystem\runechat.dm"
#include "code\controllers\subsystem\shuttles.dm"
@@ -298,6 +302,7 @@
#include "code\datums\periodic_news.dm"
#include "code\datums\pipe_datums.dm"
#include "code\datums\progressbar.dm"
+#include "code\datums\radiation_wave.dm"
#include "code\datums\radio.dm"
#include "code\datums\recipe.dm"
#include "code\datums\revision.dm"
@@ -325,6 +330,7 @@
#include "code\datums\components\material_container.dm"
#include "code\datums\components\paintable.dm"
#include "code\datums\components\proximity_monitor.dm"
+#include "code\datums\components\radioactive.dm"
#include "code\datums\components\slippery.dm"
#include "code\datums\components\spawner.dm"
#include "code\datums\components\spooky.dm"
@@ -387,6 +393,7 @@
#include "code\datums\diseases\advance\symptoms\weight.dm"
#include "code\datums\diseases\advance\symptoms\youth.dm"
#include "code\datums\elements\_element.dm"
+#include "code\datums\elements\rad_insulation.dm"
#include "code\datums\elements\waddling.dm"
#include "code\datums\helper_datums\construction_datum.dm"
#include "code\datums\helper_datums\icon_snapshot.dm"
@@ -394,6 +401,7 @@
#include "code\datums\helper_datums\map_template.dm"
#include "code\datums\helper_datums\teleport.dm"
#include "code\datums\helper_datums\topic_input.dm"
+#include "code\datums\looping_sounds\item_sounds.dm"
#include "code\datums\looping_sounds\looping_sound.dm"
#include "code\datums\looping_sounds\machinery_sounds.dm"
#include "code\datums\looping_sounds\thermal_drill.dm"
@@ -896,6 +904,7 @@
#include "code\game\objects\items\devices\flash.dm"
#include "code\game\objects\items\devices\flashlight.dm"
#include "code\game\objects\items\devices\floor_painter.dm"
+#include "code\game\objects\items\devices\geiger_counter.dm"
#include "code\game\objects\items\devices\handheld_defib.dm"
#include "code\game\objects\items\devices\laserpointer.dm"
#include "code\game\objects\items\devices\lightreplacer.dm"
@@ -1380,6 +1389,7 @@
#include "code\modules\clothing\chameleon.dm"
#include "code\modules\clothing\clothing.dm"
#include "code\modules\clothing\ears\ears.dm"
+#include "code\modules\clothing\glasses\engine_goggles.dm"
#include "code\modules\clothing\glasses\glasses.dm"
#include "code\modules\clothing\glasses\hud.dm"
#include "code\modules\clothing\gloves\boxing.dm"
diff --git a/sound/items/geiger/ext1.ogg b/sound/items/geiger/ext1.ogg
new file mode 100644
index 00000000000..ca1b44e4d85
Binary files /dev/null and b/sound/items/geiger/ext1.ogg differ
diff --git a/sound/items/geiger/ext2.ogg b/sound/items/geiger/ext2.ogg
new file mode 100644
index 00000000000..c0c316245ba
Binary files /dev/null and b/sound/items/geiger/ext2.ogg differ
diff --git a/sound/items/geiger/ext3.ogg b/sound/items/geiger/ext3.ogg
new file mode 100644
index 00000000000..fc367d94662
Binary files /dev/null and b/sound/items/geiger/ext3.ogg differ
diff --git a/sound/items/geiger/ext4.ogg b/sound/items/geiger/ext4.ogg
new file mode 100644
index 00000000000..d3b00ebaac6
Binary files /dev/null and b/sound/items/geiger/ext4.ogg differ
diff --git a/sound/items/geiger/high1.ogg b/sound/items/geiger/high1.ogg
new file mode 100644
index 00000000000..8725affdd4f
Binary files /dev/null and b/sound/items/geiger/high1.ogg differ
diff --git a/sound/items/geiger/high2.ogg b/sound/items/geiger/high2.ogg
new file mode 100644
index 00000000000..f1e3868898d
Binary files /dev/null and b/sound/items/geiger/high2.ogg differ
diff --git a/sound/items/geiger/high3.ogg b/sound/items/geiger/high3.ogg
new file mode 100644
index 00000000000..bdc5282a5c0
Binary files /dev/null and b/sound/items/geiger/high3.ogg differ
diff --git a/sound/items/geiger/high4.ogg b/sound/items/geiger/high4.ogg
new file mode 100644
index 00000000000..8e185d6f78d
Binary files /dev/null and b/sound/items/geiger/high4.ogg differ
diff --git a/sound/items/geiger/low1.ogg b/sound/items/geiger/low1.ogg
new file mode 100644
index 00000000000..9bdb8bd3275
Binary files /dev/null and b/sound/items/geiger/low1.ogg differ
diff --git a/sound/items/geiger/low2.ogg b/sound/items/geiger/low2.ogg
new file mode 100644
index 00000000000..ce4855f25fc
Binary files /dev/null and b/sound/items/geiger/low2.ogg differ
diff --git a/sound/items/geiger/low3.ogg b/sound/items/geiger/low3.ogg
new file mode 100644
index 00000000000..70aaea064f5
Binary files /dev/null and b/sound/items/geiger/low3.ogg differ
diff --git a/sound/items/geiger/low4.ogg b/sound/items/geiger/low4.ogg
new file mode 100644
index 00000000000..f36e3b7699d
Binary files /dev/null and b/sound/items/geiger/low4.ogg differ
diff --git a/sound/items/geiger/med1.ogg b/sound/items/geiger/med1.ogg
new file mode 100644
index 00000000000..c062c4d2a8f
Binary files /dev/null and b/sound/items/geiger/med1.ogg differ
diff --git a/sound/items/geiger/med2.ogg b/sound/items/geiger/med2.ogg
new file mode 100644
index 00000000000..210119a287f
Binary files /dev/null and b/sound/items/geiger/med2.ogg differ
diff --git a/sound/items/geiger/med3.ogg b/sound/items/geiger/med3.ogg
new file mode 100644
index 00000000000..ed6f0f4d7f5
Binary files /dev/null and b/sound/items/geiger/med3.ogg differ
diff --git a/sound/items/geiger/med4.ogg b/sound/items/geiger/med4.ogg
new file mode 100644
index 00000000000..70635a97a3a
Binary files /dev/null and b/sound/items/geiger/med4.ogg differ