Files
vgstation13/code/modules/virus2/helpers.dm
kane-f b1d79e4272 PDA app refactoring (#31881)
* PDA app refactoring

* Last of standard apps now, onto games next

* Minesweeper

* Snake II

* Spesspets

* Cutting down a lot of redundant code in light of these movements

* Everything somehow worked except refreshing, this commit fixes that

* Removing now unused modes

* Fixing alarm stuff

* Adding category support for sorting apps

* Testing making notepad an app, works fine, also cuts even more code down

* Sorting these into subfiles since it's getting large

* Events as an app

* Manifest as an app

* Should be okay to change these now

* Adding the basis for convering cartridge functions to built in apps

* Here too

* Also creates them on new()

* Working example with syndicate pod door cartridge

* Status displays, also cart modulisation of apps now fully works

* Sorting these for later, the files are gonna probably get big

* Records

* Scanners

* Some cleanup, and preface for app-cart interactions

* More stuff

* More engineering stuff

* Secbot app, implementing a cart connection

* Medbots

* Janitor stuff

* Quartermaster

* Last of engineering

* Last of that whole cartridge dat menu mess is now gone

* Almost done reformatting utilities, only cameras left to do (by yours truly)

* All utilities done

* Last of the utilities too, now only messaging stuff is left to do

* Some mode cleanup and file split-off

* New file too

* Clown/mime/syndicate stuff, old access vars from cartridges are now completely gone

* Some mode cleanups

* Fixes bugs with power/alert monitor, custodial locator and supply record apps as well as apps being deleted from cartridges

* Multimessager as an app, now just one left

* Moving this to own file, will get big

* Basis of app form, conversion over todo

* Now finally moves it all to the app

* Lint fix

* Some more cleanup from afterwards

* Makes messenger actually work, fixes various other bugs too

* Scanning refactors into seperated attack functions

* Fixing some bugs

* Fixing that multimessage bug while we're here

* Nicer photo display formatting

* Fixing the PDA camera bug too

* Moves these to carts, for now

Co-authored-by: kanef <kanef9x@protonmail.com>
2022-01-29 14:24:16 -06:00

381 lines
12 KiB
Plaintext

//Build random disease type
/proc/get_random_weighted_disease(var/operation = WDISH)
var/list/possibles = subtypesof(/datum/disease2/disease) - typesof(/datum/disease2/disease/predefined)
var/list/weighted_list = list()
for(var/P in possibles)
var/datum/disease2/disease/D = new P
var/weight = D.type_weight[operation]
if (weight != 0)
weighted_list[D] = weight
return pickweight(weighted_list)
////////////////////////////////////////////////////
//Checks if table-passing table can reach target (5 tile radius)
//For the record that proc is only used by the "Gregarious Impetus" symptom and super/toxic farts.
/proc/airborne_can_reach(turf/source, turf/target, var/radius=5)
var/obj/dummy = new(source)
dummy.flags = FPRINT
dummy.pass_flags = PASSTABLE
for(var/i=0, i<radius, i++) if(!step_towards(dummy, target)) break
var/rval = (target.Adjacent(dummy.loc))
dummy.forceMove(null)
dummy = null
return rval
///////////////////////////////////////////
// //
// STERILITY CHECKS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
///////////////////////////////////////////
//AIRBORNE
/mob/living/proc/check_airborne_sterility()
return 0
/mob/living/carbon/human/check_airborne_sterility()
var/block = 0
if (wear_mask && (wear_mask.body_parts_covered & MOUTH) && prob(wear_mask.sterility))
block = 1
if (head && (head.body_parts_covered & MOUTH) && prob(head.sterility))
block = 1
return block
/mob/living/carbon/monkey/check_airborne_sterility()
var/block = 0
if (wear_mask && (wear_mask.body_parts_covered & MOUTH) && prob(wear_mask.sterility))
block = 1
if (hat && (hat.body_parts_covered & MOUTH) && prob(hat.sterility))
block = 1
return block
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//CONTACT
/mob/living/proc/check_contact_sterility(var/body_part)
return 0
/mob/living/carbon/human/check_contact_sterility(var/body_part)
var/list/clothing_to_check = list(
wear_mask,
w_uniform,
head,
wear_suit,
back,
gloves,
handcuffed,
legcuffed,
belt,
shoes,
wear_mask,
glasses,
ears,
wear_id)
for (var/thing in clothing_to_check)
var/obj/item/cloth = thing
if(istype(cloth) && (cloth.body_parts_covered & body_part) && prob(cloth.sterility))
return TRUE
return FALSE
/mob/living/carbon/monkey/check_contact_sterility(var/body_part)
var/list/clothing_to_check = list(
wear_mask,
uniform,
hat,
back,
handcuffed,
legcuffed,
glasses,)
for (var/thing in clothing_to_check)
var/obj/item/cloth = thing
if(istype(cloth) && (cloth.body_parts_covered & body_part) && prob(cloth.sterility))
return TRUE
return FALSE
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//VALID COLONY (spread SPREAD_COLONY)
/mob/living/carbon/suitable_colony()
return FALSE
/mob/living/carbon/human/suitable_colony()
var/obj/item/clothing = wear_suit
if(clothing && clothing.pressure_resistance > ONE_ATMOSPHERE)
return TRUE
return FALSE
/mob/living/carbon/monkey/suitable_colony()
var/obj/item/clothing = uniform
if(istype(clothing,/obj/item/clothing/monkeyclothes/space)) //Also covers sanity if null
return TRUE
return FALSE
/proc/attempt_colony(var/atom/A, var/datum/disease2/disease/D,var/info)
if(!(D.spread & SPREAD_COLONY))
return FALSE
if(A.suitable_colony())
A.infect_disease2(D, notes="(Colonized[info ? ", [info]" : ""])")
return TRUE
return FALSE
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//BLEEDING (bleeding body parts allow SPREAD_BLOOD to infect)
/mob/living/proc/check_bodypart_bleeding(var/body_part)
return 0
/mob/living/carbon/human/check_bodypart_bleeding(var/body_part)
var/bleeding = 0
switch(body_part)
if (HEAD)//head-patting
var/datum/organ/external/head = organs_by_name[LIMB_HEAD]
if(head.status & ORGAN_BLEEDING)
bleeding = 1
if (FULL_TORSO)//hugging, lying over infected blood, broken dishes
var/datum/organ/external/chest = organs_by_name[LIMB_CHEST]
if(chest.status & ORGAN_BLEEDING)
bleeding = 1
if (FEET)//walking over infected blood, broken dishes
var/datum/organ/external/l_foot = organs_by_name[LIMB_LEFT_FOOT]
if(l_foot.status & ORGAN_BLEEDING)
bleeding = 1
var/datum/organ/external/r_foot = organs_by_name[LIMB_RIGHT_FOOT]
if(r_foot.status & ORGAN_BLEEDING)
bleeding = 1
if (HANDS)//walking over infected blood, broken dishes
var/datum/organ/external/l_hand = organs_by_name[LIMB_LEFT_HAND]
if(l_hand.status & ORGAN_BLEEDING)
bleeding = 1
var/datum/organ/external/r_hand = organs_by_name[LIMB_RIGHT_HAND]
if(r_hand.status & ORGAN_BLEEDING)
bleeding = 1
return bleeding
//until monkeys can bleed or have open wounds, they're safe on that end.
/mob/living/simple_animal/mouse/check_bodypart_bleeding(var/body_part)
return splat//visibly bleeding
///////////////////////////////////////////
// //
// INFECTION //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
///////////////////////////////////////////
//This proc is called when the disease has already bypassed clothing and other protections
//The only checks left are for antibodies/sterility and the disease's infection chance
/atom/proc/infect_disease2(var/datum/disease2/disease/disease,var/forced = 0, var/notes="")
return 0
//MOBS
var/list/infected_contact_mobs = list()
/mob/living/infect_disease2(var/datum/disease2/disease/disease,var/forced = 0, var/notes="")
if(!istype(disease))
return 0
if(disease.spread == 0)//in case admins bus'd in a non-spreadable disease.
return 0
if(!can_be_infected())//humans, monkeys, mouse, for now
return 0
if ("[disease.uniqueID]-[disease.subID]" in virus2)
return 0
if(immune_system && !immune_system.CanInfect(disease))
return 0
if(prob(disease.infectionchance) || forced)
var/datum/disease2/disease/D = disease.getcopy()
if (D.infectionchance > 10)
D.infectionchance = max(10, D.infectionchance - 10)//The virus gets weaker as it jumps from people to people
D.stage = clamp(D.stage+D.stage_variance, 1, D.max_stage)
D.log += "<br />[timestamp()] Infected [key_name(src)] [notes]. Infection chance now [D.infectionchance]%"
virus2["[D.uniqueID]-[D.subID]"] = D
D.AddToGoggleView(src)
//--Plague Stuff--
var/datum/faction/plague_mice/plague = find_active_faction_by_type(/datum/faction/plague_mice)
if (plague && ("[D.uniqueID]-[D.subID]" == plague.diseaseID))
var/datum/objective/plague/O = locate() in plague.objective_holder.objectives
if (O && !istype(src, /mob/living/simple_animal/mouse/plague))
O.total_infections++
plague.update_hud_icons()
for(var/datum/role/plague_mouse/M in plague.members)
var/datum/mind/mouse_mind = M.antag
mouse_mind.store_memory(D.get_info(TRUE), forced = 1)
mouse_mind.store_memory("<hr>")
//----------------
for (var/obj/item/device/pda/p in contents)
if (istype(p.scanning_app,/datum/pda_app/cart/scanner/medical))
playsound(loc, 'sound/machines/twobeep.ogg', 50, 1)
if("[disease.uniqueID]-[disease.subID]" in virusDB)
var/datum/data/record/V = virusDB["[disease.uniqueID]-[disease.subID]"]
var/risk = "warning"
switch (V.fields["danger"])
if ("*DANGEROUS*")
risk = "danger"
if ("Safe")
risk = "notice"
to_chat(src, "[bicon(p)]<span class='[risk]'>Infection Detected! [V.fields["name"]][V.fields["nickname"] ? " \"[V.fields["nickname"]]\"" : ""] has entered your body.</span>")
else
to_chat(src, "[bicon(p)]<span class='danger'>Infection Detected! Unknown [D.form] has entered your body.</span>")
return 1
return 0
/mob/living/proc/infect_disease2_predefined(var/category, var/forced, var/notes)
if(!global_diseases[category])
return
infect_disease2(global_diseases[category], forced, notes)
//ITEMS
var/list/infected_items = list()
/obj/item/infect_disease2(var/datum/disease2/disease/disease,var/forced = 0, var/notes="",var/decay = 1)
if(!istype(disease))
return 0
if(disease.spread == 0)
return 0
if (prob(sterility))
return 0
if ("[disease.uniqueID]-[disease.subID]" in virus2)
return 0
if(prob(disease.infectionchance) || forced)
var/datum/disease2/disease/D = disease.getcopy()
D.log += "<br />[timestamp()] Infected \a [src] [notes]"
virus2["[D.uniqueID]-[D.subID]"] = D
infected_items |= src
if (!pathogen)
pathogen = image('icons/effects/effects.dmi',src,"pathogen_contact")
pathogen.plane = HUD_PLANE
pathogen.layer = HUD_ABOVE_ITEM_LAYER
pathogen.appearance_flags = RESET_COLOR|RESET_ALPHA
for (var/mob/L in science_goggles_wearers)
if (L.client)
L.client.images |= pathogen
if (decay)
spawn((disease.infectionchance/10) MINUTES)
remove_disease2("[D.uniqueID]-[D.subID]")
return 1
return 0
/atom/proc/remove_disease2(var/diseaseID)
return 0
/obj/item/remove_disease2(var/diseaseID)
if (diseaseID)
if (diseaseID in virus2)
virus2[diseaseID] = null
virus2.Remove(diseaseID)
else
virus2 = list()
if (virus2 && virus2.len <= 0)
infected_items -= src
if (pathogen)
for (var/mob/L in science_goggles_wearers)
if (L.client)
L.client.images -= pathogen
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//MEDHUD STUFF
// Returns 1 if patient has virus2 that medHUDs would pick up.
// Otherwise returns 0
/proc/has_recorded_virus2(var/mob/living/carbon/patient)
var/highest_danger = 0
for (var/ID in patient.virus2)
if (ID in virusDB)
highest_danger = max(highest_danger,1)
var/datum/data/record/v = virusDB[ID]
if (v.fields["danger"])
switch (v.fields["danger"])
if ("*DANGEROUS*")
highest_danger = max(highest_danger,3)
if ("Undetermined")
highest_danger = max(highest_danger,1)
if ("Safe")
highest_danger = max(highest_danger,2)
return highest_danger
// This one doesn't really belong here, but old disease code has no helpers, so
// Returns 1 if patient has old-style disease that medHUDs would pick up.
// Otherwise returns 0
/proc/has_recorded_disease(var/mob/living/carbon/patient)
for(var/datum/disease/D in patient.viruses)
if(!D.hidden[SCANNER])
return 1
return 0
// combination of above two procs
/proc/has_any_recorded_disease(var/mob/living/carbon/patient)
if(has_recorded_disease(patient))
return 1
else if (has_recorded_virus2(patient))
return 1
return 0
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/proc/filter_disease_by_spread(var/list/diseases = list(), var/required = 0, var/forbidden = 0)
if (!diseases || diseases.len <= 0)
return list()
var/list/result = list()
for (var/ID in diseases)
var/datum/disease2/disease/V = diseases[ID]
if ((!required || (V.spread & required)) && (!forbidden || !(V.spread & forbidden)))
result[ID] = V
return result
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/proc/get_part_from_limb(var/limb)
var/part = FULL_TORSO
switch (limb)
if(LIMB_HEAD)
part = HEAD
if(LIMB_LEFT_HAND)
part = HAND_LEFT
if(LIMB_RIGHT_HAND)
part = HAND_RIGHT
if(LIMB_LEFT_ARM)
part = ARM_LEFT
if(LIMB_RIGHT_ARM)
part = ARM_RIGHT
if(LIMB_GROIN)
part = LOWER_TORSO
if(LIMB_LEFT_LEG)
part = LEG_LEFT
if(LIMB_RIGHT_LEG)
part = LEG_RIGHT
if(LIMB_LEFT_FOOT)
part = FOOT_LEFT
if(LIMB_RIGHT_FOOT)
part = FOOT_RIGHT
if(TARGET_MOUTH)
part = MOUTH
if("eyes")
part = EYES
return part
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/proc/spread_disease_among_crew(var/datum/disease2/disease/D, var/reason = "4noraisin")
var/list/candidates = list()
for(var/mob/living/candidate in player_list)
if(candidate.z == map.zMainStation && candidate.client && candidate.stat != DEAD && candidate.can_be_infected() && candidate.immune_system.CanInfect(D))
candidates += candidate
if(!candidates.len)
return
var/infected = 1 + round(candidates.len/10)
for (var/i = 1 to infected)
var/mob/living/candidate = pick(candidates)
candidates -= candidate
candidate.infect_disease2(D,1, reason)