From 8b21a60ac924f4eb4fa65834347df01d00118d86 Mon Sep 17 00:00:00 2001 From: Artur Date: Mon, 20 Jan 2020 14:09:22 +0200 Subject: [PATCH] MF Line endings --- code/__DEFINES/machines.dm | 226 +-- .../diseases/advance/symptoms/choking.dm | 304 ++-- .../diseases/advance/symptoms/confusion.dm | 126 +- .../datums/diseases/advance/symptoms/cough.dm | 152 +- .../diseases/advance/symptoms/deafness.dm | 122 +- .../datums/diseases/advance/symptoms/dizzy.dm | 108 +- .../datums/diseases/advance/symptoms/fever.dm | 122 +- .../diseases/advance/symptoms/flesh_eating.dm | 270 ++-- .../diseases/advance/symptoms/genetics.dm | 162 +- .../diseases/advance/symptoms/hallucigen.dm | 134 +- .../diseases/advance/symptoms/headache.dm | 122 +- code/datums/diseases/advance/symptoms/heal.dm | 994 ++++++------ .../diseases/advance/symptoms/itching.dm | 110 +- .../diseases/advance/symptoms/oxygen.dm | 138 +- .../diseases/advance/symptoms/shivering.dm | 120 +- .../diseases/advance/symptoms/sneeze.dm | 106 +- .../diseases/advance/symptoms/voice_change.dm | 166 +- .../datums/diseases/advance/symptoms/vomit.dm | 130 +- .../diseases/advance/symptoms/weight.dm | 104 +- code/game/machinery/computer/Operating.dm | 246 +-- code/game/machinery/computer/station_alert.dm | 198 +-- code/game/machinery/doors/brigdoors.dm | 512 +++--- code/game/objects/items/devices/gps.dm | 452 +++--- .../game/objects/items/devices/radio/radio.dm | 872 +++++----- .../game/objects/structures/tank_dispenser.dm | 222 +-- .../atmospherics/machinery/portable/pump.dm | 316 ++-- .../machinery/portable/scrubber.dm | 292 ++-- code/modules/cargo/console.dm | 452 +++--- code/modules/cargo/expressconsole.dm | 412 ++--- code/modules/client/asset_cache.dm | 1408 ++++++++--------- code/modules/mining/laborcamp/laborstacker.dm | 324 ++-- code/modules/mining/mint.dm | 210 +-- code/modules/mining/satchel_ore_boxdm.dm | 196 +-- code/modules/power/monitor.dm | 246 +-- 34 files changed, 5037 insertions(+), 5037 deletions(-) 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 += "

In total this machine produced [newCoins] coins." - dat += "
Make coins" - user << browse(dat, "window=mint") - -/obj/machinery/mineral/mint/Topic(href, href_list) - if(..()) - return - usr.set_machine(src) - src.add_fingerprint(usr) - if(processing==1) - to_chat(usr, "The machine is processing.") - return - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - if(href_list["choose"]) - if(materials.materials[href_list["choose"]]) - chosen = href_list["choose"] - if(href_list["chooseAmt"]) - coinsToProduce = CLAMP(coinsToProduce + text2num(href_list["chooseAmt"]), 0, 1000) - if(href_list["makeCoins"]) - var/temp_coins = coinsToProduce - processing = TRUE - icon_state = "coinpress1" - var/coin_mat = MINERAL_MATERIAL_AMOUNT * 0.2 - var/datum/material/M = materials.materials[chosen] - if(!M || !M.coin_type) - updateUsrDialog() - return - - while(coinsToProduce > 0 && materials.use_amount_type(coin_mat, chosen)) - create_coins(M.coin_type) - coinsToProduce-- - newCoins++ - src.updateUsrDialog() - sleep(5) - - icon_state = "coinpress0" - processing = FALSE - coinsToProduce = temp_coins - src.updateUsrDialog() - return - -/obj/machinery/mineral/mint/proc/create_coins(P) - var/turf/T = get_step(src,output_dir) - if(T) - var/obj/item/O = new P(src) - var/obj/item/storage/bag/money/M = locate(/obj/item/storage/bag/money, T) - if(!M) - M = new /obj/item/storage/bag/money(src) - unload_mineral(M) - O.forceMove(M) +/**********************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 += "

In total this machine produced [newCoins] coins." + dat += "
Make coins" + user << browse(dat, "window=mint") + +/obj/machinery/mineral/mint/Topic(href, href_list) + if(..()) + return + usr.set_machine(src) + src.add_fingerprint(usr) + if(processing==1) + to_chat(usr, "The machine is processing.") + return + var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) + if(href_list["choose"]) + if(materials.materials[href_list["choose"]]) + chosen = href_list["choose"] + if(href_list["chooseAmt"]) + coinsToProduce = CLAMP(coinsToProduce + text2num(href_list["chooseAmt"]), 0, 1000) + if(href_list["makeCoins"]) + var/temp_coins = coinsToProduce + processing = TRUE + icon_state = "coinpress1" + var/coin_mat = MINERAL_MATERIAL_AMOUNT * 0.2 + var/datum/material/M = materials.materials[chosen] + if(!M || !M.coin_type) + updateUsrDialog() + return + + while(coinsToProduce > 0 && materials.use_amount_type(coin_mat, chosen)) + create_coins(M.coin_type) + coinsToProduce-- + newCoins++ + src.updateUsrDialog() + sleep(5) + + icon_state = "coinpress0" + processing = FALSE + coinsToProduce = temp_coins + src.updateUsrDialog() + return + +/obj/machinery/mineral/mint/proc/create_coins(P) + var/turf/T = get_step(src,output_dir) + if(T) + var/obj/item/O = new P(src) + var/obj/item/storage/bag/money/M = locate(/obj/item/storage/bag/money, T) + if(!M) + M = new /obj/item/storage/bag/money(src) + unload_mineral(M) + O.forceMove(M) diff --git a/code/modules/mining/satchel_ore_boxdm.dm b/code/modules/mining/satchel_ore_boxdm.dm index 5118644d88..d78a406b80 100644 --- a/code/modules/mining/satchel_ore_boxdm.dm +++ b/code/modules/mining/satchel_ore_boxdm.dm @@ -1,98 +1,98 @@ - -/**********************Ore box**************************/ - -/obj/structure/ore_box - icon = 'icons/obj/mining.dmi' - icon_state = "orebox" - name = "ore box" - desc = "A heavy wooden box, which can be filled with a lot of ores." - density = TRUE - pressure_resistance = 5*ONE_ATMOSPHERE - -/obj/structure/ore_box/attackby(obj/item/W, mob/user, params) - if (istype(W, /obj/item/stack/ore)) - user.transferItemToLoc(W, src) - else if(SEND_SIGNAL(W, COMSIG_CONTAINS_STORAGE)) - SEND_SIGNAL(W, COMSIG_TRY_STORAGE_TAKE_TYPE, /obj/item/stack/ore, src) - to_chat(user, "You empty the ore in [W] into \the [src].") - else - return ..() - -/obj/structure/ore_box/crowbar_act(mob/living/user, obj/item/I) - if(I.use_tool(src, user, 50, volume=50)) - user.visible_message("[user] pries \the [src] apart.", - "You pry apart \the [src].", - "You hear splitting wood.") - deconstruct(TRUE, user) - return TRUE - -/obj/structure/ore_box/examine(mob/living/user) - if(Adjacent(user) && istype(user)) - ui_interact(user) - return ..() - -/obj/structure/ore_box/attack_hand(mob/user) - . = ..() - if(.) - return - if(Adjacent(user)) - ui_interact(user) - -/obj/structure/ore_box/attack_robot(mob/user) - if(Adjacent(user)) - ui_interact(user) - -/obj/structure/ore_box/proc/dump_box_contents() - var/drop = drop_location() - for(var/obj/item/stack/ore/O in src) - if(QDELETED(O)) - continue - if(QDELETED(src)) - break - O.forceMove(drop) - if(TICK_CHECK) - stoplag() - drop = drop_location() - -/obj/structure/ore_box/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, "ore_box", name, 335, 415, master_ui, state) - ui.open() - -/obj/structure/ore_box/ui_data() - var/contents = list() - for(var/obj/item/stack/ore/O in src) - contents[O.type] += O.amount - - var/data = list() - data["materials"] = list() - for(var/type in contents) - var/obj/item/stack/ore/O = type - var/name = initial(O.name) - data["materials"] += list(list("name" = name, "amount" = contents[type], "id" = type)) - - return data - -/obj/structure/ore_box/ui_act(action, params) - if(..()) - return - if(!Adjacent(usr)) - return - add_fingerprint(usr) - usr.set_machine(src) - switch(action) - if("removeall") - dump_box_contents() - to_chat(usr, "You open the release hatch on the box..") - -/obj/structure/ore_box/deconstruct(disassembled = TRUE, mob/user) - var/obj/item/stack/sheet/mineral/wood/WD = new (loc, 4) - if(user) - WD.add_fingerprint(user) - dump_box_contents() - qdel(src) - -/obj/structure/ore_box/onTransitZ() - return + +/**********************Ore box**************************/ + +/obj/structure/ore_box + icon = 'icons/obj/mining.dmi' + icon_state = "orebox" + name = "ore box" + desc = "A heavy wooden box, which can be filled with a lot of ores." + density = TRUE + pressure_resistance = 5*ONE_ATMOSPHERE + +/obj/structure/ore_box/attackby(obj/item/W, mob/user, params) + if (istype(W, /obj/item/stack/ore)) + user.transferItemToLoc(W, src) + else if(SEND_SIGNAL(W, COMSIG_CONTAINS_STORAGE)) + SEND_SIGNAL(W, COMSIG_TRY_STORAGE_TAKE_TYPE, /obj/item/stack/ore, src) + to_chat(user, "You empty the ore in [W] into \the [src].") + else + return ..() + +/obj/structure/ore_box/crowbar_act(mob/living/user, obj/item/I) + if(I.use_tool(src, user, 50, volume=50)) + user.visible_message("[user] pries \the [src] apart.", + "You pry apart \the [src].", + "You hear splitting wood.") + deconstruct(TRUE, user) + return TRUE + +/obj/structure/ore_box/examine(mob/living/user) + if(Adjacent(user) && istype(user)) + ui_interact(user) + return ..() + +/obj/structure/ore_box/attack_hand(mob/user) + . = ..() + if(.) + return + if(Adjacent(user)) + ui_interact(user) + +/obj/structure/ore_box/attack_robot(mob/user) + if(Adjacent(user)) + ui_interact(user) + +/obj/structure/ore_box/proc/dump_box_contents() + var/drop = drop_location() + for(var/obj/item/stack/ore/O in src) + if(QDELETED(O)) + continue + if(QDELETED(src)) + break + O.forceMove(drop) + if(TICK_CHECK) + stoplag() + drop = drop_location() + +/obj/structure/ore_box/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, "ore_box", name, 335, 415, master_ui, state) + ui.open() + +/obj/structure/ore_box/ui_data() + var/contents = list() + for(var/obj/item/stack/ore/O in src) + contents[O.type] += O.amount + + var/data = list() + data["materials"] = list() + for(var/type in contents) + var/obj/item/stack/ore/O = type + var/name = initial(O.name) + data["materials"] += list(list("name" = name, "amount" = contents[type], "id" = type)) + + return data + +/obj/structure/ore_box/ui_act(action, params) + if(..()) + return + if(!Adjacent(usr)) + return + add_fingerprint(usr) + usr.set_machine(src) + switch(action) + if("removeall") + dump_box_contents() + to_chat(usr, "You open the release hatch on the box..") + +/obj/structure/ore_box/deconstruct(disassembled = TRUE, mob/user) + var/obj/item/stack/sheet/mineral/wood/WD = new (loc, 4) + if(user) + WD.add_fingerprint(user) + dump_box_contents() + qdel(src) + +/obj/structure/ore_box/onTransitZ() + return diff --git a/code/modules/power/monitor.dm b/code/modules/power/monitor.dm index bf8f62742e..f4ee102ccc 100644 --- a/code/modules/power/monitor.dm +++ b/code/modules/power/monitor.dm @@ -1,123 +1,123 @@ -//modular computer program version is located in code\modules\modular_computers\file_system\programs\powermonitor.dm, /datum/computer_file/program/power_monitor - -/obj/machinery/computer/monitor - name = "power monitoring console" - desc = "It monitors power levels across the station." - icon_screen = "power" - icon_keyboard = "power_key" - light_color = LIGHT_COLOR_YELLOW - use_power = ACTIVE_POWER_USE - idle_power_usage = 20 - active_power_usage = 100 - circuit = /obj/item/circuitboard/computer/powermonitor - - var/obj/structure/cable/attached_wire - var/obj/machinery/power/apc/local_apc - - var/list/history = list() - var/record_size = 60 - var/record_interval = 50 - var/next_record = 0 - var/is_secret_monitor = FALSE - tgui_id = "power_monitor" - ui_style = "ntos" - -/obj/machinery/computer/monitor/secret //Hides the power monitor (such as ones on ruins & CentCom) from PDA's to prevent metagaming. - name = "outdated power monitoring console" - desc = "It monitors power levels across the local powernet." - circuit = /obj/item/circuitboard/computer/powermonitor/secret - is_secret_monitor = TRUE - -/obj/machinery/computer/monitor/secret/examine(mob/user) - . = ..() - . += "It's operating system seems quite outdated... It doesn't seem like it'd be compatible with the latest remote NTOS monitoring systems." - -/obj/machinery/computer/monitor/Initialize() - . = ..() - search() - history["supply"] = list() - history["demand"] = list() - -/obj/machinery/computer/monitor/process() - if(!get_powernet()) - use_power = IDLE_POWER_USE - search() - else - use_power = ACTIVE_POWER_USE - record() - -/obj/machinery/computer/monitor/proc/search() //keep in sync with /datum/computer_file/program/power_monitor's version - var/turf/T = get_turf(src) - attached_wire = locate(/obj/structure/cable) in T - if(attached_wire) - return - var/area/A = get_area(src) //if the computer isn't directly connected to a wire, attempt to find the APC powering it to pull it's powernet instead - if(!A) - return - local_apc = A.get_apc() - if(!local_apc) - return - if(!local_apc.terminal) //this really shouldn't happen without badminnery. - local_apc = null - -/obj/machinery/computer/monitor/proc/get_powernet() //keep in sync with /datum/computer_file/program/power_monitor's version - if(attached_wire || (local_apc && local_apc.terminal)) - return attached_wire ? attached_wire.powernet : local_apc.terminal.powernet - return FALSE - -/obj/machinery/computer/monitor/proc/record() //keep in sync with /datum/computer_file/program/power_monitor's version - if(world.time >= next_record) - next_record = world.time + record_interval - - var/datum/powernet/connected_powernet = get_powernet() - - var/list/supply = history["supply"] - if(connected_powernet) - supply += connected_powernet.viewavail - if(supply.len > record_size) - supply.Cut(1, 2) - - var/list/demand = history["demand"] - if(connected_powernet) - demand += connected_powernet.viewload - if(demand.len > record_size) - demand.Cut(1, 2) - -/obj/machinery/computer/monitor/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, tgui_id, name, 550, 700, master_ui, state) - ui.open() - -/obj/machinery/computer/monitor/ui_data() - var/datum/powernet/connected_powernet = get_powernet() - var/list/data = list() - data["stored"] = record_size - data["interval"] = record_interval / 10 - data["attached"] = connected_powernet ? TRUE : FALSE - data["history"] = history - data["areas"] = list() - - if(connected_powernet) - data["supply"] = DisplayPower(connected_powernet.viewavail) - data["demand"] = DisplayPower(connected_powernet.viewload) - for(var/obj/machinery/power/terminal/term in connected_powernet.nodes) - var/obj/machinery/power/apc/A = term.master - if(istype(A)) - var/cell_charge - if(!A.cell) - cell_charge = 0 - else - cell_charge = A.cell.percent() - data["areas"] += list(list( - "name" = A.area.name, - "charge" = cell_charge, - "load" = DisplayPower(A.lastused_total), - "charging" = A.charging, - "eqp" = A.equipment, - "lgt" = A.lighting, - "env" = A.environ - )) - - return data +//modular computer program version is located in code\modules\modular_computers\file_system\programs\powermonitor.dm, /datum/computer_file/program/power_monitor + +/obj/machinery/computer/monitor + name = "power monitoring console" + desc = "It monitors power levels across the station." + icon_screen = "power" + icon_keyboard = "power_key" + light_color = LIGHT_COLOR_YELLOW + use_power = ACTIVE_POWER_USE + idle_power_usage = 20 + active_power_usage = 100 + circuit = /obj/item/circuitboard/computer/powermonitor + + var/obj/structure/cable/attached_wire + var/obj/machinery/power/apc/local_apc + + var/list/history = list() + var/record_size = 60 + var/record_interval = 50 + var/next_record = 0 + var/is_secret_monitor = FALSE + tgui_id = "power_monitor" + ui_style = "ntos" + +/obj/machinery/computer/monitor/secret //Hides the power monitor (such as ones on ruins & CentCom) from PDA's to prevent metagaming. + name = "outdated power monitoring console" + desc = "It monitors power levels across the local powernet." + circuit = /obj/item/circuitboard/computer/powermonitor/secret + is_secret_monitor = TRUE + +/obj/machinery/computer/monitor/secret/examine(mob/user) + . = ..() + . += "It's operating system seems quite outdated... It doesn't seem like it'd be compatible with the latest remote NTOS monitoring systems." + +/obj/machinery/computer/monitor/Initialize() + . = ..() + search() + history["supply"] = list() + history["demand"] = list() + +/obj/machinery/computer/monitor/process() + if(!get_powernet()) + use_power = IDLE_POWER_USE + search() + else + use_power = ACTIVE_POWER_USE + record() + +/obj/machinery/computer/monitor/proc/search() //keep in sync with /datum/computer_file/program/power_monitor's version + var/turf/T = get_turf(src) + attached_wire = locate(/obj/structure/cable) in T + if(attached_wire) + return + var/area/A = get_area(src) //if the computer isn't directly connected to a wire, attempt to find the APC powering it to pull it's powernet instead + if(!A) + return + local_apc = A.get_apc() + if(!local_apc) + return + if(!local_apc.terminal) //this really shouldn't happen without badminnery. + local_apc = null + +/obj/machinery/computer/monitor/proc/get_powernet() //keep in sync with /datum/computer_file/program/power_monitor's version + if(attached_wire || (local_apc && local_apc.terminal)) + return attached_wire ? attached_wire.powernet : local_apc.terminal.powernet + return FALSE + +/obj/machinery/computer/monitor/proc/record() //keep in sync with /datum/computer_file/program/power_monitor's version + if(world.time >= next_record) + next_record = world.time + record_interval + + var/datum/powernet/connected_powernet = get_powernet() + + var/list/supply = history["supply"] + if(connected_powernet) + supply += connected_powernet.viewavail + if(supply.len > record_size) + supply.Cut(1, 2) + + var/list/demand = history["demand"] + if(connected_powernet) + demand += connected_powernet.viewload + if(demand.len > record_size) + demand.Cut(1, 2) + +/obj/machinery/computer/monitor/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, tgui_id, name, 550, 700, master_ui, state) + ui.open() + +/obj/machinery/computer/monitor/ui_data() + var/datum/powernet/connected_powernet = get_powernet() + var/list/data = list() + data["stored"] = record_size + data["interval"] = record_interval / 10 + data["attached"] = connected_powernet ? TRUE : FALSE + data["history"] = history + data["areas"] = list() + + if(connected_powernet) + data["supply"] = DisplayPower(connected_powernet.viewavail) + data["demand"] = DisplayPower(connected_powernet.viewload) + for(var/obj/machinery/power/terminal/term in connected_powernet.nodes) + var/obj/machinery/power/apc/A = term.master + if(istype(A)) + var/cell_charge + if(!A.cell) + cell_charge = 0 + else + cell_charge = A.cell.percent() + data["areas"] += list(list( + "name" = A.area.name, + "charge" = cell_charge, + "load" = DisplayPower(A.lastused_total), + "charging" = A.charging, + "eqp" = A.equipment, + "lgt" = A.lighting, + "env" = A.environ + )) + + return data