diff --git a/code/controllers/Processes/radiation.dm b/code/controllers/Processes/radiation.dm
new file mode 100644
index 0000000000..8ebd3a71a8
--- /dev/null
+++ b/code/controllers/Processes/radiation.dm
@@ -0,0 +1,43 @@
+/datum/controller/process/radiation
+ var/repository/radiation/linked = null
+
+/datum/controller/process/radiation/setup()
+ name = "radiation controller"
+ schedule_interval = 20 // every 2 seconds
+ linked = radiation_repository
+
+/datum/controller/process/radiation/doWork()
+// set background = 1
+ for(var/turf/T in linked.irradiated_turfs)
+ if(!T)
+ linked.irradiated_turfs.Remove(T)
+ continue
+ linked.irradiated_turfs[T] -= config.radiation_decay_rate
+ if(linked.irradiated_turfs[T] <= config.radiation_lower_limit)
+ linked.irradiated_turfs.Remove(T)
+ SCHECK
+ for(var/mob/living/L in linked.irradiated_mobs)
+ if(!L)
+ linked.irradiated_mobs.Remove(L)
+ continue
+ if(get_turf(L) in linked.irradiated_turfs)
+ L.rad_act(linked.irradiated_turfs[get_turf(L)])
+ if(!L.radiation)
+ linked.irradiated_mobs.Remove(L)
+ SCHECK
+ for(var/thing in linked.sources)
+ if(!thing)
+ linked.sources.Remove(thing)
+ continue
+ var/atom/emitter = thing
+ linked.radiate(emitter, emitter.rad_power)
+ to_process.Cut()
+ SCHECK
+ for(var/thing in linked.resistance_cache)
+ if(!thing)
+ linked.resistance_cache.Remove(thing)
+ continue
+ var/turf/T = thing
+ if((length(T.contents) + 1) != linked.resistance_cache[T])
+ T.calc_rad_resistance()
+ SCHECK
\ No newline at end of file
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 5021453462..c22ac1bc81 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -219,6 +219,10 @@ var/list/gamemode_cache = list()
var/show_human_death_message = 1
+ var/radiation_decay_rate = 1 //How much radiation is reduced by each tick
+ var/radiation_resistance_multiplier = 6.5
+ var/radiation_lower_limit = 0.35 //If the radiation level for a turf would be below this, ignore it.
+
/datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
for (var/T in L)
diff --git a/code/datums/repositories/radiation.dm b/code/datums/repositories/radiation.dm
new file mode 100644
index 0000000000..bdf2b18322
--- /dev/null
+++ b/code/datums/repositories/radiation.dm
@@ -0,0 +1,114 @@
+//#define RADDBG
+
+var/repository/radiation/radiation_repository = new()
+
+var/list/to_process = list()
+
+/repository/radiation
+ var/list/sources = list() //All the radiation sources we know about
+ var/list/irradiated_turfs = list()
+ var/list/irradiated_mobs = list()
+ var/list/resistance_cache = list()
+
+/repository/radiation/proc/report_rads(var/turf/T as turf)
+ return irradiated_turfs[T]
+
+/repository/radiation/proc/radiate(source, power) //Sends out a radiation pulse, taking walls into account
+ if(!(source && power)) //Sanity checking
+ return
+
+ var/range = min(round(sqrt(power / config.radiation_lower_limit)), 31)
+ var/turf/epicentre = get_turf(source)
+ to_process = list()
+
+ range = min(epicentre.x, world.maxx - epicentre.x, epicentre.y, world.maxy - epicentre.y, range)
+
+ to_process = trange(range, epicentre)
+ to_process[epicentre] = power
+
+ for(var/turf/spot in to_process)
+ var/turf/origin = get_turf(epicentre)
+ var/working = power
+ while(origin != spot)
+ origin = get_step_towards(origin, spot) //Raytracing
+ if(!(origin in resistance_cache)) //Only get the resistance if we don't already know it.
+ origin.calc_rad_resistance()
+ working = max((working - (origin.rad_resistance * config.radiation_resistance_multiplier)), 0)
+ if(!working)
+ break
+ if(!to_process[origin])
+ to_process[origin] = working
+
+ else
+ to_process[origin] = max(to_process[origin], working)
+
+ for(var/turf/spot in to_process)
+ irradiated_turfs[spot] = max(((to_process[spot]) * (1 / (get_dist(epicentre, spot) ** 2))), irradiated_turfs[spot]) //Butchered version of the inverse square law. Works for this purpose
+ #ifdef RADDBG
+ var/x = Clamp( irradiated_turfs[spot], 0, 255)
+ spot.color = rgb(5,x,5)
+ #endif
+
+/repository/radiation/proc/flat_radiate(source, power, range, var/respect_maint=0) //Sets the radiation in a range to a constant value.
+ if(!(source && power && range))
+ return
+ var/turf/epicentre = get_turf(source)
+ range = min(epicentre.x, world.maxx - epicentre.x, epicentre.y, world.maxy - epicentre.y, range)
+ if(!respect_maint)
+ for(var/turf/T in trange(range, epicentre))
+ irradiated_turfs[T] = max(power, irradiated_turfs[T])
+ else
+ for(var/turf/T in trange(range, epicentre))
+ var/area/A = T.loc
+ if(A.flags & RAD_SHIELDED)
+ continue
+ irradiated_turfs[T] = max(power, irradiated_turfs[T])
+
+/repository/radiation/proc/z_radiate(var/atom/source, power, var/respect_maint=0) //Irradiates a full Z-level. Hacky way of doing it, but not too expensive.
+ if(!(power && source))
+ return
+ var/turf/epicentre = locate(round(world.maxx / 2), round(world.maxy / 2), source.z)
+ flat_radiate(epicentre, power, world.maxx, respect_maint)
+
+/turf/proc/calc_rad_resistance()
+ rad_resistance = 0
+ for(var/obj/O in src.contents)
+ if(O.rad_resistance) //Override
+ rad_resistance += O.rad_resistance
+
+ else if(O.density) //So doors don't get counted
+ var/material/M = O.get_material()
+ if(!M) continue
+ rad_resistance += M.weight
+ radiation_repository.resistance_cache[src] = (length(contents) + 1)
+
+/turf/simulated/wall/calc_rad_resistance()
+ radiation_repository.resistance_cache[src] = (length(contents) + 1)
+ rad_resistance = (density ? material.weight : 0)
+
+/atom
+ var/rad_power = 0
+ var/rad_resistance = 0
+
+/atom/Destroy()
+ if(rad_power)
+ radiation_repository.sources.Remove(src)
+ . = ..()
+
+/atom/proc/update_radiation() //For VV'ing something to make it radioactive at runtime
+ if((rad_power) && (!(src in radiation_repository.sources)))
+ radiation_repository.sources.Add(src)
+ else if((!rad_power) && (src in radiation_repository.sources))
+ radiation_repository.sources.Remove(src)
+
+/atom/proc/rad_act(var/severity) //If people expand the system, this may be useful. Here as a placeholder until then
+ return 1
+
+/mob/living/rad_act(var/severity)
+ if(severity)
+ src.apply_effect(severity, IRRADIATE, src.getarmor(null, "rad"))
+ for(var/obj/I in src)
+ I.rad_act(severity)
+
+
+//#undef RADDBG
\ No newline at end of file
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index fe9f99b032..82061ddb6a 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -53,6 +53,9 @@
pulledby = null
/atom/movable/proc/initialize()
+ if(rad_power)
+ radiation_repository.sources.Add(src)
+
if(!isnull(gcDestroyed))
crash_with("GC: -- [type] had initialize() called after qdel() --")
diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm
index ad8b89ec80..c5096d12d8 100644
--- a/code/game/gamemodes/meteor/meteors.dm
+++ b/code/game/gamemodes/meteor/meteors.dm
@@ -271,8 +271,7 @@
if(explode)
explosion(src.loc, devastation_range = 0, heavy_impact_range = 0, light_impact_range = 4, flash_range = 6, adminlog = 0)
new /obj/effect/decal/cleanable/greenglow(get_turf(src))
- for(var/mob/living/L in view(10, src))
- L.apply_effect(40, IRRADIATE)
+ radiation_repository.radiate(src, 50)
// This meteor fries toasters.
/obj/effect/meteor/emp
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index e78cba3568..c1ec9287b0 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -263,6 +263,7 @@
icon = 'icons/obj/doors/Dooruranium.dmi'
mineral = "uranium"
var/last_event = 0
+ rad_power = 7.5
/obj/machinery/door/airlock/process()
// Deliberate no call to parent.
@@ -277,18 +278,6 @@
..()
-/obj/machinery/door/airlock/uranium/process()
- if(world.time > last_event+20)
- if(prob(50))
- radiate()
- last_event = world.time
- ..()
-
-/obj/machinery/door/airlock/uranium/proc/radiate()
- for(var/mob/living/L in range (3,src))
- L.apply_effect(15,IRRADIATE,0)
- return
-
/obj/machinery/door/airlock/phoron
name = "Phoron Airlock"
desc = "No way this can end badly."
diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm
index 3d899377cc..f8e1d1cbb5 100644
--- a/code/game/machinery/doors/blast_door.dm
+++ b/code/game/machinery/doors/blast_door.dm
@@ -13,7 +13,7 @@
icon = 'icons/obj/doors/rapid_pdoor.dmi'
icon_state = null
min_force = 20 //minimum amount of force needed to damage the door with a melee weapon
-
+ var/material/implicit_material
// Icon states for different shutter types. Simply change this instead of rewriting the update_icon proc.
var/icon_state_open = null
var/icon_state_opening = null
@@ -29,6 +29,13 @@
//turning this off prevents awkward zone geometry in places like medbay lobby, for example.
block_air_zones = 0
+/obj/machinery/door/blast/initialize()
+ ..()
+ implicit_material = get_material_by_name("plasteel")
+
+/obj/machinery/door/blast/get_material()
+ return implicit_material
+
// Proc: Bumped()
// Parameters: 1 (AM - Atom that tried to walk through this object)
// Description: If we are open returns zero, otherwise returns result of parent function.
@@ -46,6 +53,8 @@
icon_state = icon_state_closed
else
icon_state = icon_state_open
+ var/turf/T = get_turf(src)
+ T.calc_rad_resistance()
return
// Proc: force_open()
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 7a1d6abd02..898683192f 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -362,6 +362,8 @@
icon_state = "door1"
else
icon_state = "door0"
+ var/turf/T = get_turf(src)
+ T.calc_rad_resistance()
return
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index 3d53a053f0..58bed70d07 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -1029,7 +1029,7 @@
icon_state = "engivend"
icon_deny = "engivend-deny"
req_access = list(access_engine_equip)
- products = list(/obj/item/clothing/glasses/meson = 2,/obj/item/device/multitool = 4,/obj/item/weapon/cell/high = 10,
+ products = list(/obj/item/device/geiger = 4,/obj/item/clothing/glasses/meson = 2,/obj/item/device/multitool = 4,/obj/item/weapon/cell/high = 10,
/obj/item/weapon/airlock_electronics = 10,/obj/item/weapon/module/power_control = 10,
/obj/item/weapon/circuitboard/airalarm = 10,/obj/item/weapon/circuitboard/firealarm = 10,/obj/item/weapon/circuitboard/status_display = 2,
/obj/item/weapon/circuitboard/ai_status_display = 2,/obj/item/weapon/circuitboard/newscaster = 2,/obj/item/weapon/circuitboard/holopad = 2,
diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm
index 9b2e0aa26d..4d7ee902d8 100644
--- a/code/game/mecha/equipment/tools/tools.dm
+++ b/code/game/mecha/equipment/tools/tools.dm
@@ -973,11 +973,7 @@
process(var/obj/item/mecha_parts/mecha_equipment/generator/nuclear/EG)
if(..())
- for(var/mob/living/carbon/M in view(EG.chassis))
- if(istype(M,/mob/living/carbon/human))
- M.apply_effect((EG.rad_per_cycle*3),IRRADIATE,0)
- else
- M.apply_effect(EG.rad_per_cycle, IRRADIATE)
+ radiation_repository.radiate(EG, (EG.rad_per_cycle * 3))
return 1
diff --git a/code/game/objects/items/devices/geiger.dm b/code/game/objects/items/devices/geiger.dm
new file mode 100644
index 0000000000..acd85b730c
--- /dev/null
+++ b/code/game/objects/items/devices/geiger.dm
@@ -0,0 +1,53 @@
+#define RAD_LEVEL_LOW 5 //10 // Around the level at which radiation starts to become harmful
+#define RAD_LEVEL_MODERATE 15 //15
+#define RAD_LEVEL_HIGH 50 //50
+#define RAD_LEVEL_VERY_HIGH 100 //100
+
+//Geiger counter
+//Rewritten version of TG's geiger counter
+//I opted to show exact radiation levels
+
+/obj/item/device/geiger
+ name = "geiger counter"
+ desc = "A handheld device used for detecting and measuring radiation in an area."
+ icon_state = "geiger_off"
+ item_state = "multitool"
+ w_class = ITEMSIZE_SMALL
+ var/scanning = 0
+ var/radiation_count = 0
+
+/obj/item/device/geiger/New()
+ processing_objects |= src
+
+/obj/item/device/geiger/process()
+ if(!scanning)
+ return
+ radiation_count = radiation_repository.report_rads(get_turf(src))
+ update_icon()
+
+/obj/item/device/geiger/examine(mob/user)
+ ..(user)
+ to_chat(user, "[scanning ? "ambient" : "stored"] radiation level: [radiation_count ? radiation_count : "0"]Bq.")
+
+/obj/item/device/geiger/attack_self(var/mob/user)
+ scanning = !scanning
+ update_icon()
+ to_chat(user, "\icon[src] You switch [scanning ? "on" : "off"] [src].")
+
+/obj/item/device/geiger/update_icon()
+ if(!scanning)
+ icon_state = "geiger_off"
+ return 1
+
+ switch(radiation_count)
+ if(null) icon_state = "geiger_on_1"
+ if(-INFINITY to RAD_LEVEL_LOW) icon_state = "geiger_on_1"
+ if(RAD_LEVEL_LOW + 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 INFINITY) icon_state = "geiger_on_5"
+
+#undef RAD_LEVEL_LOW
+#undef RAD_LEVEL_MODERATE
+#undef RAD_LEVEL_HIGH
+#undef RAD_LEVEL_VERY_HIGH
\ No newline at end of file
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 5c8aa2b2e0..67a4d3e788 100644
--- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
@@ -155,6 +155,8 @@
new /obj/item/clothing/head/radiation(src)
new /obj/item/clothing/suit/radiation(src)
new /obj/item/clothing/head/radiation(src)
+ new /obj/item/device/geiger(src)
+ new /obj/item/device/geiger(src)
/*
* Bombsuit closet
diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm
index 098782ebdf..b236e4dc90 100644
--- a/code/game/turfs/simulated/wall_attacks.dm
+++ b/code/game/turfs/simulated/wall_attacks.dm
@@ -7,6 +7,8 @@
if(can_open == WALL_OPENING)
return
+ calc_rad_resistance()
+
if(density)
can_open = WALL_OPENING
//flick("[material.icon_base]fwall_opening", src)
diff --git a/code/game/turfs/simulated/wall_icon.dm b/code/game/turfs/simulated/wall_icon.dm
index dc7874b2aa..757639e1bb 100644
--- a/code/game/turfs/simulated/wall_icon.dm
+++ b/code/game/turfs/simulated/wall_icon.dm
@@ -26,6 +26,7 @@
else if(material.opacity < 0.5 && opacity)
set_light(0)
+ calc_rad_resistance()
update_connections(1)
update_icon()
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index f8544e714d..376fb8e452 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -48,6 +48,9 @@
if(!radiate())
return PROCESS_KILL
+/turf/simulated/wall/proc/get_material()
+ return material
+
/turf/simulated/wall/bullet_act(var/obj/item/projectile/Proj)
if(istype(Proj,/obj/item/projectile/beam))
burn(2500)
@@ -265,8 +268,7 @@
if(!total_radiation)
return
- for(var/mob/living/L in range(3,src))
- L.apply_effect(total_radiation, IRRADIATE,0)
+ radiation_repository.radiate(src, total_radiation)
return total_radiation
/turf/simulated/wall/proc/burn(temperature)
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 3f2e0064f2..87b4b2b648 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -140,6 +140,12 @@ var/const/enterloopsanity = 100
if(ismob(A))
var/mob/M = A
+ var/mob/living/L = A
+ if(istype(L))
+ if(!(L in radiation_repository.irradiated_mobs))
+ if(src in radiation_repository.irradiated_turfs)
+ radiation_repository.irradiated_mobs.Add(L)
+ L.handle_footstep(src)
if(!M.lastarea)
M.lastarea = get_area(M.loc)
if(M.lastarea.has_gravity == 0)
@@ -147,9 +153,6 @@ var/const/enterloopsanity = 100
else if(!is_space())
M.inertia_dir = 0
M.make_floating(0)
- if(isliving(M))
- var/mob/living/L = M
- L.handle_footstep(src)
..()
var/objects = 0
if(A && (A.flags & PROXMOVE))
@@ -255,4 +258,4 @@ var/const/enterloopsanity = 100
step(AM, turn(AM.last_move, 180))
if(isliving(AM))
var/mob/living/M = AM
- M.turf_collision(src, speed)
+ M.turf_collision(src, speed)
\ No newline at end of file
diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm
index 37a576a442..804d13404d 100644
--- a/code/modules/events/event_container.dm
+++ b/code/modules/events/event_container.dm
@@ -186,4 +186,4 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT
#undef ASSIGNMENT_JANITOR
#undef ASSIGNMENT_MEDICAL
#undef ASSIGNMENT_SCIENTIST
-#undef ASSIGNMENT_SECURITY
+#undef ASSIGNMENT_SECURITY
\ No newline at end of file
diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm
index b9435f25aa..a8c9386fde 100644
--- a/code/modules/events/radiation_storm.dm
+++ b/code/modules/events/radiation_storm.dm
@@ -30,20 +30,18 @@
command_announcement.Announce("The station has passed the radiation belt. Please report to medbay if you experience any unusual symptoms. Maintenance will lose all access again shortly.", "Anomaly Alert")
/datum/event/radiation_storm/proc/radiate()
+ var/radiation_level = rand(15, 35)
+ for(var/z in using_map.station_levels)
+ radiation_repository.z_radiate(locate(1, 1, z), radiation_level, 1)
+
for(var/mob/living/carbon/C in living_mob_list)
var/area/A = get_area(C)
if(!A)
continue
- if(!(A.z in using_map.station_levels))
- continue
- if(A.flags & RAD_SHIELDED)
- continue
if(istype(C,/mob/living/carbon/human))
var/mob/living/carbon/human/H = C
- H.apply_effect((rand(15,35)),IRRADIATE,0)
if(prob(5))
- H.apply_effect((rand(40,70)),IRRADIATE,0)
if (prob(75))
randmutb(H) // Applies bad mutation
domutcheck(H,null,MUTCHK_FORCED)
diff --git a/code/modules/events/solar_storm.dm b/code/modules/events/solar_storm.dm
index 971e0418bc..4ebfc71d55 100644
--- a/code/modules/events/solar_storm.dm
+++ b/code/modules/events/solar_storm.dm
@@ -27,17 +27,14 @@
radiate()
/datum/event/solar_storm/proc/radiate()
- for(var/mob/living/L in living_mob_list)
- var/turf/T = get_turf(L)
- if(!T)
+ var/radiation_level = rand(15, 30)
+ for(var/area/A in all_areas)
+ if(!(A.z in using_map.player_levels))
continue
-
- if(!istype(T.loc,/area/space) && !istype(T,/turf/space)) //Make sure you're in a space area or on a space turf
- continue
-
- //Todo: Apply some burn damage from the heat of the sun. Until then, enjoy some moderate radiation.
- L.apply_effect((rand(15,30)),IRRADIATE,blocked = L.getarmor(null, "rad"))
-
+ for(var/turf/T in A)
+ if(!istype(T.loc,/area/space) && !istype(T,/turf/space))
+ continue
+ radiation_repository.irradiated_turfs[T] = radiation_level
/datum/event/solar_storm/end()
command_announcement.Announce("The solar storm has passed the station. It is now safe to resume EVA activities. Please report to medbay if you experience any unusual symptoms. ", "Anomaly Alert")
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index bf59f3c382..68363fb27f 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -482,7 +482,7 @@ var/list/mining_overlay_cache = list()
M.flash_eyes()
if(prob(50))
M.Stun(5)
- M.apply_effect(25, IRRADIATE)
+ radiation_repository.flat_radiate(src, 25, 200)
if(prob(25))
excavate_find(prob(5), finds[1])
else if(rand(1,500) == 1)
@@ -559,4 +559,4 @@ var/list/mining_overlay_cache = list()
if(mineral_name && (mineral_name in ore_data))
mineral = ore_data[mineral_name]
UpdateMineral()
- update_icon()
+ update_icon()
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 61b13316b8..8f7398e0a8 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -94,7 +94,7 @@ emp_act
var/obj/item/organ/external/organ = organs_by_name[organ_name]
if(organ)
var/weight = organ_rel_size[organ_name]
- armorval += getarmor_organ(organ, type) * weight
+ armorval += (getarmor_organ(organ, type) * weight)
total += weight
return (armorval/max(total, 1))
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 795e535ebf..4b2c7f6f79 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -352,6 +352,7 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/device/pipe_painter(src)
src.modules += new /obj/item/device/floor_painter(src)
src.modules += new /obj/item/weapon/gripper/no_use/loader(src)
+ src.modules += new /obj/item/device/geiger(src)
var/datum/matter_synth/metal = new /datum/matter_synth/metal()
var/datum/matter_synth/plasteel = new /datum/matter_synth/plasteel()
@@ -396,6 +397,7 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/device/pipe_painter(src)
src.modules += new /obj/item/device/floor_painter(src)
src.emag = new /obj/item/weapon/melee/baton/robot/arm(src)
+ src.modules += new /obj/item/device/geiger(src)
var/datum/matter_synth/metal = new /datum/matter_synth/metal(40000)
var/datum/matter_synth/glass = new /datum/matter_synth/glass(40000)
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index f900f6fcf4..6a40cf3b8e 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -396,17 +396,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
+ radiation_repository.radiate(src, 4)
..()
/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_repository.radiate(src, (max(20, rads)))
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 dee15d9f14..ba817d392a 100644
--- a/code/modules/power/singularity/collector.dm
+++ b/code/modules/power/singularity/collector.dm
@@ -31,6 +31,11 @@ var/global/list/rad_collectors = list()
last_power_new = 0
+ var/turf/T = get_turf(src)
+ if(T in radiation_repository.irradiated_turfs)
+ receive_pulse((radiation_repository.irradiated_turfs[T] * 5)) //Maths is hard
+
+
if(P)
if(P.air_contents.gas["phoron"] == 0)
investigate_log("out of fuel.","singulo")
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index 39090ceac5..9309c6bd3c 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -406,15 +406,13 @@
var/toxrange = 10
var/toxdamage = 4
var/radiation = 15
- var/radiationmin = 3
if (src.energy>200)
toxdamage = round(((src.energy-150)/50)*4,1)
radiation = round(((src.energy-150)/50)*5,1)
- radiationmin = round((radiation/5),1)//
+ radiation_repository.radiate(src, radiation) //Always radiate at max, so a decent dose of radiation is applied
for(var/mob/living/M in view(toxrange, src.loc))
if(M.status_flags & GODMODE)
continue
- M.apply_effect(rand(radiationmin,radiation), IRRADIATE)
toxdamage = (toxdamage - (toxdamage*M.getarmor(null, "rad")))
M.apply_effect(toxdamage, TOX)
return
@@ -448,13 +446,13 @@
/obj/singularity/proc/smwave()
for(var/mob/living/M in view(10, src.loc))
if(prob(67))
- M.apply_effect(rand(energy), IRRADIATE)
- M << "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat."
- M << "Miraculously, it fails to kill you."
+ to_chat(M, "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.")
+ to_chat(M, "Miraculously, it fails to kill you.")
else
M << "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat."
M << "You don't even have a moment to react as you are reduced to ashes by the intense radiation."
M.dust()
+ radiation_repository.radiate(src, rand(energy))
return
/obj/singularity/proc/pulse()
diff --git a/code/modules/supermatter/supermatter.dm b/code/modules/supermatter/supermatter.dm
index 1ebd8207e0..46f8033b24 100644
--- a/code/modules/supermatter/supermatter.dm
+++ b/code/modules/supermatter/supermatter.dm
@@ -23,8 +23,11 @@
#define DAMAGE_RATE_LIMIT 3 //damage rate cap at power = 300, scales linearly with power
-//These would be what you would get at point blank, decreases with distance
-#define DETONATION_RADS 200
+// Base variants are applied to everyone on the same Z level
+// Range variants are applied on per-range basis: numbers here are on point blank, it scales with the map size (assumes square shaped Z levels)
+#define DETONATION_RADS 20
+#define DETONATION_HALLUCINATION_BASE 300
+#define DETONATION_HALLUCINATION_RANGE 300
#define DETONATION_HALLUCINATION 600
@@ -39,6 +42,7 @@
anchored = 0
light_range = 4
+ rad_power = 1 //So it gets added to the repository
var/gasefficency = 0.25
var/base_icon_state = "darkmatter"
@@ -95,6 +99,10 @@
anchored = 1
grav_pulling = 1
exploded = 1
+ var/turf/TS = get_turf(src) // The turf supermatter is on. SM being in a locker, mecha, or other container shouldn't block it's effects that way.
+ radiation_repository.z_radiate(TS, DETONATION_RADS)
+ radiation_repository.z_radiate(TS, DETONATION_RADS)
+
for(var/mob/living/mob in living_mob_list)
var/turf/T = get_turf(mob)
if(T && (loc.z == T.z))
@@ -102,8 +110,6 @@
//Hilariously enough, running into a closet should make you get hit the hardest.
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(mob, src) + 1) )
- mob.apply_effect(rads, IRRADIATE)
spawn(pull_time)
explosion(get_turf(src), explosion_power, explosion_power * 2, explosion_power * 3, explosion_power * 4, 1)
qdel(src)
@@ -258,12 +264,15 @@
if(eye_shield < 1)
l.hallucination = max(0, min(200, l.hallucination + power * config_hallucination_power * sqrt( 1 / max(1,get_dist(l, src)) ) ) )
+/*
//adjusted range so that a power of 170 (pretty high) results in 9 tiles, roughly the distance from the core to the engine monitoring room.
//note that the rads given at the maximum range is a constant 0.2 - as power increases the maximum range merely increases.
for(var/mob/living/l in range(src, round(sqrt(power / 2))))
var/radius = max(get_dist(l, src), 1)
var/rads = (power / 10) * ( 1 / (radius**2) )
l.apply_effect(rads, IRRADIATE)
+*/
+ rad_power = power * 1.5//Better close those shutters!
power -= (power/DECAY_FACTOR)**3 //energy losses due to radiation
@@ -377,8 +386,8 @@
"The unearthly ringing subsides and you notice you have new radiation burns.", 2)
else
l.show_message("You hear an uneartly ringing and notice your skin is covered in fresh radiation burns.", 2)
- var/rads = 500 * sqrt( 1 / (get_dist(l, src) + 1) )
- l.apply_effect(rads, IRRADIATE)
+ var/rads = 500
+ radiation_repository.radiate(src, rads)
/obj/machinery/power/supermatter/proc/supermatter_pull()
@@ -394,6 +403,7 @@
return
+
/obj/machinery/power/supermatter/GotoAirflowDest(n) //Supermatter not pushed around by airflow
return
diff --git a/code/modules/xenoarcheaology/effects/radiate.dm b/code/modules/xenoarcheaology/effects/radiate.dm
index 7816409757..6c8d37838a 100644
--- a/code/modules/xenoarcheaology/effects/radiate.dm
+++ b/code/modules/xenoarcheaology/effects/radiate.dm
@@ -15,16 +15,10 @@
/datum/artifact_effect/radiate/DoEffectAura()
if(holder)
- var/turf/T = get_turf(holder)
- for (var/mob/living/M in range(src.effectrange,T))
- M.apply_effect(radiation_amount,IRRADIATE,0)
- M.updatehealth()
+ radiation_repository.flat_radiate(holder, radiation_amount, src.effectrange)
return 1
/datum/artifact_effect/radiate/DoEffectPulse()
if(holder)
- var/turf/T = get_turf(holder)
- for (var/mob/living/M in range(src.effectrange,T))
- M.apply_effect(radiation_amount * 25,IRRADIATE,0)
- M.updatehealth()
+ radiation_repository.radiate(holder, ((radiation_amount * 25) * (sqrt(src.effectrange)))) //Need to get feedback on this
return 1
diff --git a/code/modules/xenoarcheaology/tools/geosample_scanner.dm b/code/modules/xenoarcheaology/tools/geosample_scanner.dm
index 9d6450a839..9e3343b680 100644
--- a/code/modules/xenoarcheaology/tools/geosample_scanner.dm
+++ b/code/modules/xenoarcheaology/tools/geosample_scanner.dm
@@ -198,8 +198,7 @@
radiation = rand() * 15 + 85
if(!rad_shield)
//irradiate nearby mobs
- for(var/mob/living/M in view(7,src))
- M.apply_effect(radiation / 25, IRRADIATE, 0)
+ radiation_repository.radiate(src, radiation / 25)
else
t_left_radspike = pick(10,15,25)
@@ -361,4 +360,4 @@
scanned_item = null
add_fingerprint(usr)
- return 1 // update UIs attached to this object
+ return 1 // update UIs attached to this object
\ No newline at end of file
diff --git a/html/changelogs/cirra-Radiation.yml b/html/changelogs/cirra-Radiation.yml
new file mode 100644
index 0000000000..53038532cd
--- /dev/null
+++ b/html/changelogs/cirra-Radiation.yml
@@ -0,0 +1,37 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+#################################
+
+# Your name.
+author: Cirra
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - rscadd: "Added a unified radiation system. Radiation is lessened by obstacles, and distance."
+ - rscadd: "Added a geiger counter for measuring radiation levels, which can be found in certain vending machines and radiation closets."
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index 336f8dfe9c..1198dc0314 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/polaris.dme b/polaris.dme
index f8f889a5d8..69d8639842 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -150,6 +150,7 @@
#include "code\controllers\Processes\nanoui.dm"
#include "code\controllers\Processes\obj.dm"
#include "code\controllers\Processes\planet.dm"
+#include "code\controllers\Processes\radiation.dm"
#include "code\controllers\Processes\scheduler.dm"
#include "code\controllers\Processes\Shuttle.dm"
#include "code\controllers\Processes\sun.dm"
@@ -212,6 +213,7 @@
#include "code\datums\repositories\cameras.dm"
#include "code\datums\repositories\crew.dm"
#include "code\datums\repositories\decls.dm"
+#include "code\datums\repositories\radiation.dm"
#include "code\datums\repositories\repository.dm"
#include "code\datums\supplypacks\atmospherics.dm"
#include "code\datums\supplypacks\contraband.dm"
@@ -768,6 +770,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.dm"
#include "code\game\objects\items\devices\hacktool.dm"
#include "code\game\objects\items\devices\lightreplacer.dm"
#include "code\game\objects\items\devices\locker_painter.dm"