diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm
index 7cef577226..8d3f07b5a6 100644
--- a/code/__DEFINES/machines.dm
+++ b/code/__DEFINES/machines.dm
@@ -1,114 +1,114 @@
-// channel numbers for power
-#define EQUIP 1
-#define LIGHT 2
-#define ENVIRON 3
-#define TOTAL 4 //for total power used only
-#define STATIC_EQUIP 5
-#define STATIC_LIGHT 6
-#define STATIC_ENVIRON 7
-
-//Power use
-#define NO_POWER_USE 0
-#define IDLE_POWER_USE 1
-#define ACTIVE_POWER_USE 2
-
-
-//bitflags for door switches.
-#define OPEN (1<<0)
-#define IDSCAN (1<<1)
-#define BOLTS (1<<2)
-#define SHOCK (1<<3)
-#define SAFE (1<<4)
-
-//used in design to specify which machine can build it
-#define IMPRINTER (1<<0) //For circuits. Uses glass/chemicals.
-#define PROTOLATHE (1<<1) //New stuff. Uses glass/metal/chemicals
-#define AUTOLATHE (1<<2) //Uses glass/metal only.
-#define CRAFTLATHE (1<<3) //Uses fuck if I know. For use eventually.
-#define MECHFAB (1<<4) //Remember, objects utilising this flag should have construction_time and construction_cost vars.
-#define BIOGENERATOR (1<<5) //Uses biomass
-#define LIMBGROWER (1<<6) //Uses synthetic flesh
-#define SMELTER (1<<7) //uses various minerals
-#define AUTOYLATHE (1<<8) // CITADEL ADD
-#define NANITE_COMPILER (1<<9) //Prints nanite disks
-#define AUTOBOTTLER (1<<10) //Uses booze, for printing
-//Note: More then one of these can be added to a design but imprinter and lathe designs are incompatable.
-
-//Modular computer/NTNet defines
-
-//Modular computer part defines
-#define MC_CPU "CPU"
-#define MC_HDD "HDD"
-#define MC_SDD "SDD"
-#define MC_CARD "CARD"
-#define MC_NET "NET"
-#define MC_PRINT "PRINT"
-#define MC_CELL "CELL"
-#define MC_CHARGE "CHARGE"
-#define MC_AI "AI"
-
-//NTNet stuff, for modular computers
- // NTNet module-configuration values. Do not change these. If you need to add another use larger number (5..6..7 etc)
-#define NTNET_SOFTWAREDOWNLOAD 1 // Downloads of software from NTNet
-#define NTNET_PEERTOPEER 2 // P2P transfers of files between devices
-#define NTNET_COMMUNICATION 3 // Communication (messaging)
-#define NTNET_SYSTEMCONTROL 4 // Control of various systems, RCon, air alarm control, etc.
-
-//NTNet transfer speeds, used when downloading/uploading a file/program.
-#define NTNETSPEED_LOWSIGNAL 0.5 // GQ/s transfer speed when the device is wirelessly connected and on Low signal
-#define NTNETSPEED_HIGHSIGNAL 1 // GQ/s transfer speed when the device is wirelessly connected and on High signal
-#define NTNETSPEED_ETHERNET 2 // GQ/s transfer speed when the device is using wired connection
-
-//Caps for NTNet logging. Less than 10 would make logging useless anyway, more than 500 may make the log browser too laggy. Defaults to 100 unless user changes it.
-#define MAX_NTNET_LOGS 300
-#define MIN_NTNET_LOGS 10
-
-//Program bitflags
-#define PROGRAM_ALL (~0)
-#define PROGRAM_CONSOLE (1<<0)
-#define PROGRAM_LAPTOP (1<<1)
-#define PROGRAM_TABLET (1<<2)
-//Program states
-#define PROGRAM_STATE_KILLED 0
-#define PROGRAM_STATE_BACKGROUND 1
-#define PROGRAM_STATE_ACTIVE 2
-
-#define FIREDOOR_OPEN 1
-#define FIREDOOR_CLOSED 2
-
-
-
-// These are used by supermatter and supermatter monitor program, mostly for UI updating purposes. Higher should always be worse!
-#define SUPERMATTER_ERROR -1 // Unknown status, shouldn't happen but just in case.
-#define SUPERMATTER_INACTIVE 0 // No or minimal energy
-#define SUPERMATTER_NORMAL 1 // Normal operation
-#define SUPERMATTER_NOTIFY 2 // Ambient temp > 80% of CRITICAL_TEMPERATURE
-#define SUPERMATTER_WARNING 3 // Ambient temp > CRITICAL_TEMPERATURE OR integrity damaged
-#define SUPERMATTER_DANGER 4 // Integrity < 50%
-#define SUPERMATTER_EMERGENCY 5 // Integrity < 25%
-#define SUPERMATTER_DELAMINATING 6 // Pretty obvious.
-
-//Nuclear bomb stuff
-#define NUKESTATE_INTACT 5
-#define NUKESTATE_UNSCREWED 4
-#define NUKESTATE_PANEL_REMOVED 3
-#define NUKESTATE_WELDED 2
-#define NUKESTATE_CORE_EXPOSED 1
-#define NUKESTATE_CORE_REMOVED 0
-
-#define NUKEUI_AWAIT_DISK 0
-#define NUKEUI_AWAIT_CODE 1
-#define NUKEUI_AWAIT_TIMER 2
-#define NUKEUI_AWAIT_ARM 3
-#define NUKEUI_TIMING 4
-#define NUKEUI_EXPLODED 5
-
-#define NUKE_OFF_LOCKED 0
-#define NUKE_OFF_UNLOCKED 1
-#define NUKE_ON_TIMING 2
-#define NUKE_ON_EXPLODING 3
-
-
-//these flags are used to tell the DNA modifier if a plant gene cannot be extracted or modified.
-#define PLANT_GENE_REMOVABLE (1<<0)
+// channel numbers for power
+#define EQUIP 1
+#define LIGHT 2
+#define ENVIRON 3
+#define TOTAL 4 //for total power used only
+#define STATIC_EQUIP 5
+#define STATIC_LIGHT 6
+#define STATIC_ENVIRON 7
+
+//Power use
+#define NO_POWER_USE 0
+#define IDLE_POWER_USE 1
+#define ACTIVE_POWER_USE 2
+
+
+//bitflags for door switches.
+#define OPEN (1<<0)
+#define IDSCAN (1<<1)
+#define BOLTS (1<<2)
+#define SHOCK (1<<3)
+#define SAFE (1<<4)
+
+//used in design to specify which machine can build it
+#define IMPRINTER (1<<0) //For circuits. Uses glass/chemicals.
+#define PROTOLATHE (1<<1) //New stuff. Uses glass/metal/chemicals
+#define AUTOLATHE (1<<2) //Uses glass/metal only.
+#define CRAFTLATHE (1<<3) //Uses fuck if I know. For use eventually.
+#define MECHFAB (1<<4) //Remember, objects utilising this flag should have construction_time and construction_cost vars.
+#define BIOGENERATOR (1<<5) //Uses biomass
+#define LIMBGROWER (1<<6) //Uses synthetic flesh
+#define SMELTER (1<<7) //uses various minerals
+#define AUTOYLATHE (1<<8) // CITADEL ADD
+#define NANITE_COMPILER (1<<9) //Prints nanite disks
+#define AUTOBOTTLER (1<<10) //Uses booze, for printing
+//Note: More then one of these can be added to a design but imprinter and lathe designs are incompatable.
+
+//Modular computer/NTNet defines
+
+//Modular computer part defines
+#define MC_CPU "CPU"
+#define MC_HDD "HDD"
+#define MC_SDD "SDD"
+#define MC_CARD "CARD"
+#define MC_NET "NET"
+#define MC_PRINT "PRINT"
+#define MC_CELL "CELL"
+#define MC_CHARGE "CHARGE"
+#define MC_AI "AI"
+
+//NTNet stuff, for modular computers
+ // NTNet module-configuration values. Do not change these. If you need to add another use larger number (5..6..7 etc)
+#define NTNET_SOFTWAREDOWNLOAD 1 // Downloads of software from NTNet
+#define NTNET_PEERTOPEER 2 // P2P transfers of files between devices
+#define NTNET_COMMUNICATION 3 // Communication (messaging)
+#define NTNET_SYSTEMCONTROL 4 // Control of various systems, RCon, air alarm control, etc.
+
+//NTNet transfer speeds, used when downloading/uploading a file/program.
+#define NTNETSPEED_LOWSIGNAL 0.5 // GQ/s transfer speed when the device is wirelessly connected and on Low signal
+#define NTNETSPEED_HIGHSIGNAL 1 // GQ/s transfer speed when the device is wirelessly connected and on High signal
+#define NTNETSPEED_ETHERNET 2 // GQ/s transfer speed when the device is using wired connection
+
+//Caps for NTNet logging. Less than 10 would make logging useless anyway, more than 500 may make the log browser too laggy. Defaults to 100 unless user changes it.
+#define MAX_NTNET_LOGS 300
+#define MIN_NTNET_LOGS 10
+
+//Program bitflags
+#define PROGRAM_ALL (~0)
+#define PROGRAM_CONSOLE (1<<0)
+#define PROGRAM_LAPTOP (1<<1)
+#define PROGRAM_TABLET (1<<2)
+//Program states
+#define PROGRAM_STATE_KILLED 0
+#define PROGRAM_STATE_BACKGROUND 1
+#define PROGRAM_STATE_ACTIVE 2
+
+#define FIREDOOR_OPEN 1
+#define FIREDOOR_CLOSED 2
+
+
+
+// These are used by supermatter and supermatter monitor program, mostly for UI updating purposes. Higher should always be worse!
+#define SUPERMATTER_ERROR -1 // Unknown status, shouldn't happen but just in case.
+#define SUPERMATTER_INACTIVE 0 // No or minimal energy
+#define SUPERMATTER_NORMAL 1 // Normal operation
+#define SUPERMATTER_NOTIFY 2 // Ambient temp > 80% of CRITICAL_TEMPERATURE
+#define SUPERMATTER_WARNING 3 // Ambient temp > CRITICAL_TEMPERATURE OR integrity damaged
+#define SUPERMATTER_DANGER 4 // Integrity < 50%
+#define SUPERMATTER_EMERGENCY 5 // Integrity < 25%
+#define SUPERMATTER_DELAMINATING 6 // Pretty obvious.
+
+//Nuclear bomb stuff
+#define NUKESTATE_INTACT 5
+#define NUKESTATE_UNSCREWED 4
+#define NUKESTATE_PANEL_REMOVED 3
+#define NUKESTATE_WELDED 2
+#define NUKESTATE_CORE_EXPOSED 1
+#define NUKESTATE_CORE_REMOVED 0
+
+#define NUKEUI_AWAIT_DISK 0
+#define NUKEUI_AWAIT_CODE 1
+#define NUKEUI_AWAIT_TIMER 2
+#define NUKEUI_AWAIT_ARM 3
+#define NUKEUI_TIMING 4
+#define NUKEUI_EXPLODED 5
+
+#define NUKE_OFF_LOCKED 0
+#define NUKE_OFF_UNLOCKED 1
+#define NUKE_ON_TIMING 2
+#define NUKE_ON_EXPLODING 3
+
+
+//these flags are used to tell the DNA modifier if a plant gene cannot be extracted or modified.
+#define PLANT_GENE_REMOVABLE (1<<0)
#define PLANT_GENE_EXTRACTABLE (1<<1)
\ No newline at end of file
diff --git a/code/datums/diseases/advance/symptoms/choking.dm b/code/datums/diseases/advance/symptoms/choking.dm
index a9776384f6..134bdfc814 100644
--- a/code/datums/diseases/advance/symptoms/choking.dm
+++ b/code/datums/diseases/advance/symptoms/choking.dm
@@ -1,152 +1,152 @@
-/*
-//////////////////////////////////////
-
-Choking
-
- Very very noticable.
- Lowers resistance.
- Decreases stage speed.
- Decreases transmittablity tremendously.
- Moderate Level.
-
-Bonus
- Inflicts spikes of oxyloss
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/choking
-
- name = "Choking"
- desc = "The virus causes inflammation of the host's air conduits, leading to intermittent choking."
- stealth = -3
- resistance = -2
- stage_speed = -2
- transmittable = -4
- level = 3
- severity = 3
- base_message_chance = 15
- symptom_delay_min = 10
- symptom_delay_max = 30
- threshold_desc = list(
- "Stage Speed 8" = "Causes choking more frequently.",
- "Stealth 4" = "The symptom remains hidden until active."
- )
-
-/datum/symptom/choking/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stage_rate"] >= 8)
- symptom_delay_min = 7
- symptom_delay_max = 24
- if(A.properties["stealth"] >= 4)
- suppress_warning = TRUE
-
-/datum/symptom/choking/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/M = A.affected_mob
- switch(A.stage)
- if(1, 2)
- if(prob(base_message_chance) && !suppress_warning)
- to_chat(M, "[pick("You're having difficulty breathing.", "Your breathing becomes heavy.")]")
- if(3, 4)
- if(!suppress_warning)
- to_chat(M, "[pick("Your windpipe feels like a straw.", "Your breathing becomes tremendously difficult.")]")
- else
- to_chat(M, "You feel very [pick("dizzy","woozy","faint")].") //fake bloodloss messages
- Choke_stage_3_4(M, A)
- M.emote("gasp")
- else
- to_chat(M, "[pick("You're choking!", "You can't breathe!")]")
- Choke(M, A)
- M.emote("gasp")
-
-/datum/symptom/choking/proc/Choke_stage_3_4(mob/living/M, datum/disease/advance/A)
- M.adjustOxyLoss(rand(6,13))
- return 1
-
-/datum/symptom/choking/proc/Choke(mob/living/M, datum/disease/advance/A)
- M.adjustOxyLoss(rand(10,18))
- return 1
-
-/*
-//////////////////////////////////////
-
-Asphyxiation
-
- Very very noticable.
- Decreases stage speed.
- Decreases transmittablity.
-
-Bonus
- Inflicts large spikes of oxyloss
- Introduces Asphyxiating drugs to the system
- Causes cardiac arrest on dying victims.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/asphyxiation
-
- name = "Acute respiratory distress syndrome"
- desc = "The virus causes shrinking of the host's lungs, causing severe asphyxiation. May also lead to heart attacks."
- stealth = -2
- resistance = -0
- stage_speed = -1
- transmittable = -2
- level = 7
- severity = 6
- base_message_chance = 15
- symptom_delay_min = 14
- symptom_delay_max = 30
- var/paralysis = FALSE
- threshold_desc = list(
- "Stage Speed 8" = "Additionally synthesizes pancuronium and sodium thiopental inside the host.",
- "Transmission 8" = "Doubles the damage caused by the symptom."
- )
-
-
-/datum/symptom/asphyxiation/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stage_rate"] >= 8)
- paralysis = TRUE
- if(A.properties["transmittable"] >= 8)
- power = 2
-
-/datum/symptom/asphyxiation/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/M = A.affected_mob
- switch(A.stage)
- if(3, 4)
- to_chat(M, "[pick("Your windpipe feels thin.", "Your lungs feel small.")]")
- Asphyxiate_stage_3_4(M, A)
- M.emote("gasp")
- if(5)
- to_chat(M, "[pick("Your lungs hurt!", "It hurts to breathe!")]")
- Asphyxiate(M, A)
- M.emote("gasp")
- if(M.getOxyLoss() >= 120)
- M.visible_message("[M] stops breathing, as if their lungs have totally collapsed!")
- Asphyxiate_death(M, A)
- return
-
-/datum/symptom/asphyxiation/proc/Asphyxiate_stage_3_4(mob/living/M, datum/disease/advance/A)
- var/get_damage = rand(10,15) * power
- M.adjustOxyLoss(get_damage)
- return 1
-
-/datum/symptom/asphyxiation/proc/Asphyxiate(mob/living/M, datum/disease/advance/A)
- var/get_damage = rand(15,21) * power
- M.adjustOxyLoss(get_damage)
- if(paralysis)
- M.reagents.add_reagent_list(list(/datum/reagent/toxin/pancuronium = 3, /datum/reagent/toxin/sodium_thiopental = 3))
- return 1
-
-/datum/symptom/asphyxiation/proc/Asphyxiate_death(mob/living/M, datum/disease/advance/A)
- var/get_damage = rand(25,35) * power
- M.adjustOxyLoss(get_damage)
- M.adjustOrganLoss(ORGAN_SLOT_BRAIN, get_damage/2)
- return 1
+/*
+//////////////////////////////////////
+
+Choking
+
+ Very very noticable.
+ Lowers resistance.
+ Decreases stage speed.
+ Decreases transmittablity tremendously.
+ Moderate Level.
+
+Bonus
+ Inflicts spikes of oxyloss
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/choking
+
+ name = "Choking"
+ desc = "The virus causes inflammation of the host's air conduits, leading to intermittent choking."
+ stealth = -3
+ resistance = -2
+ stage_speed = -2
+ transmittable = -4
+ level = 3
+ severity = 3
+ base_message_chance = 15
+ symptom_delay_min = 10
+ symptom_delay_max = 30
+ threshold_desc = list(
+ "Stage Speed 8" = "Causes choking more frequently.",
+ "Stealth 4" = "The symptom remains hidden until active."
+ )
+
+/datum/symptom/choking/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stage_rate"] >= 8)
+ symptom_delay_min = 7
+ symptom_delay_max = 24
+ if(A.properties["stealth"] >= 4)
+ suppress_warning = TRUE
+
+/datum/symptom/choking/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/M = A.affected_mob
+ switch(A.stage)
+ if(1, 2)
+ if(prob(base_message_chance) && !suppress_warning)
+ to_chat(M, "[pick("You're having difficulty breathing.", "Your breathing becomes heavy.")]")
+ if(3, 4)
+ if(!suppress_warning)
+ to_chat(M, "[pick("Your windpipe feels like a straw.", "Your breathing becomes tremendously difficult.")]")
+ else
+ to_chat(M, "You feel very [pick("dizzy","woozy","faint")].") //fake bloodloss messages
+ Choke_stage_3_4(M, A)
+ M.emote("gasp")
+ else
+ to_chat(M, "[pick("You're choking!", "You can't breathe!")]")
+ Choke(M, A)
+ M.emote("gasp")
+
+/datum/symptom/choking/proc/Choke_stage_3_4(mob/living/M, datum/disease/advance/A)
+ M.adjustOxyLoss(rand(6,13))
+ return 1
+
+/datum/symptom/choking/proc/Choke(mob/living/M, datum/disease/advance/A)
+ M.adjustOxyLoss(rand(10,18))
+ return 1
+
+/*
+//////////////////////////////////////
+
+Asphyxiation
+
+ Very very noticable.
+ Decreases stage speed.
+ Decreases transmittablity.
+
+Bonus
+ Inflicts large spikes of oxyloss
+ Introduces Asphyxiating drugs to the system
+ Causes cardiac arrest on dying victims.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/asphyxiation
+
+ name = "Acute respiratory distress syndrome"
+ desc = "The virus causes shrinking of the host's lungs, causing severe asphyxiation. May also lead to heart attacks."
+ stealth = -2
+ resistance = -0
+ stage_speed = -1
+ transmittable = -2
+ level = 7
+ severity = 6
+ base_message_chance = 15
+ symptom_delay_min = 14
+ symptom_delay_max = 30
+ var/paralysis = FALSE
+ threshold_desc = list(
+ "Stage Speed 8" = "Additionally synthesizes pancuronium and sodium thiopental inside the host.",
+ "Transmission 8" = "Doubles the damage caused by the symptom."
+ )
+
+
+/datum/symptom/asphyxiation/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stage_rate"] >= 8)
+ paralysis = TRUE
+ if(A.properties["transmittable"] >= 8)
+ power = 2
+
+/datum/symptom/asphyxiation/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/M = A.affected_mob
+ switch(A.stage)
+ if(3, 4)
+ to_chat(M, "[pick("Your windpipe feels thin.", "Your lungs feel small.")]")
+ Asphyxiate_stage_3_4(M, A)
+ M.emote("gasp")
+ if(5)
+ to_chat(M, "[pick("Your lungs hurt!", "It hurts to breathe!")]")
+ Asphyxiate(M, A)
+ M.emote("gasp")
+ if(M.getOxyLoss() >= 120)
+ M.visible_message("[M] stops breathing, as if their lungs have totally collapsed!")
+ Asphyxiate_death(M, A)
+ return
+
+/datum/symptom/asphyxiation/proc/Asphyxiate_stage_3_4(mob/living/M, datum/disease/advance/A)
+ var/get_damage = rand(10,15) * power
+ M.adjustOxyLoss(get_damage)
+ return 1
+
+/datum/symptom/asphyxiation/proc/Asphyxiate(mob/living/M, datum/disease/advance/A)
+ var/get_damage = rand(15,21) * power
+ M.adjustOxyLoss(get_damage)
+ if(paralysis)
+ M.reagents.add_reagent_list(list(/datum/reagent/toxin/pancuronium = 3, /datum/reagent/toxin/sodium_thiopental = 3))
+ return 1
+
+/datum/symptom/asphyxiation/proc/Asphyxiate_death(mob/living/M, datum/disease/advance/A)
+ var/get_damage = rand(25,35) * power
+ M.adjustOxyLoss(get_damage)
+ M.adjustOrganLoss(ORGAN_SLOT_BRAIN, get_damage/2)
+ return 1
diff --git a/code/datums/diseases/advance/symptoms/confusion.dm b/code/datums/diseases/advance/symptoms/confusion.dm
index fa6494cd83..b8a1064c34 100644
--- a/code/datums/diseases/advance/symptoms/confusion.dm
+++ b/code/datums/diseases/advance/symptoms/confusion.dm
@@ -1,63 +1,63 @@
-/*
-//////////////////////////////////////
-
-Confusion
-
- Little bit hidden.
- Lowers resistance.
- Decreases stage speed.
- Not very transmissibile.
- Intense Level.
-
-Bonus
- Makes the affected mob be confused for short periods of time.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/confusion
-
- name = "Confusion"
- desc = "The virus interferes with the proper function of the neural system, leading to bouts of confusion and erratic movement."
- stealth = 1
- resistance = -1
- stage_speed = -3
- transmittable = 0
- level = 4
- severity = 2
- base_message_chance = 25
- symptom_delay_min = 10
- symptom_delay_max = 30
- var/brain_damage = FALSE
- threshold_desc = list(
- "Resistance 6" = "Causes brain damage over time.",
- "Transmission 6" = "Increases confusion duration and strength.",
- "Stealth 4" = "The symptom remains hidden until active.",
- )
-
-/datum/symptom/confusion/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["resistance"] >= 6)
- brain_damage = TRUE
- if(A.properties["transmittable"] >= 6)
- power = 1.5
- if(A.properties["stealth"] >= 4)
- suppress_warning = TRUE
-
-/datum/symptom/confusion/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/carbon/M = A.affected_mob
- switch(A.stage)
- if(1, 2, 3, 4)
- if(prob(base_message_chance) && !suppress_warning)
- to_chat(M, "[pick("Your head hurts.", "Your mind blanks for a moment.")]")
- else
- to_chat(M, "You can't think straight!")
- M.confused = min(100 * power, M.confused + 8)
- if(brain_damage)
- M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3 * power, 80)
- M.updatehealth()
-
- return
+/*
+//////////////////////////////////////
+
+Confusion
+
+ Little bit hidden.
+ Lowers resistance.
+ Decreases stage speed.
+ Not very transmissibile.
+ Intense Level.
+
+Bonus
+ Makes the affected mob be confused for short periods of time.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/confusion
+
+ name = "Confusion"
+ desc = "The virus interferes with the proper function of the neural system, leading to bouts of confusion and erratic movement."
+ stealth = 1
+ resistance = -1
+ stage_speed = -3
+ transmittable = 0
+ level = 4
+ severity = 2
+ base_message_chance = 25
+ symptom_delay_min = 10
+ symptom_delay_max = 30
+ var/brain_damage = FALSE
+ threshold_desc = list(
+ "Resistance 6" = "Causes brain damage over time.",
+ "Transmission 6" = "Increases confusion duration and strength.",
+ "Stealth 4" = "The symptom remains hidden until active.",
+ )
+
+/datum/symptom/confusion/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["resistance"] >= 6)
+ brain_damage = TRUE
+ if(A.properties["transmittable"] >= 6)
+ power = 1.5
+ if(A.properties["stealth"] >= 4)
+ suppress_warning = TRUE
+
+/datum/symptom/confusion/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/carbon/M = A.affected_mob
+ switch(A.stage)
+ if(1, 2, 3, 4)
+ if(prob(base_message_chance) && !suppress_warning)
+ to_chat(M, "[pick("Your head hurts.", "Your mind blanks for a moment.")]")
+ else
+ to_chat(M, "You can't think straight!")
+ M.confused = min(100 * power, M.confused + 8)
+ if(brain_damage)
+ M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3 * power, 80)
+ M.updatehealth()
+
+ return
diff --git a/code/datums/diseases/advance/symptoms/cough.dm b/code/datums/diseases/advance/symptoms/cough.dm
index c3144fb6ff..ef318d7da3 100644
--- a/code/datums/diseases/advance/symptoms/cough.dm
+++ b/code/datums/diseases/advance/symptoms/cough.dm
@@ -1,76 +1,76 @@
-/*
-//////////////////////////////////////
-
-Coughing
-
- Noticable.
- Little Resistance.
- Doesn't increase stage speed much.
- Transmissibile.
- Low Level.
-
-BONUS
- Will force the affected mob to drop small items!
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/cough
-
- name = "Cough"
- desc = "The virus irritates the throat of the host, causing occasional coughing."
- stealth = -1
- resistance = 3
- stage_speed = 1
- transmittable = 2
- level = 1
- severity = 1
- base_message_chance = 15
- symptom_delay_min = 2
- symptom_delay_max = 15
- var/infective = FALSE
- threshold_desc = list(
- "Resistance 11" = "The host will drop small items when coughing.",
- "Resistance 15" = "Occasionally causes coughing fits that stun the host. The extra coughs do not spread the virus.",
- "Stage Speed 6" = "Increases cough frequency.",
- "Transmission 7" = "Coughing will now infect bystanders up to 2 tiles away.",
- "Stealth 4" = "The symptom remains hidden until active.",
- )
-/datum/symptom/cough/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stealth"] >= 4)
- suppress_warning = TRUE
- if(A.spread_flags &= DISEASE_SPREAD_AIRBORNE) //infect bystanders
- infective = TRUE
- if(A.properties["resistance"] >= 3) //strong enough to drop items
- power = 1.5
- if(A.properties["resistance"] >= 10) //strong enough to stun (rarely)
- power = 2
- if(A.properties["stage_rate"] >= 6) //cough more often
- symptom_delay_max = 10
-
-/datum/symptom/cough/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/M = A.affected_mob
- switch(A.stage)
- if(1, 2, 3)
- if(prob(base_message_chance) && !suppress_warning)
- to_chat(M, "[pick("You swallow excess mucus.", "You lightly cough.")]")
- else
- M.emote("cough")
- if(power >= 1.5)
- var/obj/item/I = M.get_active_held_item()
- if(I && I.w_class == WEIGHT_CLASS_TINY)
- M.dropItemToGround(I)
- if(power >= 2 && prob(10))
- to_chat(M, "[pick("You have a coughing fit!", "You can't stop coughing!")]")
- M.Stun(20)
- M.emote("cough")
- addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 6)
- addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 12)
- addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 18)
- if(infective && M.CanSpreadAirborneDisease())
- A.spread(1)
-
+/*
+//////////////////////////////////////
+
+Coughing
+
+ Noticable.
+ Little Resistance.
+ Doesn't increase stage speed much.
+ Transmissibile.
+ Low Level.
+
+BONUS
+ Will force the affected mob to drop small items!
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/cough
+
+ name = "Cough"
+ desc = "The virus irritates the throat of the host, causing occasional coughing."
+ stealth = -1
+ resistance = 3
+ stage_speed = 1
+ transmittable = 2
+ level = 1
+ severity = 1
+ base_message_chance = 15
+ symptom_delay_min = 2
+ symptom_delay_max = 15
+ var/infective = FALSE
+ threshold_desc = list(
+ "Resistance 11" = "The host will drop small items when coughing.",
+ "Resistance 15" = "Occasionally causes coughing fits that stun the host. The extra coughs do not spread the virus.",
+ "Stage Speed 6" = "Increases cough frequency.",
+ "Transmission 7" = "Coughing will now infect bystanders up to 2 tiles away.",
+ "Stealth 4" = "The symptom remains hidden until active.",
+ )
+/datum/symptom/cough/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stealth"] >= 4)
+ suppress_warning = TRUE
+ if(A.spread_flags &= DISEASE_SPREAD_AIRBORNE) //infect bystanders
+ infective = TRUE
+ if(A.properties["resistance"] >= 3) //strong enough to drop items
+ power = 1.5
+ if(A.properties["resistance"] >= 10) //strong enough to stun (rarely)
+ power = 2
+ if(A.properties["stage_rate"] >= 6) //cough more often
+ symptom_delay_max = 10
+
+/datum/symptom/cough/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/M = A.affected_mob
+ switch(A.stage)
+ if(1, 2, 3)
+ if(prob(base_message_chance) && !suppress_warning)
+ to_chat(M, "[pick("You swallow excess mucus.", "You lightly cough.")]")
+ else
+ M.emote("cough")
+ if(power >= 1.5)
+ var/obj/item/I = M.get_active_held_item()
+ if(I && I.w_class == WEIGHT_CLASS_TINY)
+ M.dropItemToGround(I)
+ if(power >= 2 && prob(10))
+ to_chat(M, "[pick("You have a coughing fit!", "You can't stop coughing!")]")
+ M.Stun(20)
+ M.emote("cough")
+ addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 6)
+ addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 12)
+ addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 18)
+ if(infective && M.CanSpreadAirborneDisease())
+ A.spread(1)
+
diff --git a/code/datums/diseases/advance/symptoms/deafness.dm b/code/datums/diseases/advance/symptoms/deafness.dm
index 4d4aa6dee5..b6dd185b36 100644
--- a/code/datums/diseases/advance/symptoms/deafness.dm
+++ b/code/datums/diseases/advance/symptoms/deafness.dm
@@ -1,61 +1,61 @@
-/*
-//////////////////////////////////////
-
-Deafness
-
- Slightly noticable.
- Lowers resistance.
- Decreases stage speed slightly.
- Decreases transmittablity.
- Intense Level.
-
-Bonus
- Causes intermittent loss of hearing.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/deafness
-
- name = "Deafness"
- desc = "The virus causes inflammation of the eardrums, causing intermittent deafness."
- stealth = -1
- resistance = -2
- stage_speed = -1
- transmittable = -3
- level = 4
- severity = 4
- base_message_chance = 100
- symptom_delay_min = 25
- symptom_delay_max = 80
- threshold_desc = list(
- "Resistance 9" = "Causes permanent deafness, instead of intermittent.",
- "Stealth 4" = "The symptom remains hidden until active.",
- )
-
-/datum/symptom/deafness/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stealth"] >= 4)
- suppress_warning = TRUE
- if(A.properties["resistance"] >= 9) //permanent deafness
- power = 2
-
-/datum/symptom/deafness/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/carbon/M = A.affected_mob
- switch(A.stage)
- if(3, 4)
- if(prob(base_message_chance) && !suppress_warning)
- to_chat(M, "[pick("You hear a ringing in your ear.", "Your ears pop.")]")
- if(5)
- if(power > 2)
- var/obj/item/organ/ears/ears = M.getorganslot(ORGAN_SLOT_EARS)
- if(istype(ears) && ears.damage < ears.maxHealth)
- to_chat(M, "Your ears pop painfully and start bleeding!")
- ears.damage = max(ears.damage, ears.maxHealth)
- M.emote("scream")
- else
- to_chat(M, "Your ears pop and begin ringing loudly!")
- M.minimumDeafTicks(20)
+/*
+//////////////////////////////////////
+
+Deafness
+
+ Slightly noticable.
+ Lowers resistance.
+ Decreases stage speed slightly.
+ Decreases transmittablity.
+ Intense Level.
+
+Bonus
+ Causes intermittent loss of hearing.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/deafness
+
+ name = "Deafness"
+ desc = "The virus causes inflammation of the eardrums, causing intermittent deafness."
+ stealth = -1
+ resistance = -2
+ stage_speed = -1
+ transmittable = -3
+ level = 4
+ severity = 4
+ base_message_chance = 100
+ symptom_delay_min = 25
+ symptom_delay_max = 80
+ threshold_desc = list(
+ "Resistance 9" = "Causes permanent deafness, instead of intermittent.",
+ "Stealth 4" = "The symptom remains hidden until active.",
+ )
+
+/datum/symptom/deafness/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stealth"] >= 4)
+ suppress_warning = TRUE
+ if(A.properties["resistance"] >= 9) //permanent deafness
+ power = 2
+
+/datum/symptom/deafness/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/carbon/M = A.affected_mob
+ switch(A.stage)
+ if(3, 4)
+ if(prob(base_message_chance) && !suppress_warning)
+ to_chat(M, "[pick("You hear a ringing in your ear.", "Your ears pop.")]")
+ if(5)
+ if(power > 2)
+ var/obj/item/organ/ears/ears = M.getorganslot(ORGAN_SLOT_EARS)
+ if(istype(ears) && ears.damage < ears.maxHealth)
+ to_chat(M, "Your ears pop painfully and start bleeding!")
+ ears.damage = max(ears.damage, ears.maxHealth)
+ M.emote("scream")
+ else
+ to_chat(M, "Your ears pop and begin ringing loudly!")
+ M.minimumDeafTicks(20)
diff --git a/code/datums/diseases/advance/symptoms/dizzy.dm b/code/datums/diseases/advance/symptoms/dizzy.dm
index 6f2da5d02c..be444e3916 100644
--- a/code/datums/diseases/advance/symptoms/dizzy.dm
+++ b/code/datums/diseases/advance/symptoms/dizzy.dm
@@ -1,55 +1,55 @@
-/*
-//////////////////////////////////////
-
-Dizziness
-
- Hidden.
- Lowers resistance considerably.
- Decreases stage speed.
- Reduced transmittability
- Intense Level.
-
-Bonus
- Shakes the affected mob's screen for short periods.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/dizzy // Not the egg
-
- name = "Dizziness"
- desc = "The virus causes inflammation of the vestibular system, leading to bouts of dizziness."
- resistance = -2
- stage_speed = -3
- transmittable = -1
- level = 4
- severity = 2
- base_message_chance = 50
- symptom_delay_min = 15
- symptom_delay_max = 40
- threshold_desc = list(
- "Transmission 6" = "Also causes druggy vision.",
- "Stealth 4" = "The symptom remains hidden until active.",
- )
-
-/datum/symptom/dizzy/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stealth"] >= 4)
- suppress_warning = TRUE
- if(A.properties["transmittable"] >= 6) //druggy
- power = 2
-
-/datum/symptom/dizzy/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/M = A.affected_mob
- switch(A.stage)
- if(1, 2, 3, 4)
- if(prob(base_message_chance) && !suppress_warning)
- to_chat(M, "[pick("You feel dizzy.", "Your head spins.")]")
- else
- to_chat(M, "A wave of dizziness washes over you!")
- M.Dizzy(5)
- if(power >= 2)
+/*
+//////////////////////////////////////
+
+Dizziness
+
+ Hidden.
+ Lowers resistance considerably.
+ Decreases stage speed.
+ Reduced transmittability
+ Intense Level.
+
+Bonus
+ Shakes the affected mob's screen for short periods.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/dizzy // Not the egg
+
+ name = "Dizziness"
+ desc = "The virus causes inflammation of the vestibular system, leading to bouts of dizziness."
+ resistance = -2
+ stage_speed = -3
+ transmittable = -1
+ level = 4
+ severity = 2
+ base_message_chance = 50
+ symptom_delay_min = 15
+ symptom_delay_max = 40
+ threshold_desc = list(
+ "Transmission 6" = "Also causes druggy vision.",
+ "Stealth 4" = "The symptom remains hidden until active.",
+ )
+
+/datum/symptom/dizzy/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stealth"] >= 4)
+ suppress_warning = TRUE
+ if(A.properties["transmittable"] >= 6) //druggy
+ power = 2
+
+/datum/symptom/dizzy/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/M = A.affected_mob
+ switch(A.stage)
+ if(1, 2, 3, 4)
+ if(prob(base_message_chance) && !suppress_warning)
+ to_chat(M, "[pick("You feel dizzy.", "Your head spins.")]")
+ else
+ to_chat(M, "A wave of dizziness washes over you!")
+ M.Dizzy(5)
+ if(power >= 2)
M.set_drugginess(5)
\ No newline at end of file
diff --git a/code/datums/diseases/advance/symptoms/fever.dm b/code/datums/diseases/advance/symptoms/fever.dm
index 091fe453a1..0348e39818 100644
--- a/code/datums/diseases/advance/symptoms/fever.dm
+++ b/code/datums/diseases/advance/symptoms/fever.dm
@@ -1,61 +1,61 @@
-/*
-//////////////////////////////////////
-
-Fever
-
- No change to hidden.
- Increases resistance.
- Increases stage speed.
- Little transmittable.
- Low level.
-
-Bonus
- Heats up your body.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/fever
- name = "Fever"
- desc = "The virus causes a febrile response from the host, raising its body temperature."
- stealth = 0
- resistance = 3
- stage_speed = 3
- transmittable = 2
- level = 2
- severity = 2
- base_message_chance = 20
- symptom_delay_min = 10
- symptom_delay_max = 30
- var/unsafe = FALSE //over the heat threshold
- threshold_desc = list(
- "Resistance 5" = "Increases fever intensity, fever can overheat and harm the host.",
- "Resistance 10" = "Further increases fever intensity.",
- )
-/datum/symptom/fever/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["resistance"] >= 5) //dangerous fever
- power = 1.5
- unsafe = TRUE
- if(A.properties["resistance"] >= 10)
- power = 2.5
-
-/datum/symptom/fever/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/carbon/M = A.affected_mob
- if(!unsafe || A.stage < 4)
- to_chat(M, "[pick("You feel hot.", "You feel like you're burning.")]")
- else
- to_chat(M, "[pick("You feel too hot.", "You feel like your blood is boiling.")]")
- if(M.bodytemperature < BODYTEMP_HEAT_DAMAGE_LIMIT || unsafe)
- Heat(M, A)
-
-/datum/symptom/fever/proc/Heat(mob/living/M, datum/disease/advance/A)
- var/get_heat = 6 * power
- if(!unsafe)
- M.adjust_bodytemperature(get_heat * A.stage, 0, BODYTEMP_HEAT_DAMAGE_LIMIT - 1)
- else
- M.adjust_bodytemperature(get_heat * A.stage)
- return 1
+/*
+//////////////////////////////////////
+
+Fever
+
+ No change to hidden.
+ Increases resistance.
+ Increases stage speed.
+ Little transmittable.
+ Low level.
+
+Bonus
+ Heats up your body.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/fever
+ name = "Fever"
+ desc = "The virus causes a febrile response from the host, raising its body temperature."
+ stealth = 0
+ resistance = 3
+ stage_speed = 3
+ transmittable = 2
+ level = 2
+ severity = 2
+ base_message_chance = 20
+ symptom_delay_min = 10
+ symptom_delay_max = 30
+ var/unsafe = FALSE //over the heat threshold
+ threshold_desc = list(
+ "Resistance 5" = "Increases fever intensity, fever can overheat and harm the host.",
+ "Resistance 10" = "Further increases fever intensity.",
+ )
+/datum/symptom/fever/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["resistance"] >= 5) //dangerous fever
+ power = 1.5
+ unsafe = TRUE
+ if(A.properties["resistance"] >= 10)
+ power = 2.5
+
+/datum/symptom/fever/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/carbon/M = A.affected_mob
+ if(!unsafe || A.stage < 4)
+ to_chat(M, "[pick("You feel hot.", "You feel like you're burning.")]")
+ else
+ to_chat(M, "[pick("You feel too hot.", "You feel like your blood is boiling.")]")
+ if(M.bodytemperature < BODYTEMP_HEAT_DAMAGE_LIMIT || unsafe)
+ Heat(M, A)
+
+/datum/symptom/fever/proc/Heat(mob/living/M, datum/disease/advance/A)
+ var/get_heat = 6 * power
+ if(!unsafe)
+ M.adjust_bodytemperature(get_heat * A.stage, 0, BODYTEMP_HEAT_DAMAGE_LIMIT - 1)
+ else
+ M.adjust_bodytemperature(get_heat * A.stage)
+ return 1
diff --git a/code/datums/diseases/advance/symptoms/flesh_eating.dm b/code/datums/diseases/advance/symptoms/flesh_eating.dm
index 58b2d479b7..769a9725aa 100644
--- a/code/datums/diseases/advance/symptoms/flesh_eating.dm
+++ b/code/datums/diseases/advance/symptoms/flesh_eating.dm
@@ -1,136 +1,136 @@
-/*
-//////////////////////////////////////
-
-Necrotizing Fasciitis (AKA Flesh-Eating Disease)
-
- Very very noticable.
- Lowers resistance tremendously.
- No changes to stage speed.
- Decreases transmittablity temrendously.
- Fatal Level.
-
-Bonus
- Deals brute damage over time.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/flesh_eating
-
- name = "Necrotizing Fasciitis"
- desc = "The virus aggressively attacks body cells, necrotizing tissues and organs."
- stealth = -3
- resistance = -4
- stage_speed = 0
- transmittable = -4
- level = 6
- severity = 5
- base_message_chance = 50
- symptom_delay_min = 15
- symptom_delay_max = 60
- var/bleed = FALSE
- var/pain = FALSE
- threshold_desc = list(
- "Resistance 9" = "Doubles the intensity of the immolation effect, but reduces the frequency of all of this symptom's effects.",
- "Stage Speed 8" = "Increases explosion radius and explosion damage to the host when the host is wet.",
- "Transmission 8" = "Additionally synthesizes chlorine trifluoride and napalm inside the host. More chemicals are synthesized if the resistance 9 threshold has been met."
- )
-
-/datum/symptom/flesh_eating/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["resistance"] >= 7) //extra bleeding
- bleed = TRUE
- if(A.properties["transmittable"] >= 8) //extra stamina damage
- pain = TRUE
-
-/datum/symptom/flesh_eating/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/M = A.affected_mob
- switch(A.stage)
- if(2,3)
- if(prob(base_message_chance))
- to_chat(M, "[pick("You feel a sudden pain across your body.", "Drops of blood appear suddenly on your skin.")]")
- if(4,5)
- to_chat(M, "[pick("You cringe as a violent pain takes over your body.", "It feels like your body is eating itself inside out.", "IT HURTS.")]")
- Flesheat(M, A)
-
-/datum/symptom/flesh_eating/proc/Flesheat(mob/living/M, datum/disease/advance/A)
- var/get_damage = rand(15,25) * power
- M.adjustBruteLoss(get_damage)
- if(pain)
- M.adjustStaminaLoss(get_damage)
- if(bleed)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- H.bleed_rate += 5 * power
- return 1
-
-/*
-//////////////////////////////////////
-
-Autophagocytosis (AKA Programmed mass cell death)
-
- Very noticable.
- Lowers resistance.
- Fast stage speed.
- Decreases transmittablity.
- Fatal Level.
-
-Bonus
- Deals brute damage over time.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/flesh_death
-
- name = "Autophagocytosis Necrosis"
- desc = "The virus rapidly consumes infected cells, leading to heavy and widespread damage."
- stealth = -2
- resistance = -2
- stage_speed = 1
- transmittable = -2
- level = 7
- severity = 6
- base_message_chance = 50
- symptom_delay_min = 3
- symptom_delay_max = 6
- var/chems = FALSE
- var/zombie = FALSE
- threshold_desc = list(
- "Stage Speed 7" = "Synthesizes Heparin and Lipolicide inside the host, causing increased bleeding and hunger.",
- "Stealth 5" = "The symptom remains hidden until active.",
- )
-
-
-/datum/symptom/flesh_death/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stealth"] >= 5)
- suppress_warning = TRUE
- if(A.properties["stage_rate"] >= 7) //bleeding and hunger
- chems = TRUE
-
-/datum/symptom/flesh_death/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/M = A.affected_mob
- switch(A.stage)
- if(2,3)
- if(prob(base_message_chance) && !suppress_warning)
- to_chat(M, "[pick("You feel your body break apart.", "Your skin rubs off like dust.")]")
- if(4,5)
- if(prob(base_message_chance / 2)) //reduce spam
- to_chat(M, "[pick("You feel your muscles weakening.", "Some of your skin detaches itself.", "You feel sandy.")]")
- Flesh_death(M, A)
-
-/datum/symptom/flesh_death/proc/Flesh_death(mob/living/M, datum/disease/advance/A)
- var/get_damage = rand(6,10)
- M.adjustBruteLoss(get_damage)
- if(chems)
- M.reagents.add_reagent_list(list(/datum/reagent/toxin/heparin = 2, /datum/reagent/toxin/lipolicide = 2))
- if(zombie)
- M.reagents.add_reagent(/datum/reagent/romerol, 1)
+/*
+//////////////////////////////////////
+
+Necrotizing Fasciitis (AKA Flesh-Eating Disease)
+
+ Very very noticable.
+ Lowers resistance tremendously.
+ No changes to stage speed.
+ Decreases transmittablity temrendously.
+ Fatal Level.
+
+Bonus
+ Deals brute damage over time.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/flesh_eating
+
+ name = "Necrotizing Fasciitis"
+ desc = "The virus aggressively attacks body cells, necrotizing tissues and organs."
+ stealth = -3
+ resistance = -4
+ stage_speed = 0
+ transmittable = -4
+ level = 6
+ severity = 5
+ base_message_chance = 50
+ symptom_delay_min = 15
+ symptom_delay_max = 60
+ var/bleed = FALSE
+ var/pain = FALSE
+ threshold_desc = list(
+ "Resistance 9" = "Doubles the intensity of the immolation effect, but reduces the frequency of all of this symptom's effects.",
+ "Stage Speed 8" = "Increases explosion radius and explosion damage to the host when the host is wet.",
+ "Transmission 8" = "Additionally synthesizes chlorine trifluoride and napalm inside the host. More chemicals are synthesized if the resistance 9 threshold has been met."
+ )
+
+/datum/symptom/flesh_eating/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["resistance"] >= 7) //extra bleeding
+ bleed = TRUE
+ if(A.properties["transmittable"] >= 8) //extra stamina damage
+ pain = TRUE
+
+/datum/symptom/flesh_eating/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/M = A.affected_mob
+ switch(A.stage)
+ if(2,3)
+ if(prob(base_message_chance))
+ to_chat(M, "[pick("You feel a sudden pain across your body.", "Drops of blood appear suddenly on your skin.")]")
+ if(4,5)
+ to_chat(M, "[pick("You cringe as a violent pain takes over your body.", "It feels like your body is eating itself inside out.", "IT HURTS.")]")
+ Flesheat(M, A)
+
+/datum/symptom/flesh_eating/proc/Flesheat(mob/living/M, datum/disease/advance/A)
+ var/get_damage = rand(15,25) * power
+ M.adjustBruteLoss(get_damage)
+ if(pain)
+ M.adjustStaminaLoss(get_damage)
+ if(bleed)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ H.bleed_rate += 5 * power
+ return 1
+
+/*
+//////////////////////////////////////
+
+Autophagocytosis (AKA Programmed mass cell death)
+
+ Very noticable.
+ Lowers resistance.
+ Fast stage speed.
+ Decreases transmittablity.
+ Fatal Level.
+
+Bonus
+ Deals brute damage over time.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/flesh_death
+
+ name = "Autophagocytosis Necrosis"
+ desc = "The virus rapidly consumes infected cells, leading to heavy and widespread damage."
+ stealth = -2
+ resistance = -2
+ stage_speed = 1
+ transmittable = -2
+ level = 7
+ severity = 6
+ base_message_chance = 50
+ symptom_delay_min = 3
+ symptom_delay_max = 6
+ var/chems = FALSE
+ var/zombie = FALSE
+ threshold_desc = list(
+ "Stage Speed 7" = "Synthesizes Heparin and Lipolicide inside the host, causing increased bleeding and hunger.",
+ "Stealth 5" = "The symptom remains hidden until active.",
+ )
+
+
+/datum/symptom/flesh_death/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stealth"] >= 5)
+ suppress_warning = TRUE
+ if(A.properties["stage_rate"] >= 7) //bleeding and hunger
+ chems = TRUE
+
+/datum/symptom/flesh_death/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/M = A.affected_mob
+ switch(A.stage)
+ if(2,3)
+ if(prob(base_message_chance) && !suppress_warning)
+ to_chat(M, "[pick("You feel your body break apart.", "Your skin rubs off like dust.")]")
+ if(4,5)
+ if(prob(base_message_chance / 2)) //reduce spam
+ to_chat(M, "[pick("You feel your muscles weakening.", "Some of your skin detaches itself.", "You feel sandy.")]")
+ Flesh_death(M, A)
+
+/datum/symptom/flesh_death/proc/Flesh_death(mob/living/M, datum/disease/advance/A)
+ var/get_damage = rand(6,10)
+ M.adjustBruteLoss(get_damage)
+ if(chems)
+ M.reagents.add_reagent_list(list(/datum/reagent/toxin/heparin = 2, /datum/reagent/toxin/lipolicide = 2))
+ if(zombie)
+ M.reagents.add_reagent(/datum/reagent/romerol, 1)
return 1
\ No newline at end of file
diff --git a/code/datums/diseases/advance/symptoms/genetics.dm b/code/datums/diseases/advance/symptoms/genetics.dm
index 2a7cb23e96..f6780df3fa 100644
--- a/code/datums/diseases/advance/symptoms/genetics.dm
+++ b/code/datums/diseases/advance/symptoms/genetics.dm
@@ -1,81 +1,81 @@
-/*
-//////////////////////////////////////
-
-DNA Saboteur
-
- Very noticable.
- Lowers resistance tremendously.
- No changes to stage speed.
- Decreases transmittablity tremendously.
- Fatal Level.
-
-Bonus
- Cleans the DNA of a person and then randomly gives them a trait.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/genetic_mutation
- name = "Deoxyribonucleic Acid Saboteur"
- desc = "The virus bonds with the DNA of the host, causing damaging mutations until removed."
- stealth = -2
- resistance = -3
- stage_speed = 0
- transmittable = -3
- level = 6
- severity = 4
- var/list/possible_mutations
- var/archived_dna = null
- base_message_chance = 50
- symptom_delay_min = 60
- symptom_delay_max = 120
- var/no_reset = FALSE
- threshold_desc = list(
- "Resistance 8" = "The negative and mildly negative mutations caused by the virus are mutadone-proof (but will still be undone when the virus is cured if the resistance 14 threshold is not met).",
- "Resistance 14" = "The host's genetic alterations are not undone when the virus is cured.",
- "Stage Speed 10" = "The virus activates dormant mutations at a much faster rate.",
- "Stealth 5" = "Only activates negative mutations in hosts."
- )
-
-/datum/symptom/genetic_mutation/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/carbon/C = A.affected_mob
- if(!C.has_dna())
- return
- switch(A.stage)
- if(4, 5)
- to_chat(C, "[pick("Your skin feels itchy.", "You feel light headed.")]")
- C.dna.remove_mutation_group(possible_mutations)
- for(var/i in 1 to power)
- C.randmut(possible_mutations)
-
-// Archive their DNA before they were infected.
-/datum/symptom/genetic_mutation/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stealth"] >= 5) //don't restore dna after curing
- no_reset = TRUE
- if(A.properties["stage_rate"] >= 10) //mutate more often
- symptom_delay_min = 20
- symptom_delay_max = 60
- if(A.properties["resistance"] >= 8) //mutate twice
- power = 2
- possible_mutations = (GLOB.bad_mutations | GLOB.not_good_mutations) - GLOB.mutations_list[RACEMUT]
- var/mob/living/carbon/M = A.affected_mob
- if(M)
- if(!M.has_dna())
- return
- archived_dna = M.dna.struc_enzymes
-
-// Give them back their old DNA when cured.
-/datum/symptom/genetic_mutation/End(datum/disease/advance/A)
- if(!..())
- return
- if(!no_reset)
- var/mob/living/carbon/M = A.affected_mob
- if(M && archived_dna)
- if(!M.has_dna())
- return
- M.dna.struc_enzymes = archived_dna
- M.domutcheck()
+/*
+//////////////////////////////////////
+
+DNA Saboteur
+
+ Very noticable.
+ Lowers resistance tremendously.
+ No changes to stage speed.
+ Decreases transmittablity tremendously.
+ Fatal Level.
+
+Bonus
+ Cleans the DNA of a person and then randomly gives them a trait.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/genetic_mutation
+ name = "Deoxyribonucleic Acid Saboteur"
+ desc = "The virus bonds with the DNA of the host, causing damaging mutations until removed."
+ stealth = -2
+ resistance = -3
+ stage_speed = 0
+ transmittable = -3
+ level = 6
+ severity = 4
+ var/list/possible_mutations
+ var/archived_dna = null
+ base_message_chance = 50
+ symptom_delay_min = 60
+ symptom_delay_max = 120
+ var/no_reset = FALSE
+ threshold_desc = list(
+ "Resistance 8" = "The negative and mildly negative mutations caused by the virus are mutadone-proof (but will still be undone when the virus is cured if the resistance 14 threshold is not met).",
+ "Resistance 14" = "The host's genetic alterations are not undone when the virus is cured.",
+ "Stage Speed 10" = "The virus activates dormant mutations at a much faster rate.",
+ "Stealth 5" = "Only activates negative mutations in hosts."
+ )
+
+/datum/symptom/genetic_mutation/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/carbon/C = A.affected_mob
+ if(!C.has_dna())
+ return
+ switch(A.stage)
+ if(4, 5)
+ to_chat(C, "[pick("Your skin feels itchy.", "You feel light headed.")]")
+ C.dna.remove_mutation_group(possible_mutations)
+ for(var/i in 1 to power)
+ C.randmut(possible_mutations)
+
+// Archive their DNA before they were infected.
+/datum/symptom/genetic_mutation/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stealth"] >= 5) //don't restore dna after curing
+ no_reset = TRUE
+ if(A.properties["stage_rate"] >= 10) //mutate more often
+ symptom_delay_min = 20
+ symptom_delay_max = 60
+ if(A.properties["resistance"] >= 8) //mutate twice
+ power = 2
+ possible_mutations = (GLOB.bad_mutations | GLOB.not_good_mutations) - GLOB.mutations_list[RACEMUT]
+ var/mob/living/carbon/M = A.affected_mob
+ if(M)
+ if(!M.has_dna())
+ return
+ archived_dna = M.dna.struc_enzymes
+
+// Give them back their old DNA when cured.
+/datum/symptom/genetic_mutation/End(datum/disease/advance/A)
+ if(!..())
+ return
+ if(!no_reset)
+ var/mob/living/carbon/M = A.affected_mob
+ if(M && archived_dna)
+ if(!M.has_dna())
+ return
+ M.dna.struc_enzymes = archived_dna
+ M.domutcheck()
diff --git a/code/datums/diseases/advance/symptoms/hallucigen.dm b/code/datums/diseases/advance/symptoms/hallucigen.dm
index 339df38a37..c8d25e67a4 100644
--- a/code/datums/diseases/advance/symptoms/hallucigen.dm
+++ b/code/datums/diseases/advance/symptoms/hallucigen.dm
@@ -1,67 +1,67 @@
-/*
-//////////////////////////////////////
-
-Hallucigen
-
- Very noticable.
- Lowers resistance considerably.
- Decreases stage speed.
- Reduced transmittable.
- Critical Level.
-
-Bonus
- Makes the affected mob be hallucinated for short periods of time.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/hallucigen
- name = "Hallucigen"
- desc = "The virus stimulates the brain, causing occasional hallucinations."
- stealth = -2
- resistance = -3
- stage_speed = -3
- transmittable = -1
- level = 5
- severity = 2
- base_message_chance = 25
- symptom_delay_min = 25
- symptom_delay_max = 90
- var/fake_healthy = FALSE
- threshold_desc = list(
- "Stage Speed 7" = "Increases the amount of hallucinations.",
- "Stealth 4" = "The virus mimics positive symptoms.",
- )
-
-/datum/symptom/hallucigen/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stealth"] >= 4) //fake good symptom messages
- fake_healthy = TRUE
- base_message_chance = 50
- if(A.properties["stage_rate"] >= 7) //stronger hallucinations
- power = 2
-
-/datum/symptom/hallucigen/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/carbon/M = A.affected_mob
- var/list/healthy_messages = list("Your lungs feel great.", "You realize you haven't been breathing.", "You don't feel the need to breathe.",\
- "Your eyes feel great.", "You are now blinking manually.", "You don't feel the need to blink.")
- switch(A.stage)
- if(1, 2)
- if(prob(base_message_chance))
- if(!fake_healthy)
- to_chat(M, "[pick("Something appears in your peripheral vision, then winks out.", "You hear a faint whisper with no source.", "Your head aches.")]")
- else
- to_chat(M, "[pick(healthy_messages)]")
- if(3, 4)
- if(prob(base_message_chance))
- if(!fake_healthy)
- to_chat(M, "[pick("Something is following you.", "You are being watched.", "You hear a whisper in your ear.", "Thumping footsteps slam toward you from nowhere.")]")
- else
- to_chat(M, "[pick(healthy_messages)]")
- else
- if(prob(base_message_chance))
- to_chat(M, "[pick("Oh, your head...", "Your head pounds.", "They're everywhere! Run!", "Something in the shadows...")]")
- M.hallucination += (45 * power)
+/*
+//////////////////////////////////////
+
+Hallucigen
+
+ Very noticable.
+ Lowers resistance considerably.
+ Decreases stage speed.
+ Reduced transmittable.
+ Critical Level.
+
+Bonus
+ Makes the affected mob be hallucinated for short periods of time.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/hallucigen
+ name = "Hallucigen"
+ desc = "The virus stimulates the brain, causing occasional hallucinations."
+ stealth = -2
+ resistance = -3
+ stage_speed = -3
+ transmittable = -1
+ level = 5
+ severity = 2
+ base_message_chance = 25
+ symptom_delay_min = 25
+ symptom_delay_max = 90
+ var/fake_healthy = FALSE
+ threshold_desc = list(
+ "Stage Speed 7" = "Increases the amount of hallucinations.",
+ "Stealth 4" = "The virus mimics positive symptoms.",
+ )
+
+/datum/symptom/hallucigen/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stealth"] >= 4) //fake good symptom messages
+ fake_healthy = TRUE
+ base_message_chance = 50
+ if(A.properties["stage_rate"] >= 7) //stronger hallucinations
+ power = 2
+
+/datum/symptom/hallucigen/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/carbon/M = A.affected_mob
+ var/list/healthy_messages = list("Your lungs feel great.", "You realize you haven't been breathing.", "You don't feel the need to breathe.",\
+ "Your eyes feel great.", "You are now blinking manually.", "You don't feel the need to blink.")
+ switch(A.stage)
+ if(1, 2)
+ if(prob(base_message_chance))
+ if(!fake_healthy)
+ to_chat(M, "[pick("Something appears in your peripheral vision, then winks out.", "You hear a faint whisper with no source.", "Your head aches.")]")
+ else
+ to_chat(M, "[pick(healthy_messages)]")
+ if(3, 4)
+ if(prob(base_message_chance))
+ if(!fake_healthy)
+ to_chat(M, "[pick("Something is following you.", "You are being watched.", "You hear a whisper in your ear.", "Thumping footsteps slam toward you from nowhere.")]")
+ else
+ to_chat(M, "[pick(healthy_messages)]")
+ else
+ if(prob(base_message_chance))
+ to_chat(M, "[pick("Oh, your head...", "Your head pounds.", "They're everywhere! Run!", "Something in the shadows...")]")
+ M.hallucination += (45 * power)
diff --git a/code/datums/diseases/advance/symptoms/headache.dm b/code/datums/diseases/advance/symptoms/headache.dm
index 8fcab58c0c..944333d9cf 100644
--- a/code/datums/diseases/advance/symptoms/headache.dm
+++ b/code/datums/diseases/advance/symptoms/headache.dm
@@ -1,62 +1,62 @@
-/*
-//////////////////////////////////////
-
-Headache
-
- Noticable.
- Highly resistant.
- Increases stage speed.
- Not transmittable.
- Low Level.
-
-BONUS
- Displays an annoying message!
- Should be used for buffing your disease.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/headache
-
- name = "Headache"
- desc = "The virus causes inflammation inside the brain, causing constant headaches."
- stealth = -1
- resistance = 4
- stage_speed = 2
- transmittable = 0
- level = 1
- severity = 1
- base_message_chance = 100
- symptom_delay_min = 15
- symptom_delay_max = 30
- threshold_desc = list(
- "Stage Speed 6" = "Headaches will cause severe pain, that weakens the host.",
- "Stage Speed 9" = "Headaches become less frequent but far more intense, preventing any action from the host.",
- "Stealth 4" = "Reduces headache frequency until later stages.",
- )
-
-/datum/symptom/headache/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stealth"] >= 4)
- base_message_chance = 50
- if(A.properties["stage_rate"] >= 6) //severe pain
- power = 2
- if(A.properties["stage_rate"] >= 9) //cluster headaches
- symptom_delay_min = 30
- symptom_delay_max = 60
- power = 3
-
-/datum/symptom/headache/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/M = A.affected_mob
- if(power < 2)
- if(prob(base_message_chance) || A.stage >=4)
- to_chat(M, "[pick("Your head hurts.", "Your head pounds.")]")
- if(power >= 2 && A.stage >= 4)
- to_chat(M, "[pick("Your head hurts a lot.", "Your head pounds incessantly.")]")
- M.adjustStaminaLoss(25)
- if(power >= 3 && A.stage >= 5)
- to_chat(M, "[pick("Your head hurts!", "You feel a burning knife inside your brain!", "A wave of pain fills your head!")]")
+/*
+//////////////////////////////////////
+
+Headache
+
+ Noticable.
+ Highly resistant.
+ Increases stage speed.
+ Not transmittable.
+ Low Level.
+
+BONUS
+ Displays an annoying message!
+ Should be used for buffing your disease.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/headache
+
+ name = "Headache"
+ desc = "The virus causes inflammation inside the brain, causing constant headaches."
+ stealth = -1
+ resistance = 4
+ stage_speed = 2
+ transmittable = 0
+ level = 1
+ severity = 1
+ base_message_chance = 100
+ symptom_delay_min = 15
+ symptom_delay_max = 30
+ threshold_desc = list(
+ "Stage Speed 6" = "Headaches will cause severe pain, that weakens the host.",
+ "Stage Speed 9" = "Headaches become less frequent but far more intense, preventing any action from the host.",
+ "Stealth 4" = "Reduces headache frequency until later stages.",
+ )
+
+/datum/symptom/headache/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stealth"] >= 4)
+ base_message_chance = 50
+ if(A.properties["stage_rate"] >= 6) //severe pain
+ power = 2
+ if(A.properties["stage_rate"] >= 9) //cluster headaches
+ symptom_delay_min = 30
+ symptom_delay_max = 60
+ power = 3
+
+/datum/symptom/headache/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/M = A.affected_mob
+ if(power < 2)
+ if(prob(base_message_chance) || A.stage >=4)
+ to_chat(M, "[pick("Your head hurts.", "Your head pounds.")]")
+ if(power >= 2 && A.stage >= 4)
+ to_chat(M, "[pick("Your head hurts a lot.", "Your head pounds incessantly.")]")
+ M.adjustStaminaLoss(25)
+ if(power >= 3 && A.stage >= 5)
+ to_chat(M, "[pick("Your head hurts!", "You feel a burning knife inside your brain!", "A wave of pain fills your head!")]")
M.Stun(35)
\ No newline at end of file
diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm
index 73ea5e2aad..cf14da36a0 100644
--- a/code/datums/diseases/advance/symptoms/heal.dm
+++ b/code/datums/diseases/advance/symptoms/heal.dm
@@ -1,497 +1,497 @@
-/datum/symptom/heal
- name = "Basic Healing (does nothing)" //warning for adminspawn viruses
- desc = "You should not be seeing this."
- stealth = 0
- resistance = 0
- stage_speed = 0
- transmittable = 0
- level = 0 //not obtainable
- base_message_chance = 20 //here used for the overlays
- symptom_delay_min = 1
- symptom_delay_max = 1
- var/passive_message = "" //random message to infected but not actively healing people
- threshold_desc = list(
- "Stage Speed 6" = "Doubles healing speed.",
- "Stealth 4" = "Healing will no longer be visible to onlookers.",
- )
-/datum/symptom/heal/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stage_rate"] >= 6) //stronger healing
- power = 2
-
-/datum/symptom/heal/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/M = A.affected_mob
- switch(A.stage)
- if(4, 5)
- var/effectiveness = CanHeal(A)
- if(!effectiveness)
- if(passive_message && prob(2) && passive_message_condition(M))
- to_chat(M, passive_message)
- return
- else
- Heal(M, A, effectiveness)
- return
-
-/datum/symptom/heal/proc/CanHeal(datum/disease/advance/A)
- return power
-
-/datum/symptom/heal/proc/Heal(mob/living/M, datum/disease/advance/A, actual_power)
- return TRUE
-
-/datum/symptom/heal/proc/passive_message_condition(mob/living/M)
- return TRUE
-
-
-/datum/symptom/heal/starlight
- name = "Starlight Condensation"
- desc = "The virus reacts to direct starlight, producing regenerative chemicals. Works best against toxin-based damage."
- stealth = -1
- resistance = -2
- stage_speed = 0
- transmittable = 1
- level = 6
- passive_message = "You miss the feeling of starlight on your skin."
- var/nearspace_penalty = 0.3
- threshold_desc = list(
- "Stage Speed 6" = "Increases healing speed.",
- "Transmission 6" = "Removes penalty for only being close to space.",
- )
-
-/datum/symptom/heal/starlight/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["transmittable"] >= 6)
- nearspace_penalty = 1
- if(A.properties["stage_rate"] >= 6)
- power = 2
-
-/datum/symptom/heal/starlight/CanHeal(datum/disease/advance/A)
- var/mob/living/M = A.affected_mob
- if(istype(get_turf(M), /turf/open/space))
- return power
- else
- for(var/turf/T in view(M, 2))
- if(istype(T, /turf/open/space))
- return power * nearspace_penalty
-
-/datum/symptom/heal/starlight/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
- var/heal_amt = actual_power
- if(M.getToxLoss() && prob(5))
- to_chat(M, "Your skin tingles as the starlight seems to heal you.")
-
- M.adjustToxLoss(-(4 * heal_amt), forced = TRUE) //most effective on toxins
-
- var/list/parts = M.get_damaged_bodyparts(1,1)
-
- if(!parts.len)
- return
-
- for(var/obj/item/bodypart/L in parts)
- if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
- M.update_damage_overlays()
- return 1
-
-/datum/symptom/heal/starlight/passive_message_condition(mob/living/M)
- if(M.getBruteLoss() || M.getFireLoss() || M.getToxLoss())
- return TRUE
- return FALSE
-
-/datum/symptom/heal/chem
- name = "Toxolysis"
- stealth = 0
- resistance = -2
- stage_speed = 2
- transmittable = -2
- level = 7
- var/food_conversion = FALSE
- desc = "The virus rapidly breaks down any foreign chemicals in the bloodstream."
- threshold_desc = list(
- "Resistance 7" = "Increases chem removal speed.",
- "Stage Speed 6" = "Consumed chemicals nourish the host.",
- )
-
-/datum/symptom/heal/chem/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stage_rate"] >= 6)
- food_conversion = TRUE
- if(A.properties["resistance"] >= 7)
- power = 2
-
-/datum/symptom/heal/chem/Heal(mob/living/M, datum/disease/advance/A, actual_power)
- for(var/E in M.reagents.reagent_list) //Not just toxins!
- var/datum/reagent/R = E
- M.reagents.remove_reagent(R.type, actual_power)
- if(food_conversion)
- M.nutrition += 0.3
- if(prob(2))
- to_chat(M, "You feel a mild warmth as your blood purifies itself.")
- return 1
-
-
-
-/datum/symptom/heal/metabolism
- name = "Metabolic Boost"
- stealth = -1
- resistance = -2
- stage_speed = 2
- transmittable = 1
- level = 7
- var/triple_metabolism = FALSE
- var/reduced_hunger = FALSE
- desc = "The virus causes the host's metabolism to accelerate rapidly, making them process chemicals twice as fast,\
- but also causing increased hunger."
- threshold_desc = list(
- "Stealth 3" = "Reduces hunger rate.",
- "Stage Speed 10" = "Chemical metabolization is tripled instead of doubled.",
- )
-/datum/symptom/heal/metabolism/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stage_rate"] >= 10)
- triple_metabolism = TRUE
- if(A.properties["stealth"] >= 3)
- reduced_hunger = TRUE
-
-/datum/symptom/heal/metabolism/Heal(mob/living/carbon/C, datum/disease/advance/A, actual_power)
- if(!istype(C))
- return
- C.reagents.metabolize(C, can_overdose=TRUE) //this works even without a liver; it's intentional since the virus is metabolizing by itself
- if(triple_metabolism)
- C.reagents.metabolize(C, can_overdose=TRUE)
- C.overeatduration = max(C.overeatduration - 2, 0)
- var/lost_nutrition = 9 - (reduced_hunger * 5)
- C.nutrition = max(C.nutrition - (lost_nutrition * HUNGER_FACTOR), 0) //Hunger depletes at 10x the normal speed
- if(prob(2))
- to_chat(C, "You feel an odd gurgle in your stomach, as if it was working much faster than normal.")
- return 1
-
-/datum/symptom/heal/darkness
- name = "Nocturnal Regeneration"
- desc = "The virus is able to mend the host's flesh when in conditions of low light, repairing physical damage. More effective against brute damage."
- stealth = 2
- resistance = -1
- stage_speed = -2
- transmittable = -1
- level = 6
- passive_message = "You feel tingling on your skin as light passes over it."
- threshold_desc = list(
- "Stage Speed 8" = "Doubles healing speed.",
- )
-/datum/symptom/heal/darkness/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stage_rate"] >= 8)
- power = 2
-
-/datum/symptom/heal/darkness/CanHeal(datum/disease/advance/A)
- var/mob/living/M = A.affected_mob
- var/light_amount = 0
- if(isturf(M.loc)) //else, there's considered to be no light
- var/turf/T = M.loc
- light_amount = min(1,T.get_lumcount()) - 0.5
- if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
- return power
-
-/datum/symptom/heal/darkness/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
- var/heal_amt = 2 * actual_power
-
- var/list/parts = M.get_damaged_bodyparts(1,1)
-
- if(!parts.len)
- return
-
- if(prob(5))
- to_chat(M, "The darkness soothes and mends your wounds.")
-
- for(var/obj/item/bodypart/L in parts)
- if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len * 0.5)) //more effective on brute
- M.update_damage_overlays()
- return 1
-
-/datum/symptom/heal/darkness/passive_message_condition(mob/living/M)
- if(M.getBruteLoss() || M.getFireLoss())
- return TRUE
- return FALSE
-
-/datum/symptom/heal/coma
- name = "Regenerative Coma"
- desc = "The virus causes the host to fall into a death-like coma when severely damaged, then rapidly fixes the damage."
- stealth = 0
- resistance = 2
- stage_speed = -3
- transmittable = -2
- level = 8
- passive_message = "The pain from your wounds makes you feel oddly sleepy..."
- var/deathgasp = FALSE
- var/stabilize = FALSE
- var/active_coma = FALSE //to prevent multiple coma procs
- threshold_desc = list(
- "Stealth 2" = "Host appears to die when falling into a coma.",
- "Resistance 4" = "The virus also stabilizes the host while they are in critical condition.",
- "Stage Speed 7" = "Increases healing speed.",
- )
-
-/datum/symptom/heal/coma/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stage_rate"] >= 7)
- power = 1.5
- if(A.properties["resistance"] >= 4)
- stabilize = TRUE
- if(A.properties["stealth"] >= 2)
- deathgasp = TRUE
-
-/datum/symptom/heal/coma/on_stage_change(datum/disease/advance/A) //mostly copy+pasted from the code for self-respiration's TRAIT_NOBREATH stuff
- if(!..())
- return FALSE
- if(A.stage >= 4 && stabilize)
- ADD_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT)
- else
- REMOVE_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT)
- return TRUE
-
-/datum/symptom/heal/coma/End(datum/disease/advance/A)
- if(!..())
- return
- REMOVE_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT)
-
-/datum/symptom/heal/coma/CanHeal(datum/disease/advance/A)
- var/mob/living/M = A.affected_mob
- if(HAS_TRAIT(M, TRAIT_DEATHCOMA))
- return power
- else if(M.IsUnconscious() || M.stat == UNCONSCIOUS)
- return power * 0.9
- else if(M.stat == SOFT_CRIT)
- return power * 0.5
- else if(M.IsSleeping())
- return power * 0.25
- else if(M.getBruteLoss() + M.getFireLoss() >= 70 && !active_coma)
- to_chat(M, "You feel yourself slip into a regenerative coma...")
- active_coma = TRUE
- addtimer(CALLBACK(src, .proc/coma, M), 60)
-
-/datum/symptom/heal/coma/proc/coma(mob/living/M)
- if(deathgasp)
- M.emote("deathgasp")
- M.fakedeath("regenerative_coma")
- M.update_stat()
- M.update_canmove()
- addtimer(CALLBACK(src, .proc/uncoma, M), 300)
-
-/datum/symptom/heal/coma/proc/uncoma(mob/living/M)
- if(!active_coma)
- return
- active_coma = FALSE
- M.cure_fakedeath("regenerative_coma")
- M.update_stat()
- M.update_canmove()
-
-/datum/symptom/heal/coma/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
- var/heal_amt = 4 * actual_power
-
- var/list/parts = M.get_damaged_bodyparts(1,1)
-
- if(!parts.len)
- return
-
- for(var/obj/item/bodypart/L in parts)
- if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
- M.update_damage_overlays()
-
- if(active_coma && M.getBruteLoss() + M.getFireLoss() == 0)
- uncoma(M)
-
- return 1
-
-/datum/symptom/heal/coma/passive_message_condition(mob/living/M)
- if((M.getBruteLoss() + M.getFireLoss()) > 30)
- return TRUE
- return FALSE
-
-/datum/symptom/heal/water
- name = "Tissue Hydration"
- desc = "The virus uses excess water inside and outside the body to repair damaged tissue cells. More effective against burns."
- stealth = 0
- resistance = -1
- stage_speed = 0
- transmittable = 1
- level = 6
- passive_message = "Your skin feels oddly dry..."
- var/absorption_coeff = 1
- threshold_desc = list(
- "Resistance 5" = "Water is consumed at a much slower rate.",
- "Stage Speed 7" = "Increases healing speed.",
- )
-
-/datum/symptom/heal/water/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stage_rate"] >= 7)
- power = 2
- if(A.properties["stealth"] >= 2)
- absorption_coeff = 0.25
-
-/datum/symptom/heal/water/CanHeal(datum/disease/advance/A)
- . = 0
- var/mob/living/M = A.affected_mob
- if(M.fire_stacks < 0)
- M.fire_stacks = min(M.fire_stacks + 1 * absorption_coeff, 0)
- . += power
- if(M.reagents.has_reagent(/datum/reagent/water/holywater))
- M.reagents.remove_reagent(/datum/reagent/water/holywater, 0.5 * absorption_coeff)
- . += power * 0.75
- else if(M.reagents.has_reagent(/datum/reagent/water))
- M.reagents.remove_reagent(/datum/reagent/water, 0.5 * absorption_coeff)
- . += power * 0.5
-
-/datum/symptom/heal/water/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
- var/heal_amt = 2 * actual_power
-
- var/list/parts = M.get_damaged_bodyparts(1,1) //more effective on burns
-
- if(!parts.len)
- return
-
- if(prob(5))
- to_chat(M, "You feel yourself absorbing the water around you to soothe your damaged skin.")
-
- for(var/obj/item/bodypart/L in parts)
- if(L.heal_damage(heal_amt/parts.len * 0.5, heal_amt/parts.len))
- M.update_damage_overlays()
-
- return 1
-
-/datum/symptom/heal/water/passive_message_condition(mob/living/M)
- if(M.getBruteLoss() || M.getFireLoss())
- return TRUE
- return FALSE
-
-/datum/symptom/heal/plasma
- name = "Plasma Fixation"
- desc = "The virus draws plasma from the atmosphere and from inside the body to heal and stabilize body temperature."
- stealth = 0
- resistance = 3
- stage_speed = -2
- transmittable = -2
- level = 8
- passive_message = "You feel an odd attraction to plasma."
- var/temp_rate = 1
- threshold_desc = list(
- "Transmission 6" = "Additionally increases temperature adjustment rate and heals those who love toxins",
- "Resistance 7" = "Increases healing speed.",
- )
-/datum/symptom/heal/plasma/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stage_rate"] >= 7)
- power = 2
- if(A.properties["transmittable"] >= 6)
- temp_rate = 4
-
-/datum/symptom/heal/plasma/CanHeal(datum/disease/advance/A)
- var/mob/living/M = A.affected_mob
- var/datum/gas_mixture/environment
- var/plasmamount
-
- . = 0
-
- if(M.loc)
- environment = M.loc.return_air()
- if(environment)
- plasmamount = environment.gases[/datum/gas/plasma]
- if(plasmamount && plasmamount > GLOB.meta_gas_visibility[/datum/gas/plasma]) //if there's enough plasma in the air to see
- . += power * 0.5
- if(M.reagents.has_reagent(/datum/reagent/toxin/plasma))
- . += power * 0.75
-
-/datum/symptom/heal/plasma/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
- var/heal_amt = 4 * actual_power
-
- if(prob(5))
- to_chat(M, "You feel yourself absorbing plasma inside and around you...")
-
- if(M.bodytemperature > BODYTEMP_NORMAL)
- M.adjust_bodytemperature(-20 * temp_rate * TEMPERATURE_DAMAGE_COEFFICIENT,BODYTEMP_NORMAL)
- if(prob(5))
- to_chat(M, "You feel less hot.")
- else if(M.bodytemperature < (BODYTEMP_NORMAL + 1))
- M.adjust_bodytemperature(20 * temp_rate * TEMPERATURE_DAMAGE_COEFFICIENT,0,BODYTEMP_NORMAL)
- if(prob(5))
- to_chat(M, "You feel warmer.")
-
- M.adjustToxLoss(-heal_amt, forced = (temp_rate == 4))
-
- var/list/parts = M.get_damaged_bodyparts(1,1)
- if(!parts.len)
- return
- if(prob(5))
- to_chat(M, "The pain from your wounds fades rapidly.")
- for(var/obj/item/bodypart/L in parts)
- if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
- M.update_damage_overlays()
- return 1
-
-
-/datum/symptom/heal/radiation
- name = "Radioactive Resonance"
- desc = "The virus uses radiation to fix damage through dna mutations."
- stealth = -1
- resistance = -2
- stage_speed = 2
- transmittable = -3
- level = 6
- symptom_delay_min = 1
- symptom_delay_max = 1
- passive_message = "Your skin glows faintly for a moment."
- var/cellular_damage = FALSE
- threshold_desc = "Transmission 6: Additionally heals cellular damage and toxin lovers. \
- Resistance 7: Increases healing speed."
-
-/datum/symptom/heal/radiation/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["resistance"] >= 7)
- power = 2
- if(A.properties["transmittable"] >= 6)
- cellular_damage = TRUE
-
-/datum/symptom/heal/radiation/CanHeal(datum/disease/advance/A)
- var/mob/living/M = A.affected_mob
- switch(M.radiation)
- if(0)
- return FALSE
- if(1 to RAD_MOB_SAFE)
- return 0.25
- if(RAD_MOB_SAFE to RAD_BURN_THRESHOLD)
- return 0.5
- if(RAD_BURN_THRESHOLD to RAD_MOB_MUTATE)
- return 0.75
- if(RAD_MOB_MUTATE to RAD_MOB_KNOCKDOWN)
- return 1
- else
- return 1.5
-
-/datum/symptom/heal/radiation/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
- var/heal_amt = actual_power
-
- if(cellular_damage)
- M.adjustCloneLoss(-heal_amt * 0.5)
-
- M.adjustToxLoss(-(2 * heal_amt), forced = cellular_damage)
-
- var/list/parts = M.get_damaged_bodyparts(1,1)
-
- if(!parts.len)
- return
-
- if(prob(4))
- to_chat(M, "Your skin glows faintly, and you feel your wounds mending themselves.")
-
- for(var/obj/item/bodypart/L in parts)
- if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
- M.update_damage_overlays()
- return 1
+/datum/symptom/heal
+ name = "Basic Healing (does nothing)" //warning for adminspawn viruses
+ desc = "You should not be seeing this."
+ stealth = 0
+ resistance = 0
+ stage_speed = 0
+ transmittable = 0
+ level = 0 //not obtainable
+ base_message_chance = 20 //here used for the overlays
+ symptom_delay_min = 1
+ symptom_delay_max = 1
+ var/passive_message = "" //random message to infected but not actively healing people
+ threshold_desc = list(
+ "Stage Speed 6" = "Doubles healing speed.",
+ "Stealth 4" = "Healing will no longer be visible to onlookers.",
+ )
+/datum/symptom/heal/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stage_rate"] >= 6) //stronger healing
+ power = 2
+
+/datum/symptom/heal/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/M = A.affected_mob
+ switch(A.stage)
+ if(4, 5)
+ var/effectiveness = CanHeal(A)
+ if(!effectiveness)
+ if(passive_message && prob(2) && passive_message_condition(M))
+ to_chat(M, passive_message)
+ return
+ else
+ Heal(M, A, effectiveness)
+ return
+
+/datum/symptom/heal/proc/CanHeal(datum/disease/advance/A)
+ return power
+
+/datum/symptom/heal/proc/Heal(mob/living/M, datum/disease/advance/A, actual_power)
+ return TRUE
+
+/datum/symptom/heal/proc/passive_message_condition(mob/living/M)
+ return TRUE
+
+
+/datum/symptom/heal/starlight
+ name = "Starlight Condensation"
+ desc = "The virus reacts to direct starlight, producing regenerative chemicals. Works best against toxin-based damage."
+ stealth = -1
+ resistance = -2
+ stage_speed = 0
+ transmittable = 1
+ level = 6
+ passive_message = "You miss the feeling of starlight on your skin."
+ var/nearspace_penalty = 0.3
+ threshold_desc = list(
+ "Stage Speed 6" = "Increases healing speed.",
+ "Transmission 6" = "Removes penalty for only being close to space.",
+ )
+
+/datum/symptom/heal/starlight/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["transmittable"] >= 6)
+ nearspace_penalty = 1
+ if(A.properties["stage_rate"] >= 6)
+ power = 2
+
+/datum/symptom/heal/starlight/CanHeal(datum/disease/advance/A)
+ var/mob/living/M = A.affected_mob
+ if(istype(get_turf(M), /turf/open/space))
+ return power
+ else
+ for(var/turf/T in view(M, 2))
+ if(istype(T, /turf/open/space))
+ return power * nearspace_penalty
+
+/datum/symptom/heal/starlight/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
+ var/heal_amt = actual_power
+ if(M.getToxLoss() && prob(5))
+ to_chat(M, "Your skin tingles as the starlight seems to heal you.")
+
+ M.adjustToxLoss(-(4 * heal_amt), forced = TRUE) //most effective on toxins
+
+ var/list/parts = M.get_damaged_bodyparts(1,1)
+
+ if(!parts.len)
+ return
+
+ for(var/obj/item/bodypart/L in parts)
+ if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
+ M.update_damage_overlays()
+ return 1
+
+/datum/symptom/heal/starlight/passive_message_condition(mob/living/M)
+ if(M.getBruteLoss() || M.getFireLoss() || M.getToxLoss())
+ return TRUE
+ return FALSE
+
+/datum/symptom/heal/chem
+ name = "Toxolysis"
+ stealth = 0
+ resistance = -2
+ stage_speed = 2
+ transmittable = -2
+ level = 7
+ var/food_conversion = FALSE
+ desc = "The virus rapidly breaks down any foreign chemicals in the bloodstream."
+ threshold_desc = list(
+ "Resistance 7" = "Increases chem removal speed.",
+ "Stage Speed 6" = "Consumed chemicals nourish the host.",
+ )
+
+/datum/symptom/heal/chem/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stage_rate"] >= 6)
+ food_conversion = TRUE
+ if(A.properties["resistance"] >= 7)
+ power = 2
+
+/datum/symptom/heal/chem/Heal(mob/living/M, datum/disease/advance/A, actual_power)
+ for(var/E in M.reagents.reagent_list) //Not just toxins!
+ var/datum/reagent/R = E
+ M.reagents.remove_reagent(R.type, actual_power)
+ if(food_conversion)
+ M.nutrition += 0.3
+ if(prob(2))
+ to_chat(M, "You feel a mild warmth as your blood purifies itself.")
+ return 1
+
+
+
+/datum/symptom/heal/metabolism
+ name = "Metabolic Boost"
+ stealth = -1
+ resistance = -2
+ stage_speed = 2
+ transmittable = 1
+ level = 7
+ var/triple_metabolism = FALSE
+ var/reduced_hunger = FALSE
+ desc = "The virus causes the host's metabolism to accelerate rapidly, making them process chemicals twice as fast,\
+ but also causing increased hunger."
+ threshold_desc = list(
+ "Stealth 3" = "Reduces hunger rate.",
+ "Stage Speed 10" = "Chemical metabolization is tripled instead of doubled.",
+ )
+/datum/symptom/heal/metabolism/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stage_rate"] >= 10)
+ triple_metabolism = TRUE
+ if(A.properties["stealth"] >= 3)
+ reduced_hunger = TRUE
+
+/datum/symptom/heal/metabolism/Heal(mob/living/carbon/C, datum/disease/advance/A, actual_power)
+ if(!istype(C))
+ return
+ C.reagents.metabolize(C, can_overdose=TRUE) //this works even without a liver; it's intentional since the virus is metabolizing by itself
+ if(triple_metabolism)
+ C.reagents.metabolize(C, can_overdose=TRUE)
+ C.overeatduration = max(C.overeatduration - 2, 0)
+ var/lost_nutrition = 9 - (reduced_hunger * 5)
+ C.nutrition = max(C.nutrition - (lost_nutrition * HUNGER_FACTOR), 0) //Hunger depletes at 10x the normal speed
+ if(prob(2))
+ to_chat(C, "You feel an odd gurgle in your stomach, as if it was working much faster than normal.")
+ return 1
+
+/datum/symptom/heal/darkness
+ name = "Nocturnal Regeneration"
+ desc = "The virus is able to mend the host's flesh when in conditions of low light, repairing physical damage. More effective against brute damage."
+ stealth = 2
+ resistance = -1
+ stage_speed = -2
+ transmittable = -1
+ level = 6
+ passive_message = "You feel tingling on your skin as light passes over it."
+ threshold_desc = list(
+ "Stage Speed 8" = "Doubles healing speed.",
+ )
+/datum/symptom/heal/darkness/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stage_rate"] >= 8)
+ power = 2
+
+/datum/symptom/heal/darkness/CanHeal(datum/disease/advance/A)
+ var/mob/living/M = A.affected_mob
+ var/light_amount = 0
+ if(isturf(M.loc)) //else, there's considered to be no light
+ var/turf/T = M.loc
+ light_amount = min(1,T.get_lumcount()) - 0.5
+ if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
+ return power
+
+/datum/symptom/heal/darkness/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
+ var/heal_amt = 2 * actual_power
+
+ var/list/parts = M.get_damaged_bodyparts(1,1)
+
+ if(!parts.len)
+ return
+
+ if(prob(5))
+ to_chat(M, "The darkness soothes and mends your wounds.")
+
+ for(var/obj/item/bodypart/L in parts)
+ if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len * 0.5)) //more effective on brute
+ M.update_damage_overlays()
+ return 1
+
+/datum/symptom/heal/darkness/passive_message_condition(mob/living/M)
+ if(M.getBruteLoss() || M.getFireLoss())
+ return TRUE
+ return FALSE
+
+/datum/symptom/heal/coma
+ name = "Regenerative Coma"
+ desc = "The virus causes the host to fall into a death-like coma when severely damaged, then rapidly fixes the damage."
+ stealth = 0
+ resistance = 2
+ stage_speed = -3
+ transmittable = -2
+ level = 8
+ passive_message = "The pain from your wounds makes you feel oddly sleepy..."
+ var/deathgasp = FALSE
+ var/stabilize = FALSE
+ var/active_coma = FALSE //to prevent multiple coma procs
+ threshold_desc = list(
+ "Stealth 2" = "Host appears to die when falling into a coma.",
+ "Resistance 4" = "The virus also stabilizes the host while they are in critical condition.",
+ "Stage Speed 7" = "Increases healing speed.",
+ )
+
+/datum/symptom/heal/coma/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stage_rate"] >= 7)
+ power = 1.5
+ if(A.properties["resistance"] >= 4)
+ stabilize = TRUE
+ if(A.properties["stealth"] >= 2)
+ deathgasp = TRUE
+
+/datum/symptom/heal/coma/on_stage_change(datum/disease/advance/A) //mostly copy+pasted from the code for self-respiration's TRAIT_NOBREATH stuff
+ if(!..())
+ return FALSE
+ if(A.stage >= 4 && stabilize)
+ ADD_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT)
+ else
+ REMOVE_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT)
+ return TRUE
+
+/datum/symptom/heal/coma/End(datum/disease/advance/A)
+ if(!..())
+ return
+ REMOVE_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT)
+
+/datum/symptom/heal/coma/CanHeal(datum/disease/advance/A)
+ var/mob/living/M = A.affected_mob
+ if(HAS_TRAIT(M, TRAIT_DEATHCOMA))
+ return power
+ else if(M.IsUnconscious() || M.stat == UNCONSCIOUS)
+ return power * 0.9
+ else if(M.stat == SOFT_CRIT)
+ return power * 0.5
+ else if(M.IsSleeping())
+ return power * 0.25
+ else if(M.getBruteLoss() + M.getFireLoss() >= 70 && !active_coma)
+ to_chat(M, "You feel yourself slip into a regenerative coma...")
+ active_coma = TRUE
+ addtimer(CALLBACK(src, .proc/coma, M), 60)
+
+/datum/symptom/heal/coma/proc/coma(mob/living/M)
+ if(deathgasp)
+ M.emote("deathgasp")
+ M.fakedeath("regenerative_coma")
+ M.update_stat()
+ M.update_canmove()
+ addtimer(CALLBACK(src, .proc/uncoma, M), 300)
+
+/datum/symptom/heal/coma/proc/uncoma(mob/living/M)
+ if(!active_coma)
+ return
+ active_coma = FALSE
+ M.cure_fakedeath("regenerative_coma")
+ M.update_stat()
+ M.update_canmove()
+
+/datum/symptom/heal/coma/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
+ var/heal_amt = 4 * actual_power
+
+ var/list/parts = M.get_damaged_bodyparts(1,1)
+
+ if(!parts.len)
+ return
+
+ for(var/obj/item/bodypart/L in parts)
+ if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
+ M.update_damage_overlays()
+
+ if(active_coma && M.getBruteLoss() + M.getFireLoss() == 0)
+ uncoma(M)
+
+ return 1
+
+/datum/symptom/heal/coma/passive_message_condition(mob/living/M)
+ if((M.getBruteLoss() + M.getFireLoss()) > 30)
+ return TRUE
+ return FALSE
+
+/datum/symptom/heal/water
+ name = "Tissue Hydration"
+ desc = "The virus uses excess water inside and outside the body to repair damaged tissue cells. More effective against burns."
+ stealth = 0
+ resistance = -1
+ stage_speed = 0
+ transmittable = 1
+ level = 6
+ passive_message = "Your skin feels oddly dry..."
+ var/absorption_coeff = 1
+ threshold_desc = list(
+ "Resistance 5" = "Water is consumed at a much slower rate.",
+ "Stage Speed 7" = "Increases healing speed.",
+ )
+
+/datum/symptom/heal/water/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stage_rate"] >= 7)
+ power = 2
+ if(A.properties["stealth"] >= 2)
+ absorption_coeff = 0.25
+
+/datum/symptom/heal/water/CanHeal(datum/disease/advance/A)
+ . = 0
+ var/mob/living/M = A.affected_mob
+ if(M.fire_stacks < 0)
+ M.fire_stacks = min(M.fire_stacks + 1 * absorption_coeff, 0)
+ . += power
+ if(M.reagents.has_reagent(/datum/reagent/water/holywater))
+ M.reagents.remove_reagent(/datum/reagent/water/holywater, 0.5 * absorption_coeff)
+ . += power * 0.75
+ else if(M.reagents.has_reagent(/datum/reagent/water))
+ M.reagents.remove_reagent(/datum/reagent/water, 0.5 * absorption_coeff)
+ . += power * 0.5
+
+/datum/symptom/heal/water/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
+ var/heal_amt = 2 * actual_power
+
+ var/list/parts = M.get_damaged_bodyparts(1,1) //more effective on burns
+
+ if(!parts.len)
+ return
+
+ if(prob(5))
+ to_chat(M, "You feel yourself absorbing the water around you to soothe your damaged skin.")
+
+ for(var/obj/item/bodypart/L in parts)
+ if(L.heal_damage(heal_amt/parts.len * 0.5, heal_amt/parts.len))
+ M.update_damage_overlays()
+
+ return 1
+
+/datum/symptom/heal/water/passive_message_condition(mob/living/M)
+ if(M.getBruteLoss() || M.getFireLoss())
+ return TRUE
+ return FALSE
+
+/datum/symptom/heal/plasma
+ name = "Plasma Fixation"
+ desc = "The virus draws plasma from the atmosphere and from inside the body to heal and stabilize body temperature."
+ stealth = 0
+ resistance = 3
+ stage_speed = -2
+ transmittable = -2
+ level = 8
+ passive_message = "You feel an odd attraction to plasma."
+ var/temp_rate = 1
+ threshold_desc = list(
+ "Transmission 6" = "Additionally increases temperature adjustment rate and heals those who love toxins",
+ "Resistance 7" = "Increases healing speed.",
+ )
+/datum/symptom/heal/plasma/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stage_rate"] >= 7)
+ power = 2
+ if(A.properties["transmittable"] >= 6)
+ temp_rate = 4
+
+/datum/symptom/heal/plasma/CanHeal(datum/disease/advance/A)
+ var/mob/living/M = A.affected_mob
+ var/datum/gas_mixture/environment
+ var/plasmamount
+
+ . = 0
+
+ if(M.loc)
+ environment = M.loc.return_air()
+ if(environment)
+ plasmamount = environment.gases[/datum/gas/plasma]
+ if(plasmamount && plasmamount > GLOB.meta_gas_visibility[/datum/gas/plasma]) //if there's enough plasma in the air to see
+ . += power * 0.5
+ if(M.reagents.has_reagent(/datum/reagent/toxin/plasma))
+ . += power * 0.75
+
+/datum/symptom/heal/plasma/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
+ var/heal_amt = 4 * actual_power
+
+ if(prob(5))
+ to_chat(M, "You feel yourself absorbing plasma inside and around you...")
+
+ if(M.bodytemperature > BODYTEMP_NORMAL)
+ M.adjust_bodytemperature(-20 * temp_rate * TEMPERATURE_DAMAGE_COEFFICIENT,BODYTEMP_NORMAL)
+ if(prob(5))
+ to_chat(M, "You feel less hot.")
+ else if(M.bodytemperature < (BODYTEMP_NORMAL + 1))
+ M.adjust_bodytemperature(20 * temp_rate * TEMPERATURE_DAMAGE_COEFFICIENT,0,BODYTEMP_NORMAL)
+ if(prob(5))
+ to_chat(M, "You feel warmer.")
+
+ M.adjustToxLoss(-heal_amt, forced = (temp_rate == 4))
+
+ var/list/parts = M.get_damaged_bodyparts(1,1)
+ if(!parts.len)
+ return
+ if(prob(5))
+ to_chat(M, "The pain from your wounds fades rapidly.")
+ for(var/obj/item/bodypart/L in parts)
+ if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
+ M.update_damage_overlays()
+ return 1
+
+
+/datum/symptom/heal/radiation
+ name = "Radioactive Resonance"
+ desc = "The virus uses radiation to fix damage through dna mutations."
+ stealth = -1
+ resistance = -2
+ stage_speed = 2
+ transmittable = -3
+ level = 6
+ symptom_delay_min = 1
+ symptom_delay_max = 1
+ passive_message = "Your skin glows faintly for a moment."
+ var/cellular_damage = FALSE
+ threshold_desc = "Transmission 6: Additionally heals cellular damage and toxin lovers. \
+ Resistance 7: Increases healing speed."
+
+/datum/symptom/heal/radiation/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["resistance"] >= 7)
+ power = 2
+ if(A.properties["transmittable"] >= 6)
+ cellular_damage = TRUE
+
+/datum/symptom/heal/radiation/CanHeal(datum/disease/advance/A)
+ var/mob/living/M = A.affected_mob
+ switch(M.radiation)
+ if(0)
+ return FALSE
+ if(1 to RAD_MOB_SAFE)
+ return 0.25
+ if(RAD_MOB_SAFE to RAD_BURN_THRESHOLD)
+ return 0.5
+ if(RAD_BURN_THRESHOLD to RAD_MOB_MUTATE)
+ return 0.75
+ if(RAD_MOB_MUTATE to RAD_MOB_KNOCKDOWN)
+ return 1
+ else
+ return 1.5
+
+/datum/symptom/heal/radiation/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
+ var/heal_amt = actual_power
+
+ if(cellular_damage)
+ M.adjustCloneLoss(-heal_amt * 0.5)
+
+ M.adjustToxLoss(-(2 * heal_amt), forced = cellular_damage)
+
+ var/list/parts = M.get_damaged_bodyparts(1,1)
+
+ if(!parts.len)
+ return
+
+ if(prob(4))
+ to_chat(M, "Your skin glows faintly, and you feel your wounds mending themselves.")
+
+ for(var/obj/item/bodypart/L in parts)
+ if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
+ M.update_damage_overlays()
+ return 1
diff --git a/code/datums/diseases/advance/symptoms/itching.dm b/code/datums/diseases/advance/symptoms/itching.dm
index edcd1f3a73..c0c312cbc2 100644
--- a/code/datums/diseases/advance/symptoms/itching.dm
+++ b/code/datums/diseases/advance/symptoms/itching.dm
@@ -1,56 +1,56 @@
-/*
-//////////////////////////////////////
-
-Itching
-
- Not noticable or unnoticable.
- Resistant.
- Increases stage speed.
- Little transmissibility.
- Low Level.
-
-BONUS
- Displays an annoying message!
- Should be used for buffing your disease.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/itching
-
- name = "Itching"
- desc = "The virus irritates the skin, causing itching."
- stealth = 0
- resistance = 3
- stage_speed = 3
- transmittable = 1
- level = 1
- severity = 1
- symptom_delay_min = 5
- symptom_delay_max = 25
- var/scratch = FALSE
- threshold_desc = list(
- "Transmission 6" = "Increases frequency of itching.",
- "Stage Speed 7" = "The host will scrath itself when itching, causing superficial damage.",
- )
-
-/datum/symptom/itching/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["transmittable"] >= 6) //itch more often
- symptom_delay_min = 1
- symptom_delay_max = 4
- if(A.properties["stage_rate"] >= 7) //scratch
- scratch = TRUE
-
-/datum/symptom/itching/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/carbon/M = A.affected_mob
- var/picked_bodypart = pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
- var/obj/item/bodypart/bodypart = M.get_bodypart(picked_bodypart)
- if(bodypart && bodypart.status == BODYPART_ORGANIC && !bodypart.is_pseudopart) //robotic limbs will mean less scratching overall
- var/can_scratch = scratch && !M.incapacitated() && get_location_accessible(M, picked_bodypart)
- M.visible_message("[can_scratch ? "[M] scratches [M.p_their()] [bodypart.name]." : ""]", "Your [bodypart.name] itches. [can_scratch ? " You scratch it." : ""]")
- if(can_scratch)
+/*
+//////////////////////////////////////
+
+Itching
+
+ Not noticable or unnoticable.
+ Resistant.
+ Increases stage speed.
+ Little transmissibility.
+ Low Level.
+
+BONUS
+ Displays an annoying message!
+ Should be used for buffing your disease.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/itching
+
+ name = "Itching"
+ desc = "The virus irritates the skin, causing itching."
+ stealth = 0
+ resistance = 3
+ stage_speed = 3
+ transmittable = 1
+ level = 1
+ severity = 1
+ symptom_delay_min = 5
+ symptom_delay_max = 25
+ var/scratch = FALSE
+ threshold_desc = list(
+ "Transmission 6" = "Increases frequency of itching.",
+ "Stage Speed 7" = "The host will scrath itself when itching, causing superficial damage.",
+ )
+
+/datum/symptom/itching/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["transmittable"] >= 6) //itch more often
+ symptom_delay_min = 1
+ symptom_delay_max = 4
+ if(A.properties["stage_rate"] >= 7) //scratch
+ scratch = TRUE
+
+/datum/symptom/itching/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/carbon/M = A.affected_mob
+ var/picked_bodypart = pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
+ var/obj/item/bodypart/bodypart = M.get_bodypart(picked_bodypart)
+ if(bodypart && bodypart.status == BODYPART_ORGANIC && !bodypart.is_pseudopart) //robotic limbs will mean less scratching overall
+ var/can_scratch = scratch && !M.incapacitated() && get_location_accessible(M, picked_bodypart)
+ M.visible_message("[can_scratch ? "[M] scratches [M.p_their()] [bodypart.name]." : ""]", "Your [bodypart.name] itches. [can_scratch ? " You scratch it." : ""]")
+ if(can_scratch)
bodypart.receive_damage(0.5)
\ No newline at end of file
diff --git a/code/datums/diseases/advance/symptoms/oxygen.dm b/code/datums/diseases/advance/symptoms/oxygen.dm
index bc56e027f7..3821c0585e 100644
--- a/code/datums/diseases/advance/symptoms/oxygen.dm
+++ b/code/datums/diseases/advance/symptoms/oxygen.dm
@@ -1,70 +1,70 @@
-/*
-//////////////////////////////////////
-
-Self-Respiration
-
- Slightly hidden.
- Lowers resistance significantly.
- Decreases stage speed significantly.
- Decreases transmittablity tremendously.
- Fatal Level.
-
-Bonus
- The body generates salbutamol.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/oxygen
-
- name = "Self-Respiration"
- desc = "The virus rapidly synthesizes oxygen, effectively removing the need for breathing."
- stealth = 1
- resistance = -3
- stage_speed = -3
- transmittable = -4
- level = 6
- base_message_chance = 5
- symptom_delay_min = 1
- symptom_delay_max = 1
- var/regenerate_blood = FALSE
- threshold_desc = list(
- "Resistance 8" = "Additionally regenerates lost blood."
- )
-
-/datum/symptom/oxygen/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["resistance"] >= 8) //blood regeneration
- regenerate_blood = TRUE
-
-/datum/symptom/oxygen/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/carbon/M = A.affected_mob
- switch(A.stage)
- if(4, 5)
- M.adjustOxyLoss(-7, 0)
- M.losebreath = max(0, M.losebreath - 4)
- if(regenerate_blood && M.blood_volume < (BLOOD_VOLUME_NORMAL * M.blood_ratio))
- M.blood_volume += 1
- else
- if(prob(base_message_chance))
- to_chat(M, "[pick("Your lungs feel great.", "You realize you haven't been breathing.", "You don't feel the need to breathe.")]")
- return
-
-/datum/symptom/oxygen/on_stage_change(datum/disease/advance/A)
- if(!..())
- return FALSE
- var/mob/living/carbon/M = A.affected_mob
- if(A.stage >= 4)
- ADD_TRAIT(M, TRAIT_NOBREATH, DISEASE_TRAIT)
- else
- REMOVE_TRAIT(M, TRAIT_NOBREATH, DISEASE_TRAIT)
- return TRUE
-
-/datum/symptom/oxygen/End(datum/disease/advance/A)
- if(!..())
- return
- if(A.stage >= 4)
+/*
+//////////////////////////////////////
+
+Self-Respiration
+
+ Slightly hidden.
+ Lowers resistance significantly.
+ Decreases stage speed significantly.
+ Decreases transmittablity tremendously.
+ Fatal Level.
+
+Bonus
+ The body generates salbutamol.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/oxygen
+
+ name = "Self-Respiration"
+ desc = "The virus rapidly synthesizes oxygen, effectively removing the need for breathing."
+ stealth = 1
+ resistance = -3
+ stage_speed = -3
+ transmittable = -4
+ level = 6
+ base_message_chance = 5
+ symptom_delay_min = 1
+ symptom_delay_max = 1
+ var/regenerate_blood = FALSE
+ threshold_desc = list(
+ "Resistance 8" = "Additionally regenerates lost blood."
+ )
+
+/datum/symptom/oxygen/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["resistance"] >= 8) //blood regeneration
+ regenerate_blood = TRUE
+
+/datum/symptom/oxygen/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/carbon/M = A.affected_mob
+ switch(A.stage)
+ if(4, 5)
+ M.adjustOxyLoss(-7, 0)
+ M.losebreath = max(0, M.losebreath - 4)
+ if(regenerate_blood && M.blood_volume < (BLOOD_VOLUME_NORMAL * M.blood_ratio))
+ M.blood_volume += 1
+ else
+ if(prob(base_message_chance))
+ to_chat(M, "[pick("Your lungs feel great.", "You realize you haven't been breathing.", "You don't feel the need to breathe.")]")
+ return
+
+/datum/symptom/oxygen/on_stage_change(datum/disease/advance/A)
+ if(!..())
+ return FALSE
+ var/mob/living/carbon/M = A.affected_mob
+ if(A.stage >= 4)
+ ADD_TRAIT(M, TRAIT_NOBREATH, DISEASE_TRAIT)
+ else
+ REMOVE_TRAIT(M, TRAIT_NOBREATH, DISEASE_TRAIT)
+ return TRUE
+
+/datum/symptom/oxygen/End(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.stage >= 4)
REMOVE_TRAIT(A.affected_mob, TRAIT_NOBREATH, DISEASE_TRAIT)
\ No newline at end of file
diff --git a/code/datums/diseases/advance/symptoms/shivering.dm b/code/datums/diseases/advance/symptoms/shivering.dm
index fa51f8fa7e..f695ddde07 100644
--- a/code/datums/diseases/advance/symptoms/shivering.dm
+++ b/code/datums/diseases/advance/symptoms/shivering.dm
@@ -1,61 +1,61 @@
-/*
-//////////////////////////////////////
-
-Shivering
-
- No change to hidden.
- Increases resistance.
- Increases stage speed.
- Little transmittable.
- Low level.
-
-Bonus
- Cools down your body.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/shivering
- name = "Shivering"
- desc = "The virus inhibits the body's thermoregulation, cooling the body down."
- stealth = 0
- resistance = 2
- stage_speed = 2
- transmittable = 2
- level = 2
- severity = 2
- symptom_delay_min = 10
- symptom_delay_max = 30
- var/unsafe = FALSE //over the cold threshold
- threshold_desc = list(
- "Stage Speed 5" = "Increases cooling speed,; the host can fall below safe temperature levels.",
- "Stage Speed 10" = "Further increases cooling speed."
- )
-
-/datum/symptom/fever/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stage_rate"] >= 5) //dangerous cold
- power = 1.5
- unsafe = TRUE
- if(A.properties["stage_rate"] >= 10)
- power = 2.5
-
-/datum/symptom/shivering/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/carbon/M = A.affected_mob
- if(!unsafe || A.stage < 4)
- to_chat(M, "[pick("You feel cold.", "You shiver.")]")
- else
- to_chat(M, "[pick("You feel your blood run cold.", "You feel ice in your veins.", "You feel like you can't heat up.", "You shiver violently." )]")
- if(M.bodytemperature > BODYTEMP_COLD_DAMAGE_LIMIT || unsafe)
- Chill(M, A)
-
-/datum/symptom/shivering/proc/Chill(mob/living/M, datum/disease/advance/A)
- var/get_cold = 6 * power
- var/limit = BODYTEMP_COLD_DAMAGE_LIMIT + 1
- if(unsafe)
- limit = 0
- M.adjust_bodytemperature(-get_cold * A.stage, limit)
+/*
+//////////////////////////////////////
+
+Shivering
+
+ No change to hidden.
+ Increases resistance.
+ Increases stage speed.
+ Little transmittable.
+ Low level.
+
+Bonus
+ Cools down your body.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/shivering
+ name = "Shivering"
+ desc = "The virus inhibits the body's thermoregulation, cooling the body down."
+ stealth = 0
+ resistance = 2
+ stage_speed = 2
+ transmittable = 2
+ level = 2
+ severity = 2
+ symptom_delay_min = 10
+ symptom_delay_max = 30
+ var/unsafe = FALSE //over the cold threshold
+ threshold_desc = list(
+ "Stage Speed 5" = "Increases cooling speed,; the host can fall below safe temperature levels.",
+ "Stage Speed 10" = "Further increases cooling speed."
+ )
+
+/datum/symptom/fever/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stage_rate"] >= 5) //dangerous cold
+ power = 1.5
+ unsafe = TRUE
+ if(A.properties["stage_rate"] >= 10)
+ power = 2.5
+
+/datum/symptom/shivering/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/carbon/M = A.affected_mob
+ if(!unsafe || A.stage < 4)
+ to_chat(M, "[pick("You feel cold.", "You shiver.")]")
+ else
+ to_chat(M, "[pick("You feel your blood run cold.", "You feel ice in your veins.", "You feel like you can't heat up.", "You shiver violently." )]")
+ if(M.bodytemperature > BODYTEMP_COLD_DAMAGE_LIMIT || unsafe)
+ Chill(M, A)
+
+/datum/symptom/shivering/proc/Chill(mob/living/M, datum/disease/advance/A)
+ var/get_cold = 6 * power
+ var/limit = BODYTEMP_COLD_DAMAGE_LIMIT + 1
+ if(unsafe)
+ limit = 0
+ M.adjust_bodytemperature(-get_cold * A.stage, limit)
return 1
\ No newline at end of file
diff --git a/code/datums/diseases/advance/symptoms/sneeze.dm b/code/datums/diseases/advance/symptoms/sneeze.dm
index c6a3431750..5655cbc9c7 100644
--- a/code/datums/diseases/advance/symptoms/sneeze.dm
+++ b/code/datums/diseases/advance/symptoms/sneeze.dm
@@ -1,54 +1,54 @@
-/*
-//////////////////////////////////////
-
-Sneezing
-
- Very Noticable.
- Increases resistance.
- Doesn't increase stage speed.
- Very transmissible.
- Low Level.
-
-Bonus
- Forces a spread type of AIRBORNE
- with extra range!
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/sneeze
- name = "Sneezing"
- desc = "The virus causes irritation of the nasal cavity, making the host sneeze occasionally."
- stealth = -2
- resistance = 3
- stage_speed = 0
- transmittable = 4
- level = 1
- severity = 1
- symptom_delay_min = 5
- symptom_delay_max = 35
- threshold_desc = list(
- "Transmission 9" = "Increases sneezing range, spreading the virus over 6 meter cone instead of over a 4 meter cone.",
- "Stealth 4" = "The symptom remains hidden until active.",
- )
-
-/datum/symptom/sneeze/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["transmittable"] >= 9) //longer spread range
- power = 2
- if(A.properties["stealth"] >= 4)
- suppress_warning = TRUE
-
-/datum/symptom/sneeze/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/M = A.affected_mob
- switch(A.stage)
- if(1, 2, 3)
- if(!suppress_warning)
- M.emote("sniff")
- else
- M.emote("sneeze")
- if(M.CanSpreadAirborneDisease()) //don't spread germs if they covered their mouth
+/*
+//////////////////////////////////////
+
+Sneezing
+
+ Very Noticable.
+ Increases resistance.
+ Doesn't increase stage speed.
+ Very transmissible.
+ Low Level.
+
+Bonus
+ Forces a spread type of AIRBORNE
+ with extra range!
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/sneeze
+ name = "Sneezing"
+ desc = "The virus causes irritation of the nasal cavity, making the host sneeze occasionally."
+ stealth = -2
+ resistance = 3
+ stage_speed = 0
+ transmittable = 4
+ level = 1
+ severity = 1
+ symptom_delay_min = 5
+ symptom_delay_max = 35
+ threshold_desc = list(
+ "Transmission 9" = "Increases sneezing range, spreading the virus over 6 meter cone instead of over a 4 meter cone.",
+ "Stealth 4" = "The symptom remains hidden until active.",
+ )
+
+/datum/symptom/sneeze/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["transmittable"] >= 9) //longer spread range
+ power = 2
+ if(A.properties["stealth"] >= 4)
+ suppress_warning = TRUE
+
+/datum/symptom/sneeze/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/M = A.affected_mob
+ switch(A.stage)
+ if(1, 2, 3)
+ if(!suppress_warning)
+ M.emote("sniff")
+ else
+ M.emote("sneeze")
+ if(M.CanSpreadAirborneDisease()) //don't spread germs if they covered their mouth
A.spread(4 + power)
\ No newline at end of file
diff --git a/code/datums/diseases/advance/symptoms/voice_change.dm b/code/datums/diseases/advance/symptoms/voice_change.dm
index f065708c16..9be484d99a 100644
--- a/code/datums/diseases/advance/symptoms/voice_change.dm
+++ b/code/datums/diseases/advance/symptoms/voice_change.dm
@@ -1,83 +1,83 @@
-/*
-//////////////////////////////////////
-
-Voice Change
-
- Noticeable.
- Lowers resistance.
- Decreases stage speed.
- Increased transmittable.
- Fatal Level.
-
-Bonus
- Changes the voice of the affected mob. Causing confusion in communication.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/voice_change
-
- name = "Voice Change"
- desc = "The virus alters the pitch and tone of the host's vocal cords, changing how their voice sounds."
- stealth = -1
- resistance = -2
- stage_speed = -2
- transmittable = 2
- level = 6
- severity = 2
- base_message_chance = 100
- symptom_delay_min = 60
- symptom_delay_max = 120
- var/scramble_language = FALSE
- var/datum/language/current_language
- var/datum/language_holder/original_language
- threshold_desc = list(
- "Transmission 14" = "The host's language center of the brain is damaged, leading to complete inability to speak or understand any language.",
- "Stage Speed 7" = "Changes voice more often.",
- "Stealth 3" = "The symptom remains hidden until active."
- )
-
-/datum/symptom/voice_change/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stealth"] >= 3)
- suppress_warning = TRUE
- if(A.properties["stage_rate"] >= 7) //faster change of voice
- base_message_chance = 25
- symptom_delay_min = 25
- symptom_delay_max = 85
- if(A.properties["transmittable"] >= 14) //random language
- scramble_language = TRUE
- var/mob/living/M = A.affected_mob
- var/datum/language_holder/mob_language = M.get_language_holder()
- original_language = mob_language.copy()
-
-/datum/symptom/voice_change/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/carbon/M = A.affected_mob
- switch(A.stage)
- if(1, 2, 3, 4)
- if(prob(base_message_chance) && !suppress_warning)
- to_chat(M, "[pick("Your throat hurts.", "You clear your throat.")]")
- else
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- H.SetSpecialVoice(H.dna.species.random_name(H.gender))
- if(scramble_language)
- H.remove_language(current_language)
- current_language = pick(subtypesof(/datum/language) - /datum/language/common)
- H.grant_language(current_language)
- var/datum/language_holder/mob_language = H.get_language_holder()
- mob_language.only_speaks_language = current_language
-
-/datum/symptom/voice_change/End(datum/disease/advance/A)
- ..()
- if(ishuman(A.affected_mob))
- var/mob/living/carbon/human/H = A.affected_mob
- H.UnsetSpecialVoice()
- if(scramble_language)
- var/mob/living/M = A.affected_mob
- M.copy_known_languages_from(original_language, TRUE)
- current_language = null
- QDEL_NULL(original_language)
+/*
+//////////////////////////////////////
+
+Voice Change
+
+ Noticeable.
+ Lowers resistance.
+ Decreases stage speed.
+ Increased transmittable.
+ Fatal Level.
+
+Bonus
+ Changes the voice of the affected mob. Causing confusion in communication.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/voice_change
+
+ name = "Voice Change"
+ desc = "The virus alters the pitch and tone of the host's vocal cords, changing how their voice sounds."
+ stealth = -1
+ resistance = -2
+ stage_speed = -2
+ transmittable = 2
+ level = 6
+ severity = 2
+ base_message_chance = 100
+ symptom_delay_min = 60
+ symptom_delay_max = 120
+ var/scramble_language = FALSE
+ var/datum/language/current_language
+ var/datum/language_holder/original_language
+ threshold_desc = list(
+ "Transmission 14" = "The host's language center of the brain is damaged, leading to complete inability to speak or understand any language.",
+ "Stage Speed 7" = "Changes voice more often.",
+ "Stealth 3" = "The symptom remains hidden until active."
+ )
+
+/datum/symptom/voice_change/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stealth"] >= 3)
+ suppress_warning = TRUE
+ if(A.properties["stage_rate"] >= 7) //faster change of voice
+ base_message_chance = 25
+ symptom_delay_min = 25
+ symptom_delay_max = 85
+ if(A.properties["transmittable"] >= 14) //random language
+ scramble_language = TRUE
+ var/mob/living/M = A.affected_mob
+ var/datum/language_holder/mob_language = M.get_language_holder()
+ original_language = mob_language.copy()
+
+/datum/symptom/voice_change/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/carbon/M = A.affected_mob
+ switch(A.stage)
+ if(1, 2, 3, 4)
+ if(prob(base_message_chance) && !suppress_warning)
+ to_chat(M, "[pick("Your throat hurts.", "You clear your throat.")]")
+ else
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ H.SetSpecialVoice(H.dna.species.random_name(H.gender))
+ if(scramble_language)
+ H.remove_language(current_language)
+ current_language = pick(subtypesof(/datum/language) - /datum/language/common)
+ H.grant_language(current_language)
+ var/datum/language_holder/mob_language = H.get_language_holder()
+ mob_language.only_speaks_language = current_language
+
+/datum/symptom/voice_change/End(datum/disease/advance/A)
+ ..()
+ if(ishuman(A.affected_mob))
+ var/mob/living/carbon/human/H = A.affected_mob
+ H.UnsetSpecialVoice()
+ if(scramble_language)
+ var/mob/living/M = A.affected_mob
+ M.copy_known_languages_from(original_language, TRUE)
+ current_language = null
+ QDEL_NULL(original_language)
diff --git a/code/datums/diseases/advance/symptoms/vomit.dm b/code/datums/diseases/advance/symptoms/vomit.dm
index a937e9e212..95b4b6a70a 100644
--- a/code/datums/diseases/advance/symptoms/vomit.dm
+++ b/code/datums/diseases/advance/symptoms/vomit.dm
@@ -1,65 +1,65 @@
-/*
-//////////////////////////////////////
-
-Vomiting
-
- Very Very Noticable.
- Decreases resistance.
- Doesn't increase stage speed.
- Little transmissibility.
- Medium Level.
-
-Bonus
- Forces the affected mob to vomit!
- Meaning your disease can spread via
- people walking on vomit.
- Makes the affected mob lose nutrition and
- heal toxin damage.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/vomit
-
- name = "Vomiting"
- desc = "The virus causes nausea and irritates the stomach, causing occasional vomit."
- stealth = -2
- resistance = -1
- stage_speed = 0
- transmittable = 1
- level = 3
- severity = 3
- base_message_chance = 100
- symptom_delay_min = 25
- symptom_delay_max = 80
- var/vomit_blood = FALSE
- var/proj_vomit = 0
- threshold_desc = list(
- "Resistance 7" = "Host will vomit blood, causing internal damage.",
- "Transmission 7" = "Host will projectile vomit, increasing vomiting range.",
- "Stealth 4" = "The symptom remains hidden until active."
- )
-
-/datum/symptom/vomit/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stealth"] >= 4)
- suppress_warning = TRUE
- if(A.properties["resistance"] >= 7) //blood vomit
- vomit_blood = TRUE
- if(A.properties["transmittable"] >= 7) //projectile vomit
- proj_vomit = 5
-
-/datum/symptom/vomit/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/M = A.affected_mob
- switch(A.stage)
- if(1, 2, 3, 4)
- if(prob(base_message_chance) && !suppress_warning)
- to_chat(M, "[pick("You feel nauseated.", "You feel like you're going to throw up!")]")
- else
- vomit(M)
-
-/datum/symptom/vomit/proc/vomit(mob/living/carbon/M)
- M.vomit(20, vomit_blood, distance = proj_vomit)
+/*
+//////////////////////////////////////
+
+Vomiting
+
+ Very Very Noticable.
+ Decreases resistance.
+ Doesn't increase stage speed.
+ Little transmissibility.
+ Medium Level.
+
+Bonus
+ Forces the affected mob to vomit!
+ Meaning your disease can spread via
+ people walking on vomit.
+ Makes the affected mob lose nutrition and
+ heal toxin damage.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/vomit
+
+ name = "Vomiting"
+ desc = "The virus causes nausea and irritates the stomach, causing occasional vomit."
+ stealth = -2
+ resistance = -1
+ stage_speed = 0
+ transmittable = 1
+ level = 3
+ severity = 3
+ base_message_chance = 100
+ symptom_delay_min = 25
+ symptom_delay_max = 80
+ var/vomit_blood = FALSE
+ var/proj_vomit = 0
+ threshold_desc = list(
+ "Resistance 7" = "Host will vomit blood, causing internal damage.",
+ "Transmission 7" = "Host will projectile vomit, increasing vomiting range.",
+ "Stealth 4" = "The symptom remains hidden until active."
+ )
+
+/datum/symptom/vomit/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stealth"] >= 4)
+ suppress_warning = TRUE
+ if(A.properties["resistance"] >= 7) //blood vomit
+ vomit_blood = TRUE
+ if(A.properties["transmittable"] >= 7) //projectile vomit
+ proj_vomit = 5
+
+/datum/symptom/vomit/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/M = A.affected_mob
+ switch(A.stage)
+ if(1, 2, 3, 4)
+ if(prob(base_message_chance) && !suppress_warning)
+ to_chat(M, "[pick("You feel nauseated.", "You feel like you're going to throw up!")]")
+ else
+ vomit(M)
+
+/datum/symptom/vomit/proc/vomit(mob/living/carbon/M)
+ M.vomit(20, vomit_blood, distance = proj_vomit)
diff --git a/code/datums/diseases/advance/symptoms/weight.dm b/code/datums/diseases/advance/symptoms/weight.dm
index 92f05ce3ea..5eab698750 100644
--- a/code/datums/diseases/advance/symptoms/weight.dm
+++ b/code/datums/diseases/advance/symptoms/weight.dm
@@ -1,53 +1,53 @@
-/*
-//////////////////////////////////////
-
-Weight Loss
-
- Very Very Noticable.
- Decreases resistance.
- Decreases stage speed.
- Reduced Transmittable.
- High level.
-
-Bonus
- Decreases the weight of the mob,
- forcing it to be skinny.
-
-//////////////////////////////////////
-*/
-
-/datum/symptom/weight_loss
-
- name = "Weight Loss"
- desc = "The virus mutates the host's metabolism, making it almost unable to gain nutrition from food."
- stealth = -2
- resistance = 2
- stage_speed = -2
- transmittable = -2
- level = 3
- severity = 3
- base_message_chance = 100
- symptom_delay_min = 15
- symptom_delay_max = 45
- threshold_desc = list(
- "Stealth 4" = "The symptom is less noticeable."
- )
-
-/datum/symptom/weight_loss/Start(datum/disease/advance/A)
- if(!..())
- return
- if(A.properties["stealth"] >= 4) //warn less often
- base_message_chance = 25
-
-/datum/symptom/weight_loss/Activate(datum/disease/advance/A)
- if(!..())
- return
- var/mob/living/M = A.affected_mob
- switch(A.stage)
- if(1, 2, 3, 4)
- if(prob(base_message_chance))
- to_chat(M, "[pick("You feel hungry.", "You crave for food.")]")
- else
- to_chat(M, "[pick("So hungry...", "You'd kill someone for a bite of food...", "Hunger cramps seize you...")]")
- M.overeatduration = max(M.overeatduration - 100, 0)
+/*
+//////////////////////////////////////
+
+Weight Loss
+
+ Very Very Noticable.
+ Decreases resistance.
+ Decreases stage speed.
+ Reduced Transmittable.
+ High level.
+
+Bonus
+ Decreases the weight of the mob,
+ forcing it to be skinny.
+
+//////////////////////////////////////
+*/
+
+/datum/symptom/weight_loss
+
+ name = "Weight Loss"
+ desc = "The virus mutates the host's metabolism, making it almost unable to gain nutrition from food."
+ stealth = -2
+ resistance = 2
+ stage_speed = -2
+ transmittable = -2
+ level = 3
+ severity = 3
+ base_message_chance = 100
+ symptom_delay_min = 15
+ symptom_delay_max = 45
+ threshold_desc = list(
+ "Stealth 4" = "The symptom is less noticeable."
+ )
+
+/datum/symptom/weight_loss/Start(datum/disease/advance/A)
+ if(!..())
+ return
+ if(A.properties["stealth"] >= 4) //warn less often
+ base_message_chance = 25
+
+/datum/symptom/weight_loss/Activate(datum/disease/advance/A)
+ if(!..())
+ return
+ var/mob/living/M = A.affected_mob
+ switch(A.stage)
+ if(1, 2, 3, 4)
+ if(prob(base_message_chance))
+ to_chat(M, "[pick("You feel hungry.", "You crave for food.")]")
+ else
+ to_chat(M, "[pick("So hungry...", "You'd kill someone for a bite of food...", "Hunger cramps seize you...")]")
+ M.overeatduration = max(M.overeatduration - 100, 0)
M.nutrition = max(M.nutrition - 100, 0)
\ No newline at end of file
diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm
index f68da2bdc2..7439fd1b8b 100644
--- a/code/game/machinery/computer/Operating.dm
+++ b/code/game/machinery/computer/Operating.dm
@@ -1,123 +1,123 @@
-#define MENU_OPERATION 1
-#define MENU_SURGERIES 2
-
-/obj/machinery/computer/operating
- name = "operating computer"
- desc = "Monitors patient vitals and displays surgery steps. Can be loaded with surgery disks to perform experimental procedures."
- icon_screen = "crew"
- icon_keyboard = "med_key"
- circuit = /obj/item/circuitboard/computer/operating
- var/mob/living/carbon/human/patient
- var/obj/structure/table/optable/table
- var/list/advanced_surgeries = list()
- var/datum/techweb/linked_techweb
- light_color = LIGHT_COLOR_BLUE
-
-/obj/machinery/computer/operating/Initialize()
- . = ..()
- linked_techweb = SSresearch.science_tech
- find_table()
-
-/obj/machinery/computer/operating/attackby(obj/item/O, mob/user, params)
- if(istype(O, /obj/item/disk/surgery))
- user.visible_message("[user] begins to load \the [O] in \the [src]...",
- "You begin to load a surgery protocol from \the [O]...",
- "You hear the chatter of a floppy drive.")
- var/obj/item/disk/surgery/D = O
- if(do_after(user, 10, target = src))
- advanced_surgeries |= D.surgeries
- return TRUE
- return ..()
-
-/obj/machinery/computer/operating/proc/sync_surgeries()
- for(var/i in linked_techweb.researched_designs)
- var/datum/design/surgery/D = SSresearch.techweb_design_by_id(i)
- if(!istype(D))
- continue
- advanced_surgeries |= D.surgery
-
-/obj/machinery/computer/operating/proc/find_table()
- for(var/direction in GLOB.cardinals)
- table = locate(/obj/structure/table/optable, get_step(src, direction))
- if(table)
- table.computer = src
- break
-
-/obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "operating_computer", name, 350, 470, master_ui, state)
- ui.open()
-
-/obj/machinery/computer/operating/ui_data(mob/user)
- var/list/data = list()
- data["table"] = table
- if(table)
- var/list/surgeries = list()
- for(var/X in advanced_surgeries)
- var/datum/surgery/S = X
- var/list/surgery = list()
- surgery["name"] = initial(S.name)
- surgery["desc"] = initial(S.desc)
- surgeries += list(surgery)
- data["surgeries"] = surgeries
- if(table.check_patient())
- data["patient"] = list()
- patient = table.patient
- switch(patient.stat)
- if(CONSCIOUS)
- data["patient"]["stat"] = "Conscious"
- data["patient"]["statstate"] = "good"
- if(SOFT_CRIT)
- data["patient"]["stat"] = "Conscious"
- data["patient"]["statstate"] = "average"
- if(UNCONSCIOUS)
- data["patient"]["stat"] = "Unconscious"
- data["patient"]["statstate"] = "average"
- if(DEAD)
- data["patient"]["stat"] = "Dead"
- data["patient"]["statstate"] = "bad"
- data["patient"]["health"] = patient.health
- data["patient"]["blood_type"] = patient.dna.blood_type
- data["patient"]["maxHealth"] = patient.maxHealth
- data["patient"]["minHealth"] = HEALTH_THRESHOLD_DEAD
- data["patient"]["bruteLoss"] = patient.getBruteLoss()
- data["patient"]["fireLoss"] = patient.getFireLoss()
- data["patient"]["toxLoss"] = patient.getToxLoss()
- data["patient"]["oxyLoss"] = patient.getOxyLoss()
- if(patient.surgeries.len)
- data["procedures"] = list()
- for(var/datum/surgery/procedure in patient.surgeries)
- var/datum/surgery_step/surgery_step = procedure.get_surgery_step()
- var/chems_needed = surgery_step.get_chem_list()
- var/alternative_step
- var/alt_chems_needed = ""
- if(surgery_step.repeatable)
- var/datum/surgery_step/next_step = procedure.get_surgery_next_step()
- if(next_step)
- alternative_step = capitalize(next_step.name)
- alt_chems_needed = next_step.get_chem_list()
- else
- alternative_step = "Finish operation"
- data["procedures"] += list(list(
- "name" = capitalize(procedure.name),
- "next_step" = capitalize(surgery_step.name),
- "chems_needed" = chems_needed,
- "alternative_step" = alternative_step,
- "alt_chems_needed" = alt_chems_needed
- ))
- else
- data["patient"] = null
- return data
-
-/obj/machinery/computer/operating/ui_act(action, params)
- if(..())
- return
- switch(action)
- if("sync")
- sync_surgeries()
- . = TRUE
- . = TRUE
-
-#undef MENU_OPERATION
-#undef MENU_SURGERIES
+#define MENU_OPERATION 1
+#define MENU_SURGERIES 2
+
+/obj/machinery/computer/operating
+ name = "operating computer"
+ desc = "Monitors patient vitals and displays surgery steps. Can be loaded with surgery disks to perform experimental procedures."
+ icon_screen = "crew"
+ icon_keyboard = "med_key"
+ circuit = /obj/item/circuitboard/computer/operating
+ var/mob/living/carbon/human/patient
+ var/obj/structure/table/optable/table
+ var/list/advanced_surgeries = list()
+ var/datum/techweb/linked_techweb
+ light_color = LIGHT_COLOR_BLUE
+
+/obj/machinery/computer/operating/Initialize()
+ . = ..()
+ linked_techweb = SSresearch.science_tech
+ find_table()
+
+/obj/machinery/computer/operating/attackby(obj/item/O, mob/user, params)
+ if(istype(O, /obj/item/disk/surgery))
+ user.visible_message("[user] begins to load \the [O] in \the [src]...",
+ "You begin to load a surgery protocol from \the [O]...",
+ "You hear the chatter of a floppy drive.")
+ var/obj/item/disk/surgery/D = O
+ if(do_after(user, 10, target = src))
+ advanced_surgeries |= D.surgeries
+ return TRUE
+ return ..()
+
+/obj/machinery/computer/operating/proc/sync_surgeries()
+ for(var/i in linked_techweb.researched_designs)
+ var/datum/design/surgery/D = SSresearch.techweb_design_by_id(i)
+ if(!istype(D))
+ continue
+ advanced_surgeries |= D.surgery
+
+/obj/machinery/computer/operating/proc/find_table()
+ for(var/direction in GLOB.cardinals)
+ table = locate(/obj/structure/table/optable, get_step(src, direction))
+ if(table)
+ table.computer = src
+ break
+
+/obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "operating_computer", name, 350, 470, master_ui, state)
+ ui.open()
+
+/obj/machinery/computer/operating/ui_data(mob/user)
+ var/list/data = list()
+ data["table"] = table
+ if(table)
+ var/list/surgeries = list()
+ for(var/X in advanced_surgeries)
+ var/datum/surgery/S = X
+ var/list/surgery = list()
+ surgery["name"] = initial(S.name)
+ surgery["desc"] = initial(S.desc)
+ surgeries += list(surgery)
+ data["surgeries"] = surgeries
+ if(table.check_patient())
+ data["patient"] = list()
+ patient = table.patient
+ switch(patient.stat)
+ if(CONSCIOUS)
+ data["patient"]["stat"] = "Conscious"
+ data["patient"]["statstate"] = "good"
+ if(SOFT_CRIT)
+ data["patient"]["stat"] = "Conscious"
+ data["patient"]["statstate"] = "average"
+ if(UNCONSCIOUS)
+ data["patient"]["stat"] = "Unconscious"
+ data["patient"]["statstate"] = "average"
+ if(DEAD)
+ data["patient"]["stat"] = "Dead"
+ data["patient"]["statstate"] = "bad"
+ data["patient"]["health"] = patient.health
+ data["patient"]["blood_type"] = patient.dna.blood_type
+ data["patient"]["maxHealth"] = patient.maxHealth
+ data["patient"]["minHealth"] = HEALTH_THRESHOLD_DEAD
+ data["patient"]["bruteLoss"] = patient.getBruteLoss()
+ data["patient"]["fireLoss"] = patient.getFireLoss()
+ data["patient"]["toxLoss"] = patient.getToxLoss()
+ data["patient"]["oxyLoss"] = patient.getOxyLoss()
+ if(patient.surgeries.len)
+ data["procedures"] = list()
+ for(var/datum/surgery/procedure in patient.surgeries)
+ var/datum/surgery_step/surgery_step = procedure.get_surgery_step()
+ var/chems_needed = surgery_step.get_chem_list()
+ var/alternative_step
+ var/alt_chems_needed = ""
+ if(surgery_step.repeatable)
+ var/datum/surgery_step/next_step = procedure.get_surgery_next_step()
+ if(next_step)
+ alternative_step = capitalize(next_step.name)
+ alt_chems_needed = next_step.get_chem_list()
+ else
+ alternative_step = "Finish operation"
+ data["procedures"] += list(list(
+ "name" = capitalize(procedure.name),
+ "next_step" = capitalize(surgery_step.name),
+ "chems_needed" = chems_needed,
+ "alternative_step" = alternative_step,
+ "alt_chems_needed" = alt_chems_needed
+ ))
+ else
+ data["patient"] = null
+ return data
+
+/obj/machinery/computer/operating/ui_act(action, params)
+ if(..())
+ return
+ switch(action)
+ if("sync")
+ sync_surgeries()
+ . = TRUE
+ . = TRUE
+
+#undef MENU_OPERATION
+#undef MENU_SURGERIES
diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm
index 90488346da..c3fef3ff92 100644
--- a/code/game/machinery/computer/station_alert.dm
+++ b/code/game/machinery/computer/station_alert.dm
@@ -1,99 +1,99 @@
-/obj/machinery/computer/station_alert
- name = "station alert console"
- desc = "Used to access the station's automated alert system."
- icon_screen = "alert:0"
- icon_keyboard = "atmos_key"
- circuit = /obj/item/circuitboard/computer/stationalert
- var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
-
- light_color = LIGHT_COLOR_CYAN
-
-/obj/machinery/computer/station_alert/Initialize()
- . = ..()
- GLOB.alert_consoles += src
-
-/obj/machinery/computer/station_alert/Destroy()
- GLOB.alert_consoles -= src
- return ..()
-
-/obj/machinery/computer/station_alert/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "station_alert", name, 325, 500, master_ui, state)
- ui.open()
-
-/obj/machinery/computer/station_alert/ui_data(mob/user)
- var/list/data = list()
-
- data["alarms"] = list()
- for(var/class in alarms)
- data["alarms"][class] = list()
- for(var/area in alarms[class])
- data["alarms"][class] += area
- return data
-
-/obj/machinery/computer/station_alert/proc/triggerAlarm(class, area/A, O, obj/source)
- if(source.z != z)
- return
- if(stat & (BROKEN))
- return
-
- var/list/L = alarms[class]
- for(var/I in L)
- if (I == A.name)
- var/list/alarm = L[I]
- var/list/sources = alarm[3]
- if (!(source in sources))
- sources += source
- return 1
- var/obj/machinery/camera/C = null
- var/list/CL = null
- if(O && islist(O))
- CL = O
- if (CL.len == 1)
- C = CL[1]
- else if(O && istype(O, /obj/machinery/camera))
- C = O
- L[A.name] = list(A, (C ? C : O), list(source))
- return 1
-
-
-/obj/machinery/computer/station_alert/proc/cancelAlarm(class, area/A, obj/origin)
- if(stat & (BROKEN))
- return
- var/list/L = alarms[class]
- var/cleared = 0
- for (var/I in L)
- if (I == A.name)
- var/list/alarm = L[I]
- var/list/srcs = alarm[3]
- if (origin in srcs)
- srcs -= origin
- if (srcs.len == 0)
- cleared = 1
- L -= I
- return !cleared
-
-/obj/machinery/computer/station_alert/update_icon()
- ..()
- cut_overlays()
- SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
- var/overlay_state = icon_screen
- if(stat & (NOPOWER|BROKEN))
- add_overlay("[icon_keyboard]_off")
- return
- add_overlay(icon_keyboard)
- var/active_alarms = FALSE
- for(var/cat in alarms)
- var/list/L = alarms[cat]
- if(L.len)
- active_alarms = TRUE
- if(active_alarms)
- overlay_state = "alert:2"
- add_overlay("alert:2")
- else
- overlay_state = "alert:0"
- add_overlay("alert:0")
- SSvis_overlays.add_vis_overlay(src, icon, overlay_state, layer, plane, dir)
- SSvis_overlays.add_vis_overlay(src, icon, overlay_state, ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir, alpha=128)
+/obj/machinery/computer/station_alert
+ name = "station alert console"
+ desc = "Used to access the station's automated alert system."
+ icon_screen = "alert:0"
+ icon_keyboard = "atmos_key"
+ circuit = /obj/item/circuitboard/computer/stationalert
+ var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
+
+ light_color = LIGHT_COLOR_CYAN
+
+/obj/machinery/computer/station_alert/Initialize()
+ . = ..()
+ GLOB.alert_consoles += src
+
+/obj/machinery/computer/station_alert/Destroy()
+ GLOB.alert_consoles -= src
+ return ..()
+
+/obj/machinery/computer/station_alert/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "station_alert", name, 325, 500, master_ui, state)
+ ui.open()
+
+/obj/machinery/computer/station_alert/ui_data(mob/user)
+ var/list/data = list()
+
+ data["alarms"] = list()
+ for(var/class in alarms)
+ data["alarms"][class] = list()
+ for(var/area in alarms[class])
+ data["alarms"][class] += area
+ return data
+
+/obj/machinery/computer/station_alert/proc/triggerAlarm(class, area/A, O, obj/source)
+ if(source.z != z)
+ return
+ if(stat & (BROKEN))
+ return
+
+ var/list/L = alarms[class]
+ for(var/I in L)
+ if (I == A.name)
+ var/list/alarm = L[I]
+ var/list/sources = alarm[3]
+ if (!(source in sources))
+ sources += source
+ return 1
+ var/obj/machinery/camera/C = null
+ var/list/CL = null
+ if(O && islist(O))
+ CL = O
+ if (CL.len == 1)
+ C = CL[1]
+ else if(O && istype(O, /obj/machinery/camera))
+ C = O
+ L[A.name] = list(A, (C ? C : O), list(source))
+ return 1
+
+
+/obj/machinery/computer/station_alert/proc/cancelAlarm(class, area/A, obj/origin)
+ if(stat & (BROKEN))
+ return
+ var/list/L = alarms[class]
+ var/cleared = 0
+ for (var/I in L)
+ if (I == A.name)
+ var/list/alarm = L[I]
+ var/list/srcs = alarm[3]
+ if (origin in srcs)
+ srcs -= origin
+ if (srcs.len == 0)
+ cleared = 1
+ L -= I
+ return !cleared
+
+/obj/machinery/computer/station_alert/update_icon()
+ ..()
+ cut_overlays()
+ SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
+ var/overlay_state = icon_screen
+ if(stat & (NOPOWER|BROKEN))
+ add_overlay("[icon_keyboard]_off")
+ return
+ add_overlay(icon_keyboard)
+ var/active_alarms = FALSE
+ for(var/cat in alarms)
+ var/list/L = alarms[cat]
+ if(L.len)
+ active_alarms = TRUE
+ if(active_alarms)
+ overlay_state = "alert:2"
+ add_overlay("alert:2")
+ else
+ overlay_state = "alert:0"
+ add_overlay("alert:0")
+ SSvis_overlays.add_vis_overlay(src, icon, overlay_state, layer, plane, dir)
+ SSvis_overlays.add_vis_overlay(src, icon, overlay_state, ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir, alpha=128)
diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm
index 3655fbe135..7bbf819028 100644
--- a/code/game/machinery/doors/brigdoors.dm
+++ b/code/game/machinery/doors/brigdoors.dm
@@ -1,256 +1,256 @@
-#define CHARS_PER_LINE 5
-#define FONT_SIZE "5pt"
-#define FONT_COLOR "#09f"
-#define FONT_STYLE "Arial Black"
-#define MAX_TIMER 9000
-
-#define PRESET_SHORT 1200
-#define PRESET_MEDIUM 1800
-#define PRESET_LONG 3000
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// Brig Door control displays.
-// Description: This is a controls the timer for the brig doors, displays the timer on itself and
-// has a popup window when used, allowing to set the timer.
-// Code Notes: Combination of old brigdoor.dm code from rev4407 and the status_display.dm code
-// Date: 01/September/2010
-// Programmer: Veryinky
-/////////////////////////////////////////////////////////////////////////////////////////////////
-/obj/machinery/door_timer
- name = "door timer"
- icon = 'icons/obj/status_display.dmi'
- icon_state = "frame"
- desc = "A remote control for a door."
- req_access = list(ACCESS_SECURITY)
- density = FALSE
- var/id = null // id of linked machinery/lockers
-
- var/activation_time = 0
- var/timer_duration = 0
-
- var/timing = FALSE // boolean, true/1 timer is on, false/0 means it's not timing
- var/list/obj/machinery/targets = list()
- var/obj/item/radio/Radio //needed to send messages to sec radio
-
- maptext_height = 26
- maptext_width = 32
-
-/obj/machinery/door_timer/Initialize()
- . = ..()
-
- Radio = new/obj/item/radio(src)
- Radio.listening = 0
-
-/obj/machinery/door_timer/Initialize()
- . = ..()
- if(id != null)
- for(var/obj/machinery/door/window/brigdoor/M in urange(20, src))
- if (M.id == id)
- targets += M
-
- for(var/obj/machinery/flasher/F in urange(20, src))
- if(F.id == id)
- targets += F
-
- for(var/obj/structure/closet/secure_closet/brig/C in urange(20, src))
- if(C.id == id)
- targets += C
-
- if(!targets.len)
- stat |= BROKEN
- update_icon()
-
-
-//Main door timer loop, if it's timing and time is >0 reduce time by 1.
-// if it's less than 0, open door, reset timer
-// update the door_timer window and the icon
-/obj/machinery/door_timer/process()
- if(stat & (NOPOWER|BROKEN))
- return
-
- if(timing)
- if(world.realtime - activation_time >= timer_duration)
- timer_end() // open doors, reset timer, clear status screen
- update_icon()
-
-// has the door power sitatuation changed, if so update icon.
-/obj/machinery/door_timer/power_change()
- ..()
- update_icon()
-
-
-// open/closedoor checks if door_timer has power, if so it checks if the
-// linked door is open/closed (by density) then opens it/closes it.
-/obj/machinery/door_timer/proc/timer_start()
- if(stat & (NOPOWER|BROKEN))
- return 0
-
- activation_time = world.realtime
- timing = TRUE
-
- for(var/obj/machinery/door/window/brigdoor/door in targets)
- if(door.density)
- continue
- INVOKE_ASYNC(door, /obj/machinery/door/window/brigdoor.proc/close)
-
- for(var/obj/structure/closet/secure_closet/brig/C in targets)
- if(C.broken)
- continue
- if(C.opened && !C.close())
- continue
- C.locked = TRUE
- C.update_icon()
- return 1
-
-
-/obj/machinery/door_timer/proc/timer_end(forced = FALSE)
-
- if(stat & (NOPOWER|BROKEN))
- return 0
-
- if(!forced)
- Radio.set_frequency(FREQ_SECURITY)
- Radio.talk_into(src, "Timer has expired. Releasing prisoner.", FREQ_SECURITY)
-
- timing = FALSE
- activation_time = null
- set_timer(0)
- update_icon()
-
- for(var/obj/machinery/door/window/brigdoor/door in targets)
- if(!door.density)
- continue
- INVOKE_ASYNC(door, /obj/machinery/door/window/brigdoor.proc/open)
-
- for(var/obj/structure/closet/secure_closet/brig/C in targets)
- if(C.broken)
- continue
- if(C.opened)
- continue
- C.locked = FALSE
- C.update_icon()
-
- return 1
-
-
-/obj/machinery/door_timer/proc/time_left(seconds = FALSE)
- . = max(0,timer_duration - (activation_time ? world.realtime - activation_time : 0))
- if(seconds)
- . /= 10
-
-/obj/machinery/door_timer/proc/set_timer(value)
- var/new_time = CLAMP(value,0,MAX_TIMER)
- . = new_time == timer_duration //return 1 on no change
- timer_duration = new_time
-
-/obj/machinery/door_timer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "brig_timer", name, 300, 138, master_ui, state)
- ui.open()
-
-//icon update function
-// if NOPOWER, display blank
-// if BROKEN, display blue screen of death icon AI uses
-// if timing=true, run update display function
-/obj/machinery/door_timer/update_icon()
- if(stat & (NOPOWER))
- icon_state = "frame"
- return
-
- if(stat & (BROKEN))
- set_picture("ai_bsod")
- return
-
- if(timing)
- var/disp1 = id
- var/time_left = time_left(seconds = TRUE)
- var/disp2 = "[add_zero(num2text((time_left / 60) % 60),2)]~[add_zero(num2text(time_left % 60), 2)]"
- if(length(disp2) > CHARS_PER_LINE)
- disp2 = "Error"
- update_display(disp1, disp2)
- else
- if(maptext)
- maptext = ""
- return
-
-
-// Adds an icon in case the screen is broken/off, stolen from status_display.dm
-/obj/machinery/door_timer/proc/set_picture(state)
- if(maptext)
- maptext = ""
- cut_overlays()
- add_overlay(mutable_appearance('icons/obj/status_display.dmi', state))
-
-
-//Checks to see if there's 1 line or 2, adds text-icons-numbers/letters over display
-// Stolen from status_display
-/obj/machinery/door_timer/proc/update_display(line1, line2)
- var/new_text = {"
[line1] [line2]
"}
- if(maptext != new_text)
- maptext = new_text
-
-/obj/machinery/door_timer/ui_data()
- var/list/data = list()
- var/time_left = time_left(seconds = TRUE)
- data["seconds"] = round(time_left % 60)
- data["minutes"] = round((time_left - data["seconds"]) / 60)
- data["timing"] = timing
- data["flash_charging"] = FALSE
- for(var/obj/machinery/flasher/F in targets)
- if(F.last_flash && (F.last_flash + 150) > world.time)
- data["flash_charging"] = TRUE
- break
- return data
-
-
-/obj/machinery/door_timer/ui_act(action, params)
- if(..())
- return
- . = TRUE
-
- if(!allowed(usr))
- to_chat(usr, "Access denied.")
- return FALSE
-
- switch(action)
- if("time")
- var/value = text2num(params["adjust"])
- if(value)
- . = set_timer(time_left()+value)
- if("start")
- timer_start()
- if("stop")
- timer_end(forced = TRUE)
- if("flash")
- for(var/obj/machinery/flasher/F in targets)
- F.flash()
- if("preset")
- var/preset = params["preset"]
- var/preset_time = time_left()
- switch(preset)
- if("short")
- preset_time = PRESET_SHORT
- if("medium")
- preset_time = PRESET_MEDIUM
- if("long")
- preset_time = PRESET_LONG
- . = set_timer(preset_time)
- if(timing)
- activation_time = world.realtime
- else
- . = FALSE
-
-
-#undef PRESET_SHORT
-#undef PRESET_MEDIUM
-#undef PRESET_LONG
-
-#undef MAX_TIMER
-#undef FONT_SIZE
-#undef FONT_COLOR
-#undef FONT_STYLE
-#undef CHARS_PER_LINE
+#define CHARS_PER_LINE 5
+#define FONT_SIZE "5pt"
+#define FONT_COLOR "#09f"
+#define FONT_STYLE "Arial Black"
+#define MAX_TIMER 9000
+
+#define PRESET_SHORT 1200
+#define PRESET_MEDIUM 1800
+#define PRESET_LONG 3000
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// Brig Door control displays.
+// Description: This is a controls the timer for the brig doors, displays the timer on itself and
+// has a popup window when used, allowing to set the timer.
+// Code Notes: Combination of old brigdoor.dm code from rev4407 and the status_display.dm code
+// Date: 01/September/2010
+// Programmer: Veryinky
+/////////////////////////////////////////////////////////////////////////////////////////////////
+/obj/machinery/door_timer
+ name = "door timer"
+ icon = 'icons/obj/status_display.dmi'
+ icon_state = "frame"
+ desc = "A remote control for a door."
+ req_access = list(ACCESS_SECURITY)
+ density = FALSE
+ var/id = null // id of linked machinery/lockers
+
+ var/activation_time = 0
+ var/timer_duration = 0
+
+ var/timing = FALSE // boolean, true/1 timer is on, false/0 means it's not timing
+ var/list/obj/machinery/targets = list()
+ var/obj/item/radio/Radio //needed to send messages to sec radio
+
+ maptext_height = 26
+ maptext_width = 32
+
+/obj/machinery/door_timer/Initialize()
+ . = ..()
+
+ Radio = new/obj/item/radio(src)
+ Radio.listening = 0
+
+/obj/machinery/door_timer/Initialize()
+ . = ..()
+ if(id != null)
+ for(var/obj/machinery/door/window/brigdoor/M in urange(20, src))
+ if (M.id == id)
+ targets += M
+
+ for(var/obj/machinery/flasher/F in urange(20, src))
+ if(F.id == id)
+ targets += F
+
+ for(var/obj/structure/closet/secure_closet/brig/C in urange(20, src))
+ if(C.id == id)
+ targets += C
+
+ if(!targets.len)
+ stat |= BROKEN
+ update_icon()
+
+
+//Main door timer loop, if it's timing and time is >0 reduce time by 1.
+// if it's less than 0, open door, reset timer
+// update the door_timer window and the icon
+/obj/machinery/door_timer/process()
+ if(stat & (NOPOWER|BROKEN))
+ return
+
+ if(timing)
+ if(world.realtime - activation_time >= timer_duration)
+ timer_end() // open doors, reset timer, clear status screen
+ update_icon()
+
+// has the door power sitatuation changed, if so update icon.
+/obj/machinery/door_timer/power_change()
+ ..()
+ update_icon()
+
+
+// open/closedoor checks if door_timer has power, if so it checks if the
+// linked door is open/closed (by density) then opens it/closes it.
+/obj/machinery/door_timer/proc/timer_start()
+ if(stat & (NOPOWER|BROKEN))
+ return 0
+
+ activation_time = world.realtime
+ timing = TRUE
+
+ for(var/obj/machinery/door/window/brigdoor/door in targets)
+ if(door.density)
+ continue
+ INVOKE_ASYNC(door, /obj/machinery/door/window/brigdoor.proc/close)
+
+ for(var/obj/structure/closet/secure_closet/brig/C in targets)
+ if(C.broken)
+ continue
+ if(C.opened && !C.close())
+ continue
+ C.locked = TRUE
+ C.update_icon()
+ return 1
+
+
+/obj/machinery/door_timer/proc/timer_end(forced = FALSE)
+
+ if(stat & (NOPOWER|BROKEN))
+ return 0
+
+ if(!forced)
+ Radio.set_frequency(FREQ_SECURITY)
+ Radio.talk_into(src, "Timer has expired. Releasing prisoner.", FREQ_SECURITY)
+
+ timing = FALSE
+ activation_time = null
+ set_timer(0)
+ update_icon()
+
+ for(var/obj/machinery/door/window/brigdoor/door in targets)
+ if(!door.density)
+ continue
+ INVOKE_ASYNC(door, /obj/machinery/door/window/brigdoor.proc/open)
+
+ for(var/obj/structure/closet/secure_closet/brig/C in targets)
+ if(C.broken)
+ continue
+ if(C.opened)
+ continue
+ C.locked = FALSE
+ C.update_icon()
+
+ return 1
+
+
+/obj/machinery/door_timer/proc/time_left(seconds = FALSE)
+ . = max(0,timer_duration - (activation_time ? world.realtime - activation_time : 0))
+ if(seconds)
+ . /= 10
+
+/obj/machinery/door_timer/proc/set_timer(value)
+ var/new_time = CLAMP(value,0,MAX_TIMER)
+ . = new_time == timer_duration //return 1 on no change
+ timer_duration = new_time
+
+/obj/machinery/door_timer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "brig_timer", name, 300, 138, master_ui, state)
+ ui.open()
+
+//icon update function
+// if NOPOWER, display blank
+// if BROKEN, display blue screen of death icon AI uses
+// if timing=true, run update display function
+/obj/machinery/door_timer/update_icon()
+ if(stat & (NOPOWER))
+ icon_state = "frame"
+ return
+
+ if(stat & (BROKEN))
+ set_picture("ai_bsod")
+ return
+
+ if(timing)
+ var/disp1 = id
+ var/time_left = time_left(seconds = TRUE)
+ var/disp2 = "[add_zero(num2text((time_left / 60) % 60),2)]~[add_zero(num2text(time_left % 60), 2)]"
+ if(length(disp2) > CHARS_PER_LINE)
+ disp2 = "Error"
+ update_display(disp1, disp2)
+ else
+ if(maptext)
+ maptext = ""
+ return
+
+
+// Adds an icon in case the screen is broken/off, stolen from status_display.dm
+/obj/machinery/door_timer/proc/set_picture(state)
+ if(maptext)
+ maptext = ""
+ cut_overlays()
+ add_overlay(mutable_appearance('icons/obj/status_display.dmi', state))
+
+
+//Checks to see if there's 1 line or 2, adds text-icons-numbers/letters over display
+// Stolen from status_display
+/obj/machinery/door_timer/proc/update_display(line1, line2)
+ var/new_text = {"
[line1] [line2]
"}
+ if(maptext != new_text)
+ maptext = new_text
+
+/obj/machinery/door_timer/ui_data()
+ var/list/data = list()
+ var/time_left = time_left(seconds = TRUE)
+ data["seconds"] = round(time_left % 60)
+ data["minutes"] = round((time_left - data["seconds"]) / 60)
+ data["timing"] = timing
+ data["flash_charging"] = FALSE
+ for(var/obj/machinery/flasher/F in targets)
+ if(F.last_flash && (F.last_flash + 150) > world.time)
+ data["flash_charging"] = TRUE
+ break
+ return data
+
+
+/obj/machinery/door_timer/ui_act(action, params)
+ if(..())
+ return
+ . = TRUE
+
+ if(!allowed(usr))
+ to_chat(usr, "Access denied.")
+ return FALSE
+
+ switch(action)
+ if("time")
+ var/value = text2num(params["adjust"])
+ if(value)
+ . = set_timer(time_left()+value)
+ if("start")
+ timer_start()
+ if("stop")
+ timer_end(forced = TRUE)
+ if("flash")
+ for(var/obj/machinery/flasher/F in targets)
+ F.flash()
+ if("preset")
+ var/preset = params["preset"]
+ var/preset_time = time_left()
+ switch(preset)
+ if("short")
+ preset_time = PRESET_SHORT
+ if("medium")
+ preset_time = PRESET_MEDIUM
+ if("long")
+ preset_time = PRESET_LONG
+ . = set_timer(preset_time)
+ if(timing)
+ activation_time = world.realtime
+ else
+ . = FALSE
+
+
+#undef PRESET_SHORT
+#undef PRESET_MEDIUM
+#undef PRESET_LONG
+
+#undef MAX_TIMER
+#undef FONT_SIZE
+#undef FONT_COLOR
+#undef FONT_STYLE
+#undef CHARS_PER_LINE
diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm
index da1cef2592..9a09be093d 100644
--- a/code/game/objects/items/devices/gps.dm
+++ b/code/game/objects/items/devices/gps.dm
@@ -1,226 +1,226 @@
-GLOBAL_LIST_EMPTY(GPS_list)
-/obj/item/gps
- name = "global positioning system"
- desc = "Helping lost spacemen find their way through the planets since 2016."
- icon = 'icons/obj/telescience.dmi'
- icon_state = "gps-c"
- w_class = WEIGHT_CLASS_SMALL
- slot_flags = ITEM_SLOT_BELT
- obj_flags = UNIQUE_RENAME
- var/gpstag = "COM0"
- var/emped = FALSE
- var/tracking = TRUE
- var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user.
- var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown
-
-/obj/item/gps/examine(mob/user)
- . = ..()
- var/turf/curr = get_turf(src)
- . += "The screen says: [get_area_name(curr, TRUE)] ([curr.x], [curr.y], [curr.z])"
- . += "Alt-click to switch it [tracking ? "off":"on"]."
-
-/obj/item/gps/Initialize()
- . = ..()
- GLOB.GPS_list += src
- name = "global positioning system ([gpstag])"
- add_overlay("working")
-
-/obj/item/gps/Destroy()
- GLOB.GPS_list -= src
- return ..()
-
-/obj/item/gps/emp_act(severity)
- . = ..()
- if (. & EMP_PROTECT_SELF)
- return
- emped = TRUE
- cut_overlay("working")
- add_overlay("emp")
- addtimer(CALLBACK(src, .proc/reboot), 300, TIMER_UNIQUE|TIMER_OVERRIDE) //if a new EMP happens, remove the old timer so it doesn't reactivate early
- SStgui.close_uis(src) //Close the UI control if it is open.
-
-/obj/item/gps/proc/reboot()
- emped = FALSE
- cut_overlay("emp")
- add_overlay("working")
-
-/obj/item/gps/AltClick(mob/user)
- . = ..()
- if(!user.canUseTopic(src, BE_CLOSE))
- return
- toggletracking(user)
- return TRUE
-
-/obj/item/gps/proc/toggletracking(mob/user)
- if(!user.canUseTopic(src, BE_CLOSE))
- return //user not valid to use gps
- if(emped)
- to_chat(user, "It's busted!")
- return
- if(tracking)
- cut_overlay("working")
- to_chat(user, "[src] is no longer tracking, or visible to other GPS devices.")
- tracking = FALSE
- else
- add_overlay("working")
- to_chat(user, "[src] is now tracking, and visible to other GPS devices.")
- tracking = TRUE
-
-
-/obj/item/gps/ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
- if(emped)
- to_chat(user, "[src] fizzles weakly.")
- return
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- // Variable window height, depending on how many GPS units there are
- // to show, clamped to relatively safe range.
- var/gps_window_height = CLAMP(325 + GLOB.GPS_list.len * 14, 325, 700)
- ui = new(user, src, ui_key, "gps", "Global Positioning System", 470, gps_window_height, master_ui, state) //width, height
- ui.open()
-
- ui.set_autoupdate(state = updating)
-
-
-/obj/item/gps/ui_data(mob/user)
- var/list/data = list()
- data["power"] = tracking
- data["tag"] = gpstag
- data["updating"] = updating
- data["globalmode"] = global_mode
- if(!tracking || emped) //Do not bother scanning if the GPS is off or EMPed
- return data
-
- var/turf/curr = get_turf(src)
- data["current"] = "[get_area_name(curr, TRUE)] ([curr.x], [curr.y], [curr.z])"
- data["currentArea"] = "[get_area_name(curr, TRUE)]"
- data["currentCoords"] = "[curr.x], [curr.y], [curr.z]"
-
- var/list/signals = list()
- data["signals"] = list()
-
- for(var/gps in GLOB.GPS_list)
- var/obj/item/gps/G = gps
- if(G.emped || !G.tracking || G == src)
- continue
- var/turf/pos = get_turf(G)
- if(!global_mode && pos.z != curr.z)
- continue
- var/list/signal = list()
- signal["entrytag"] = G.gpstag //Name or 'tag' of the GPS
- signal["coords"] = "[pos.x], [pos.y], [pos.z]"
- if(pos.z == curr.z) //Distance/Direction calculations for same z-level only
- signal["dist"] = max(get_dist(curr, pos), 0) //Distance between the src and remote GPS turfs
- signal["degrees"] = round(Get_Angle(curr, pos)) //0-360 degree directional bearing, for more precision.
-
- signals += list(signal) //Add this signal to the list of signals
- data["signals"] = signals
- return data
-
-
-
-/obj/item/gps/ui_act(action, params)
- if(..())
- return
- switch(action)
- if("rename")
- var/a = input("Please enter desired tag.", name, gpstag) as text
- a = copytext(sanitize(a), 1, 20)
- gpstag = a
- . = TRUE
- name = "global positioning system ([gpstag])"
-
- if("power")
- toggletracking(usr)
- . = TRUE
- if("updating")
- updating = !updating
- . = TRUE
- if("globalmode")
- global_mode = !global_mode
- . = TRUE
-
-
-/obj/item/gps/science
- icon_state = "gps-s"
- gpstag = "SCI0"
-
-/obj/item/gps/engineering
- icon_state = "gps-e"
- gpstag = "ENG0"
-
-/obj/item/gps/mining
- icon_state = "gps-m"
- gpstag = "MINE0"
- desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life."
-
-/obj/item/gps/cyborg
- icon_state = "gps-b"
- gpstag = "BORG0"
- desc = "A mining cyborg internal positioning system. Used as a recovery beacon for damaged cyborg assets, or a collaboration tool for mining teams."
-
-/obj/item/gps/cyborg/Initialize()
- . = ..()
- ADD_TRAIT(src, TRAIT_NODROP, CYBORG_ITEM_TRAIT)
-
-/obj/item/gps/internal
- icon_state = null
- item_flags = ABSTRACT
- gpstag = "Eerie Signal"
- desc = "Report to a coder immediately."
- invisibility = INVISIBILITY_MAXIMUM
- var/obj/item/implant/gps/implant
-
-/obj/item/gps/internal/Initialize(mapload, obj/item/implant/gps/_implant)
- . = ..()
- implant = _implant
-
-/obj/item/gps/internal/Destroy()
- if(implant?.imp_in)
- qdel(implant)
- else
- return ..()
-
-/obj/item/gps/internal/mining
- icon_state = "gps-m"
- gpstag = "MINER"
- desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life."
-
-/obj/item/gps/internal/base
- gpstag = "NT_AUX"
- desc = "A homing signal from Nanotrasen's mining base."
-
-/obj/item/gps/visible_debug
- name = "visible GPS"
- gpstag = "ADMIN"
- desc = "This admin-spawn GPS unit leaves the coordinates visible \
- on any turf that it passes over, for debugging. Especially useful \
- for marking the area around the transition edges."
- var/list/turf/tagged
-
-/obj/item/gps/visible_debug/Initialize()
- . = ..()
- tagged = list()
- START_PROCESSING(SSfastprocess, src)
-
-/obj/item/gps/visible_debug/process()
- var/turf/T = get_turf(src)
- if(T)
- // I assume it's faster to color,tag and OR the turf in, rather
- // then checking if its there
- T.color = RANDOM_COLOUR
- T.maptext = "[T.x],[T.y],[T.z]"
- tagged |= T
-
-/obj/item/gps/visible_debug/proc/clear()
- while(tagged.len)
- var/turf/T = pop(tagged)
- T.color = initial(T.color)
- T.maptext = initial(T.maptext)
-
-/obj/item/gps/visible_debug/Destroy()
- if(tagged)
- clear()
- tagged = null
- STOP_PROCESSING(SSfastprocess, src)
- . = ..()
+GLOBAL_LIST_EMPTY(GPS_list)
+/obj/item/gps
+ name = "global positioning system"
+ desc = "Helping lost spacemen find their way through the planets since 2016."
+ icon = 'icons/obj/telescience.dmi'
+ icon_state = "gps-c"
+ w_class = WEIGHT_CLASS_SMALL
+ slot_flags = ITEM_SLOT_BELT
+ obj_flags = UNIQUE_RENAME
+ var/gpstag = "COM0"
+ var/emped = FALSE
+ var/tracking = TRUE
+ var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user.
+ var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown
+
+/obj/item/gps/examine(mob/user)
+ . = ..()
+ var/turf/curr = get_turf(src)
+ . += "The screen says: [get_area_name(curr, TRUE)] ([curr.x], [curr.y], [curr.z])"
+ . += "Alt-click to switch it [tracking ? "off":"on"]."
+
+/obj/item/gps/Initialize()
+ . = ..()
+ GLOB.GPS_list += src
+ name = "global positioning system ([gpstag])"
+ add_overlay("working")
+
+/obj/item/gps/Destroy()
+ GLOB.GPS_list -= src
+ return ..()
+
+/obj/item/gps/emp_act(severity)
+ . = ..()
+ if (. & EMP_PROTECT_SELF)
+ return
+ emped = TRUE
+ cut_overlay("working")
+ add_overlay("emp")
+ addtimer(CALLBACK(src, .proc/reboot), 300, TIMER_UNIQUE|TIMER_OVERRIDE) //if a new EMP happens, remove the old timer so it doesn't reactivate early
+ SStgui.close_uis(src) //Close the UI control if it is open.
+
+/obj/item/gps/proc/reboot()
+ emped = FALSE
+ cut_overlay("emp")
+ add_overlay("working")
+
+/obj/item/gps/AltClick(mob/user)
+ . = ..()
+ if(!user.canUseTopic(src, BE_CLOSE))
+ return
+ toggletracking(user)
+ return TRUE
+
+/obj/item/gps/proc/toggletracking(mob/user)
+ if(!user.canUseTopic(src, BE_CLOSE))
+ return //user not valid to use gps
+ if(emped)
+ to_chat(user, "It's busted!")
+ return
+ if(tracking)
+ cut_overlay("working")
+ to_chat(user, "[src] is no longer tracking, or visible to other GPS devices.")
+ tracking = FALSE
+ else
+ add_overlay("working")
+ to_chat(user, "[src] is now tracking, and visible to other GPS devices.")
+ tracking = TRUE
+
+
+/obj/item/gps/ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
+ if(emped)
+ to_chat(user, "[src] fizzles weakly.")
+ return
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ // Variable window height, depending on how many GPS units there are
+ // to show, clamped to relatively safe range.
+ var/gps_window_height = CLAMP(325 + GLOB.GPS_list.len * 14, 325, 700)
+ ui = new(user, src, ui_key, "gps", "Global Positioning System", 470, gps_window_height, master_ui, state) //width, height
+ ui.open()
+
+ ui.set_autoupdate(state = updating)
+
+
+/obj/item/gps/ui_data(mob/user)
+ var/list/data = list()
+ data["power"] = tracking
+ data["tag"] = gpstag
+ data["updating"] = updating
+ data["globalmode"] = global_mode
+ if(!tracking || emped) //Do not bother scanning if the GPS is off or EMPed
+ return data
+
+ var/turf/curr = get_turf(src)
+ data["current"] = "[get_area_name(curr, TRUE)] ([curr.x], [curr.y], [curr.z])"
+ data["currentArea"] = "[get_area_name(curr, TRUE)]"
+ data["currentCoords"] = "[curr.x], [curr.y], [curr.z]"
+
+ var/list/signals = list()
+ data["signals"] = list()
+
+ for(var/gps in GLOB.GPS_list)
+ var/obj/item/gps/G = gps
+ if(G.emped || !G.tracking || G == src)
+ continue
+ var/turf/pos = get_turf(G)
+ if(!global_mode && pos.z != curr.z)
+ continue
+ var/list/signal = list()
+ signal["entrytag"] = G.gpstag //Name or 'tag' of the GPS
+ signal["coords"] = "[pos.x], [pos.y], [pos.z]"
+ if(pos.z == curr.z) //Distance/Direction calculations for same z-level only
+ signal["dist"] = max(get_dist(curr, pos), 0) //Distance between the src and remote GPS turfs
+ signal["degrees"] = round(Get_Angle(curr, pos)) //0-360 degree directional bearing, for more precision.
+
+ signals += list(signal) //Add this signal to the list of signals
+ data["signals"] = signals
+ return data
+
+
+
+/obj/item/gps/ui_act(action, params)
+ if(..())
+ return
+ switch(action)
+ if("rename")
+ var/a = input("Please enter desired tag.", name, gpstag) as text
+ a = copytext(sanitize(a), 1, 20)
+ gpstag = a
+ . = TRUE
+ name = "global positioning system ([gpstag])"
+
+ if("power")
+ toggletracking(usr)
+ . = TRUE
+ if("updating")
+ updating = !updating
+ . = TRUE
+ if("globalmode")
+ global_mode = !global_mode
+ . = TRUE
+
+
+/obj/item/gps/science
+ icon_state = "gps-s"
+ gpstag = "SCI0"
+
+/obj/item/gps/engineering
+ icon_state = "gps-e"
+ gpstag = "ENG0"
+
+/obj/item/gps/mining
+ icon_state = "gps-m"
+ gpstag = "MINE0"
+ desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life."
+
+/obj/item/gps/cyborg
+ icon_state = "gps-b"
+ gpstag = "BORG0"
+ desc = "A mining cyborg internal positioning system. Used as a recovery beacon for damaged cyborg assets, or a collaboration tool for mining teams."
+
+/obj/item/gps/cyborg/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, CYBORG_ITEM_TRAIT)
+
+/obj/item/gps/internal
+ icon_state = null
+ item_flags = ABSTRACT
+ gpstag = "Eerie Signal"
+ desc = "Report to a coder immediately."
+ invisibility = INVISIBILITY_MAXIMUM
+ var/obj/item/implant/gps/implant
+
+/obj/item/gps/internal/Initialize(mapload, obj/item/implant/gps/_implant)
+ . = ..()
+ implant = _implant
+
+/obj/item/gps/internal/Destroy()
+ if(implant?.imp_in)
+ qdel(implant)
+ else
+ return ..()
+
+/obj/item/gps/internal/mining
+ icon_state = "gps-m"
+ gpstag = "MINER"
+ desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life."
+
+/obj/item/gps/internal/base
+ gpstag = "NT_AUX"
+ desc = "A homing signal from Nanotrasen's mining base."
+
+/obj/item/gps/visible_debug
+ name = "visible GPS"
+ gpstag = "ADMIN"
+ desc = "This admin-spawn GPS unit leaves the coordinates visible \
+ on any turf that it passes over, for debugging. Especially useful \
+ for marking the area around the transition edges."
+ var/list/turf/tagged
+
+/obj/item/gps/visible_debug/Initialize()
+ . = ..()
+ tagged = list()
+ START_PROCESSING(SSfastprocess, src)
+
+/obj/item/gps/visible_debug/process()
+ var/turf/T = get_turf(src)
+ if(T)
+ // I assume it's faster to color,tag and OR the turf in, rather
+ // then checking if its there
+ T.color = RANDOM_COLOUR
+ T.maptext = "[T.x],[T.y],[T.z]"
+ tagged |= T
+
+/obj/item/gps/visible_debug/proc/clear()
+ while(tagged.len)
+ var/turf/T = pop(tagged)
+ T.color = initial(T.color)
+ T.maptext = initial(T.maptext)
+
+/obj/item/gps/visible_debug/Destroy()
+ if(tagged)
+ clear()
+ tagged = null
+ STOP_PROCESSING(SSfastprocess, src)
+ . = ..()
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 273868c3e0..b87b7b11bd 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -1,436 +1,436 @@
-/obj/item/radio
- icon = 'icons/obj/radio.dmi'
- name = "station bounced radio"
- icon_state = "walkietalkie"
- item_state = "walkietalkie"
- desc = "A basic handheld radio that communicates with local telecommunication networks."
- dog_fashion = /datum/dog_fashion/back
-
- flags_1 = CONDUCT_1 | HEAR_1
- slot_flags = ITEM_SLOT_BELT
- throw_speed = 3
- throw_range = 7
- w_class = WEIGHT_CLASS_SMALL
- materials = list(MAT_METAL=75, MAT_GLASS=25)
- obj_flags = USES_TGUI
-
- var/on = TRUE
- var/frequency = FREQ_COMMON
- var/canhear_range = 3 // The range around the radio in which mobs can hear what it receives.
- var/emped = 0 // Tracks the number of EMPs currently stacked.
-
- var/broadcasting = FALSE // Whether the radio will transmit dialogue it hears nearby.
- var/listening = TRUE // Whether the radio is currently receiving.
- var/prison_radio = FALSE // If true, the transmit wire starts cut.
- var/unscrewed = FALSE // Whether wires are accessible. Toggleable by screwdrivering.
- var/freerange = FALSE // If true, the radio has access to the full spectrum.
- var/subspace_transmission = FALSE // If true, the radio transmits and receives on subspace exclusively.
- var/subspace_switchable = FALSE // If true, subspace_transmission can be toggled at will.
- var/freqlock = FALSE // Frequency lock to stop the user from untuning specialist radios.
- var/use_command = FALSE // If true, broadcasts will be large and BOLD.
- var/command = FALSE // If true, use_command can be toggled at will.
- var/commandspan = SPAN_COMMAND //allow us to set what the fuck we want for headsets
-
- // Encryption key handling
- var/obj/item/encryptionkey/keyslot
- var/translate_binary = FALSE // If true, can hear the special binary channel.
- var/independent = FALSE // If true, can say/hear on the special CentCom channel.
- var/syndie = FALSE // If true, hears all well-known channels automatically, and can say/hear on the Syndicate channel.
- var/list/channels = list() // Map from name (see communications.dm) to on/off. First entry is current department (:h).
- var/list/secure_radio_connections
-
- var/const/FREQ_LISTENING = 1
- //FREQ_BROADCASTING = 2
-
-/obj/item/radio/suicide_act(mob/living/user)
- user.visible_message("[user] starts bouncing [src] off [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!")
- return BRUTELOSS
-
-/obj/item/radio/proc/set_frequency(new_frequency)
- SEND_SIGNAL(src, COMSIG_RADIO_NEW_FREQUENCY, args)
- remove_radio(src, frequency)
- frequency = add_radio(src, new_frequency)
-
-/obj/item/radio/proc/recalculateChannels()
- channels = list()
- translate_binary = FALSE
- syndie = FALSE
- independent = FALSE
-
- if(keyslot)
- for(var/ch_name in keyslot.channels)
- if(!(ch_name in channels))
- channels[ch_name] = keyslot.channels[ch_name]
-
- if(keyslot.translate_binary)
- translate_binary = TRUE
- if(keyslot.syndie)
- syndie = TRUE
- if(keyslot.independent)
- independent = TRUE
-
- for(var/ch_name in channels)
- secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name])
-
-/obj/item/radio/proc/make_syndie() // Turns normal radios into Syndicate radios!
- qdel(keyslot)
- keyslot = new /obj/item/encryptionkey/syndicate
- syndie = 1
- recalculateChannels()
-
-/obj/item/radio/Destroy()
- remove_radio_all(src) //Just to be sure
- QDEL_NULL(wires)
- QDEL_NULL(keyslot)
- return ..()
-
-/obj/item/radio/Initialize()
- wires = new /datum/wires/radio(src)
- if(prison_radio)
- wires.cut(WIRE_TX) // OH GOD WHY
- secure_radio_connections = new
- . = ..()
- frequency = sanitize_frequency(frequency, freerange)
- set_frequency(frequency)
-
- for(var/ch_name in channels)
- secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name])
-
-/obj/item/radio/ComponentInitialize()
- . = ..()
- AddComponent(/datum/component/empprotection, EMP_PROTECT_WIRES)
-
-/obj/item/radio/interact(mob/user)
- if(unscrewed && !isAI(user))
- wires.interact(user)
- add_fingerprint(user)
- else
- ..()
-
-/obj/item/radio/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state)
- . = ..()
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- var/ui_width = 360
- var/ui_height = 106
- if(subspace_transmission)
- if(channels.len > 0)
- ui_height += 6 + channels.len * 21
- else
- ui_height += 24
- ui = new(user, src, ui_key, "radio", name, ui_width, ui_height, master_ui, state)
- ui.open()
-
-/obj/item/radio/ui_data(mob/user)
- var/list/data = list()
-
- data["broadcasting"] = broadcasting
- data["listening"] = listening
- data["frequency"] = frequency
- data["minFrequency"] = freerange ? MIN_FREE_FREQ : MIN_FREQ
- data["maxFrequency"] = freerange ? MAX_FREE_FREQ : MAX_FREQ
- data["freqlock"] = freqlock
- data["channels"] = list()
- for(var/channel in channels)
- data["channels"][channel] = channels[channel] & FREQ_LISTENING
- data["command"] = command
- data["useCommand"] = use_command
- data["subspace"] = subspace_transmission
- data["subspaceSwitchable"] = subspace_switchable
- data["headset"] = istype(src, /obj/item/radio/headset)
-
- return data
-
-/obj/item/radio/ui_act(action, params, datum/tgui/ui)
- if(..())
- return
- switch(action)
- if("frequency")
- if(freqlock)
- return
- var/tune = params["tune"]
- var/adjust = text2num(params["adjust"])
- if(tune == "input")
- var/min = format_frequency(freerange ? MIN_FREE_FREQ : MIN_FREQ)
- var/max = format_frequency(freerange ? MAX_FREE_FREQ : MAX_FREQ)
- tune = input("Tune frequency ([min]-[max]):", name, format_frequency(frequency)) as null|num
- if(!isnull(tune) && !..())
- if (tune < MIN_FREE_FREQ && tune <= MAX_FREE_FREQ / 10)
- // allow typing 144.7 to get 1447
- tune *= 10
- . = TRUE
- else if(adjust)
- tune = frequency + adjust * 10
- . = TRUE
- else if(text2num(tune) != null)
- tune = tune * 10
- . = TRUE
- if(.)
- set_frequency(sanitize_frequency(tune, freerange))
- if("listen")
- listening = !listening
- . = TRUE
- if("broadcast")
- broadcasting = !broadcasting
- . = TRUE
- if("channel")
- var/channel = params["channel"]
- if(!(channel in channels))
- return
- if(channels[channel] & FREQ_LISTENING)
- channels[channel] &= ~FREQ_LISTENING
- else
- channels[channel] |= FREQ_LISTENING
- . = TRUE
- if("command")
- use_command = !use_command
- . = TRUE
- if("subspace")
- if(subspace_switchable)
- subspace_transmission = !subspace_transmission
- if(!subspace_transmission)
- channels = list()
- else
- recalculateChannels()
- . = TRUE
-
-/obj/item/radio/talk_into(atom/movable/M, message, channel, list/spans, datum/language/language)
- if(!spans)
- spans = list(M.speech_span)
- if(!language)
- language = M.get_default_language()
- INVOKE_ASYNC(src, .proc/talk_into_impl, M, message, channel, spans.Copy(), language)
- return ITALICS | REDUCE_RANGE
-
-/obj/item/radio/proc/talk_into_impl(atom/movable/M, message, channel, list/spans, datum/language/language)
- if(!on)
- return // the device has to be on
- if(!M || !message)
- return
- if(wires.is_cut(WIRE_TX)) // Permacell and otherwise tampered-with radios
- return
- if(!M.IsVocal())
- return
-
- if(use_command)
- spans |= commandspan
-
- /*
- Roughly speaking, radios attempt to make a subspace transmission (which
- is received, processed, and rebroadcast by the telecomms satellite) and
- if that fails, they send a mundane radio transmission.
-
- Headsets cannot send/receive mundane transmissions, only subspace.
- Syndicate radios can hear transmissions on all well-known frequencies.
- CentCom radios can hear the CentCom frequency no matter what.
- */
-
- // From the channel, determine the frequency and get a reference to it.
- var/freq
- if(channel && channels && channels.len > 0)
- if(channel == MODE_DEPARTMENT)
- channel = channels[1]
- freq = secure_radio_connections[channel]
- if (!channels[channel]) // if the channel is turned off, don't broadcast
- return
- else
- freq = frequency
- channel = null
-
- // Nearby active jammers severely gibberish the message
- var/turf/position = get_turf(src)
- for(var/obj/item/jammer/jammer in GLOB.active_jammers)
- var/turf/jammer_turf = get_turf(jammer)
- if(position.z == jammer_turf.z && (get_dist(position, jammer_turf) < jammer.range))
- message = Gibberish(message,100)
- break
-
- // Determine the identity information which will be attached to the signal.
- var/atom/movable/virtualspeaker/speaker = new(null, M, src)
-
- // Construct the signal
- var/datum/signal/subspace/vocal/signal = new(src, freq, speaker, language, message, spans)
-
- // Independent radios, on the CentCom frequency, reach all independent radios
- if (independent && (freq == FREQ_CENTCOM || freq == FREQ_CTF_RED || freq == FREQ_CTF_BLUE))
- signal.data["compression"] = 0
- signal.transmission_method = TRANSMISSION_SUPERSPACE
- signal.levels = list(0) // reaches all Z-levels
- signal.broadcast()
- return
-
- // All radios make an attempt to use the subspace system first
- signal.send_to_receivers()
-
- // If the radio is subspace-only, that's all it can do
- if (subspace_transmission)
- return
-
- // Non-subspace radios will check in a couple of seconds, and if the signal
- // was never received, send a mundane broadcast (no headsets).
- addtimer(CALLBACK(src, .proc/backup_transmission, signal), 20)
-
-/obj/item/radio/proc/backup_transmission(datum/signal/subspace/vocal/signal)
- var/turf/T = get_turf(src)
- if (signal.data["done"] && (T.z in signal.levels))
- return
-
- // Okay, the signal was never processed, send a mundane broadcast.
- signal.data["compression"] = 0
- signal.transmission_method = TRANSMISSION_RADIO
- signal.levels = list(T.z)
- signal.broadcast()
-
-/obj/item/radio/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
- . = ..()
- if(radio_freq || !broadcasting || get_dist(src, speaker) > canhear_range)
- return
-
- if(message_mode == MODE_WHISPER || message_mode == MODE_WHISPER_CRIT)
- // radios don't pick up whispers very well
- raw_message = stars(raw_message)
- else if(message_mode == MODE_L_HAND || message_mode == MODE_R_HAND)
- // try to avoid being heard double
- if (loc == speaker && ismob(speaker))
- var/mob/M = speaker
- var/idx = M.get_held_index_of_item(src)
- // left hands are odd slots
- if (idx && (idx % 2) == (message_mode == MODE_L_HAND))
- return
-
- talk_into(speaker, raw_message, , spans, language=message_language)
-
-// Checks if this radio can receive on the given frequency.
-/obj/item/radio/proc/can_receive(freq, level)
- // deny checks
- if (!on || !listening || wires.is_cut(WIRE_RX))
- return FALSE
- if (freq == FREQ_SYNDICATE && !syndie)
- return FALSE
- if (freq == FREQ_CENTCOM)
- return independent // hard-ignores the z-level check
- if (!(0 in level))
- var/turf/position = get_turf(src)
- if(!position || !(position.z in level))
- return FALSE
-
- // allow checks: are we listening on that frequency?
- if (freq == frequency)
- return TRUE
- for(var/ch_name in channels)
- if(channels[ch_name] & FREQ_LISTENING)
- //the GLOB.radiochannels list is located in communications.dm
- if(GLOB.radiochannels[ch_name] == text2num(freq) || syndie)
- return TRUE
- return FALSE
-
-
-/obj/item/radio/examine(mob/user)
- . = ..()
- if (unscrewed)
- . += "It can be attached and modified."
- else
- . += "It cannot be modified or attached."
-
-/obj/item/radio/attackby(obj/item/W, mob/user, params)
- add_fingerprint(user)
- if(istype(W, /obj/item/screwdriver))
- unscrewed = !unscrewed
- if(unscrewed)
- to_chat(user, "The radio can now be attached and modified!")
- else
- to_chat(user, "The radio can no longer be modified or attached!")
- else
- return ..()
-
-/obj/item/radio/emp_act(severity)
- . = ..()
- if (. & EMP_PROTECT_SELF)
- return
- emped++ //There's been an EMP; better count it
- var/curremp = emped //Remember which EMP this was
- if (listening && ismob(loc)) // if the radio is turned on and on someone's person they notice
- to_chat(loc, "\The [src] overloads.")
- broadcasting = FALSE
- listening = FALSE
- for (var/ch_name in channels)
- channels[ch_name] = 0
- on = FALSE
- spawn(200)
- if(emped == curremp) //Don't fix it if it's been EMP'd again
- emped = 0
- if (!istype(src, /obj/item/radio/intercom)) // intercoms will turn back on on their own
- on = TRUE
-
-///////////////////////////////
-//////////Borg Radios//////////
-///////////////////////////////
-//Giving borgs their own radio to have some more room to work with -Sieve
-
-/obj/item/radio/borg
- name = "cyborg radio"
- subspace_switchable = TRUE
- dog_fashion = null
-
-/obj/item/radio/borg/Initialize(mapload)
- . = ..()
-
-/obj/item/radio/borg/syndicate
- syndie = 1
- keyslot = new /obj/item/encryptionkey/syndicate
-
-/obj/item/radio/borg/syndicate/Initialize()
- . = ..()
- set_frequency(FREQ_SYNDICATE)
-
-/obj/item/radio/borg/attackby(obj/item/W, mob/user, params)
-
- if(istype(W, /obj/item/screwdriver))
- if(keyslot)
- for(var/ch_name in channels)
- SSradio.remove_object(src, GLOB.radiochannels[ch_name])
- secure_radio_connections[ch_name] = null
-
-
- if(keyslot)
- var/turf/T = get_turf(user)
- if(T)
- keyslot.forceMove(T)
- keyslot = null
-
- recalculateChannels()
- to_chat(user, "You pop out the encryption key in the radio.")
-
- else
- to_chat(user, "This radio doesn't have any encryption keys!")
-
- else if(istype(W, /obj/item/encryptionkey/))
- if(keyslot)
- to_chat(user, "The radio can't hold another key!")
- return
-
- if(!keyslot)
- if(!user.transferItemToLoc(W, src))
- return
- keyslot = W
-
- recalculateChannels()
-
-
-/obj/item/radio/off // Station bounced radios, their only difference is spawning with the speakers off, this was made to help the lag.
- listening = 0 // And it's nice to have a subtype too for future features.
- dog_fashion = /datum/dog_fashion/back
-
-/obj/item/radio/internal
- var/obj/item/implant/radio/implant
-
-/obj/item/radio/internal/Initialize(mapload, obj/item/implant/radio/_implant)
- . = ..()
- implant = _implant
-
-/obj/item/radio/internal/Destroy()
- if(implant?.imp_in)
- qdel(implant)
- else
- return ..()
+/obj/item/radio
+ icon = 'icons/obj/radio.dmi'
+ name = "station bounced radio"
+ icon_state = "walkietalkie"
+ item_state = "walkietalkie"
+ desc = "A basic handheld radio that communicates with local telecommunication networks."
+ dog_fashion = /datum/dog_fashion/back
+
+ flags_1 = CONDUCT_1 | HEAR_1
+ slot_flags = ITEM_SLOT_BELT
+ throw_speed = 3
+ throw_range = 7
+ w_class = WEIGHT_CLASS_SMALL
+ materials = list(MAT_METAL=75, MAT_GLASS=25)
+ obj_flags = USES_TGUI
+
+ var/on = TRUE
+ var/frequency = FREQ_COMMON
+ var/canhear_range = 3 // The range around the radio in which mobs can hear what it receives.
+ var/emped = 0 // Tracks the number of EMPs currently stacked.
+
+ var/broadcasting = FALSE // Whether the radio will transmit dialogue it hears nearby.
+ var/listening = TRUE // Whether the radio is currently receiving.
+ var/prison_radio = FALSE // If true, the transmit wire starts cut.
+ var/unscrewed = FALSE // Whether wires are accessible. Toggleable by screwdrivering.
+ var/freerange = FALSE // If true, the radio has access to the full spectrum.
+ var/subspace_transmission = FALSE // If true, the radio transmits and receives on subspace exclusively.
+ var/subspace_switchable = FALSE // If true, subspace_transmission can be toggled at will.
+ var/freqlock = FALSE // Frequency lock to stop the user from untuning specialist radios.
+ var/use_command = FALSE // If true, broadcasts will be large and BOLD.
+ var/command = FALSE // If true, use_command can be toggled at will.
+ var/commandspan = SPAN_COMMAND //allow us to set what the fuck we want for headsets
+
+ // Encryption key handling
+ var/obj/item/encryptionkey/keyslot
+ var/translate_binary = FALSE // If true, can hear the special binary channel.
+ var/independent = FALSE // If true, can say/hear on the special CentCom channel.
+ var/syndie = FALSE // If true, hears all well-known channels automatically, and can say/hear on the Syndicate channel.
+ var/list/channels = list() // Map from name (see communications.dm) to on/off. First entry is current department (:h).
+ var/list/secure_radio_connections
+
+ var/const/FREQ_LISTENING = 1
+ //FREQ_BROADCASTING = 2
+
+/obj/item/radio/suicide_act(mob/living/user)
+ user.visible_message("[user] starts bouncing [src] off [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!")
+ return BRUTELOSS
+
+/obj/item/radio/proc/set_frequency(new_frequency)
+ SEND_SIGNAL(src, COMSIG_RADIO_NEW_FREQUENCY, args)
+ remove_radio(src, frequency)
+ frequency = add_radio(src, new_frequency)
+
+/obj/item/radio/proc/recalculateChannels()
+ channels = list()
+ translate_binary = FALSE
+ syndie = FALSE
+ independent = FALSE
+
+ if(keyslot)
+ for(var/ch_name in keyslot.channels)
+ if(!(ch_name in channels))
+ channels[ch_name] = keyslot.channels[ch_name]
+
+ if(keyslot.translate_binary)
+ translate_binary = TRUE
+ if(keyslot.syndie)
+ syndie = TRUE
+ if(keyslot.independent)
+ independent = TRUE
+
+ for(var/ch_name in channels)
+ secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name])
+
+/obj/item/radio/proc/make_syndie() // Turns normal radios into Syndicate radios!
+ qdel(keyslot)
+ keyslot = new /obj/item/encryptionkey/syndicate
+ syndie = 1
+ recalculateChannels()
+
+/obj/item/radio/Destroy()
+ remove_radio_all(src) //Just to be sure
+ QDEL_NULL(wires)
+ QDEL_NULL(keyslot)
+ return ..()
+
+/obj/item/radio/Initialize()
+ wires = new /datum/wires/radio(src)
+ if(prison_radio)
+ wires.cut(WIRE_TX) // OH GOD WHY
+ secure_radio_connections = new
+ . = ..()
+ frequency = sanitize_frequency(frequency, freerange)
+ set_frequency(frequency)
+
+ for(var/ch_name in channels)
+ secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name])
+
+/obj/item/radio/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/empprotection, EMP_PROTECT_WIRES)
+
+/obj/item/radio/interact(mob/user)
+ if(unscrewed && !isAI(user))
+ wires.interact(user)
+ add_fingerprint(user)
+ else
+ ..()
+
+/obj/item/radio/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state)
+ . = ..()
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ var/ui_width = 360
+ var/ui_height = 106
+ if(subspace_transmission)
+ if(channels.len > 0)
+ ui_height += 6 + channels.len * 21
+ else
+ ui_height += 24
+ ui = new(user, src, ui_key, "radio", name, ui_width, ui_height, master_ui, state)
+ ui.open()
+
+/obj/item/radio/ui_data(mob/user)
+ var/list/data = list()
+
+ data["broadcasting"] = broadcasting
+ data["listening"] = listening
+ data["frequency"] = frequency
+ data["minFrequency"] = freerange ? MIN_FREE_FREQ : MIN_FREQ
+ data["maxFrequency"] = freerange ? MAX_FREE_FREQ : MAX_FREQ
+ data["freqlock"] = freqlock
+ data["channels"] = list()
+ for(var/channel in channels)
+ data["channels"][channel] = channels[channel] & FREQ_LISTENING
+ data["command"] = command
+ data["useCommand"] = use_command
+ data["subspace"] = subspace_transmission
+ data["subspaceSwitchable"] = subspace_switchable
+ data["headset"] = istype(src, /obj/item/radio/headset)
+
+ return data
+
+/obj/item/radio/ui_act(action, params, datum/tgui/ui)
+ if(..())
+ return
+ switch(action)
+ if("frequency")
+ if(freqlock)
+ return
+ var/tune = params["tune"]
+ var/adjust = text2num(params["adjust"])
+ if(tune == "input")
+ var/min = format_frequency(freerange ? MIN_FREE_FREQ : MIN_FREQ)
+ var/max = format_frequency(freerange ? MAX_FREE_FREQ : MAX_FREQ)
+ tune = input("Tune frequency ([min]-[max]):", name, format_frequency(frequency)) as null|num
+ if(!isnull(tune) && !..())
+ if (tune < MIN_FREE_FREQ && tune <= MAX_FREE_FREQ / 10)
+ // allow typing 144.7 to get 1447
+ tune *= 10
+ . = TRUE
+ else if(adjust)
+ tune = frequency + adjust * 10
+ . = TRUE
+ else if(text2num(tune) != null)
+ tune = tune * 10
+ . = TRUE
+ if(.)
+ set_frequency(sanitize_frequency(tune, freerange))
+ if("listen")
+ listening = !listening
+ . = TRUE
+ if("broadcast")
+ broadcasting = !broadcasting
+ . = TRUE
+ if("channel")
+ var/channel = params["channel"]
+ if(!(channel in channels))
+ return
+ if(channels[channel] & FREQ_LISTENING)
+ channels[channel] &= ~FREQ_LISTENING
+ else
+ channels[channel] |= FREQ_LISTENING
+ . = TRUE
+ if("command")
+ use_command = !use_command
+ . = TRUE
+ if("subspace")
+ if(subspace_switchable)
+ subspace_transmission = !subspace_transmission
+ if(!subspace_transmission)
+ channels = list()
+ else
+ recalculateChannels()
+ . = TRUE
+
+/obj/item/radio/talk_into(atom/movable/M, message, channel, list/spans, datum/language/language)
+ if(!spans)
+ spans = list(M.speech_span)
+ if(!language)
+ language = M.get_default_language()
+ INVOKE_ASYNC(src, .proc/talk_into_impl, M, message, channel, spans.Copy(), language)
+ return ITALICS | REDUCE_RANGE
+
+/obj/item/radio/proc/talk_into_impl(atom/movable/M, message, channel, list/spans, datum/language/language)
+ if(!on)
+ return // the device has to be on
+ if(!M || !message)
+ return
+ if(wires.is_cut(WIRE_TX)) // Permacell and otherwise tampered-with radios
+ return
+ if(!M.IsVocal())
+ return
+
+ if(use_command)
+ spans |= commandspan
+
+ /*
+ Roughly speaking, radios attempt to make a subspace transmission (which
+ is received, processed, and rebroadcast by the telecomms satellite) and
+ if that fails, they send a mundane radio transmission.
+
+ Headsets cannot send/receive mundane transmissions, only subspace.
+ Syndicate radios can hear transmissions on all well-known frequencies.
+ CentCom radios can hear the CentCom frequency no matter what.
+ */
+
+ // From the channel, determine the frequency and get a reference to it.
+ var/freq
+ if(channel && channels && channels.len > 0)
+ if(channel == MODE_DEPARTMENT)
+ channel = channels[1]
+ freq = secure_radio_connections[channel]
+ if (!channels[channel]) // if the channel is turned off, don't broadcast
+ return
+ else
+ freq = frequency
+ channel = null
+
+ // Nearby active jammers severely gibberish the message
+ var/turf/position = get_turf(src)
+ for(var/obj/item/jammer/jammer in GLOB.active_jammers)
+ var/turf/jammer_turf = get_turf(jammer)
+ if(position.z == jammer_turf.z && (get_dist(position, jammer_turf) < jammer.range))
+ message = Gibberish(message,100)
+ break
+
+ // Determine the identity information which will be attached to the signal.
+ var/atom/movable/virtualspeaker/speaker = new(null, M, src)
+
+ // Construct the signal
+ var/datum/signal/subspace/vocal/signal = new(src, freq, speaker, language, message, spans)
+
+ // Independent radios, on the CentCom frequency, reach all independent radios
+ if (independent && (freq == FREQ_CENTCOM || freq == FREQ_CTF_RED || freq == FREQ_CTF_BLUE))
+ signal.data["compression"] = 0
+ signal.transmission_method = TRANSMISSION_SUPERSPACE
+ signal.levels = list(0) // reaches all Z-levels
+ signal.broadcast()
+ return
+
+ // All radios make an attempt to use the subspace system first
+ signal.send_to_receivers()
+
+ // If the radio is subspace-only, that's all it can do
+ if (subspace_transmission)
+ return
+
+ // Non-subspace radios will check in a couple of seconds, and if the signal
+ // was never received, send a mundane broadcast (no headsets).
+ addtimer(CALLBACK(src, .proc/backup_transmission, signal), 20)
+
+/obj/item/radio/proc/backup_transmission(datum/signal/subspace/vocal/signal)
+ var/turf/T = get_turf(src)
+ if (signal.data["done"] && (T.z in signal.levels))
+ return
+
+ // Okay, the signal was never processed, send a mundane broadcast.
+ signal.data["compression"] = 0
+ signal.transmission_method = TRANSMISSION_RADIO
+ signal.levels = list(T.z)
+ signal.broadcast()
+
+/obj/item/radio/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
+ . = ..()
+ if(radio_freq || !broadcasting || get_dist(src, speaker) > canhear_range)
+ return
+
+ if(message_mode == MODE_WHISPER || message_mode == MODE_WHISPER_CRIT)
+ // radios don't pick up whispers very well
+ raw_message = stars(raw_message)
+ else if(message_mode == MODE_L_HAND || message_mode == MODE_R_HAND)
+ // try to avoid being heard double
+ if (loc == speaker && ismob(speaker))
+ var/mob/M = speaker
+ var/idx = M.get_held_index_of_item(src)
+ // left hands are odd slots
+ if (idx && (idx % 2) == (message_mode == MODE_L_HAND))
+ return
+
+ talk_into(speaker, raw_message, , spans, language=message_language)
+
+// Checks if this radio can receive on the given frequency.
+/obj/item/radio/proc/can_receive(freq, level)
+ // deny checks
+ if (!on || !listening || wires.is_cut(WIRE_RX))
+ return FALSE
+ if (freq == FREQ_SYNDICATE && !syndie)
+ return FALSE
+ if (freq == FREQ_CENTCOM)
+ return independent // hard-ignores the z-level check
+ if (!(0 in level))
+ var/turf/position = get_turf(src)
+ if(!position || !(position.z in level))
+ return FALSE
+
+ // allow checks: are we listening on that frequency?
+ if (freq == frequency)
+ return TRUE
+ for(var/ch_name in channels)
+ if(channels[ch_name] & FREQ_LISTENING)
+ //the GLOB.radiochannels list is located in communications.dm
+ if(GLOB.radiochannels[ch_name] == text2num(freq) || syndie)
+ return TRUE
+ return FALSE
+
+
+/obj/item/radio/examine(mob/user)
+ . = ..()
+ if (unscrewed)
+ . += "It can be attached and modified."
+ else
+ . += "It cannot be modified or attached."
+
+/obj/item/radio/attackby(obj/item/W, mob/user, params)
+ add_fingerprint(user)
+ if(istype(W, /obj/item/screwdriver))
+ unscrewed = !unscrewed
+ if(unscrewed)
+ to_chat(user, "The radio can now be attached and modified!")
+ else
+ to_chat(user, "The radio can no longer be modified or attached!")
+ else
+ return ..()
+
+/obj/item/radio/emp_act(severity)
+ . = ..()
+ if (. & EMP_PROTECT_SELF)
+ return
+ emped++ //There's been an EMP; better count it
+ var/curremp = emped //Remember which EMP this was
+ if (listening && ismob(loc)) // if the radio is turned on and on someone's person they notice
+ to_chat(loc, "\The [src] overloads.")
+ broadcasting = FALSE
+ listening = FALSE
+ for (var/ch_name in channels)
+ channels[ch_name] = 0
+ on = FALSE
+ spawn(200)
+ if(emped == curremp) //Don't fix it if it's been EMP'd again
+ emped = 0
+ if (!istype(src, /obj/item/radio/intercom)) // intercoms will turn back on on their own
+ on = TRUE
+
+///////////////////////////////
+//////////Borg Radios//////////
+///////////////////////////////
+//Giving borgs their own radio to have some more room to work with -Sieve
+
+/obj/item/radio/borg
+ name = "cyborg radio"
+ subspace_switchable = TRUE
+ dog_fashion = null
+
+/obj/item/radio/borg/Initialize(mapload)
+ . = ..()
+
+/obj/item/radio/borg/syndicate
+ syndie = 1
+ keyslot = new /obj/item/encryptionkey/syndicate
+
+/obj/item/radio/borg/syndicate/Initialize()
+ . = ..()
+ set_frequency(FREQ_SYNDICATE)
+
+/obj/item/radio/borg/attackby(obj/item/W, mob/user, params)
+
+ if(istype(W, /obj/item/screwdriver))
+ if(keyslot)
+ for(var/ch_name in channels)
+ SSradio.remove_object(src, GLOB.radiochannels[ch_name])
+ secure_radio_connections[ch_name] = null
+
+
+ if(keyslot)
+ var/turf/T = get_turf(user)
+ if(T)
+ keyslot.forceMove(T)
+ keyslot = null
+
+ recalculateChannels()
+ to_chat(user, "You pop out the encryption key in the radio.")
+
+ else
+ to_chat(user, "This radio doesn't have any encryption keys!")
+
+ else if(istype(W, /obj/item/encryptionkey/))
+ if(keyslot)
+ to_chat(user, "The radio can't hold another key!")
+ return
+
+ if(!keyslot)
+ if(!user.transferItemToLoc(W, src))
+ return
+ keyslot = W
+
+ recalculateChannels()
+
+
+/obj/item/radio/off // Station bounced radios, their only difference is spawning with the speakers off, this was made to help the lag.
+ listening = 0 // And it's nice to have a subtype too for future features.
+ dog_fashion = /datum/dog_fashion/back
+
+/obj/item/radio/internal
+ var/obj/item/implant/radio/implant
+
+/obj/item/radio/internal/Initialize(mapload, obj/item/implant/radio/_implant)
+ . = ..()
+ implant = _implant
+
+/obj/item/radio/internal/Destroy()
+ if(implant?.imp_in)
+ qdel(implant)
+ else
+ return ..()
diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm
index babf001276..5fabcafd75 100644
--- a/code/game/objects/structures/tank_dispenser.dm
+++ b/code/game/objects/structures/tank_dispenser.dm
@@ -1,111 +1,111 @@
-#define TANK_DISPENSER_CAPACITY 10
-
-/obj/structure/tank_dispenser
- name = "tank dispenser"
- desc = "A simple yet bulky storage device for gas tanks. Holds up to 10 oxygen tanks and 10 plasma tanks."
- icon = 'icons/obj/objects.dmi'
- icon_state = "dispenser"
- density = TRUE
- anchored = TRUE
- max_integrity = 300
- var/oxygentanks = TANK_DISPENSER_CAPACITY
- var/plasmatanks = TANK_DISPENSER_CAPACITY
-
-/obj/structure/tank_dispenser/oxygen
- plasmatanks = 0
-
-/obj/structure/tank_dispenser/plasma
- oxygentanks = 0
-
-/obj/structure/tank_dispenser/Initialize()
- . = ..()
- for(var/i in 1 to oxygentanks)
- new /obj/item/tank/internals/oxygen(src)
- for(var/i in 1 to plasmatanks)
- new /obj/item/tank/internals/plasma(src)
- update_icon()
-
-/obj/structure/tank_dispenser/update_icon()
- cut_overlays()
- switch(oxygentanks)
- if(1 to 3)
- add_overlay("oxygen-[oxygentanks]")
- if(4 to TANK_DISPENSER_CAPACITY)
- add_overlay("oxygen-4")
- switch(plasmatanks)
- if(1 to 4)
- add_overlay("plasma-[plasmatanks]")
- if(5 to TANK_DISPENSER_CAPACITY)
- add_overlay("plasma-5")
-
-/obj/structure/tank_dispenser/attackby(obj/item/I, mob/user, params)
- var/full
- if(istype(I, /obj/item/tank/internals/plasma))
- if(plasmatanks < TANK_DISPENSER_CAPACITY)
- plasmatanks++
- else
- full = TRUE
- else if(istype(I, /obj/item/tank/internals/oxygen))
- if(oxygentanks < TANK_DISPENSER_CAPACITY)
- oxygentanks++
- else
- full = TRUE
- else if(istype(I, /obj/item/wrench))
- default_unfasten_wrench(user, I, time = 20)
- return
- else if(user.a_intent != INTENT_HARM)
- to_chat(user, "[I] does not fit into [src].")
- return
- else
- return ..()
- if(full)
- to_chat(user, "[src] can't hold any more of [I].")
- return
-
- if(!user.transferItemToLoc(I, src))
- return
- to_chat(user, "You put [I] in [src].")
- update_icon()
-
-/obj/structure/tank_dispenser/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "tank_dispenser", name, 275, 103, master_ui, state)
- ui.open()
-
-/obj/structure/tank_dispenser/ui_data(mob/user)
- var/list/data = list()
- data["oxygen"] = oxygentanks
- data["plasma"] = plasmatanks
-
- return data
-
-/obj/structure/tank_dispenser/ui_act(action, params)
- if(..())
- return
- switch(action)
- if("plasma")
- var/obj/item/tank/internals/plasma/tank = locate() in src
- if(tank && Adjacent(usr))
- usr.put_in_hands(tank)
- plasmatanks--
- . = TRUE
- if("oxygen")
- var/obj/item/tank/internals/oxygen/tank = locate() in src
- if(tank && Adjacent(usr))
- usr.put_in_hands(tank)
- oxygentanks--
- . = TRUE
- update_icon()
-
-
-/obj/structure/tank_dispenser/deconstruct(disassembled = TRUE)
- if(!(flags_1 & NODECONSTRUCT_1))
- for(var/X in src)
- var/obj/item/I = X
- I.forceMove(loc)
- new /obj/item/stack/sheet/metal (loc, 2)
- qdel(src)
-
-#undef TANK_DISPENSER_CAPACITY
+#define TANK_DISPENSER_CAPACITY 10
+
+/obj/structure/tank_dispenser
+ name = "tank dispenser"
+ desc = "A simple yet bulky storage device for gas tanks. Holds up to 10 oxygen tanks and 10 plasma tanks."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "dispenser"
+ density = TRUE
+ anchored = TRUE
+ max_integrity = 300
+ var/oxygentanks = TANK_DISPENSER_CAPACITY
+ var/plasmatanks = TANK_DISPENSER_CAPACITY
+
+/obj/structure/tank_dispenser/oxygen
+ plasmatanks = 0
+
+/obj/structure/tank_dispenser/plasma
+ oxygentanks = 0
+
+/obj/structure/tank_dispenser/Initialize()
+ . = ..()
+ for(var/i in 1 to oxygentanks)
+ new /obj/item/tank/internals/oxygen(src)
+ for(var/i in 1 to plasmatanks)
+ new /obj/item/tank/internals/plasma(src)
+ update_icon()
+
+/obj/structure/tank_dispenser/update_icon()
+ cut_overlays()
+ switch(oxygentanks)
+ if(1 to 3)
+ add_overlay("oxygen-[oxygentanks]")
+ if(4 to TANK_DISPENSER_CAPACITY)
+ add_overlay("oxygen-4")
+ switch(plasmatanks)
+ if(1 to 4)
+ add_overlay("plasma-[plasmatanks]")
+ if(5 to TANK_DISPENSER_CAPACITY)
+ add_overlay("plasma-5")
+
+/obj/structure/tank_dispenser/attackby(obj/item/I, mob/user, params)
+ var/full
+ if(istype(I, /obj/item/tank/internals/plasma))
+ if(plasmatanks < TANK_DISPENSER_CAPACITY)
+ plasmatanks++
+ else
+ full = TRUE
+ else if(istype(I, /obj/item/tank/internals/oxygen))
+ if(oxygentanks < TANK_DISPENSER_CAPACITY)
+ oxygentanks++
+ else
+ full = TRUE
+ else if(istype(I, /obj/item/wrench))
+ default_unfasten_wrench(user, I, time = 20)
+ return
+ else if(user.a_intent != INTENT_HARM)
+ to_chat(user, "[I] does not fit into [src].")
+ return
+ else
+ return ..()
+ if(full)
+ to_chat(user, "[src] can't hold any more of [I].")
+ return
+
+ if(!user.transferItemToLoc(I, src))
+ return
+ to_chat(user, "You put [I] in [src].")
+ update_icon()
+
+/obj/structure/tank_dispenser/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "tank_dispenser", name, 275, 103, master_ui, state)
+ ui.open()
+
+/obj/structure/tank_dispenser/ui_data(mob/user)
+ var/list/data = list()
+ data["oxygen"] = oxygentanks
+ data["plasma"] = plasmatanks
+
+ return data
+
+/obj/structure/tank_dispenser/ui_act(action, params)
+ if(..())
+ return
+ switch(action)
+ if("plasma")
+ var/obj/item/tank/internals/plasma/tank = locate() in src
+ if(tank && Adjacent(usr))
+ usr.put_in_hands(tank)
+ plasmatanks--
+ . = TRUE
+ if("oxygen")
+ var/obj/item/tank/internals/oxygen/tank = locate() in src
+ if(tank && Adjacent(usr))
+ usr.put_in_hands(tank)
+ oxygentanks--
+ . = TRUE
+ update_icon()
+
+
+/obj/structure/tank_dispenser/deconstruct(disassembled = TRUE)
+ if(!(flags_1 & NODECONSTRUCT_1))
+ for(var/X in src)
+ var/obj/item/I = X
+ I.forceMove(loc)
+ new /obj/item/stack/sheet/metal (loc, 2)
+ qdel(src)
+
+#undef TANK_DISPENSER_CAPACITY
diff --git a/code/modules/atmospherics/machinery/portable/pump.dm b/code/modules/atmospherics/machinery/portable/pump.dm
index c4fa6c10f2..ddb907a2ad 100644
--- a/code/modules/atmospherics/machinery/portable/pump.dm
+++ b/code/modules/atmospherics/machinery/portable/pump.dm
@@ -1,158 +1,158 @@
-#define PUMP_OUT "out"
-#define PUMP_IN "in"
-#define PUMP_MAX_PRESSURE (ONE_ATMOSPHERE * 25)
-#define PUMP_MIN_PRESSURE (ONE_ATMOSPHERE / 10)
-#define PUMP_DEFAULT_PRESSURE (ONE_ATMOSPHERE)
-
-/obj/machinery/portable_atmospherics/pump
- name = "portable air pump"
- icon_state = "psiphon:0"
- density = TRUE
-
- var/on = FALSE
- var/direction = PUMP_OUT
- var/obj/machinery/atmospherics/components/binary/pump/pump
-
- volume = 1000
-
-/obj/machinery/portable_atmospherics/pump/Initialize()
- . = ..()
- pump = new(src, FALSE)
- pump.on = TRUE
- pump.stat = 0
- pump.build_network()
-
-/obj/machinery/portable_atmospherics/pump/Destroy()
- var/turf/T = get_turf(src)
- T.assume_air(air_contents)
- air_update_turf()
- QDEL_NULL(pump)
- return ..()
-
-/obj/machinery/portable_atmospherics/pump/update_icon()
- icon_state = "psiphon:[on]"
-
- cut_overlays()
- if(holding)
- add_overlay("siphon-open")
- if(connected_port)
- add_overlay("siphon-connector")
-
-/obj/machinery/portable_atmospherics/pump/process_atmos()
- ..()
- if(!on)
- pump.airs[1] = null
- pump.airs[2] = null
- return
-
- var/turf/T = get_turf(src)
- if(direction == PUMP_OUT) // Hook up the internal pump.
- pump.airs[1] = holding ? holding.air_contents : air_contents
- pump.airs[2] = holding ? air_contents : T.return_air()
- else
- pump.airs[1] = holding ? air_contents : T.return_air()
- pump.airs[2] = holding ? holding.air_contents : air_contents
-
- pump.process_atmos() // Pump gas.
- if(!holding)
- air_update_turf() // Update the environment if needed.
-
-/obj/machinery/portable_atmospherics/pump/emp_act(severity)
- . = ..()
- if(. & EMP_PROTECT_SELF)
- return
- if(is_operational())
- if(prob(50 / severity))
- on = !on
- if(prob(100 / severity))
- direction = PUMP_OUT
- pump.target_pressure = rand(0, 100 * ONE_ATMOSPHERE)
- update_icon()
-
-/obj/machinery/portable_atmospherics/pump/replace_tank(mob/living/user, close_valve)
- . = ..()
- if(.)
- if(close_valve)
- if(on)
- on = FALSE
- update_icon()
- else if(on && holding && direction == PUMP_OUT)
- investigate_log("[key_name(user)] started a transfer into [holding]. ", INVESTIGATE_ATMOS)
-
-
-/obj/machinery/portable_atmospherics/pump/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "portable_pump", name, 300, 315, master_ui, state)
- ui.open()
-
-/obj/machinery/portable_atmospherics/pump/ui_data()
- var/data = list()
- data["on"] = on
- data["direction"] = direction == PUMP_IN ? TRUE : FALSE
- data["connected"] = connected_port ? TRUE : FALSE
- data["pressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
- data["target_pressure"] = round(pump.target_pressure ? pump.target_pressure : 0)
- data["default_pressure"] = round(PUMP_DEFAULT_PRESSURE)
- data["min_pressure"] = round(PUMP_MIN_PRESSURE)
- data["max_pressure"] = round(PUMP_MAX_PRESSURE)
-
- if(holding)
- data["holding"] = list()
- data["holding"]["name"] = holding.name
- data["holding"]["pressure"] = round(holding.air_contents.return_pressure())
- else
- data["holding"] = null
- return data
-
-/obj/machinery/portable_atmospherics/pump/ui_act(action, params)
- if(..())
- return
- switch(action)
- if("power")
- on = !on
- if(on && !holding)
- var/plasma = air_contents.gases[/datum/gas/plasma]
- var/n2o = air_contents.gases[/datum/gas/nitrous_oxide]
- if(n2o || plasma)
- message_admins("[ADMIN_LOOKUPFLW(usr)] turned on a pump that contains [n2o ? "N2O" : ""][n2o && plasma ? " & " : ""][plasma ? "Plasma" : ""] at [ADMIN_VERBOSEJMP(src)]")
- log_admin("[key_name(usr)] turned on a pump that contains [n2o ? "N2O" : ""][n2o && plasma ? " & " : ""][plasma ? "Plasma" : ""] at [AREACOORD(src)]")
- else if(on && direction == PUMP_OUT)
- investigate_log("[key_name(usr)] started a transfer into [holding]. ", INVESTIGATE_ATMOS)
- . = TRUE
- if("direction")
- if(direction == PUMP_OUT)
- direction = PUMP_IN
- else
- if(on && holding)
- investigate_log("[key_name(usr)] started a transfer into [holding]. ", INVESTIGATE_ATMOS)
- direction = PUMP_OUT
- . = TRUE
- if("pressure")
- var/pressure = params["pressure"]
- if(pressure == "reset")
- pressure = PUMP_DEFAULT_PRESSURE
- . = TRUE
- else if(pressure == "min")
- pressure = PUMP_MIN_PRESSURE
- . = TRUE
- else if(pressure == "max")
- pressure = PUMP_MAX_PRESSURE
- . = TRUE
- else if(pressure == "input")
- pressure = input("New release pressure ([PUMP_MIN_PRESSURE]-[PUMP_MAX_PRESSURE] kPa):", name, pump.target_pressure) as num|null
- if(!isnull(pressure) && !..())
- . = TRUE
- else if(text2num(pressure) != null)
- pressure = text2num(pressure)
- . = TRUE
- if(.)
- pump.target_pressure = CLAMP(round(pressure), PUMP_MIN_PRESSURE, PUMP_MAX_PRESSURE)
- investigate_log("was set to [pump.target_pressure] kPa by [key_name(usr)].", INVESTIGATE_ATMOS)
- if("eject")
- if(holding)
- holding.forceMove(drop_location())
- holding = null
- . = TRUE
- update_icon()
+#define PUMP_OUT "out"
+#define PUMP_IN "in"
+#define PUMP_MAX_PRESSURE (ONE_ATMOSPHERE * 25)
+#define PUMP_MIN_PRESSURE (ONE_ATMOSPHERE / 10)
+#define PUMP_DEFAULT_PRESSURE (ONE_ATMOSPHERE)
+
+/obj/machinery/portable_atmospherics/pump
+ name = "portable air pump"
+ icon_state = "psiphon:0"
+ density = TRUE
+
+ var/on = FALSE
+ var/direction = PUMP_OUT
+ var/obj/machinery/atmospherics/components/binary/pump/pump
+
+ volume = 1000
+
+/obj/machinery/portable_atmospherics/pump/Initialize()
+ . = ..()
+ pump = new(src, FALSE)
+ pump.on = TRUE
+ pump.stat = 0
+ pump.build_network()
+
+/obj/machinery/portable_atmospherics/pump/Destroy()
+ var/turf/T = get_turf(src)
+ T.assume_air(air_contents)
+ air_update_turf()
+ QDEL_NULL(pump)
+ return ..()
+
+/obj/machinery/portable_atmospherics/pump/update_icon()
+ icon_state = "psiphon:[on]"
+
+ cut_overlays()
+ if(holding)
+ add_overlay("siphon-open")
+ if(connected_port)
+ add_overlay("siphon-connector")
+
+/obj/machinery/portable_atmospherics/pump/process_atmos()
+ ..()
+ if(!on)
+ pump.airs[1] = null
+ pump.airs[2] = null
+ return
+
+ var/turf/T = get_turf(src)
+ if(direction == PUMP_OUT) // Hook up the internal pump.
+ pump.airs[1] = holding ? holding.air_contents : air_contents
+ pump.airs[2] = holding ? air_contents : T.return_air()
+ else
+ pump.airs[1] = holding ? air_contents : T.return_air()
+ pump.airs[2] = holding ? holding.air_contents : air_contents
+
+ pump.process_atmos() // Pump gas.
+ if(!holding)
+ air_update_turf() // Update the environment if needed.
+
+/obj/machinery/portable_atmospherics/pump/emp_act(severity)
+ . = ..()
+ if(. & EMP_PROTECT_SELF)
+ return
+ if(is_operational())
+ if(prob(50 / severity))
+ on = !on
+ if(prob(100 / severity))
+ direction = PUMP_OUT
+ pump.target_pressure = rand(0, 100 * ONE_ATMOSPHERE)
+ update_icon()
+
+/obj/machinery/portable_atmospherics/pump/replace_tank(mob/living/user, close_valve)
+ . = ..()
+ if(.)
+ if(close_valve)
+ if(on)
+ on = FALSE
+ update_icon()
+ else if(on && holding && direction == PUMP_OUT)
+ investigate_log("[key_name(user)] started a transfer into [holding]. ", INVESTIGATE_ATMOS)
+
+
+/obj/machinery/portable_atmospherics/pump/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "portable_pump", name, 300, 315, master_ui, state)
+ ui.open()
+
+/obj/machinery/portable_atmospherics/pump/ui_data()
+ var/data = list()
+ data["on"] = on
+ data["direction"] = direction == PUMP_IN ? TRUE : FALSE
+ data["connected"] = connected_port ? TRUE : FALSE
+ data["pressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
+ data["target_pressure"] = round(pump.target_pressure ? pump.target_pressure : 0)
+ data["default_pressure"] = round(PUMP_DEFAULT_PRESSURE)
+ data["min_pressure"] = round(PUMP_MIN_PRESSURE)
+ data["max_pressure"] = round(PUMP_MAX_PRESSURE)
+
+ if(holding)
+ data["holding"] = list()
+ data["holding"]["name"] = holding.name
+ data["holding"]["pressure"] = round(holding.air_contents.return_pressure())
+ else
+ data["holding"] = null
+ return data
+
+/obj/machinery/portable_atmospherics/pump/ui_act(action, params)
+ if(..())
+ return
+ switch(action)
+ if("power")
+ on = !on
+ if(on && !holding)
+ var/plasma = air_contents.gases[/datum/gas/plasma]
+ var/n2o = air_contents.gases[/datum/gas/nitrous_oxide]
+ if(n2o || plasma)
+ message_admins("[ADMIN_LOOKUPFLW(usr)] turned on a pump that contains [n2o ? "N2O" : ""][n2o && plasma ? " & " : ""][plasma ? "Plasma" : ""] at [ADMIN_VERBOSEJMP(src)]")
+ log_admin("[key_name(usr)] turned on a pump that contains [n2o ? "N2O" : ""][n2o && plasma ? " & " : ""][plasma ? "Plasma" : ""] at [AREACOORD(src)]")
+ else if(on && direction == PUMP_OUT)
+ investigate_log("[key_name(usr)] started a transfer into [holding]. ", INVESTIGATE_ATMOS)
+ . = TRUE
+ if("direction")
+ if(direction == PUMP_OUT)
+ direction = PUMP_IN
+ else
+ if(on && holding)
+ investigate_log("[key_name(usr)] started a transfer into [holding]. ", INVESTIGATE_ATMOS)
+ direction = PUMP_OUT
+ . = TRUE
+ if("pressure")
+ var/pressure = params["pressure"]
+ if(pressure == "reset")
+ pressure = PUMP_DEFAULT_PRESSURE
+ . = TRUE
+ else if(pressure == "min")
+ pressure = PUMP_MIN_PRESSURE
+ . = TRUE
+ else if(pressure == "max")
+ pressure = PUMP_MAX_PRESSURE
+ . = TRUE
+ else if(pressure == "input")
+ pressure = input("New release pressure ([PUMP_MIN_PRESSURE]-[PUMP_MAX_PRESSURE] kPa):", name, pump.target_pressure) as num|null
+ if(!isnull(pressure) && !..())
+ . = TRUE
+ else if(text2num(pressure) != null)
+ pressure = text2num(pressure)
+ . = TRUE
+ if(.)
+ pump.target_pressure = CLAMP(round(pressure), PUMP_MIN_PRESSURE, PUMP_MAX_PRESSURE)
+ investigate_log("was set to [pump.target_pressure] kPa by [key_name(usr)].", INVESTIGATE_ATMOS)
+ if("eject")
+ if(holding)
+ holding.forceMove(drop_location())
+ holding = null
+ . = TRUE
+ update_icon()
diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm
index c10018e727..0c902e0426 100644
--- a/code/modules/atmospherics/machinery/portable/scrubber.dm
+++ b/code/modules/atmospherics/machinery/portable/scrubber.dm
@@ -1,146 +1,146 @@
-/obj/machinery/portable_atmospherics/scrubber
- name = "portable air scrubber"
- icon_state = "pscrubber:0"
- density = TRUE
-
- var/on = FALSE
- var/volume_rate = 1000
- volume = 1000
-
- var/list/scrubbing = list(/datum/gas/plasma, /datum/gas/carbon_dioxide, /datum/gas/nitrous_oxide, /datum/gas/bz, /datum/gas/nitryl, /datum/gas/tritium, /datum/gas/hypernoblium, /datum/gas/water_vapor)
-
-/obj/machinery/portable_atmospherics/scrubber/Destroy()
- var/turf/T = get_turf(src)
- T.assume_air(air_contents)
- air_update_turf()
- return ..()
-
-/obj/machinery/portable_atmospherics/scrubber/update_icon()
- icon_state = "pscrubber:[on]"
-
- cut_overlays()
- if(holding)
- add_overlay("scrubber-open")
- if(connected_port)
- add_overlay("scrubber-connector")
-
-/obj/machinery/portable_atmospherics/scrubber/process_atmos()
- ..()
- if(!on)
- return
-
- if(holding)
- scrub(holding.air_contents)
- else
- var/turf/T = get_turf(src)
- scrub(T.return_air())
-
-/obj/machinery/portable_atmospherics/scrubber/proc/scrub(var/datum/gas_mixture/mixture)
- var/transfer_moles = min(1, volume_rate / mixture.volume) * mixture.total_moles()
-
- var/datum/gas_mixture/filtering = mixture.remove(transfer_moles) // Remove part of the mixture to filter.
- var/datum/gas_mixture/filtered = new
- if(!filtering)
- return
-
- filtered.temperature = filtering.temperature
- for(var/gas in filtering.gases & scrubbing)
- filtered.gases[gas] = filtering.gases[gas] // Shuffle the "bad" gasses to the filtered mixture.
- filtering.gases[gas] = 0
- GAS_GARBAGE_COLLECT(filtering.gases)
-
- air_contents.merge(filtered) // Store filtered out gasses.
- mixture.merge(filtering) // Returned the cleaned gas.
- if(!holding)
- air_update_turf()
-
-/obj/machinery/portable_atmospherics/scrubber/emp_act(severity)
- . = ..()
- if(. & EMP_PROTECT_SELF)
- return
- if(is_operational())
- if(prob(50 / severity))
- on = !on
- update_icon()
-
-/obj/machinery/portable_atmospherics/scrubber/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "portable_scrubber", name, 320, 335, master_ui, state)
- ui.open()
-
-/obj/machinery/portable_atmospherics/scrubber/ui_data()
- var/data = list()
- data["on"] = on
- data["connected"] = connected_port ? 1 : 0
- data["pressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
-
- data["id_tag"] = -1 //must be defined in order to reuse code between portable and vent scrubbers
- data["filter_types"] = list()
- for(var/path in GLOB.meta_gas_ids)
- data["filter_types"] += list(list("gas_id" = GLOB.meta_gas_ids[path], "gas_name" = GLOB.meta_gas_names[path], "enabled" = (path in scrubbing)))
-
- if(holding)
- data["holding"] = list()
- data["holding"]["name"] = holding.name
- data["holding"]["pressure"] = round(holding.air_contents.return_pressure())
- else
- data["holding"] = null
- return data
-
-/obj/machinery/portable_atmospherics/scrubber/ui_act(action, params)
- if(..())
- return
- switch(action)
- if("power")
- on = !on
- . = TRUE
- if("eject")
- if(holding)
- holding.forceMove(drop_location())
- holding = null
- . = TRUE
- if("toggle_filter")
- scrubbing ^= gas_id2path(params["val"])
- . = TRUE
- update_icon()
-
-/obj/machinery/portable_atmospherics/scrubber/huge
- name = "huge air scrubber"
- icon_state = "scrubber:0"
- anchored = TRUE
- active_power_usage = 500
- idle_power_usage = 10
-
- volume_rate = 1500
- volume = 50000
-
- var/movable = FALSE
-
-/obj/machinery/portable_atmospherics/scrubber/huge/movable
- movable = TRUE
-
-/obj/machinery/portable_atmospherics/scrubber/huge/update_icon()
- icon_state = "scrubber:[on]"
-
-/obj/machinery/portable_atmospherics/scrubber/huge/process_atmos()
- if((!anchored && !movable) || !is_operational())
- on = FALSE
- update_icon()
- use_power = on ? ACTIVE_POWER_USE : IDLE_POWER_USE
- if(!on)
- return
-
- ..()
- if(!holding)
- var/turf/T = get_turf(src)
- for(var/turf/AT in T.GetAtmosAdjacentTurfs(alldir = TRUE))
- scrub(AT.return_air())
-
-/obj/machinery/portable_atmospherics/scrubber/huge/attackby(obj/item/W, mob/user)
- if(default_unfasten_wrench(user, W))
- if(!movable)
- on = FALSE
- else
- return ..()
+/obj/machinery/portable_atmospherics/scrubber
+ name = "portable air scrubber"
+ icon_state = "pscrubber:0"
+ density = TRUE
+
+ var/on = FALSE
+ var/volume_rate = 1000
+ volume = 1000
+
+ var/list/scrubbing = list(/datum/gas/plasma, /datum/gas/carbon_dioxide, /datum/gas/nitrous_oxide, /datum/gas/bz, /datum/gas/nitryl, /datum/gas/tritium, /datum/gas/hypernoblium, /datum/gas/water_vapor)
+
+/obj/machinery/portable_atmospherics/scrubber/Destroy()
+ var/turf/T = get_turf(src)
+ T.assume_air(air_contents)
+ air_update_turf()
+ return ..()
+
+/obj/machinery/portable_atmospherics/scrubber/update_icon()
+ icon_state = "pscrubber:[on]"
+
+ cut_overlays()
+ if(holding)
+ add_overlay("scrubber-open")
+ if(connected_port)
+ add_overlay("scrubber-connector")
+
+/obj/machinery/portable_atmospherics/scrubber/process_atmos()
+ ..()
+ if(!on)
+ return
+
+ if(holding)
+ scrub(holding.air_contents)
+ else
+ var/turf/T = get_turf(src)
+ scrub(T.return_air())
+
+/obj/machinery/portable_atmospherics/scrubber/proc/scrub(var/datum/gas_mixture/mixture)
+ var/transfer_moles = min(1, volume_rate / mixture.volume) * mixture.total_moles()
+
+ var/datum/gas_mixture/filtering = mixture.remove(transfer_moles) // Remove part of the mixture to filter.
+ var/datum/gas_mixture/filtered = new
+ if(!filtering)
+ return
+
+ filtered.temperature = filtering.temperature
+ for(var/gas in filtering.gases & scrubbing)
+ filtered.gases[gas] = filtering.gases[gas] // Shuffle the "bad" gasses to the filtered mixture.
+ filtering.gases[gas] = 0
+ GAS_GARBAGE_COLLECT(filtering.gases)
+
+ air_contents.merge(filtered) // Store filtered out gasses.
+ mixture.merge(filtering) // Returned the cleaned gas.
+ if(!holding)
+ air_update_turf()
+
+/obj/machinery/portable_atmospherics/scrubber/emp_act(severity)
+ . = ..()
+ if(. & EMP_PROTECT_SELF)
+ return
+ if(is_operational())
+ if(prob(50 / severity))
+ on = !on
+ update_icon()
+
+/obj/machinery/portable_atmospherics/scrubber/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "portable_scrubber", name, 320, 335, master_ui, state)
+ ui.open()
+
+/obj/machinery/portable_atmospherics/scrubber/ui_data()
+ var/data = list()
+ data["on"] = on
+ data["connected"] = connected_port ? 1 : 0
+ data["pressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
+
+ data["id_tag"] = -1 //must be defined in order to reuse code between portable and vent scrubbers
+ data["filter_types"] = list()
+ for(var/path in GLOB.meta_gas_ids)
+ data["filter_types"] += list(list("gas_id" = GLOB.meta_gas_ids[path], "gas_name" = GLOB.meta_gas_names[path], "enabled" = (path in scrubbing)))
+
+ if(holding)
+ data["holding"] = list()
+ data["holding"]["name"] = holding.name
+ data["holding"]["pressure"] = round(holding.air_contents.return_pressure())
+ else
+ data["holding"] = null
+ return data
+
+/obj/machinery/portable_atmospherics/scrubber/ui_act(action, params)
+ if(..())
+ return
+ switch(action)
+ if("power")
+ on = !on
+ . = TRUE
+ if("eject")
+ if(holding)
+ holding.forceMove(drop_location())
+ holding = null
+ . = TRUE
+ if("toggle_filter")
+ scrubbing ^= gas_id2path(params["val"])
+ . = TRUE
+ update_icon()
+
+/obj/machinery/portable_atmospherics/scrubber/huge
+ name = "huge air scrubber"
+ icon_state = "scrubber:0"
+ anchored = TRUE
+ active_power_usage = 500
+ idle_power_usage = 10
+
+ volume_rate = 1500
+ volume = 50000
+
+ var/movable = FALSE
+
+/obj/machinery/portable_atmospherics/scrubber/huge/movable
+ movable = TRUE
+
+/obj/machinery/portable_atmospherics/scrubber/huge/update_icon()
+ icon_state = "scrubber:[on]"
+
+/obj/machinery/portable_atmospherics/scrubber/huge/process_atmos()
+ if((!anchored && !movable) || !is_operational())
+ on = FALSE
+ update_icon()
+ use_power = on ? ACTIVE_POWER_USE : IDLE_POWER_USE
+ if(!on)
+ return
+
+ ..()
+ if(!holding)
+ var/turf/T = get_turf(src)
+ for(var/turf/AT in T.GetAtmosAdjacentTurfs(alldir = TRUE))
+ scrub(AT.return_air())
+
+/obj/machinery/portable_atmospherics/scrubber/huge/attackby(obj/item/W, mob/user)
+ if(default_unfasten_wrench(user, W))
+ if(!movable)
+ on = FALSE
+ else
+ return ..()
diff --git a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm
index 8af58c7cbf..3a1606657b 100644
--- a/code/modules/cargo/console.dm
+++ b/code/modules/cargo/console.dm
@@ -1,226 +1,226 @@
-/obj/machinery/computer/cargo
- name = "supply console"
- desc = "Used to order supplies, approve requests, and control the shuttle."
- icon_screen = "supply"
- circuit = /obj/item/circuitboard/computer/cargo
- req_access = list(ACCESS_CARGO)
- var/requestonly = FALSE
- var/contraband = FALSE
- var/safety_warning = "For safety reasons, the automated supply shuttle \
- cannot transport live organisms, human remains, classified nuclear weaponry \
- or homing beacons."
- var/blockade_warning = "Bluespace instability detected. Shuttle movement impossible."
-
- light_color = "#E2853D"//orange
-
-/obj/machinery/computer/cargo/request
- name = "supply request console"
- desc = "Used to request supplies from cargo."
- icon_screen = "request"
- circuit = /obj/item/circuitboard/computer/cargo/request
- req_access = list()
- requestonly = TRUE
-
-/obj/machinery/computer/cargo/Initialize()
- . = ..()
- var/obj/item/circuitboard/computer/cargo/board = circuit
- contraband = board.contraband
- if (board.obj_flags & EMAGGED)
- obj_flags |= EMAGGED
- else
- obj_flags &= ~EMAGGED
-
-/obj/machinery/computer/cargo/proc/get_export_categories()
- . = EXPORT_CARGO
- if(contraband)
- . |= EXPORT_CONTRABAND
- if(obj_flags & EMAGGED)
- . |= EXPORT_EMAG
-
-/obj/machinery/computer/cargo/emag_act(mob/user)
- . = ..()
- if(obj_flags & EMAGGED)
- return
- user.visible_message("[user] swipes a suspicious card through [src]!",
- "You adjust [src]'s routing and receiver spectrum, unlocking special supplies and contraband.")
-
- obj_flags |= EMAGGED
- contraband = TRUE
-
- // This also permamently sets this on the circuit board
- var/obj/item/circuitboard/computer/cargo/board = circuit
- board.contraband = TRUE
- board.obj_flags |= EMAGGED
- req_access = list()
- return TRUE
-
-/obj/machinery/computer/cargo/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "cargo", name, 780, 750, master_ui, state)
- ui.open()
-
-/obj/machinery/computer/cargo/ui_data()
- var/list/data = list()
- data["requestonly"] = requestonly
- data["location"] = SSshuttle.supply.getStatusText()
- data["points"] = SSshuttle.points
- data["away"] = SSshuttle.supply.getDockedId() == "supply_away"
- data["docked"] = SSshuttle.supply.mode == SHUTTLE_IDLE
- data["loan"] = !!SSshuttle.shuttle_loan
- data["loan_dispatched"] = SSshuttle.shuttle_loan && SSshuttle.shuttle_loan.dispatched
- var/message = "Remember to stamp and send back the supply manifests."
- if(SSshuttle.centcom_message)
- message = SSshuttle.centcom_message
- if(SSshuttle.supplyBlocked)
- message = blockade_warning
- data["message"] = message
- data["supplies"] = list()
- for(var/pack in SSshuttle.supply_packs)
- var/datum/supply_pack/P = SSshuttle.supply_packs[pack]
- if(!data["supplies"][P.group])
- data["supplies"][P.group] = list(
- "name" = P.group,
- "packs" = list()
- )
- if((P.hidden && !(obj_flags & EMAGGED)) || (P.contraband && !contraband) || (P.special && !P.special_enabled) || P.DropPodOnly)
- continue
- data["supplies"][P.group]["packs"] += list(list(
- "name" = P.name,
- "cost" = P.cost,
- "id" = pack,
- "desc" = P.desc || P.name // If there is a description, use it. Otherwise use the pack's name.
- ))
-
- data["cart"] = list()
- for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
- data["cart"] += list(list(
- "object" = SO.pack.name,
- "cost" = SO.pack.cost,
- "id" = SO.id
- ))
-
- data["requests"] = list()
- for(var/datum/supply_order/SO in SSshuttle.requestlist)
- data["requests"] += list(list(
- "object" = SO.pack.name,
- "cost" = SO.pack.cost,
- "orderer" = SO.orderer,
- "reason" = SO.reason,
- "id" = SO.id
- ))
-
- return data
-
-/obj/machinery/computer/cargo/ui_act(action, params, datum/tgui/ui)
- if(..())
- return
- if(!allowed(usr))
- to_chat(usr, "Access denied.")
- return
- switch(action)
- if("send")
- if(!SSshuttle.supply.canMove())
- say(safety_warning)
- return
- if(SSshuttle.supplyBlocked)
- say(blockade_warning)
- return
- if(SSshuttle.supply.getDockedId() == "supply_home")
- SSshuttle.supply.export_categories = get_export_categories()
- SSshuttle.moveShuttle("supply", "supply_away", TRUE)
- say("The supply shuttle is departing.")
- investigate_log("[key_name(usr)] sent the supply shuttle away.", INVESTIGATE_CARGO)
- else
- investigate_log("[key_name(usr)] called the supply shuttle.", INVESTIGATE_CARGO)
- say("The supply shuttle has been called and will arrive in [SSshuttle.supply.timeLeft(600)] minutes.")
- SSshuttle.moveShuttle("supply", "supply_home", TRUE)
- . = TRUE
- if("loan")
- if(!SSshuttle.shuttle_loan)
- return
- if(SSshuttle.supplyBlocked)
- say(blockade_warning)
- return
- else if(SSshuttle.supply.mode != SHUTTLE_IDLE)
- return
- else if(SSshuttle.supply.getDockedId() != "supply_away")
- return
- else
- SSshuttle.shuttle_loan.loan_shuttle()
- say("The supply shuttle has been loaned to CentCom.")
- . = TRUE
- if("add")
- var/id = text2path(params["id"])
- var/datum/supply_pack/pack = SSshuttle.supply_packs[id]
- if(!istype(pack))
- return
- if((pack.hidden && !(obj_flags & EMAGGED)) || (pack.contraband && !contraband) || pack.DropPodOnly)
- return
-
- var/name = "*None Provided*"
- var/rank = "*None Provided*"
- var/ckey = usr.ckey
- if(ishuman(usr))
- var/mob/living/carbon/human/H = usr
- name = H.get_authentification_name()
- rank = H.get_assignment(hand_first = TRUE)
- else if(issilicon(usr))
- name = usr.real_name
- rank = "Silicon"
-
- var/reason = ""
- if(requestonly)
- reason = stripped_input("Reason:", name, "")
- if(isnull(reason) || ..())
- return
-
- var/turf/T = get_turf(src)
- var/datum/supply_order/SO = new(pack, name, rank, ckey, reason)
- SO.generateRequisition(T)
- if(requestonly)
- SSshuttle.requestlist += SO
- else
- SSshuttle.shoppinglist += SO
- . = TRUE
- if("remove")
- var/id = text2num(params["id"])
- for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
- if(SO.id == id)
- SSshuttle.shoppinglist -= SO
- . = TRUE
- break
- if("clear")
- SSshuttle.shoppinglist.Cut()
- . = TRUE
- if("approve")
- var/id = text2num(params["id"])
- for(var/datum/supply_order/SO in SSshuttle.requestlist)
- if(SO.id == id)
- SSshuttle.requestlist -= SO
- SSshuttle.shoppinglist += SO
- . = TRUE
- break
- if("deny")
- var/id = text2num(params["id"])
- for(var/datum/supply_order/SO in SSshuttle.requestlist)
- if(SO.id == id)
- SSshuttle.requestlist -= SO
- . = TRUE
- break
- if("denyall")
- SSshuttle.requestlist.Cut()
- . = TRUE
- if(.)
- post_signal("supply")
-
-/obj/machinery/computer/cargo/proc/post_signal(command)
-
- var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS)
-
- if(!frequency)
- return
-
- var/datum/signal/status_signal = new(list("command" = command))
- frequency.post_signal(src, status_signal)
+/obj/machinery/computer/cargo
+ name = "supply console"
+ desc = "Used to order supplies, approve requests, and control the shuttle."
+ icon_screen = "supply"
+ circuit = /obj/item/circuitboard/computer/cargo
+ req_access = list(ACCESS_CARGO)
+ var/requestonly = FALSE
+ var/contraband = FALSE
+ var/safety_warning = "For safety reasons, the automated supply shuttle \
+ cannot transport live organisms, human remains, classified nuclear weaponry \
+ or homing beacons."
+ var/blockade_warning = "Bluespace instability detected. Shuttle movement impossible."
+
+ light_color = "#E2853D"//orange
+
+/obj/machinery/computer/cargo/request
+ name = "supply request console"
+ desc = "Used to request supplies from cargo."
+ icon_screen = "request"
+ circuit = /obj/item/circuitboard/computer/cargo/request
+ req_access = list()
+ requestonly = TRUE
+
+/obj/machinery/computer/cargo/Initialize()
+ . = ..()
+ var/obj/item/circuitboard/computer/cargo/board = circuit
+ contraband = board.contraband
+ if (board.obj_flags & EMAGGED)
+ obj_flags |= EMAGGED
+ else
+ obj_flags &= ~EMAGGED
+
+/obj/machinery/computer/cargo/proc/get_export_categories()
+ . = EXPORT_CARGO
+ if(contraband)
+ . |= EXPORT_CONTRABAND
+ if(obj_flags & EMAGGED)
+ . |= EXPORT_EMAG
+
+/obj/machinery/computer/cargo/emag_act(mob/user)
+ . = ..()
+ if(obj_flags & EMAGGED)
+ return
+ user.visible_message("[user] swipes a suspicious card through [src]!",
+ "You adjust [src]'s routing and receiver spectrum, unlocking special supplies and contraband.")
+
+ obj_flags |= EMAGGED
+ contraband = TRUE
+
+ // This also permamently sets this on the circuit board
+ var/obj/item/circuitboard/computer/cargo/board = circuit
+ board.contraband = TRUE
+ board.obj_flags |= EMAGGED
+ req_access = list()
+ return TRUE
+
+/obj/machinery/computer/cargo/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "cargo", name, 780, 750, master_ui, state)
+ ui.open()
+
+/obj/machinery/computer/cargo/ui_data()
+ var/list/data = list()
+ data["requestonly"] = requestonly
+ data["location"] = SSshuttle.supply.getStatusText()
+ data["points"] = SSshuttle.points
+ data["away"] = SSshuttle.supply.getDockedId() == "supply_away"
+ data["docked"] = SSshuttle.supply.mode == SHUTTLE_IDLE
+ data["loan"] = !!SSshuttle.shuttle_loan
+ data["loan_dispatched"] = SSshuttle.shuttle_loan && SSshuttle.shuttle_loan.dispatched
+ var/message = "Remember to stamp and send back the supply manifests."
+ if(SSshuttle.centcom_message)
+ message = SSshuttle.centcom_message
+ if(SSshuttle.supplyBlocked)
+ message = blockade_warning
+ data["message"] = message
+ data["supplies"] = list()
+ for(var/pack in SSshuttle.supply_packs)
+ var/datum/supply_pack/P = SSshuttle.supply_packs[pack]
+ if(!data["supplies"][P.group])
+ data["supplies"][P.group] = list(
+ "name" = P.group,
+ "packs" = list()
+ )
+ if((P.hidden && !(obj_flags & EMAGGED)) || (P.contraband && !contraband) || (P.special && !P.special_enabled) || P.DropPodOnly)
+ continue
+ data["supplies"][P.group]["packs"] += list(list(
+ "name" = P.name,
+ "cost" = P.cost,
+ "id" = pack,
+ "desc" = P.desc || P.name // If there is a description, use it. Otherwise use the pack's name.
+ ))
+
+ data["cart"] = list()
+ for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
+ data["cart"] += list(list(
+ "object" = SO.pack.name,
+ "cost" = SO.pack.cost,
+ "id" = SO.id
+ ))
+
+ data["requests"] = list()
+ for(var/datum/supply_order/SO in SSshuttle.requestlist)
+ data["requests"] += list(list(
+ "object" = SO.pack.name,
+ "cost" = SO.pack.cost,
+ "orderer" = SO.orderer,
+ "reason" = SO.reason,
+ "id" = SO.id
+ ))
+
+ return data
+
+/obj/machinery/computer/cargo/ui_act(action, params, datum/tgui/ui)
+ if(..())
+ return
+ if(!allowed(usr))
+ to_chat(usr, "Access denied.")
+ return
+ switch(action)
+ if("send")
+ if(!SSshuttle.supply.canMove())
+ say(safety_warning)
+ return
+ if(SSshuttle.supplyBlocked)
+ say(blockade_warning)
+ return
+ if(SSshuttle.supply.getDockedId() == "supply_home")
+ SSshuttle.supply.export_categories = get_export_categories()
+ SSshuttle.moveShuttle("supply", "supply_away", TRUE)
+ say("The supply shuttle is departing.")
+ investigate_log("[key_name(usr)] sent the supply shuttle away.", INVESTIGATE_CARGO)
+ else
+ investigate_log("[key_name(usr)] called the supply shuttle.", INVESTIGATE_CARGO)
+ say("The supply shuttle has been called and will arrive in [SSshuttle.supply.timeLeft(600)] minutes.")
+ SSshuttle.moveShuttle("supply", "supply_home", TRUE)
+ . = TRUE
+ if("loan")
+ if(!SSshuttle.shuttle_loan)
+ return
+ if(SSshuttle.supplyBlocked)
+ say(blockade_warning)
+ return
+ else if(SSshuttle.supply.mode != SHUTTLE_IDLE)
+ return
+ else if(SSshuttle.supply.getDockedId() != "supply_away")
+ return
+ else
+ SSshuttle.shuttle_loan.loan_shuttle()
+ say("The supply shuttle has been loaned to CentCom.")
+ . = TRUE
+ if("add")
+ var/id = text2path(params["id"])
+ var/datum/supply_pack/pack = SSshuttle.supply_packs[id]
+ if(!istype(pack))
+ return
+ if((pack.hidden && !(obj_flags & EMAGGED)) || (pack.contraband && !contraband) || pack.DropPodOnly)
+ return
+
+ var/name = "*None Provided*"
+ var/rank = "*None Provided*"
+ var/ckey = usr.ckey
+ if(ishuman(usr))
+ var/mob/living/carbon/human/H = usr
+ name = H.get_authentification_name()
+ rank = H.get_assignment(hand_first = TRUE)
+ else if(issilicon(usr))
+ name = usr.real_name
+ rank = "Silicon"
+
+ var/reason = ""
+ if(requestonly)
+ reason = stripped_input("Reason:", name, "")
+ if(isnull(reason) || ..())
+ return
+
+ var/turf/T = get_turf(src)
+ var/datum/supply_order/SO = new(pack, name, rank, ckey, reason)
+ SO.generateRequisition(T)
+ if(requestonly)
+ SSshuttle.requestlist += SO
+ else
+ SSshuttle.shoppinglist += SO
+ . = TRUE
+ if("remove")
+ var/id = text2num(params["id"])
+ for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
+ if(SO.id == id)
+ SSshuttle.shoppinglist -= SO
+ . = TRUE
+ break
+ if("clear")
+ SSshuttle.shoppinglist.Cut()
+ . = TRUE
+ if("approve")
+ var/id = text2num(params["id"])
+ for(var/datum/supply_order/SO in SSshuttle.requestlist)
+ if(SO.id == id)
+ SSshuttle.requestlist -= SO
+ SSshuttle.shoppinglist += SO
+ . = TRUE
+ break
+ if("deny")
+ var/id = text2num(params["id"])
+ for(var/datum/supply_order/SO in SSshuttle.requestlist)
+ if(SO.id == id)
+ SSshuttle.requestlist -= SO
+ . = TRUE
+ break
+ if("denyall")
+ SSshuttle.requestlist.Cut()
+ . = TRUE
+ if(.)
+ post_signal("supply")
+
+/obj/machinery/computer/cargo/proc/post_signal(command)
+
+ var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS)
+
+ if(!frequency)
+ return
+
+ var/datum/signal/status_signal = new(list("command" = command))
+ frequency.post_signal(src, status_signal)
diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm
index ea00a85715..20dc724707 100644
--- a/code/modules/cargo/expressconsole.dm
+++ b/code/modules/cargo/expressconsole.dm
@@ -1,206 +1,206 @@
-#define MAX_EMAG_ROCKETS 8
-#define BEACON_COST 5000
-#define SP_LINKED 1
-#define SP_READY 2
-#define SP_LAUNCH 3
-#define SP_UNLINK 4
-#define SP_UNREADY 5
-
-/obj/machinery/computer/cargo/express
- name = "express supply console"
- desc = "This console allows the user to purchase a package \
- with 1/40th of the delivery time: made possible by NanoTrasen's new \"1500mm Orbital Railgun\".\
- All sales are near instantaneous - please choose carefully"
- icon_screen = "supply_express"
- circuit = /obj/item/circuitboard/computer/cargo/express
- blockade_warning = "Bluespace instability detected. Delivery impossible."
- req_access = list(ACCESS_QM)
- var/message
- var/printed_beacons = 0 //number of beacons printed. Used to determine beacon names.
- var/list/meme_pack_data
- var/obj/item/supplypod_beacon/beacon //the linked supplypod beacon
- var/area/landingzone = /area/quartermaster/storage //where we droppin boys
- var/podType = /obj/structure/closet/supplypod
- var/cooldown = 0 //cooldown to prevent printing supplypod beacon spam
- var/locked = TRUE //is the console locked? unlock with ID
- var/usingBeacon = FALSE //is the console in beacon mode? exists to let beacon know when a pod may come in
-
-/obj/machinery/computer/cargo/express/Initialize()
- . = ..()
- packin_up()
-
-/obj/machinery/computer/cargo/express/Destroy()
- if(beacon)
- beacon.unlink_console()
- return ..()
-
-/obj/machinery/computer/cargo/express/attackby(obj/item/W, mob/living/user, params)
- if((istype(W, /obj/item/card/id) || istype(W, /obj/item/pda)) && allowed(user))
- locked = !locked
- to_chat(user, "You [locked ? "lock" : "unlock"] the interface.")
- return
- else if(istype(W, /obj/item/disk/cargo/bluespace_pod))
- podType = /obj/structure/closet/supplypod/bluespacepod
- to_chat(user, "You insert the disk into [src], allowing for advanced supply delivery vehicles.")
- qdel(W)
- return TRUE
- else if(istype(W, /obj/item/supplypod_beacon))
- var/obj/item/supplypod_beacon/sb = W
- if (sb.express_console != src)
- sb.link_console(src, user)
- return TRUE
- else
- to_chat(user, "[src] is already linked to [sb].")
- ..()
-
-/obj/machinery/computer/cargo/express/emag_act(mob/living/user)
- . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
- if(obj_flags & EMAGGED)
- return
- user.visible_message("[user] swipes a suspicious card through [src]!",
- "You change the routing protocols, allowing the Supply Pod to land anywhere on the station.")
- obj_flags |= EMAGGED
- // This also sets this on the circuit board
- var/obj/item/circuitboard/computer/cargo/board = circuit
- board.obj_flags |= EMAGGED
- packin_up()
- req_access = list()
- return TRUE
-
-/obj/machinery/computer/cargo/express/proc/packin_up() // oh shit, I'm sorry
- meme_pack_data = list() // sorry for what?
- for(var/pack in SSshuttle.supply_packs) // our quartermaster taught us not to be ashamed of our supply packs
- var/datum/supply_pack/P = SSshuttle.supply_packs[pack] // specially since they're such a good price and all
- if(!meme_pack_data[P.group]) // yeah, I see that, your quartermaster gave you good advice
- meme_pack_data[P.group] = list( // it gets cheaper when I return it
- "name" = P.group, // mmhm
- "packs" = list() // sometimes, I return it so much, I rip the manifest
- ) // see, my quartermaster taught me a few things too
- if((P.hidden) || (P.special)) // like, how not to rip the manifest
- continue// by using someone else's crate
- if(!(obj_flags & EMAGGED) && P.contraband) // will you show me?
- continue // i'd be right happy to
- meme_pack_data[P.group]["packs"] += list(list(
- "name" = P.name,
- "cost" = P.cost,
- "id" = pack,
- "desc" = P.desc || P.name // If there is a description, use it. Otherwise use the pack's name.
- ))
-
-/obj/machinery/computer/cargo/express/ui_interact(mob/living/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "cargo_express", name, 600, 700, master_ui, state)
- ui.open()
-
-/obj/machinery/computer/cargo/express/ui_data(mob/user)
- var/canBeacon = beacon && (isturf(beacon.loc) || ismob(beacon.loc))//is the beacon in a valid location?
- var/list/data = list()
- data["locked"] = locked//swipe an ID to unlock
- data["siliconUser"] = user.has_unlimited_silicon_privilege
- data["beaconzone"] = beacon ? get_area(beacon) : ""//where is the beacon located? outputs in the tgui
- data["usingBeacon"] = usingBeacon //is the mode set to deliver to the beacon or the cargobay?
- data["canBeacon"] = !usingBeacon || canBeacon //is the mode set to beacon delivery, and is the beacon in a valid location?
- data["canBuyBeacon"] = cooldown <= 0 && SSshuttle.points >= BEACON_COST
- data["beaconError"] = usingBeacon && !canBeacon ? "(BEACON ERROR)" : ""//changes button text to include an error alert if necessary
- data["hasBeacon"] = beacon != null//is there a linked beacon?
- data["beaconName"] = beacon ? beacon.name : "No Beacon Found"
- data["printMsg"] = cooldown > 0 ? "Print Beacon for [BEACON_COST] credits ([cooldown])" : "Print Beacon for [BEACON_COST] credits"//buttontext for printing beacons
- data["points"] = SSshuttle.points
- data["supplies"] = list()
- message = "Sales are near-instantaneous - please choose carefully."
- if(SSshuttle.supplyBlocked)
- message = blockade_warning
- if(usingBeacon && !beacon)
- message = "BEACON ERROR: BEACON MISSING"//beacon was destroyed
- else if (usingBeacon && !canBeacon)
- message = "BEACON ERROR: MUST BE EXPOSED"//beacon's loc/user's loc must be a turf
- if(obj_flags & EMAGGED)
- message = "(&!#@ERROR: ROUTING_#PROTOCOL MALF(*CT#ON. $UG%ESTE@ ACT#0N: !^/PULS3-%E)ET CIR*)ITB%ARD."
- data["message"] = message
- if(!meme_pack_data)
- packin_up()
- stack_trace("You didn't give the cargo tech good advice, and he ripped the manifest. As a result, there was no pack data for [src]")
- data["supplies"] = meme_pack_data
- if (cooldown > 0)//cooldown used for printing beacons
- cooldown--
- return data
-
-/obj/machinery/computer/cargo/express/ui_act(action, params, datum/tgui/ui)
- switch(action)
- if("LZCargo")
- usingBeacon = FALSE
- if (beacon)
- beacon.update_status(SP_UNREADY) //ready light on beacon will turn off
- if("LZBeacon")
- usingBeacon = TRUE
- if (beacon)
- beacon.update_status(SP_READY) //turns on the beacon's ready light
- if("printBeacon")
- if (SSshuttle.points >= BEACON_COST)
- cooldown = 10//a ~ten second cooldown for printing beacons to prevent spam
- var/obj/item/supplypod_beacon/C = new /obj/item/supplypod_beacon(drop_location())
- C.link_console(src, usr)//rather than in beacon's Initialize(), we can assign the computer to the beacon by reusing this proc)
- printed_beacons++//printed_beacons starts at 0, so the first one out will be called beacon # 1
- beacon.name = "Supply Pod Beacon #[printed_beacons]"
- SSshuttle.points -= BEACON_COST
-
- if("add")//Generate Supply Order first
- var/id = text2path(params["id"])
- var/datum/supply_pack/pack = SSshuttle.supply_packs[id]
- if(!istype(pack))
- return
- var/name = "*None Provided*"
- var/rank = "*None Provided*"
- var/ckey = usr.ckey
- if(ishuman(usr))
- var/mob/living/carbon/human/H = usr
- name = H.get_authentification_name()
- rank = H.get_assignment(hand_first = TRUE)
- else if(issilicon(usr))
- name = usr.real_name
- rank = "Silicon"
- var/reason = ""
- var/list/empty_turfs
- var/datum/supply_order/SO = new(pack, name, rank, ckey, reason)
- if(!(obj_flags & EMAGGED))
- if(SO.pack.cost <= SSshuttle.points)
- var/LZ
- if (istype(beacon) && usingBeacon)//prioritize beacons over landing in cargobay
- LZ = get_turf(beacon)
- beacon.update_status(SP_LAUNCH)
- else if (!usingBeacon)//find a suitable supplypod landing zone in cargobay
- landingzone = GLOB.areas_by_type[/area/quartermaster/storage]
- if (!landingzone)
- WARNING("[src] couldnt find a Quartermaster/Storage (aka cargobay) area on the station, and as such it has set the supplypod landingzone to the area it resides in.")
- landingzone = get_area(src)
- for(var/turf/open/floor/T in landingzone.contents)//uses default landing zone
- if(is_blocked_turf(T))
- continue
- LAZYADD(empty_turfs, T)
- CHECK_TICK
- if(empty_turfs && empty_turfs.len)
- LZ = pick(empty_turfs)
- if (SO.pack.cost <= SSshuttle.points && LZ)//we need to call the cost check again because of the CHECK_TICK call
- SSshuttle.points -= SO.pack.cost
- new /obj/effect/abstract/DPtarget(LZ, podType, SO)
- . = TRUE
- update_icon()
- else
- if(SO.pack.cost * (0.72*MAX_EMAG_ROCKETS) <= SSshuttle.points) // bulk discount :^)
- landingzone = GLOB.areas_by_type[pick(GLOB.the_station_areas)] //override default landing zone
- for(var/turf/open/floor/T in landingzone.contents)
- if(is_blocked_turf(T))
- continue
- LAZYADD(empty_turfs, T)
- CHECK_TICK
- if(empty_turfs && empty_turfs.len)
- SSshuttle.points -= SO.pack.cost * (0.72*MAX_EMAG_ROCKETS)
- SO.generateRequisition(get_turf(src))
- for(var/i in 1 to MAX_EMAG_ROCKETS)
- var/LZ = pick(empty_turfs)
- LAZYREMOVE(empty_turfs, LZ)
- new /obj/effect/abstract/DPtarget(LZ, podType, SO)
- . = TRUE
- update_icon()
- CHECK_TICK
+#define MAX_EMAG_ROCKETS 8
+#define BEACON_COST 5000
+#define SP_LINKED 1
+#define SP_READY 2
+#define SP_LAUNCH 3
+#define SP_UNLINK 4
+#define SP_UNREADY 5
+
+/obj/machinery/computer/cargo/express
+ name = "express supply console"
+ desc = "This console allows the user to purchase a package \
+ with 1/40th of the delivery time: made possible by NanoTrasen's new \"1500mm Orbital Railgun\".\
+ All sales are near instantaneous - please choose carefully"
+ icon_screen = "supply_express"
+ circuit = /obj/item/circuitboard/computer/cargo/express
+ blockade_warning = "Bluespace instability detected. Delivery impossible."
+ req_access = list(ACCESS_QM)
+ var/message
+ var/printed_beacons = 0 //number of beacons printed. Used to determine beacon names.
+ var/list/meme_pack_data
+ var/obj/item/supplypod_beacon/beacon //the linked supplypod beacon
+ var/area/landingzone = /area/quartermaster/storage //where we droppin boys
+ var/podType = /obj/structure/closet/supplypod
+ var/cooldown = 0 //cooldown to prevent printing supplypod beacon spam
+ var/locked = TRUE //is the console locked? unlock with ID
+ var/usingBeacon = FALSE //is the console in beacon mode? exists to let beacon know when a pod may come in
+
+/obj/machinery/computer/cargo/express/Initialize()
+ . = ..()
+ packin_up()
+
+/obj/machinery/computer/cargo/express/Destroy()
+ if(beacon)
+ beacon.unlink_console()
+ return ..()
+
+/obj/machinery/computer/cargo/express/attackby(obj/item/W, mob/living/user, params)
+ if((istype(W, /obj/item/card/id) || istype(W, /obj/item/pda)) && allowed(user))
+ locked = !locked
+ to_chat(user, "You [locked ? "lock" : "unlock"] the interface.")
+ return
+ else if(istype(W, /obj/item/disk/cargo/bluespace_pod))
+ podType = /obj/structure/closet/supplypod/bluespacepod
+ to_chat(user, "You insert the disk into [src], allowing for advanced supply delivery vehicles.")
+ qdel(W)
+ return TRUE
+ else if(istype(W, /obj/item/supplypod_beacon))
+ var/obj/item/supplypod_beacon/sb = W
+ if (sb.express_console != src)
+ sb.link_console(src, user)
+ return TRUE
+ else
+ to_chat(user, "[src] is already linked to [sb].")
+ ..()
+
+/obj/machinery/computer/cargo/express/emag_act(mob/living/user)
+ . = SEND_SIGNAL(src, COMSIG_ATOM_EMAG_ACT)
+ if(obj_flags & EMAGGED)
+ return
+ user.visible_message("[user] swipes a suspicious card through [src]!",
+ "You change the routing protocols, allowing the Supply Pod to land anywhere on the station.")
+ obj_flags |= EMAGGED
+ // This also sets this on the circuit board
+ var/obj/item/circuitboard/computer/cargo/board = circuit
+ board.obj_flags |= EMAGGED
+ packin_up()
+ req_access = list()
+ return TRUE
+
+/obj/machinery/computer/cargo/express/proc/packin_up() // oh shit, I'm sorry
+ meme_pack_data = list() // sorry for what?
+ for(var/pack in SSshuttle.supply_packs) // our quartermaster taught us not to be ashamed of our supply packs
+ var/datum/supply_pack/P = SSshuttle.supply_packs[pack] // specially since they're such a good price and all
+ if(!meme_pack_data[P.group]) // yeah, I see that, your quartermaster gave you good advice
+ meme_pack_data[P.group] = list( // it gets cheaper when I return it
+ "name" = P.group, // mmhm
+ "packs" = list() // sometimes, I return it so much, I rip the manifest
+ ) // see, my quartermaster taught me a few things too
+ if((P.hidden) || (P.special)) // like, how not to rip the manifest
+ continue// by using someone else's crate
+ if(!(obj_flags & EMAGGED) && P.contraband) // will you show me?
+ continue // i'd be right happy to
+ meme_pack_data[P.group]["packs"] += list(list(
+ "name" = P.name,
+ "cost" = P.cost,
+ "id" = pack,
+ "desc" = P.desc || P.name // If there is a description, use it. Otherwise use the pack's name.
+ ))
+
+/obj/machinery/computer/cargo/express/ui_interact(mob/living/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "cargo_express", name, 600, 700, master_ui, state)
+ ui.open()
+
+/obj/machinery/computer/cargo/express/ui_data(mob/user)
+ var/canBeacon = beacon && (isturf(beacon.loc) || ismob(beacon.loc))//is the beacon in a valid location?
+ var/list/data = list()
+ data["locked"] = locked//swipe an ID to unlock
+ data["siliconUser"] = user.has_unlimited_silicon_privilege
+ data["beaconzone"] = beacon ? get_area(beacon) : ""//where is the beacon located? outputs in the tgui
+ data["usingBeacon"] = usingBeacon //is the mode set to deliver to the beacon or the cargobay?
+ data["canBeacon"] = !usingBeacon || canBeacon //is the mode set to beacon delivery, and is the beacon in a valid location?
+ data["canBuyBeacon"] = cooldown <= 0 && SSshuttle.points >= BEACON_COST
+ data["beaconError"] = usingBeacon && !canBeacon ? "(BEACON ERROR)" : ""//changes button text to include an error alert if necessary
+ data["hasBeacon"] = beacon != null//is there a linked beacon?
+ data["beaconName"] = beacon ? beacon.name : "No Beacon Found"
+ data["printMsg"] = cooldown > 0 ? "Print Beacon for [BEACON_COST] credits ([cooldown])" : "Print Beacon for [BEACON_COST] credits"//buttontext for printing beacons
+ data["points"] = SSshuttle.points
+ data["supplies"] = list()
+ message = "Sales are near-instantaneous - please choose carefully."
+ if(SSshuttle.supplyBlocked)
+ message = blockade_warning
+ if(usingBeacon && !beacon)
+ message = "BEACON ERROR: BEACON MISSING"//beacon was destroyed
+ else if (usingBeacon && !canBeacon)
+ message = "BEACON ERROR: MUST BE EXPOSED"//beacon's loc/user's loc must be a turf
+ if(obj_flags & EMAGGED)
+ message = "(&!#@ERROR: ROUTING_#PROTOCOL MALF(*CT#ON. $UG%ESTE@ ACT#0N: !^/PULS3-%E)ET CIR*)ITB%ARD."
+ data["message"] = message
+ if(!meme_pack_data)
+ packin_up()
+ stack_trace("You didn't give the cargo tech good advice, and he ripped the manifest. As a result, there was no pack data for [src]")
+ data["supplies"] = meme_pack_data
+ if (cooldown > 0)//cooldown used for printing beacons
+ cooldown--
+ return data
+
+/obj/machinery/computer/cargo/express/ui_act(action, params, datum/tgui/ui)
+ switch(action)
+ if("LZCargo")
+ usingBeacon = FALSE
+ if (beacon)
+ beacon.update_status(SP_UNREADY) //ready light on beacon will turn off
+ if("LZBeacon")
+ usingBeacon = TRUE
+ if (beacon)
+ beacon.update_status(SP_READY) //turns on the beacon's ready light
+ if("printBeacon")
+ if (SSshuttle.points >= BEACON_COST)
+ cooldown = 10//a ~ten second cooldown for printing beacons to prevent spam
+ var/obj/item/supplypod_beacon/C = new /obj/item/supplypod_beacon(drop_location())
+ C.link_console(src, usr)//rather than in beacon's Initialize(), we can assign the computer to the beacon by reusing this proc)
+ printed_beacons++//printed_beacons starts at 0, so the first one out will be called beacon # 1
+ beacon.name = "Supply Pod Beacon #[printed_beacons]"
+ SSshuttle.points -= BEACON_COST
+
+ if("add")//Generate Supply Order first
+ var/id = text2path(params["id"])
+ var/datum/supply_pack/pack = SSshuttle.supply_packs[id]
+ if(!istype(pack))
+ return
+ var/name = "*None Provided*"
+ var/rank = "*None Provided*"
+ var/ckey = usr.ckey
+ if(ishuman(usr))
+ var/mob/living/carbon/human/H = usr
+ name = H.get_authentification_name()
+ rank = H.get_assignment(hand_first = TRUE)
+ else if(issilicon(usr))
+ name = usr.real_name
+ rank = "Silicon"
+ var/reason = ""
+ var/list/empty_turfs
+ var/datum/supply_order/SO = new(pack, name, rank, ckey, reason)
+ if(!(obj_flags & EMAGGED))
+ if(SO.pack.cost <= SSshuttle.points)
+ var/LZ
+ if (istype(beacon) && usingBeacon)//prioritize beacons over landing in cargobay
+ LZ = get_turf(beacon)
+ beacon.update_status(SP_LAUNCH)
+ else if (!usingBeacon)//find a suitable supplypod landing zone in cargobay
+ landingzone = GLOB.areas_by_type[/area/quartermaster/storage]
+ if (!landingzone)
+ WARNING("[src] couldnt find a Quartermaster/Storage (aka cargobay) area on the station, and as such it has set the supplypod landingzone to the area it resides in.")
+ landingzone = get_area(src)
+ for(var/turf/open/floor/T in landingzone.contents)//uses default landing zone
+ if(is_blocked_turf(T))
+ continue
+ LAZYADD(empty_turfs, T)
+ CHECK_TICK
+ if(empty_turfs && empty_turfs.len)
+ LZ = pick(empty_turfs)
+ if (SO.pack.cost <= SSshuttle.points && LZ)//we need to call the cost check again because of the CHECK_TICK call
+ SSshuttle.points -= SO.pack.cost
+ new /obj/effect/abstract/DPtarget(LZ, podType, SO)
+ . = TRUE
+ update_icon()
+ else
+ if(SO.pack.cost * (0.72*MAX_EMAG_ROCKETS) <= SSshuttle.points) // bulk discount :^)
+ landingzone = GLOB.areas_by_type[pick(GLOB.the_station_areas)] //override default landing zone
+ for(var/turf/open/floor/T in landingzone.contents)
+ if(is_blocked_turf(T))
+ continue
+ LAZYADD(empty_turfs, T)
+ CHECK_TICK
+ if(empty_turfs && empty_turfs.len)
+ SSshuttle.points -= SO.pack.cost * (0.72*MAX_EMAG_ROCKETS)
+ SO.generateRequisition(get_turf(src))
+ for(var/i in 1 to MAX_EMAG_ROCKETS)
+ var/LZ = pick(empty_turfs)
+ LAZYREMOVE(empty_turfs, LZ)
+ new /obj/effect/abstract/DPtarget(LZ, podType, SO)
+ . = TRUE
+ update_icon()
+ CHECK_TICK
diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm
index 821d3d184b..4acae30d11 100644
--- a/code/modules/client/asset_cache.dm
+++ b/code/modules/client/asset_cache.dm
@@ -1,704 +1,704 @@
-/*
-Asset cache quick users guide:
-
-Make a datum at the bottom of this file with your assets for your thing.
-The simple subsystem will most like be of use for most cases.
-Then call get_asset_datum() with the type of the datum you created and store the return
-Then call .send(client) on that stored return value.
-
-You can set verify to TRUE if you want send() to sleep until the client has the assets.
-*/
-
-
-// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping.
-// This is doubled for the first asset, then added per asset after
-#define ASSET_CACHE_SEND_TIMEOUT 7
-
-//When sending mutiple assets, how many before we give the client a quaint little sending resources message
-#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
-
-//When passively preloading assets, how many to send at once? Too high creates noticable lag where as too low can flood the client's cache with "verify" files
-#define ASSET_CACHE_PRELOAD_CONCURRENT 3
-
-/client
- var/list/cache = list() // List of all assets sent to this client by the asset cache.
- var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement.
- var/list/sending = list()
- var/last_asset_job = 0 // Last job done.
-
-//This proc sends the asset to the client, but only if it needs it.
-//This proc blocks(sleeps) unless verify is set to false
-/proc/send_asset(client/client, asset_name, verify = TRUE)
- if(!istype(client))
- if(ismob(client))
- var/mob/M = client
- if(M.client)
- client = M.client
-
- else
- return 0
-
- else
- return 0
-
- if(client.cache.Find(asset_name) || client.sending.Find(asset_name))
- return 0
-
- client << browse_rsc(SSassets.cache[asset_name], asset_name)
- if(!verify)
- client.cache += asset_name
- return 1
-
- client.sending |= asset_name
- var/job = ++client.last_asset_job
-
- client << browse({"
-
- "}, "window=asset_cache_browser")
-
- var/t = 0
- var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT
- while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
- stoplag(1) // Lock up the caller until this is received.
- t++
-
- if(client)
- client.sending -= asset_name
- client.cache |= asset_name
- client.completed_asset_jobs -= job
-
- return 1
-
-//This proc blocks(sleeps) unless verify is set to false
-/proc/send_asset_list(client/client, list/asset_list, verify = TRUE)
- if(!istype(client))
- if(ismob(client))
- var/mob/M = client
- if(M.client)
- client = M.client
-
- else
- return 0
-
- else
- return 0
-
- var/list/unreceived = asset_list - (client.cache + client.sending)
- if(!unreceived || !unreceived.len)
- return 0
- if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
- to_chat(client, "Sending Resources...")
- for(var/asset in unreceived)
- if (asset in SSassets.cache)
- client << browse_rsc(SSassets.cache[asset], asset)
-
- if(!verify) // Can't access the asset cache browser, rip.
- client.cache += unreceived
- return 1
-
- client.sending |= unreceived
- var/job = ++client.last_asset_job
-
- client << browse({"
-
- "}, "window=asset_cache_browser")
-
- var/t = 0
- var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len
- while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
- stoplag(1) // Lock up the caller until this is received.
- t++
-
- if(client)
- client.sending -= unreceived
- client.cache |= unreceived
- client.completed_asset_jobs -= job
-
- return 1
-
-//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
-//The proc calls procs that sleep for long times.
-/proc/getFilesSlow(client/client, list/files, register_asset = TRUE)
- var/concurrent_tracker = 1
- for(var/file in files)
- if (!client)
- break
- if (register_asset)
- register_asset(file, files[file])
- if (concurrent_tracker >= ASSET_CACHE_PRELOAD_CONCURRENT)
- concurrent_tracker = 1
- send_asset(client, file)
- else
- concurrent_tracker++
- send_asset(client, file, verify=FALSE)
-
- stoplag(0) //queuing calls like this too quickly can cause issues in some client versions
-
-//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
-//if it's an icon or something be careful, you'll have to copy it before further use.
-/proc/register_asset(asset_name, asset)
- SSassets.cache[asset_name] = asset
-
-//Generated names do not include file extention.
-//Used mainly for code that deals with assets in a generic way
-//The same asset will always lead to the same asset name
-/proc/generate_asset_name(file)
- return "asset.[md5(fcopy_rsc(file))]"
-
-
-//These datums are used to populate the asset cache, the proc "register()" does this.
-
-//all of our asset datums, used for referring to these later
-GLOBAL_LIST_EMPTY(asset_datums)
-
-//get an assetdatum or make a new one
-/proc/get_asset_datum(type)
- return GLOB.asset_datums[type] || new type()
-
-/datum/asset
- var/_abstract = /datum/asset
-
-/datum/asset/New()
- GLOB.asset_datums[type] = src
- register()
-
-/datum/asset/proc/register()
- return
-
-/datum/asset/proc/send(client)
- return
-
-
-//If you don't need anything complicated.
-/datum/asset/simple
- _abstract = /datum/asset/simple
- var/assets = list()
- var/verify = FALSE
-
-/datum/asset/simple/register()
- for(var/asset_name in assets)
- register_asset(asset_name, assets[asset_name])
-
-/datum/asset/simple/send(client)
- send_asset_list(client,assets,verify)
-
-
-// For registering or sending multiple others at once
-/datum/asset/group
- _abstract = /datum/asset/group
- var/list/children
-
-/datum/asset/group/register()
- for(var/type in children)
- get_asset_datum(type)
-
-/datum/asset/group/send(client/C)
- for(var/type in children)
- var/datum/asset/A = get_asset_datum(type)
- A.send(C)
-
-
-// spritesheet implementation - coalesces various icons into a single .png file
-// and uses CSS to select icons out of that file - saves on transferring some
-// 1400-odd individual PNG files
-#define SPR_SIZE 1
-#define SPR_IDX 2
-#define SPRSZ_COUNT 1
-#define SPRSZ_ICON 2
-#define SPRSZ_STRIPPED 3
-
-/datum/asset/spritesheet
- _abstract = /datum/asset/spritesheet
- var/name
- var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped)
- var/list/sprites = list() // "foo_bar" -> list("32x32", 5)
- var/verify = FALSE
-
-/datum/asset/spritesheet/register()
- if (!name)
- CRASH("spritesheet [type] cannot register without a name")
- ensure_stripped()
-
- var/res_name = "spritesheet_[name].css"
- var/fname = "data/spritesheets/[res_name]"
- fdel(fname)
- text2file(generate_css(), fname)
- register_asset(res_name, fcopy_rsc(fname))
- fdel(fname)
-
- for(var/size_id in sizes)
- var/size = sizes[size_id]
- register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
-
-/datum/asset/spritesheet/send(client/C)
- if (!name)
- return
- var/all = list("spritesheet_[name].css")
- for(var/size_id in sizes)
- all += "[name]_[size_id].png"
- send_asset_list(C, all, verify)
-
-/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes)
- for(var/size_id in sizes_to_strip)
- var/size = sizes[size_id]
- if (size[SPRSZ_STRIPPED])
- continue
-
- // save flattened version
- var/fname = "data/spritesheets/[name]_[size_id].png"
- fcopy(size[SPRSZ_ICON], fname)
- var/error = rustg_dmi_strip_metadata(fname)
- if(length(error))
- stack_trace("Failed to strip [name]_[size_id].png: [error]")
- size[SPRSZ_STRIPPED] = icon(fname)
- fdel(fname)
-
-/datum/asset/spritesheet/proc/generate_css()
- var/list/out = list()
-
- for (var/size_id in sizes)
- var/size = sizes[size_id]
- var/icon/tiny = size[SPRSZ_ICON]
- out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[name]_[size_id].png') no-repeat;}"
-
- for (var/sprite_id in sprites)
- var/sprite = sprites[sprite_id]
- var/size_id = sprite[SPR_SIZE]
- var/idx = sprite[SPR_IDX]
- var/size = sizes[size_id]
-
- var/icon/tiny = size[SPRSZ_ICON]
- var/icon/big = size[SPRSZ_STRIPPED]
- var/per_line = big.Width() / tiny.Width()
- var/x = (idx % per_line) * tiny.Width()
- var/y = round(idx / per_line) * tiny.Height()
-
- out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}"
-
- return out.Join("\n")
-
-/datum/asset/spritesheet/proc/Insert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
- I = icon(I, icon_state=icon_state, dir=dir, frame=frame, moving=moving)
- if (!I || !length(icon_states(I))) // that direction or state doesn't exist
- return
- var/size_id = "[I.Width()]x[I.Height()]"
- var/size = sizes[size_id]
-
- if (sprites[sprite_name])
- CRASH("duplicate sprite \"[sprite_name]\" in sheet [name] ([type])")
-
- if (size)
- var/position = size[SPRSZ_COUNT]++
- var/icon/sheet = size[SPRSZ_ICON]
- size[SPRSZ_STRIPPED] = null
- sheet.Insert(I, icon_state=sprite_name)
- sprites[sprite_name] = list(size_id, position)
- else
- sizes[size_id] = size = list(1, I, null)
- sprites[sprite_name] = list(size_id, 0)
-
-/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions)
- if (length(prefix))
- prefix = "[prefix]-"
-
- if (!directions)
- directions = list(SOUTH)
-
- for (var/icon_state_name in icon_states(I))
- for (var/direction in directions)
- var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : ""
- Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction)
-
-/datum/asset/spritesheet/proc/css_tag()
- return {""}
-
-/datum/asset/spritesheet/proc/icon_tag(sprite_name)
- var/sprite = sprites[sprite_name]
- if (!sprite)
- return null
- var/size_id = sprite[SPR_SIZE]
- return {""}
-
-/datum/asset/spritesheet/proc/icon_class_name(sprite_name)
- var/sprite = sprites[sprite_name]
- if (!sprite)
- return null
- var/size_id = sprite[SPR_SIZE]
- return {"[name][size_id] [sprite_name]"}
-
-#undef SPR_SIZE
-#undef SPR_IDX
-#undef SPRSZ_COUNT
-#undef SPRSZ_ICON
-#undef SPRSZ_STRIPPED
-
-
-/datum/asset/spritesheet/simple
- _abstract = /datum/asset/spritesheet/simple
- var/list/assets
-
-/datum/asset/spritesheet/simple/register()
- for (var/key in assets)
- Insert(key, assets[key])
- ..()
-
-//Generates assets based on iconstates of a single icon
-/datum/asset/simple/icon_states
- _abstract = /datum/asset/simple/icon_states
- var/icon
- var/list/directions = list(SOUTH)
- var/frame = 1
- var/movement_states = FALSE
-
- var/prefix = "default" //asset_name = "[prefix].[icon_state_name].png"
- var/generic_icon_names = FALSE //generate icon filenames using generate_asset_name() instead the above format
-
- verify = FALSE
-
-/datum/asset/simple/icon_states/register(_icon = icon)
- for(var/icon_state_name in icon_states(_icon))
- for(var/direction in directions)
- var/asset = icon(_icon, icon_state_name, direction, frame, movement_states)
- if (!asset)
- continue
- asset = fcopy_rsc(asset) //dedupe
- var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]." : ""
- var/asset_name = sanitize_filename("[prefix].[prefix2][icon_state_name].png")
- if (generic_icon_names)
- asset_name = "[generate_asset_name(asset)].png"
-
- register_asset(asset_name, asset)
-
-/datum/asset/simple/icon_states/multiple_icons
- _abstract = /datum/asset/simple/icon_states/multiple_icons
- var/list/icons
-
-/datum/asset/simple/icon_states/multiple_icons/register()
- for(var/i in icons)
- ..(i)
-
-
-//DEFINITIONS FOR ASSET DATUMS START HERE.
-
-/datum/asset/simple/tgui
- assets = list(
- // tgui
- "tgui.css" = 'tgui/assets/tgui.css',
- "tgui.js" = 'tgui/assets/tgui.js',
- // tgui-next
- "tgui-main.html" = 'tgui-next/packages/tgui/public/tgui-main.html',
- "tgui-fallback.html" = 'tgui-next/packages/tgui/public/tgui-fallback.html',
- "tgui.bundle.js" = 'tgui-next/packages/tgui/public/tgui.bundle.js',
- "tgui.bundle.css" = 'tgui-next/packages/tgui/public/tgui.bundle.css',
- "shim-html5shiv.js" = 'tgui-next/packages/tgui/public/shim-html5shiv.js',
- "shim-ie8.js" = 'tgui-next/packages/tgui/public/shim-ie8.js',
- "shim-dom4.js" = 'tgui-next/packages/tgui/public/shim-dom4.js',
- "shim-css-om.js" = 'tgui-next/packages/tgui/public/shim-css-om.js',
- )
-
-/datum/asset/group/tgui
- children = list(
- /datum/asset/simple/tgui,
- /datum/asset/simple/fontawesome
- )
-
-/datum/asset/simple/headers
- assets = list(
- "alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
- "alarm_red.gif" = 'icons/program_icons/alarm_red.gif',
- "batt_5.gif" = 'icons/program_icons/batt_5.gif',
- "batt_20.gif" = 'icons/program_icons/batt_20.gif',
- "batt_40.gif" = 'icons/program_icons/batt_40.gif',
- "batt_60.gif" = 'icons/program_icons/batt_60.gif',
- "batt_80.gif" = 'icons/program_icons/batt_80.gif',
- "batt_100.gif" = 'icons/program_icons/batt_100.gif',
- "charging.gif" = 'icons/program_icons/charging.gif',
- "downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif',
- "downloader_running.gif" = 'icons/program_icons/downloader_running.gif',
- "ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif',
- "ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif',
- "power_norm.gif" = 'icons/program_icons/power_norm.gif',
- "power_warn.gif" = 'icons/program_icons/power_warn.gif',
- "sig_high.gif" = 'icons/program_icons/sig_high.gif',
- "sig_low.gif" = 'icons/program_icons/sig_low.gif',
- "sig_lan.gif" = 'icons/program_icons/sig_lan.gif',
- "sig_none.gif" = 'icons/program_icons/sig_none.gif',
- "smmon_0.gif" = 'icons/program_icons/smmon_0.gif',
- "smmon_1.gif" = 'icons/program_icons/smmon_1.gif',
- "smmon_2.gif" = 'icons/program_icons/smmon_2.gif',
- "smmon_3.gif" = 'icons/program_icons/smmon_3.gif',
- "smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
- "smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
- "smmon_6.gif" = 'icons/program_icons/smmon_6.gif'
- )
-
-/datum/asset/spritesheet/simple/pda
- name = "pda"
- assets = list(
- "atmos" = 'icons/pda_icons/pda_atmos.png',
- "back" = 'icons/pda_icons/pda_back.png',
- "bell" = 'icons/pda_icons/pda_bell.png',
- "blank" = 'icons/pda_icons/pda_blank.png',
- "boom" = 'icons/pda_icons/pda_boom.png',
- "bucket" = 'icons/pda_icons/pda_bucket.png',
- "medbot" = 'icons/pda_icons/pda_medbot.png',
- "floorbot" = 'icons/pda_icons/pda_floorbot.png',
- "cleanbot" = 'icons/pda_icons/pda_cleanbot.png',
- "crate" = 'icons/pda_icons/pda_crate.png',
- "cuffs" = 'icons/pda_icons/pda_cuffs.png',
- "eject" = 'icons/pda_icons/pda_eject.png',
- "flashlight" = 'icons/pda_icons/pda_flashlight.png',
- "honk" = 'icons/pda_icons/pda_honk.png',
- "mail" = 'icons/pda_icons/pda_mail.png',
- "medical" = 'icons/pda_icons/pda_medical.png',
- "menu" = 'icons/pda_icons/pda_menu.png',
- "mule" = 'icons/pda_icons/pda_mule.png',
- "notes" = 'icons/pda_icons/pda_notes.png',
- "power" = 'icons/pda_icons/pda_power.png',
- "rdoor" = 'icons/pda_icons/pda_rdoor.png',
- "reagent" = 'icons/pda_icons/pda_reagent.png',
- "refresh" = 'icons/pda_icons/pda_refresh.png',
- "scanner" = 'icons/pda_icons/pda_scanner.png',
- "signaler" = 'icons/pda_icons/pda_signaler.png',
- "status" = 'icons/pda_icons/pda_status.png',
- "dronephone" = 'icons/pda_icons/pda_dronephone.png'
- )
-
-/datum/asset/spritesheet/simple/paper
- name = "paper"
- assets = list(
- "stamp-clown" = 'icons/stamp_icons/large_stamp-clown.png',
- "stamp-deny" = 'icons/stamp_icons/large_stamp-deny.png',
- "stamp-ok" = 'icons/stamp_icons/large_stamp-ok.png',
- "stamp-hop" = 'icons/stamp_icons/large_stamp-hop.png',
- "stamp-cmo" = 'icons/stamp_icons/large_stamp-cmo.png',
- "stamp-ce" = 'icons/stamp_icons/large_stamp-ce.png',
- "stamp-hos" = 'icons/stamp_icons/large_stamp-hos.png',
- "stamp-rd" = 'icons/stamp_icons/large_stamp-rd.png',
- "stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png',
- "stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png',
- "stamp-law" = 'icons/stamp_icons/large_stamp-law.png'
- )
-
-/datum/asset/spritesheet/simple/minesweeper
- name = "minesweeper"
- assets = list(
- "1" = 'icons/UI_Icons/minesweeper_tiles/one.png',
- "2" = 'icons/UI_Icons/minesweeper_tiles/two.png',
- "3" = 'icons/UI_Icons/minesweeper_tiles/three.png',
- "4" = 'icons/UI_Icons/minesweeper_tiles/four.png',
- "5" = 'icons/UI_Icons/minesweeper_tiles/five.png',
- "6" = 'icons/UI_Icons/minesweeper_tiles/six.png',
- "7" = 'icons/UI_Icons/minesweeper_tiles/seven.png',
- "8" = 'icons/UI_Icons/minesweeper_tiles/eight.png',
- "empty" = 'icons/UI_Icons/minesweeper_tiles/empty.png',
- "flag" = 'icons/UI_Icons/minesweeper_tiles/flag.png',
- "hidden" = 'icons/UI_Icons/minesweeper_tiles/hidden.png',
- "mine" = 'icons/UI_Icons/minesweeper_tiles/mine.png',
- "minehit" = 'icons/UI_Icons/minesweeper_tiles/minehit.png'
- )
-
-/datum/asset/spritesheet/simple/pills
- name = "pills"
- assets = list(
- "pill1" = 'icons/UI_Icons/Pills/pill1.png',
- "pill2" = 'icons/UI_Icons/Pills/pill2.png',
- "pill3" = 'icons/UI_Icons/Pills/pill3.png',
- "pill4" = 'icons/UI_Icons/Pills/pill4.png',
- "pill5" = 'icons/UI_Icons/Pills/pill5.png',
- "pill6" = 'icons/UI_Icons/Pills/pill6.png',
- "pill7" = 'icons/UI_Icons/Pills/pill7.png',
- "pill8" = 'icons/UI_Icons/Pills/pill8.png',
- "pill9" = 'icons/UI_Icons/Pills/pill9.png',
- "pill10" = 'icons/UI_Icons/Pills/pill10.png',
- "pill11" = 'icons/UI_Icons/Pills/pill11.png',
- "pill12" = 'icons/UI_Icons/Pills/pill12.png',
- "pill13" = 'icons/UI_Icons/Pills/pill13.png',
- "pill14" = 'icons/UI_Icons/Pills/pill14.png',
- "pill15" = 'icons/UI_Icons/Pills/pill15.png',
- "pill16" = 'icons/UI_Icons/Pills/pill16.png',
- "pill17" = 'icons/UI_Icons/Pills/pill17.png',
- "pill18" = 'icons/UI_Icons/Pills/pill18.png',
- "pill19" = 'icons/UI_Icons/Pills/pill19.png',
- "pill20" = 'icons/UI_Icons/Pills/pill20.png',
- "pill21" = 'icons/UI_Icons/Pills/pill21.png',
- "pill22" = 'icons/UI_Icons/Pills/pill22.png',
- )
-
-/datum/asset/simple/IRV
- assets = list(
- "jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js',
- )
-
-/datum/asset/group/IRV
- children = list(
- /datum/asset/simple/jquery,
- /datum/asset/simple/IRV
- )
-
-/datum/asset/simple/changelog
- assets = list(
- "88x31.png" = 'html/88x31.png',
- "bug-minus.png" = 'html/bug-minus.png',
- "cross-circle.png" = 'html/cross-circle.png',
- "hard-hat-exclamation.png" = 'html/hard-hat-exclamation.png',
- "image-minus.png" = 'html/image-minus.png',
- "image-plus.png" = 'html/image-plus.png',
- "music-minus.png" = 'html/music-minus.png',
- "music-plus.png" = 'html/music-plus.png',
- "tick-circle.png" = 'html/tick-circle.png',
- "wrench-screwdriver.png" = 'html/wrench-screwdriver.png',
- "spell-check.png" = 'html/spell-check.png',
- "burn-exclamation.png" = 'html/burn-exclamation.png',
- "chevron.png" = 'html/chevron.png',
- "chevron-expand.png" = 'html/chevron-expand.png',
- "scales.png" = 'html/scales.png',
- "coding.png" = 'html/coding.png',
- "ban.png" = 'html/ban.png',
- "chrome-wrench.png" = 'html/chrome-wrench.png',
- "changelog.css" = 'html/changelog.css'
- )
-
-/datum/asset/group/goonchat
- children = list(
- /datum/asset/simple/jquery,
- /datum/asset/simple/goonchat,
- /datum/asset/spritesheet/goonchat,
- /datum/asset/simple/fontawesome
- )
-
-/datum/asset/simple/jquery
- verify = FALSE
- assets = list(
- "jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js',
- )
-
-/datum/asset/simple/goonchat
- verify = FALSE
- assets = list(
- "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
- "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js',
- "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css',
- "browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css',
- "browserOutput_light.css" = 'code/modules/goonchat/browserassets/css/browserOutput_light.css'
- )
-
-/datum/asset/simple/fontawesome
- verify = FALSE
- assets = list(
- "fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot',
- "fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff',
- "fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot',
- "fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff',
- "font-awesome.css" = 'html/font-awesome/css/all.min.css',
- "v4shim.css" = 'html/font-awesome/css/v4-shims.min.css'
- )
-
-/datum/asset/spritesheet/goonchat
- name = "chat"
-
-/datum/asset/spritesheet/goonchat/register()
- InsertAll("emoji", 'icons/emoji.dmi')
-
- // pre-loading all lanugage icons also helps to avoid meta
- InsertAll("language", 'icons/misc/language.dmi')
- // catch languages which are pulling icons from another file
- for(var/path in typesof(/datum/language))
- var/datum/language/L = path
- var/icon = initial(L.icon)
- if (icon != 'icons/misc/language.dmi')
- var/icon_state = initial(L.icon_state)
- Insert("language-[icon_state]", icon, icon_state=icon_state)
-
- ..()
-
-/datum/asset/simple/permissions
- assets = list(
- "padlock.png" = 'html/padlock.png'
- )
-
-/datum/asset/simple/notes
- assets = list(
- "high_button.png" = 'html/high_button.png',
- "medium_button.png" = 'html/medium_button.png',
- "minor_button.png" = 'html/minor_button.png',
- "none_button.png" = 'html/none_button.png',
- )
-
-//this exists purely to avoid meta by pre-loading all language icons.
-/datum/asset/language/register()
- for(var/path in typesof(/datum/language))
- set waitfor = FALSE
- var/datum/language/L = new path ()
- L.get_icon()
-
-/datum/asset/spritesheet/pipes
- name = "pipes"
-
-/datum/asset/spritesheet/pipes/register()
- for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi'))
- InsertAll("", each, GLOB.alldirs)
- ..()
-
-// Representative icons for each research design
-/datum/asset/spritesheet/research_designs
- name = "design"
-
-/datum/asset/spritesheet/research_designs/register()
- for (var/path in subtypesof(/datum/design))
- var/datum/design/D = path
-
- var/icon_file
- var/icon_state
- var/icon/I
-
- if(initial(D.research_icon) && initial(D.research_icon_state)) //If the design has an icon replacement skip the rest
- icon_file = initial(D.research_icon)
- icon_state = initial(D.research_icon_state)
- if(!(icon_state in icon_states(icon_file)))
- warning("design [D] with icon '[icon_file]' missing state '[icon_state]'")
- continue
- I = icon(icon_file, icon_state, SOUTH)
-
- else
- // construct the icon and slap it into the resource cache
- var/atom/item = initial(D.build_path)
- if (!ispath(item, /atom))
- // biogenerator outputs to beakers by default
- if (initial(D.build_type) & BIOGENERATOR)
- item = /obj/item/reagent_containers/glass/beaker/large
- else
- continue // shouldn't happen, but just in case
-
- // circuit boards become their resulting machines or computers
- if (ispath(item, /obj/item/circuitboard))
- var/obj/item/circuitboard/C = item
- var/machine = initial(C.build_path)
- if (machine)
- item = machine
-
- icon_file = initial(item.icon)
- icon_state = initial(item.icon_state)
-
- if(!(icon_state in icon_states(icon_file)))
- warning("design [D] with icon '[icon_file]' missing state '[icon_state]'")
- continue
- I = icon(icon_file, icon_state, SOUTH)
-
- // computers (and snowflakes) get their screen and keyboard sprites
- if (ispath(item, /obj/machinery/computer) || ispath(item, /obj/machinery/power/solar_control))
- var/obj/machinery/computer/C = item
- var/screen = initial(C.icon_screen)
- var/keyboard = initial(C.icon_keyboard)
- var/all_states = icon_states(icon_file)
- if (screen && (screen in all_states))
- I.Blend(icon(icon_file, screen, SOUTH), ICON_OVERLAY)
- if (keyboard && (keyboard in all_states))
- I.Blend(icon(icon_file, keyboard, SOUTH), ICON_OVERLAY)
-
- Insert(initial(D.id), I)
- return ..()
+/*
+Asset cache quick users guide:
+
+Make a datum at the bottom of this file with your assets for your thing.
+The simple subsystem will most like be of use for most cases.
+Then call get_asset_datum() with the type of the datum you created and store the return
+Then call .send(client) on that stored return value.
+
+You can set verify to TRUE if you want send() to sleep until the client has the assets.
+*/
+
+
+// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping.
+// This is doubled for the first asset, then added per asset after
+#define ASSET_CACHE_SEND_TIMEOUT 7
+
+//When sending mutiple assets, how many before we give the client a quaint little sending resources message
+#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
+
+//When passively preloading assets, how many to send at once? Too high creates noticable lag where as too low can flood the client's cache with "verify" files
+#define ASSET_CACHE_PRELOAD_CONCURRENT 3
+
+/client
+ var/list/cache = list() // List of all assets sent to this client by the asset cache.
+ var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement.
+ var/list/sending = list()
+ var/last_asset_job = 0 // Last job done.
+
+//This proc sends the asset to the client, but only if it needs it.
+//This proc blocks(sleeps) unless verify is set to false
+/proc/send_asset(client/client, asset_name, verify = TRUE)
+ if(!istype(client))
+ if(ismob(client))
+ var/mob/M = client
+ if(M.client)
+ client = M.client
+
+ else
+ return 0
+
+ else
+ return 0
+
+ if(client.cache.Find(asset_name) || client.sending.Find(asset_name))
+ return 0
+
+ client << browse_rsc(SSassets.cache[asset_name], asset_name)
+ if(!verify)
+ client.cache += asset_name
+ return 1
+
+ client.sending |= asset_name
+ var/job = ++client.last_asset_job
+
+ client << browse({"
+
+ "}, "window=asset_cache_browser")
+
+ var/t = 0
+ var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT
+ while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
+ stoplag(1) // Lock up the caller until this is received.
+ t++
+
+ if(client)
+ client.sending -= asset_name
+ client.cache |= asset_name
+ client.completed_asset_jobs -= job
+
+ return 1
+
+//This proc blocks(sleeps) unless verify is set to false
+/proc/send_asset_list(client/client, list/asset_list, verify = TRUE)
+ if(!istype(client))
+ if(ismob(client))
+ var/mob/M = client
+ if(M.client)
+ client = M.client
+
+ else
+ return 0
+
+ else
+ return 0
+
+ var/list/unreceived = asset_list - (client.cache + client.sending)
+ if(!unreceived || !unreceived.len)
+ return 0
+ if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
+ to_chat(client, "Sending Resources...")
+ for(var/asset in unreceived)
+ if (asset in SSassets.cache)
+ client << browse_rsc(SSassets.cache[asset], asset)
+
+ if(!verify) // Can't access the asset cache browser, rip.
+ client.cache += unreceived
+ return 1
+
+ client.sending |= unreceived
+ var/job = ++client.last_asset_job
+
+ client << browse({"
+
+ "}, "window=asset_cache_browser")
+
+ var/t = 0
+ var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len
+ while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
+ stoplag(1) // Lock up the caller until this is received.
+ t++
+
+ if(client)
+ client.sending -= unreceived
+ client.cache |= unreceived
+ client.completed_asset_jobs -= job
+
+ return 1
+
+//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
+//The proc calls procs that sleep for long times.
+/proc/getFilesSlow(client/client, list/files, register_asset = TRUE)
+ var/concurrent_tracker = 1
+ for(var/file in files)
+ if (!client)
+ break
+ if (register_asset)
+ register_asset(file, files[file])
+ if (concurrent_tracker >= ASSET_CACHE_PRELOAD_CONCURRENT)
+ concurrent_tracker = 1
+ send_asset(client, file)
+ else
+ concurrent_tracker++
+ send_asset(client, file, verify=FALSE)
+
+ stoplag(0) //queuing calls like this too quickly can cause issues in some client versions
+
+//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
+//if it's an icon or something be careful, you'll have to copy it before further use.
+/proc/register_asset(asset_name, asset)
+ SSassets.cache[asset_name] = asset
+
+//Generated names do not include file extention.
+//Used mainly for code that deals with assets in a generic way
+//The same asset will always lead to the same asset name
+/proc/generate_asset_name(file)
+ return "asset.[md5(fcopy_rsc(file))]"
+
+
+//These datums are used to populate the asset cache, the proc "register()" does this.
+
+//all of our asset datums, used for referring to these later
+GLOBAL_LIST_EMPTY(asset_datums)
+
+//get an assetdatum or make a new one
+/proc/get_asset_datum(type)
+ return GLOB.asset_datums[type] || new type()
+
+/datum/asset
+ var/_abstract = /datum/asset
+
+/datum/asset/New()
+ GLOB.asset_datums[type] = src
+ register()
+
+/datum/asset/proc/register()
+ return
+
+/datum/asset/proc/send(client)
+ return
+
+
+//If you don't need anything complicated.
+/datum/asset/simple
+ _abstract = /datum/asset/simple
+ var/assets = list()
+ var/verify = FALSE
+
+/datum/asset/simple/register()
+ for(var/asset_name in assets)
+ register_asset(asset_name, assets[asset_name])
+
+/datum/asset/simple/send(client)
+ send_asset_list(client,assets,verify)
+
+
+// For registering or sending multiple others at once
+/datum/asset/group
+ _abstract = /datum/asset/group
+ var/list/children
+
+/datum/asset/group/register()
+ for(var/type in children)
+ get_asset_datum(type)
+
+/datum/asset/group/send(client/C)
+ for(var/type in children)
+ var/datum/asset/A = get_asset_datum(type)
+ A.send(C)
+
+
+// spritesheet implementation - coalesces various icons into a single .png file
+// and uses CSS to select icons out of that file - saves on transferring some
+// 1400-odd individual PNG files
+#define SPR_SIZE 1
+#define SPR_IDX 2
+#define SPRSZ_COUNT 1
+#define SPRSZ_ICON 2
+#define SPRSZ_STRIPPED 3
+
+/datum/asset/spritesheet
+ _abstract = /datum/asset/spritesheet
+ var/name
+ var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped)
+ var/list/sprites = list() // "foo_bar" -> list("32x32", 5)
+ var/verify = FALSE
+
+/datum/asset/spritesheet/register()
+ if (!name)
+ CRASH("spritesheet [type] cannot register without a name")
+ ensure_stripped()
+
+ var/res_name = "spritesheet_[name].css"
+ var/fname = "data/spritesheets/[res_name]"
+ fdel(fname)
+ text2file(generate_css(), fname)
+ register_asset(res_name, fcopy_rsc(fname))
+ fdel(fname)
+
+ for(var/size_id in sizes)
+ var/size = sizes[size_id]
+ register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
+
+/datum/asset/spritesheet/send(client/C)
+ if (!name)
+ return
+ var/all = list("spritesheet_[name].css")
+ for(var/size_id in sizes)
+ all += "[name]_[size_id].png"
+ send_asset_list(C, all, verify)
+
+/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes)
+ for(var/size_id in sizes_to_strip)
+ var/size = sizes[size_id]
+ if (size[SPRSZ_STRIPPED])
+ continue
+
+ // save flattened version
+ var/fname = "data/spritesheets/[name]_[size_id].png"
+ fcopy(size[SPRSZ_ICON], fname)
+ var/error = rustg_dmi_strip_metadata(fname)
+ if(length(error))
+ stack_trace("Failed to strip [name]_[size_id].png: [error]")
+ size[SPRSZ_STRIPPED] = icon(fname)
+ fdel(fname)
+
+/datum/asset/spritesheet/proc/generate_css()
+ var/list/out = list()
+
+ for (var/size_id in sizes)
+ var/size = sizes[size_id]
+ var/icon/tiny = size[SPRSZ_ICON]
+ out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[name]_[size_id].png') no-repeat;}"
+
+ for (var/sprite_id in sprites)
+ var/sprite = sprites[sprite_id]
+ var/size_id = sprite[SPR_SIZE]
+ var/idx = sprite[SPR_IDX]
+ var/size = sizes[size_id]
+
+ var/icon/tiny = size[SPRSZ_ICON]
+ var/icon/big = size[SPRSZ_STRIPPED]
+ var/per_line = big.Width() / tiny.Width()
+ var/x = (idx % per_line) * tiny.Width()
+ var/y = round(idx / per_line) * tiny.Height()
+
+ out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}"
+
+ return out.Join("\n")
+
+/datum/asset/spritesheet/proc/Insert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
+ I = icon(I, icon_state=icon_state, dir=dir, frame=frame, moving=moving)
+ if (!I || !length(icon_states(I))) // that direction or state doesn't exist
+ return
+ var/size_id = "[I.Width()]x[I.Height()]"
+ var/size = sizes[size_id]
+
+ if (sprites[sprite_name])
+ CRASH("duplicate sprite \"[sprite_name]\" in sheet [name] ([type])")
+
+ if (size)
+ var/position = size[SPRSZ_COUNT]++
+ var/icon/sheet = size[SPRSZ_ICON]
+ size[SPRSZ_STRIPPED] = null
+ sheet.Insert(I, icon_state=sprite_name)
+ sprites[sprite_name] = list(size_id, position)
+ else
+ sizes[size_id] = size = list(1, I, null)
+ sprites[sprite_name] = list(size_id, 0)
+
+/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions)
+ if (length(prefix))
+ prefix = "[prefix]-"
+
+ if (!directions)
+ directions = list(SOUTH)
+
+ for (var/icon_state_name in icon_states(I))
+ for (var/direction in directions)
+ var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : ""
+ Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction)
+
+/datum/asset/spritesheet/proc/css_tag()
+ return {""}
+
+/datum/asset/spritesheet/proc/icon_tag(sprite_name)
+ var/sprite = sprites[sprite_name]
+ if (!sprite)
+ return null
+ var/size_id = sprite[SPR_SIZE]
+ return {""}
+
+/datum/asset/spritesheet/proc/icon_class_name(sprite_name)
+ var/sprite = sprites[sprite_name]
+ if (!sprite)
+ return null
+ var/size_id = sprite[SPR_SIZE]
+ return {"[name][size_id] [sprite_name]"}
+
+#undef SPR_SIZE
+#undef SPR_IDX
+#undef SPRSZ_COUNT
+#undef SPRSZ_ICON
+#undef SPRSZ_STRIPPED
+
+
+/datum/asset/spritesheet/simple
+ _abstract = /datum/asset/spritesheet/simple
+ var/list/assets
+
+/datum/asset/spritesheet/simple/register()
+ for (var/key in assets)
+ Insert(key, assets[key])
+ ..()
+
+//Generates assets based on iconstates of a single icon
+/datum/asset/simple/icon_states
+ _abstract = /datum/asset/simple/icon_states
+ var/icon
+ var/list/directions = list(SOUTH)
+ var/frame = 1
+ var/movement_states = FALSE
+
+ var/prefix = "default" //asset_name = "[prefix].[icon_state_name].png"
+ var/generic_icon_names = FALSE //generate icon filenames using generate_asset_name() instead the above format
+
+ verify = FALSE
+
+/datum/asset/simple/icon_states/register(_icon = icon)
+ for(var/icon_state_name in icon_states(_icon))
+ for(var/direction in directions)
+ var/asset = icon(_icon, icon_state_name, direction, frame, movement_states)
+ if (!asset)
+ continue
+ asset = fcopy_rsc(asset) //dedupe
+ var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]." : ""
+ var/asset_name = sanitize_filename("[prefix].[prefix2][icon_state_name].png")
+ if (generic_icon_names)
+ asset_name = "[generate_asset_name(asset)].png"
+
+ register_asset(asset_name, asset)
+
+/datum/asset/simple/icon_states/multiple_icons
+ _abstract = /datum/asset/simple/icon_states/multiple_icons
+ var/list/icons
+
+/datum/asset/simple/icon_states/multiple_icons/register()
+ for(var/i in icons)
+ ..(i)
+
+
+//DEFINITIONS FOR ASSET DATUMS START HERE.
+
+/datum/asset/simple/tgui
+ assets = list(
+ // tgui
+ "tgui.css" = 'tgui/assets/tgui.css',
+ "tgui.js" = 'tgui/assets/tgui.js',
+ // tgui-next
+ "tgui-main.html" = 'tgui-next/packages/tgui/public/tgui-main.html',
+ "tgui-fallback.html" = 'tgui-next/packages/tgui/public/tgui-fallback.html',
+ "tgui.bundle.js" = 'tgui-next/packages/tgui/public/tgui.bundle.js',
+ "tgui.bundle.css" = 'tgui-next/packages/tgui/public/tgui.bundle.css',
+ "shim-html5shiv.js" = 'tgui-next/packages/tgui/public/shim-html5shiv.js',
+ "shim-ie8.js" = 'tgui-next/packages/tgui/public/shim-ie8.js',
+ "shim-dom4.js" = 'tgui-next/packages/tgui/public/shim-dom4.js',
+ "shim-css-om.js" = 'tgui-next/packages/tgui/public/shim-css-om.js',
+ )
+
+/datum/asset/group/tgui
+ children = list(
+ /datum/asset/simple/tgui,
+ /datum/asset/simple/fontawesome
+ )
+
+/datum/asset/simple/headers
+ assets = list(
+ "alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
+ "alarm_red.gif" = 'icons/program_icons/alarm_red.gif',
+ "batt_5.gif" = 'icons/program_icons/batt_5.gif',
+ "batt_20.gif" = 'icons/program_icons/batt_20.gif',
+ "batt_40.gif" = 'icons/program_icons/batt_40.gif',
+ "batt_60.gif" = 'icons/program_icons/batt_60.gif',
+ "batt_80.gif" = 'icons/program_icons/batt_80.gif',
+ "batt_100.gif" = 'icons/program_icons/batt_100.gif',
+ "charging.gif" = 'icons/program_icons/charging.gif',
+ "downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif',
+ "downloader_running.gif" = 'icons/program_icons/downloader_running.gif',
+ "ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif',
+ "ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif',
+ "power_norm.gif" = 'icons/program_icons/power_norm.gif',
+ "power_warn.gif" = 'icons/program_icons/power_warn.gif',
+ "sig_high.gif" = 'icons/program_icons/sig_high.gif',
+ "sig_low.gif" = 'icons/program_icons/sig_low.gif',
+ "sig_lan.gif" = 'icons/program_icons/sig_lan.gif',
+ "sig_none.gif" = 'icons/program_icons/sig_none.gif',
+ "smmon_0.gif" = 'icons/program_icons/smmon_0.gif',
+ "smmon_1.gif" = 'icons/program_icons/smmon_1.gif',
+ "smmon_2.gif" = 'icons/program_icons/smmon_2.gif',
+ "smmon_3.gif" = 'icons/program_icons/smmon_3.gif',
+ "smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
+ "smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
+ "smmon_6.gif" = 'icons/program_icons/smmon_6.gif'
+ )
+
+/datum/asset/spritesheet/simple/pda
+ name = "pda"
+ assets = list(
+ "atmos" = 'icons/pda_icons/pda_atmos.png',
+ "back" = 'icons/pda_icons/pda_back.png',
+ "bell" = 'icons/pda_icons/pda_bell.png',
+ "blank" = 'icons/pda_icons/pda_blank.png',
+ "boom" = 'icons/pda_icons/pda_boom.png',
+ "bucket" = 'icons/pda_icons/pda_bucket.png',
+ "medbot" = 'icons/pda_icons/pda_medbot.png',
+ "floorbot" = 'icons/pda_icons/pda_floorbot.png',
+ "cleanbot" = 'icons/pda_icons/pda_cleanbot.png',
+ "crate" = 'icons/pda_icons/pda_crate.png',
+ "cuffs" = 'icons/pda_icons/pda_cuffs.png',
+ "eject" = 'icons/pda_icons/pda_eject.png',
+ "flashlight" = 'icons/pda_icons/pda_flashlight.png',
+ "honk" = 'icons/pda_icons/pda_honk.png',
+ "mail" = 'icons/pda_icons/pda_mail.png',
+ "medical" = 'icons/pda_icons/pda_medical.png',
+ "menu" = 'icons/pda_icons/pda_menu.png',
+ "mule" = 'icons/pda_icons/pda_mule.png',
+ "notes" = 'icons/pda_icons/pda_notes.png',
+ "power" = 'icons/pda_icons/pda_power.png',
+ "rdoor" = 'icons/pda_icons/pda_rdoor.png',
+ "reagent" = 'icons/pda_icons/pda_reagent.png',
+ "refresh" = 'icons/pda_icons/pda_refresh.png',
+ "scanner" = 'icons/pda_icons/pda_scanner.png',
+ "signaler" = 'icons/pda_icons/pda_signaler.png',
+ "status" = 'icons/pda_icons/pda_status.png',
+ "dronephone" = 'icons/pda_icons/pda_dronephone.png'
+ )
+
+/datum/asset/spritesheet/simple/paper
+ name = "paper"
+ assets = list(
+ "stamp-clown" = 'icons/stamp_icons/large_stamp-clown.png',
+ "stamp-deny" = 'icons/stamp_icons/large_stamp-deny.png',
+ "stamp-ok" = 'icons/stamp_icons/large_stamp-ok.png',
+ "stamp-hop" = 'icons/stamp_icons/large_stamp-hop.png',
+ "stamp-cmo" = 'icons/stamp_icons/large_stamp-cmo.png',
+ "stamp-ce" = 'icons/stamp_icons/large_stamp-ce.png',
+ "stamp-hos" = 'icons/stamp_icons/large_stamp-hos.png',
+ "stamp-rd" = 'icons/stamp_icons/large_stamp-rd.png',
+ "stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png',
+ "stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png',
+ "stamp-law" = 'icons/stamp_icons/large_stamp-law.png'
+ )
+
+/datum/asset/spritesheet/simple/minesweeper
+ name = "minesweeper"
+ assets = list(
+ "1" = 'icons/UI_Icons/minesweeper_tiles/one.png',
+ "2" = 'icons/UI_Icons/minesweeper_tiles/two.png',
+ "3" = 'icons/UI_Icons/minesweeper_tiles/three.png',
+ "4" = 'icons/UI_Icons/minesweeper_tiles/four.png',
+ "5" = 'icons/UI_Icons/minesweeper_tiles/five.png',
+ "6" = 'icons/UI_Icons/minesweeper_tiles/six.png',
+ "7" = 'icons/UI_Icons/minesweeper_tiles/seven.png',
+ "8" = 'icons/UI_Icons/minesweeper_tiles/eight.png',
+ "empty" = 'icons/UI_Icons/minesweeper_tiles/empty.png',
+ "flag" = 'icons/UI_Icons/minesweeper_tiles/flag.png',
+ "hidden" = 'icons/UI_Icons/minesweeper_tiles/hidden.png',
+ "mine" = 'icons/UI_Icons/minesweeper_tiles/mine.png',
+ "minehit" = 'icons/UI_Icons/minesweeper_tiles/minehit.png'
+ )
+
+/datum/asset/spritesheet/simple/pills
+ name = "pills"
+ assets = list(
+ "pill1" = 'icons/UI_Icons/Pills/pill1.png',
+ "pill2" = 'icons/UI_Icons/Pills/pill2.png',
+ "pill3" = 'icons/UI_Icons/Pills/pill3.png',
+ "pill4" = 'icons/UI_Icons/Pills/pill4.png',
+ "pill5" = 'icons/UI_Icons/Pills/pill5.png',
+ "pill6" = 'icons/UI_Icons/Pills/pill6.png',
+ "pill7" = 'icons/UI_Icons/Pills/pill7.png',
+ "pill8" = 'icons/UI_Icons/Pills/pill8.png',
+ "pill9" = 'icons/UI_Icons/Pills/pill9.png',
+ "pill10" = 'icons/UI_Icons/Pills/pill10.png',
+ "pill11" = 'icons/UI_Icons/Pills/pill11.png',
+ "pill12" = 'icons/UI_Icons/Pills/pill12.png',
+ "pill13" = 'icons/UI_Icons/Pills/pill13.png',
+ "pill14" = 'icons/UI_Icons/Pills/pill14.png',
+ "pill15" = 'icons/UI_Icons/Pills/pill15.png',
+ "pill16" = 'icons/UI_Icons/Pills/pill16.png',
+ "pill17" = 'icons/UI_Icons/Pills/pill17.png',
+ "pill18" = 'icons/UI_Icons/Pills/pill18.png',
+ "pill19" = 'icons/UI_Icons/Pills/pill19.png',
+ "pill20" = 'icons/UI_Icons/Pills/pill20.png',
+ "pill21" = 'icons/UI_Icons/Pills/pill21.png',
+ "pill22" = 'icons/UI_Icons/Pills/pill22.png',
+ )
+
+/datum/asset/simple/IRV
+ assets = list(
+ "jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js',
+ )
+
+/datum/asset/group/IRV
+ children = list(
+ /datum/asset/simple/jquery,
+ /datum/asset/simple/IRV
+ )
+
+/datum/asset/simple/changelog
+ assets = list(
+ "88x31.png" = 'html/88x31.png',
+ "bug-minus.png" = 'html/bug-minus.png',
+ "cross-circle.png" = 'html/cross-circle.png',
+ "hard-hat-exclamation.png" = 'html/hard-hat-exclamation.png',
+ "image-minus.png" = 'html/image-minus.png',
+ "image-plus.png" = 'html/image-plus.png',
+ "music-minus.png" = 'html/music-minus.png',
+ "music-plus.png" = 'html/music-plus.png',
+ "tick-circle.png" = 'html/tick-circle.png',
+ "wrench-screwdriver.png" = 'html/wrench-screwdriver.png',
+ "spell-check.png" = 'html/spell-check.png',
+ "burn-exclamation.png" = 'html/burn-exclamation.png',
+ "chevron.png" = 'html/chevron.png',
+ "chevron-expand.png" = 'html/chevron-expand.png',
+ "scales.png" = 'html/scales.png',
+ "coding.png" = 'html/coding.png',
+ "ban.png" = 'html/ban.png',
+ "chrome-wrench.png" = 'html/chrome-wrench.png',
+ "changelog.css" = 'html/changelog.css'
+ )
+
+/datum/asset/group/goonchat
+ children = list(
+ /datum/asset/simple/jquery,
+ /datum/asset/simple/goonchat,
+ /datum/asset/spritesheet/goonchat,
+ /datum/asset/simple/fontawesome
+ )
+
+/datum/asset/simple/jquery
+ verify = FALSE
+ assets = list(
+ "jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js',
+ )
+
+/datum/asset/simple/goonchat
+ verify = FALSE
+ assets = list(
+ "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
+ "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js',
+ "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css',
+ "browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css',
+ "browserOutput_light.css" = 'code/modules/goonchat/browserassets/css/browserOutput_light.css'
+ )
+
+/datum/asset/simple/fontawesome
+ verify = FALSE
+ assets = list(
+ "fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot',
+ "fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff',
+ "fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot',
+ "fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff',
+ "font-awesome.css" = 'html/font-awesome/css/all.min.css',
+ "v4shim.css" = 'html/font-awesome/css/v4-shims.min.css'
+ )
+
+/datum/asset/spritesheet/goonchat
+ name = "chat"
+
+/datum/asset/spritesheet/goonchat/register()
+ InsertAll("emoji", 'icons/emoji.dmi')
+
+ // pre-loading all lanugage icons also helps to avoid meta
+ InsertAll("language", 'icons/misc/language.dmi')
+ // catch languages which are pulling icons from another file
+ for(var/path in typesof(/datum/language))
+ var/datum/language/L = path
+ var/icon = initial(L.icon)
+ if (icon != 'icons/misc/language.dmi')
+ var/icon_state = initial(L.icon_state)
+ Insert("language-[icon_state]", icon, icon_state=icon_state)
+
+ ..()
+
+/datum/asset/simple/permissions
+ assets = list(
+ "padlock.png" = 'html/padlock.png'
+ )
+
+/datum/asset/simple/notes
+ assets = list(
+ "high_button.png" = 'html/high_button.png',
+ "medium_button.png" = 'html/medium_button.png',
+ "minor_button.png" = 'html/minor_button.png',
+ "none_button.png" = 'html/none_button.png',
+ )
+
+//this exists purely to avoid meta by pre-loading all language icons.
+/datum/asset/language/register()
+ for(var/path in typesof(/datum/language))
+ set waitfor = FALSE
+ var/datum/language/L = new path ()
+ L.get_icon()
+
+/datum/asset/spritesheet/pipes
+ name = "pipes"
+
+/datum/asset/spritesheet/pipes/register()
+ for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi'))
+ InsertAll("", each, GLOB.alldirs)
+ ..()
+
+// Representative icons for each research design
+/datum/asset/spritesheet/research_designs
+ name = "design"
+
+/datum/asset/spritesheet/research_designs/register()
+ for (var/path in subtypesof(/datum/design))
+ var/datum/design/D = path
+
+ var/icon_file
+ var/icon_state
+ var/icon/I
+
+ if(initial(D.research_icon) && initial(D.research_icon_state)) //If the design has an icon replacement skip the rest
+ icon_file = initial(D.research_icon)
+ icon_state = initial(D.research_icon_state)
+ if(!(icon_state in icon_states(icon_file)))
+ warning("design [D] with icon '[icon_file]' missing state '[icon_state]'")
+ continue
+ I = icon(icon_file, icon_state, SOUTH)
+
+ else
+ // construct the icon and slap it into the resource cache
+ var/atom/item = initial(D.build_path)
+ if (!ispath(item, /atom))
+ // biogenerator outputs to beakers by default
+ if (initial(D.build_type) & BIOGENERATOR)
+ item = /obj/item/reagent_containers/glass/beaker/large
+ else
+ continue // shouldn't happen, but just in case
+
+ // circuit boards become their resulting machines or computers
+ if (ispath(item, /obj/item/circuitboard))
+ var/obj/item/circuitboard/C = item
+ var/machine = initial(C.build_path)
+ if (machine)
+ item = machine
+
+ icon_file = initial(item.icon)
+ icon_state = initial(item.icon_state)
+
+ if(!(icon_state in icon_states(icon_file)))
+ warning("design [D] with icon '[icon_file]' missing state '[icon_state]'")
+ continue
+ I = icon(icon_file, icon_state, SOUTH)
+
+ // computers (and snowflakes) get their screen and keyboard sprites
+ if (ispath(item, /obj/machinery/computer) || ispath(item, /obj/machinery/power/solar_control))
+ var/obj/machinery/computer/C = item
+ var/screen = initial(C.icon_screen)
+ var/keyboard = initial(C.icon_keyboard)
+ var/all_states = icon_states(icon_file)
+ if (screen && (screen in all_states))
+ I.Blend(icon(icon_file, screen, SOUTH), ICON_OVERLAY)
+ if (keyboard && (keyboard in all_states))
+ I.Blend(icon(icon_file, keyboard, SOUTH), ICON_OVERLAY)
+
+ Insert(initial(D.id), I)
+ return ..()
diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm
index 4367f552f9..14a277a66c 100644
--- a/code/modules/mining/laborcamp/laborstacker.dm
+++ b/code/modules/mining/laborcamp/laborstacker.dm
@@ -1,162 +1,162 @@
-GLOBAL_LIST(labor_sheet_values)
-
-/**********************Prisoners' Console**************************/
-
-/obj/machinery/mineral/labor_claim_console
- name = "point claim console"
- desc = "A stacking console with an electromagnetic writer, used to track ore mined by prisoners."
- icon = 'icons/obj/machines/mining_machines.dmi'
- icon_state = "console"
- density = FALSE
- var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null
- var/machinedir = SOUTH
- var/obj/machinery/door/airlock/release_door
- var/door_tag = "prisonshuttle"
- var/obj/item/radio/Radio //needed to send messages to sec radio
-
-/obj/machinery/mineral/labor_claim_console/Initialize()
- . = ..()
- Radio = new/obj/item/radio(src)
- Radio.listening = FALSE
- locate_stacking_machine()
-
- if(!GLOB.labor_sheet_values)
- var/sheet_list = list()
- for(var/sheet_type in subtypesof(/obj/item/stack/sheet))
- var/obj/item/stack/sheet/sheet = sheet_type
- if(!initial(sheet.point_value) || (initial(sheet.merge_type) && initial(sheet.merge_type) != sheet_type)) //ignore no-value sheets and x/fifty subtypes
- continue
- sheet_list += list(list("ore" = initial(sheet.name), "value" = initial(sheet.point_value)))
- GLOB.labor_sheet_values = sortList(sheet_list, /proc/cmp_sheet_list)
-
-/proc/cmp_sheet_list(list/a, list/b)
- return a["value"] - b["value"]
-
-/obj/machinery/mineral/labor_claim_console/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "labor_claim_console", name, 315, 430, master_ui, state)
- ui.open()
-
-/obj/machinery/mineral/labor_claim_console/ui_data(mob/user)
- var/list/data = list()
- var/can_go_home = FALSE
-
- data["emagged"] = (obj_flags & EMAGGED) ? 1 : 0
- if(obj_flags & EMAGGED)
- can_go_home = TRUE
-
- var/obj/item/card/id/I = user.get_idcard(TRUE)
- if(istype(I, /obj/item/card/id/prisoner))
- var/obj/item/card/id/prisoner/P = I
- data["id_points"] = P.points
- if(P.points >= P.goal)
- can_go_home = TRUE
- data["status_info"] = "Goal met!"
- else
- data["status_info"] = "You are [(P.goal - P.points)] points away."
- else
- data["status_info"] = "No Prisoner ID detected."
- data["id_points"] = 0
-
- if(stacking_machine)
- data["unclaimed_points"] = stacking_machine.points
-
- data["ores"] = GLOB.labor_sheet_values
- data["can_go_home"] = can_go_home
-
- return data
-
-/obj/machinery/mineral/labor_claim_console/ui_act(action, params)
- if(..())
- return
- switch(action)
- if("claim_points")
- var/mob/M = usr
- var/obj/item/card/id/I = M.get_idcard(TRUE)
- if(istype(I, /obj/item/card/id/prisoner))
- var/obj/item/card/id/prisoner/P = I
- P.points += stacking_machine.points
- stacking_machine.points = 0
- to_chat(usr, "Points transferred.")
- . = TRUE
- else
- to_chat(usr, "No valid id for point transfer detected.")
- if("move_shuttle")
- if(!alone_in_area(get_area(src), usr))
- to_chat(usr, "Prisoners are only allowed to be released while alone.")
- else
- switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE))
- if(1)
- to_chat(usr, "Shuttle not found.")
- if(2)
- to_chat(usr, "Shuttle already at station.")
- if(3)
- to_chat(usr, "No permission to dock could be granted.")
- else
- if(!(obj_flags & EMAGGED))
- Radio.set_frequency(FREQ_SECURITY)
- Radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY)
- to_chat(usr, "Shuttle received message and will be sent shortly.")
- . = TRUE
-
-
-/obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine()
- stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
- if(stacking_machine)
- stacking_machine.CONSOLE = src
- else
- qdel(src)
-
-/obj/machinery/mineral/labor_claim_console/emag_act(mob/user)
- . = ..()
- if(obj_flags & EMAGGED)
- return
- obj_flags |= EMAGGED
- to_chat(user, "PZZTTPFFFT")
- return TRUE
-
-/**********************Prisoner Collection Unit**************************/
-
-/obj/machinery/mineral/stacking_machine/laborstacker
- force_connect = TRUE
- var/points = 0 //The unclaimed value of ore stacked.
-
-/obj/machinery/mineral/stacking_machine/laborstacker/process_sheet(obj/item/stack/sheet/inp)
- points += inp.point_value * inp.amount
- ..()
-
-/obj/machinery/mineral/stacking_machine/laborstacker/attackby(obj/item/I, mob/living/user)
- if(istype(I, /obj/item/stack/sheet) && user.canUnEquip(I))
- var/obj/item/stack/sheet/inp = I
- points += inp.point_value * inp.amount
- return ..()
-
-/**********************Point Lookup Console**************************/
-
-/obj/machinery/mineral/labor_points_checker
- name = "points checking console"
- desc = "A console used by prisoners to check the progress on their quotas. Simply swipe a prisoner ID."
- icon = 'icons/obj/machines/mining_machines.dmi'
- icon_state = "console"
- density = FALSE
-
-/obj/machinery/mineral/labor_points_checker/attack_hand(mob/user)
- . = ..()
- if(.)
- return
- user.examinate(src)
-
-/obj/machinery/mineral/labor_points_checker/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/card/id))
- if(istype(I, /obj/item/card/id/prisoner))
- var/obj/item/card/id/prisoner/prisoner_id = I
- to_chat(user, "ID: [prisoner_id.registered_name]")
- to_chat(user, "Points Collected:[prisoner_id.points]")
- to_chat(user, "Point Quota: [prisoner_id.goal]")
- to_chat(user, "Collect points by bringing smelted minerals to the Labor Shuttle stacking machine. Reach your quota to earn your release.")
- else
- to_chat(user, "Error: Invalid ID")
- else
- return ..()
+GLOBAL_LIST(labor_sheet_values)
+
+/**********************Prisoners' Console**************************/
+
+/obj/machinery/mineral/labor_claim_console
+ name = "point claim console"
+ desc = "A stacking console with an electromagnetic writer, used to track ore mined by prisoners."
+ icon = 'icons/obj/machines/mining_machines.dmi'
+ icon_state = "console"
+ density = FALSE
+ var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null
+ var/machinedir = SOUTH
+ var/obj/machinery/door/airlock/release_door
+ var/door_tag = "prisonshuttle"
+ var/obj/item/radio/Radio //needed to send messages to sec radio
+
+/obj/machinery/mineral/labor_claim_console/Initialize()
+ . = ..()
+ Radio = new/obj/item/radio(src)
+ Radio.listening = FALSE
+ locate_stacking_machine()
+
+ if(!GLOB.labor_sheet_values)
+ var/sheet_list = list()
+ for(var/sheet_type in subtypesof(/obj/item/stack/sheet))
+ var/obj/item/stack/sheet/sheet = sheet_type
+ if(!initial(sheet.point_value) || (initial(sheet.merge_type) && initial(sheet.merge_type) != sheet_type)) //ignore no-value sheets and x/fifty subtypes
+ continue
+ sheet_list += list(list("ore" = initial(sheet.name), "value" = initial(sheet.point_value)))
+ GLOB.labor_sheet_values = sortList(sheet_list, /proc/cmp_sheet_list)
+
+/proc/cmp_sheet_list(list/a, list/b)
+ return a["value"] - b["value"]
+
+/obj/machinery/mineral/labor_claim_console/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "labor_claim_console", name, 315, 430, master_ui, state)
+ ui.open()
+
+/obj/machinery/mineral/labor_claim_console/ui_data(mob/user)
+ var/list/data = list()
+ var/can_go_home = FALSE
+
+ data["emagged"] = (obj_flags & EMAGGED) ? 1 : 0
+ if(obj_flags & EMAGGED)
+ can_go_home = TRUE
+
+ var/obj/item/card/id/I = user.get_idcard(TRUE)
+ if(istype(I, /obj/item/card/id/prisoner))
+ var/obj/item/card/id/prisoner/P = I
+ data["id_points"] = P.points
+ if(P.points >= P.goal)
+ can_go_home = TRUE
+ data["status_info"] = "Goal met!"
+ else
+ data["status_info"] = "You are [(P.goal - P.points)] points away."
+ else
+ data["status_info"] = "No Prisoner ID detected."
+ data["id_points"] = 0
+
+ if(stacking_machine)
+ data["unclaimed_points"] = stacking_machine.points
+
+ data["ores"] = GLOB.labor_sheet_values
+ data["can_go_home"] = can_go_home
+
+ return data
+
+/obj/machinery/mineral/labor_claim_console/ui_act(action, params)
+ if(..())
+ return
+ switch(action)
+ if("claim_points")
+ var/mob/M = usr
+ var/obj/item/card/id/I = M.get_idcard(TRUE)
+ if(istype(I, /obj/item/card/id/prisoner))
+ var/obj/item/card/id/prisoner/P = I
+ P.points += stacking_machine.points
+ stacking_machine.points = 0
+ to_chat(usr, "Points transferred.")
+ . = TRUE
+ else
+ to_chat(usr, "No valid id for point transfer detected.")
+ if("move_shuttle")
+ if(!alone_in_area(get_area(src), usr))
+ to_chat(usr, "Prisoners are only allowed to be released while alone.")
+ else
+ switch(SSshuttle.moveShuttle("laborcamp", "laborcamp_home", TRUE))
+ if(1)
+ to_chat(usr, "Shuttle not found.")
+ if(2)
+ to_chat(usr, "Shuttle already at station.")
+ if(3)
+ to_chat(usr, "No permission to dock could be granted.")
+ else
+ if(!(obj_flags & EMAGGED))
+ Radio.set_frequency(FREQ_SECURITY)
+ Radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY)
+ to_chat(usr, "Shuttle received message and will be sent shortly.")
+ . = TRUE
+
+
+/obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine()
+ stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
+ if(stacking_machine)
+ stacking_machine.CONSOLE = src
+ else
+ qdel(src)
+
+/obj/machinery/mineral/labor_claim_console/emag_act(mob/user)
+ . = ..()
+ if(obj_flags & EMAGGED)
+ return
+ obj_flags |= EMAGGED
+ to_chat(user, "PZZTTPFFFT")
+ return TRUE
+
+/**********************Prisoner Collection Unit**************************/
+
+/obj/machinery/mineral/stacking_machine/laborstacker
+ force_connect = TRUE
+ var/points = 0 //The unclaimed value of ore stacked.
+
+/obj/machinery/mineral/stacking_machine/laborstacker/process_sheet(obj/item/stack/sheet/inp)
+ points += inp.point_value * inp.amount
+ ..()
+
+/obj/machinery/mineral/stacking_machine/laborstacker/attackby(obj/item/I, mob/living/user)
+ if(istype(I, /obj/item/stack/sheet) && user.canUnEquip(I))
+ var/obj/item/stack/sheet/inp = I
+ points += inp.point_value * inp.amount
+ return ..()
+
+/**********************Point Lookup Console**************************/
+
+/obj/machinery/mineral/labor_points_checker
+ name = "points checking console"
+ desc = "A console used by prisoners to check the progress on their quotas. Simply swipe a prisoner ID."
+ icon = 'icons/obj/machines/mining_machines.dmi'
+ icon_state = "console"
+ density = FALSE
+
+/obj/machinery/mineral/labor_points_checker/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
+ user.examinate(src)
+
+/obj/machinery/mineral/labor_points_checker/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/card/id))
+ if(istype(I, /obj/item/card/id/prisoner))
+ var/obj/item/card/id/prisoner/prisoner_id = I
+ to_chat(user, "ID: [prisoner_id.registered_name]")
+ to_chat(user, "Points Collected:[prisoner_id.points]")
+ to_chat(user, "Point Quota: [prisoner_id.goal]")
+ to_chat(user, "Collect points by bringing smelted minerals to the Labor Shuttle stacking machine. Reach your quota to earn your release.")
+ else
+ to_chat(user, "Error: Invalid ID")
+ else
+ return ..()
diff --git a/code/modules/mining/mint.dm b/code/modules/mining/mint.dm
index 8204977058..f32afb2898 100644
--- a/code/modules/mining/mint.dm
+++ b/code/modules/mining/mint.dm
@@ -1,105 +1,105 @@
-/**********************Mint**************************/
-
-
-/obj/machinery/mineral/mint
- name = "coin press"
- icon = 'icons/obj/economy.dmi'
- icon_state = "coinpress0"
- density = TRUE
- var/newCoins = 0 //how many coins the machine made in it's last load
- var/processing = FALSE
- var/chosen = MAT_METAL //which material will be used to make coins
- var/coinsToProduce = 10
- speed_process = TRUE
-
-
-/obj/machinery/mineral/mint/Initialize()
- . = ..()
- AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_PLASMA, MAT_SILVER, MAT_GOLD, MAT_URANIUM, MAT_DIAMOND, MAT_BANANIUM), MINERAL_MATERIAL_AMOUNT * 50, FALSE, /obj/item/stack)
-
-/obj/machinery/mineral/mint/process()
- var/turf/T = get_step(src, input_dir)
- if(!T)
- return
-
- var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
- for(var/obj/item/stack/sheet/O in T)
- materials.insert_stack(O, O.amount)
-
-/obj/machinery/mineral/mint/attack_hand(mob/user)
- . = ..()
- if(.)
- return
- var/dat = "Coin Press "
-
- var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
- for(var/mat_id in materials.materials)
- var/datum/material/M = materials.materials[mat_id]
- if(!M.amount && chosen != mat_id)
- continue
- dat += " [M.name] amount: [M.amount] cm3 "
- if (chosen == mat_id)
- dat += "Chosen"
- else
- dat += "Choose"
-
- var/datum/material/M = materials.materials[chosen]
-
- dat += "
Will produce [coinsToProduce] [lowertext(M.name)] coins if enough materials are available. "
- dat += "-10 "
- dat += "-5 "
- dat += "-1 "
- dat += "+1 "
- dat += "+5 "
- dat += "+10 "
-
- dat += "
Will produce [coinsToProduce] [lowertext(M.name)] coins if enough materials are available. "
+ dat += "-10 "
+ dat += "-5 "
+ dat += "-1 "
+ dat += "+1 "
+ dat += "+5 "
+ dat += "+10 "
+
+ dat += "