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