#define COOLDOWN_MULTIPLIER 1 #define INFECT_NONE 0 #define INFECT_TOUCH 1 #define INFECT_AREA 3 #define INFECT_AREA_LARGE 5 // --SYMPTOM RARITIES-- // All symptom contains a rarity value. Use these constants to describe their rarity. // For malevolent symptoms: // RARITY_VERY_COMMON: The symptoms are barely noticable. Should not affect gameplay significantly or infect in a large area. // RARITY_COMMON: The symptoms are noticeable, and may cause occasional inconveniences. May infect in a large area (instead). // RARITY_UNCOMMON: The symptoms may do occasional damage or longer stuns. // RARITY_RARE: The symptoms have a ramp in stages from relatively mundane to rather deadly. // RARITY_VERY_RARE: You are fucked. // For benevolent symptoms: // RARITY_VERY_COMMON: As for malevolents, except in the positive direction obviously. // RARITY_COMMON: The symptom may heal slightly or give an insignificant boost to any statistic. // RARITY_UNCOMMON: Commonly symptoms which may give you an upper hand in a fight. // RARITY_RARE: Power-healing and heavy offense/defense symptoms. May contain downsides. // RARITY_VERY_RARE: God complex with actual godlike powers, traitor items infused in body. Should contain flipsides. // And for all: // RARITY_ABSTRACT: Used strictly for categorization. ABSTRACT symptoms will never appear. // ie. if lingual is a symptom category with multiple subsymptoms (for easy mutex), it should be abstract. #define RARITY_VERY_COMMON 10 #define RARITY_COMMON 5 #define RARITY_UNCOMMON 3 #define RARITY_RARE 2 #define RARITY_VERY_RARE 1 #define RARITY_ABSTRACT 0 datum/pathogen_cdc var/uid = null var/patient_zero = null var/patient_zero_kname = "" var/creation_time = null var/microbody_type = null var/list/infections = list() var/list/mutations = list() New(var/pathogen_uid) creation_time = world.time / 600 src.uid = pathogen_uid datum/controller/pathogen var/list/next_mutation = new/list() var/list/pathogen_trees = new/list() var/next_uid = 1 var/list/UID_to_symptom var/list/symptom_to_UID var/list/UID_to_suppressant var/list/suppressant_to_UID var/list/microbody_to_UID var/list/UID_to_carrier var/list/carrier_to_UID var/list/path_to_symptom = list() var/list/path_to_microbody = list() var/list/path_to_suppressant = list() var/list/path_to_mutation = list() var/list/disabled_mutations = list() var/list/pathogen_affected_reagents = list("blood", "pathogen", "bloodc") var/list/microbody_choices = list() var/choicemax = 0 var/list/l_vc var/list/l_c var/list/l_u var/list/l_r var/list/l_vr var/list/lnums = list() var/list/lalph = list() var/list/nutrients = list() var/list/media = list() var/list/cure_bases = list() proc/get_microbody(var/strength) var/datum/microbody/M var/finished = 0 var/tried = 0 while (!finished) var/choice = rand(1, choicemax) for (var/datum/choice/C in microbody_choices) if (C.min <= choice && choice <= C.max) M = C.target if (M.strength <= strength) finished = 1 else tried++ if (tried > 10) return M return M proc/mob_infected(var/datum/pathogen/P, var/mob/living/carbon/human/H) var/datum/pathogen_cdc/CDC = src.pathogen_trees[P.name_base] if (!CDC) return if (!CDC.patient_zero) CDC.patient_zero = H CDC.patient_zero_kname = "[H]" if (!(P.name in CDC.mutations)) CDC.mutations += P.name var/datum/pathogen/template = unpool(/datum/pathogen) template.setup(0, P, 0) CDC.mutations[P.name] = template if (!(H in CDC.infections)) CDC.infections += H CDC.infections[H] = P.name proc/mob_cured(var/datum/pathogen/P, var/mob/living/carbon/human/H) var/datum/pathogen_cdc/CDC = src.pathogen_trees[P.name_base] if (!CDC) return if (H in CDC.infections) CDC.infections -= H proc/patient_zero(var/datum/pathogen_cdc/CDC, var/topic_holder) if (CDC.patient_zero) return replacetext(CDC.patient_zero_kname, "%holder%", "\ref[topic_holder]") Topic(href, href_list) var/key = usr.ckey var/th = locate(href_list["topic_holder"]) switch(href_list["action"]) if ("setstate") cdc_state[key] = text2num(href_list["state"]) if ("strain_cure") var/strain = href_list["strain"] var/datum/pathogen_cdc/CDC = pathogen_trees[strain] var/count = 0 for (var/mob/living/carbon/human/H in world) if (CDC.uid in H.pathogens) H.cured(H.pathogens[CDC.uid]) count++ message_admins("[key_name(usr)] cured [count] humans from pathogen strain [strain].") if ("strain_details") cdc_state[key] = href_list["strain"] if ("pathogen_creator") var/datum/pathogen/P = src.cdc_creator[usr.ckey] switch (href_list["do"]) if ("reset") src.gen_empty(usr.ckey) if ("body_type") var/list/types = list() for (var/btpath in src.path_to_microbody) var/datum/microbody/MB = src.path_to_microbody[btpath] types += MB.name types[MB.name] = MB var/chosen = input("Which microbody?", "Microbody", types[1]) in types P.body_type = types[chosen] P.maliciousness = rand(-2, 6) P.mutation_speed = rand(-2, 10) P.suppression_threshold = rand(1,3) * P.maliciousness P.suppression_threshold += rand(-5, 10) P.advance_speed = rand(-2, 7) P.mutativeness = P.body_type.mutativeness P.symptomatic = 1 P.generation = 1 P.maliciousness *= P.body_type.maliciousness_multiplier P.mutation_speed *= P.body_type.mutation_speed_multiplier P.stages = P.body_type.stages if ("suppressant") var/list/types = list() for (var/spath in src.path_to_suppressant) var/datum/suppressant/S = src.path_to_suppressant[spath] types += S.name types[S.name] = S var/chosen = input("Which suppresant?", "Suppressant", types[1]) in types P.suppressant = types[chosen] P.desc = "[P.suppressant.color] dodecahedrical [P.body_type.plural]" if ("add") var/list/types = list() for (var/efpath in src.path_to_symptom) var/datum/pathogeneffects/EF = src.path_to_symptom[efpath] types += EF.name types[EF.name] = EF var/chosen = input("Which symptom?", "Add new symptom", types[1]) in types if (!(types[chosen] in P.effects)) P.effects += types[chosen] var/datum/pathogeneffects/EF = types[chosen] EF.onadd(P) if ("remove") var/datum/pathogeneffects/EF = locate(href_list["which"]) if (EF in P.effects) P.effects -= EF if ("advance_speed") P.advance_speed = input("New advance speed?", "Advance speed", P.advance_speed) as num if ("mutation_speed") P.mutation_speed = input("New mutation speed?", "mutation speed", P.mutation_speed) as num if ("maliciousness") P.maliciousness = input("New maliciousness?", "Maliciousness", P.maliciousness) as num if ("mutativeness") P.mutativeness = input("New mutativeness?", "Mutativeness", P.mutativeness) as num if ("suppression_threshold") P.suppression_threshold = input("New suppression threshold?", "Suppression threshold", P.suppression_threshold) as num if ("symptomatic") P.symptomatic = !P.symptomatic if ("stages") var/value = P.stages var/newval = input("New stages (3-5)?", "Stages", value) as num if (newval >= 3 && newval <= 5) P.stages = newval if ("create") P.dnasample = new/datum/pathogendna(P) P.pathogen_uid = "[next_uid]" next_uid++ pathogen_trees += P.name_base var/datum/pathogen_cdc/CDC = new /datum/pathogen_cdc(P.pathogen_uid) pathogen_trees[P.name_base] = CDC next_mutation[P.pathogen_uid] = P.mutation + 1 CDC.microbody_type = "[P.body_type]" CDC.mutations += P.name CDC.mutations[P.name] = P message_admins("[key_name(usr)] created a new pathogen ([P]) via the creator.") src.gen_empty(usr.ckey) if ("strain_data") var/datum/pathogen_cdc/CDC = locate(href_list["which"]) var/name = href_list["name"] var/datum/pathogen/reference = CDC.mutations[name] switch (href_list["data"]) if ("advance_speed") var/value = reference.advance_speed var/newval = input("New advance speed?", "Advance speed", value) as num for (var/mob/living/carbon/human/H in CDC.infections) if (CDC.uid in H.pathogens) var/datum/pathogen/target = H.pathogens[CDC.uid] if (target.name == name) target.advance_speed = newval reference.advance_speed = newval message_admins("[key_name(usr)] set the advance speed on pathogen strain mutation [name] to [newval].") if ("mutation_speed") var/value = reference.mutation_speed var/newval = input("New mutation speed?", "Mutation speed", value) as num for (var/mob/living/carbon/human/H in CDC.infections) if (CDC.uid in H.pathogens) var/datum/pathogen/target = H.pathogens[CDC.uid] if (target.name == name) target.mutation_speed = newval reference.mutation_speed = newval message_admins("[key_name(usr)] set the mutation speed on pathogen strain mutation [name] to [newval].") if ("maliciousness") var/value = reference.maliciousness var/newval = input("New maliciousness?", "Maliciousness", value) as num for (var/mob/living/carbon/human/H in CDC.infections) if (CDC.uid in H.pathogens) var/datum/pathogen/target = H.pathogens[CDC.uid] if (target.name == name) target.maliciousness = newval reference.maliciousness = newval message_admins("[key_name(usr)] set the maliciousness on pathogen strain mutation [name] to [newval].") if ("mutativeness") var/value = reference.mutativeness var/newval = input("New mutativeness?", "Mutativeness", value) as num for (var/mob/living/carbon/human/H in CDC.infections) if (CDC.uid in H.pathogens) var/datum/pathogen/target = H.pathogens[CDC.uid] if (target.name == name) target.mutativeness = newval reference.mutativeness = newval message_admins("[key_name(usr)] set the mutativeness on pathogen strain mutation [name] to [newval].") if ("suppression_threshold") var/value = reference.suppression_threshold var/newval = input("New suppression threshold?", "Suppression threshold", value) as num for (var/mob/living/carbon/human/H in CDC.infections) if (CDC.uid in H.pathogens) var/datum/pathogen/target = H.pathogens[CDC.uid] if (target.name == name) target.suppression_threshold = newval reference.suppression_threshold = newval message_admins("[key_name(usr)] set the suppression threshold on pathogen strain mutation [name] to [newval].") if ("symptomatic") var/value = reference.symptomatic var/newval = !value for (var/mob/living/carbon/human/H in CDC.infections) if (CDC.uid in H.pathogens) var/datum/pathogen/target = H.pathogens[CDC.uid] if (target.name == name) target.symptomatic = newval reference.symptomatic = newval message_admins("[key_name(usr)] set the symptomaticity for pathogen strain mutation [name] to [newval ? "Yes" : "No"].") if ("stages") var/value = reference.stages var/newval = input("New stages (3-5)?", "Stages", value) as num if (newval >= 3 && newval <= 5) for (var/mob/living/carbon/human/H in CDC.infections) if (CDC.uid in H.pathogens) var/datum/pathogen/target = H.pathogens[CDC.uid] if (target.name == name) target.stages = newval reference.stages = newval message_admins("[key_name(usr)] set the stages on pathogen strain mutation [name] to [newval].") if ("cure") var/count = 0 for (var/mob/living/carbon/human/H in world) if (CDC.uid in H.pathogens) var/datum/pathogen/P = H.pathogens[CDC.uid] if (P.name == name) H.cured(P) count++ message_admins("[key_name(usr)] cured [count] humans from pathogen strain mutation [name].") if ("infect") var/mob/living/carbon/human/target = input("Who would you like to infect with this mutation?", "Infect") as mob in world if (!istype(target)) boutput(usr, "Cannot infect that. Must be human.") else target.infected(reference) message_admins("[key_name(usr)] infected [target] with [name].") if ("spawn") var/obj/item/reagent_containers/glass/vial/V = new /obj/item/reagent_containers/glass/vial(get_turf(usr)) var/datum/reagent/blood/pathogen/RE = new /datum/reagent/blood/pathogen() RE.volume = 5 RE.pathogens += reference.pathogen_uid RE.pathogens[reference.pathogen_uid] = reference RE.holder = V.reagents V.reagents.reagent_list += RE.id V.reagents.reagent_list[RE.id] = RE V.reagents.update_total() if ("microbody_data") var/datum/microbody/MB = locate(href_list["which"]) switch (href_list["data"]) if ("stages") var/new_stages = input("Stage cap for [MB] microbodies? (3-5)", "Stage cap", MB.stages) as num if (new_stages >= 3 && new_stages <= 5) MB.stages = new_stages message_admins("[key_name(usr)] set the initial stage cap for pathogen microbody [MB.plural] to [new_stages].") if ("vaccinable") MB.vaccination = !MB.vaccination message_admins("[key_name(usr)] set the vaccinability for pathogen microbody [MB.plural] to [MB.vaccination ? "On" : "Off"].") if ("activity") var/stage = text2num(href_list["stage"]) var/new_act = input("New activity percentage for stage [stage] of [MB] (0-100)?", "Activity", MB.activity[stage]) as num if (new_act >= 0 && new_act <= 100) MB.activity[stage] = new_act message_admins("[key_name(usr)] set the activity for pathogen microbody [MB.plural] on stage [stage] to [new_act].") if ("mutativeness") MB.mutativeness = input("New base mutativeness for [MB]? The higher, the more likely it is to mutate on transmission.", "Base mutativeness", MB.mutativeness) as num message_admins("[key_name(usr)] set the initial mutativeness for pathogen microbody [MB.plural] to [MB.mutativeness].") if ("mutation_data") var/datum/pathogen_mutation/MUT = locate(href_list["which"]) switch (href_list["data"]) if ("info") alert(usr, MUT.desc) if ("session_maximum") MUT.session_maximum = input("New session maximum for [MUT]? The higher, the more times this mutation can occur during one mutation proc call.", "Session maximum", MUT.session_maximum) as num message_admins("[key_name(usr)] set the session maximum for pathogen mutation [MUT] to [MUT.session_maximum].") if ("chance_base") var/new_chn = input("New base chance of [MUT] occurrence (0-100)?", "Activity", MUT.chance_base) as num if (new_chn >= 0 && new_chn <= 100) MUT.chance_base = new_chn message_admins("[key_name(usr)] set the base chance for pathogen mutation [MUT] to [new_chn].") if ("disable") src.path_to_mutation -= MUT.type src.disabled_mutations += MUT.type src.disabled_mutations[MUT.type] = MUT message_admins("[key_name(usr)] disabled pathogen mutation [MUT].") if ("enable") src.disabled_mutations -= MUT.type src.path_to_mutation += MUT.type src.path_to_mutation[MUT.type] = MUT message_admins("[key_name(usr)] enabled pathogen mutation [MUT].") if ("symptom_data") var/datum/pathogeneffects/EF = locate(href_list["which"]) switch (href_list["data"]) if ("info") alert(usr, EF.desc) cdc_main(th) var/list/cdc_creator = list() var/list/cdc_state = list() var/static/list/states = list("strains", "symptoms", "microbodies", "suppressants", "mutations", "pathogen creator") proc/severity_color(var/datum/pathogeneffects/EF) if (EF.rarity == RARITY_ABSTRACT) return "[EF]" var/color_value = round(255 / EF.rarity) if (istype(EF, /datum/pathogeneffects/malevolent)) return "[EF]" else return "[EF]" proc/cdc_main(var/topic_holder) if (!usr || !usr.client) return if (!usr.client.holder) boutput(usr, "Visitors of the CDC are not allowed to interact with the equipment!") return if (usr.client.holder.level < LEVEL_PA) boutput(usr, "I'm sorry, you require a security clearance of Primary Researcher to go in there. Protocol and all. You know.") return var/state = 1 if (usr.ckey in cdc_state) state = cdc_state[usr.ckey] else cdc_state += usr.ckey cdc_state[usr.ckey] = 1 var/stylesheet = {""} var/output = "Center for Disease Control[stylesheet]

Center for Disease Control

" for (var/i = 1, i <= src.states.len, i++) if (i != 1) output += " - " if (state != i) output += "[states[i]]" else output += "[states[i]]" output += "
" if (istext(state)) output += "

Details for pathogen strain [state]

" if (state in pathogen_trees) var/datum/pathogen_cdc/CDC = pathogen_trees[state] output += "" for (var/name in CDC.mutations) output += "" var/datum/pathogen/P = CDC.mutations[name] output += "" var/symptoms = "" var/first = 1 for (var/datum/pathogeneffects/EF in P.effects) if (first) symptoms = severity_color(EF) first = 0 else symptoms += "
[severity_color(EF)]" output += "" output += "" output += "" output += "" var/infected = 0 for (var/mob/living/carbon/human/H in CDC.infections) var/pname = CDC.infections[H] if (pname == P.name) infected++ output += "" output += "" output += "" else output += "

This pathogen no longer exists.

" else switch (states[state]) if ("strains") output += "
Mutation nameSymptomsPrimary attributesSymptomaticStagesInfectedActions
[name][symptoms]" output += "Advance speed: [P.advance_speed]
" output += "Maliciousness: [P.maliciousness]
" output += "Mutation speed: [P.mutation_speed]
" output += "Mutativeness: [P.mutativeness]
" output += "Suppression: [P.suppression_threshold]
" output += "
[P.symptomatic ? "Yes" : "No"][P.stages][infected]" output += "(SPAWN)
" output += "(INFECT)
" output += "(CURE)
" output += "(LOGS)" output += "
" for (var/pathogen_name in pathogen_trees) var/datum/pathogen_cdc/CDC = pathogen_trees[pathogen_name] output += "" output += "" output += "" output += "" if (CDC.patient_zero) output += "" else output += "" var/infections = 0 var/immunities = 0 for (var/mob/living/carbon/human/M in world) if (CDC.uid in M.pathogens) infections++ else if (CDC.uid in M.immunities) immunities++ output += "" output += "" output += "" output += "" output += "" output += "" output += "" output += "
CreatedStrain nameUIDPatient ZeroInfectedImmuneMicrobodyCure allDetailsLogs
[round(CDC.creation_time)]M[pathogen_name][CDC.uid][CDC.patient_zero_kname]No infections yet[infections][immunities][CDC.microbody_type](CURE)(VIEW)(LOGS)
" if ("microbodies") output += "

Changes to stage cap and base mutativeness only affects future pathogens.

" output += "" for (var/microbody_path in src.path_to_microbody) output += "" var/datum/microbody/MB = src.path_to_microbody[microbody_path] output += "" output += "" var/nutrition = "" var/first = 1 for (var/nutrient in MB.nutrients) if (first) first = 0 else nutrition += "
" nutrition += "[nutrient]" output += "" output += "" output += "" output += "" output += "" output += "" output += "
NameMediumNutritionStagesVaccinableActivityBase mutativeness
[MB][MB.growth_medium][nutrition][MB.stages][MB.vaccination ? "Yes" : "No"]" for (var/stage = 1, stage <= 5, stage++) if (stage != 1) output += "
" output += "[MB.activity[stage]]%" output += "
[MB.mutativeness]
" if ("mutations") output += "

Enabled mutations

" output += "" for (var/mutation_path in src.path_to_mutation) output += "" var/datum/pathogen_mutation/MUT = src.path_to_mutation[mutation_path] output += "" output += "" output += "" output += "" output += "" output += "" output += "
NameInfoSession maximumBase occurrence chanceDisable
[MUT]Show information[MUT.session_maximum][MUT.chance_base]%Disable

" output += "

Disabled mutations

" output += "" for (var/mutation_path in src.disabled_mutations) output += "" var/datum/pathogen_mutation/MUT = src.disabled_mutations[mutation_path] output += "" output += "" output += "" output += "" output += "" output += "" output += "
NameInfoSession maximumBase occurrence chanceEnable
[MUT]Show information[MUT.session_maximum][MUT.chance_base]%Enable
" if ("symptoms") output += "" for (var/sym_path in src.path_to_symptom) var/datum/pathogeneffects/EF = src.path_to_symptom[sym_path] output += "" output += "" output += "" output += "" output += "" switch (EF.rarity) if (RARITY_ABSTRACT) output += "" if (RARITY_VERY_COMMON) output += "" if (RARITY_COMMON) output += "" if (RARITY_UNCOMMON) output += "" if (RARITY_RARE) output += "" if (RARITY_VERY_RARE) output += "" var/DNA = src.symptom_to_UID[EF.type] output += "" output += "" if ("suppressants") output += "
NameInfoInfection rangeInfection coefficientRarityDNA
[EF]Show information[EF.infect_type][EF.infection_coefficient]Non-existentVery commonCommonUncommonRareVery Rare[DNA]
" for (var/sup_path in src.path_to_suppressant) output += "" var/datum/suppressant/S = src.path_to_suppressant[sup_path] output += "" var/first = 1 var/supp = "" for (var/reagent in S.cure_synthesis) if (first) first = 0 else supp += "
" supp += "[reagent]" output += "" output += "" if ("pathogen creator") if (!(usr.ckey in src.cdc_creator)) src.gen_empty(usr.ckey) var/datum/pathogen/P = src.cdc_creator[usr.ckey] output += "

Pathogen Creator

" output += "Strain: [P.name_base]
" output += "Base mutation: [P.mutation]
" output += "Name: [P.name]
" if (P.suppressant) output += "Description: [P.desc]
" if (!P.body_type) output += "Assign microbody
" else output += "Microbody: [P.body_type]
" output += "Stages:[P.stages]
" output += "Advance speed:[P.advance_speed]
" output += "Maliciousness:[P.maliciousness]
" output += "Mutation speed:[P.mutation_speed]
" output += "Mutativeness:[P.mutativeness]
" output += "Symptomatic:[P.symptomatic ? "Yes" : "No"]
" output += "Suppression threshold:[P.suppression_threshold]
" if (!P.suppressant) output += "Assign suppressant
" else output += "Suppressant: [P.suppressant]

" output += "Effects:
" if (P.effects.len) for (var/datum/pathogeneffects/EF in P.effects) output += "- [EF] (remove)
" else output += " -- None --
" output += "Add effect

" output += "Reset pathogen" if (P.body_type && P.suppressant && P.effects.len) output += " -- Create pathogen" else output += "

NOTHING TO SEE HERE YET

" output += "" usr << browse(output, "window=cdc;size=800x480") proc/gen_empty(var/key) if (!(key in src.cdc_creator)) src.cdc_creator += key var/datum/pathogen/P = unpool(/datum/pathogen) P.mutation = pick(lnums) do P.name_base = pick(lalph) + pick(lnums) + pick(lalph) while (P.name_base in pathogen_trees) P.name = P.name_base + P.mutation P.mutation = text2num(P.mutation) P.base_mutation = 0 src.cdc_creator[key] = P New() UID_to_symptom = list() symptom_to_UID = list() UID_to_suppressant = list() suppressant_to_UID = list() UID_to_carrier = list() carrier_to_UID = list() microbody_to_UID = list() for (var/T in typesof(/datum/microbody) - /datum/microbody) var/datum/microbody/B = new T() microbody_to_UID[T] = B.uniqueid path_to_microbody[T] = B if (!(B.growth_medium in media)) media += B.growth_medium if (!(B.cure_base in cure_bases)) cure_bases += B.cure_base for (var/nutrient in B.nutrients) if (!(nutrient in nutrients)) nutrients += nutrient var/datum/choice/C = new C.target = B C.min = choicemax + 1 choicemax += B.commonness C.max = choicemax microbody_choices += C var/list/available_mutations = typesof(/datum/pathogen_mutation) - /datum/pathogen_mutation for (var/mutation in available_mutations) path_to_mutation[mutation] += new mutation() var/list/eff = typesof(/datum/pathogeneffects) l_vc = list() l_c = list() l_u = list() l_r = list() l_vr = list() for (var/E in eff) var/datum/pathogeneffects/inst = new E() if (inst.rarity == RARITY_ABSTRACT) continue path_to_symptom[E] = inst switch (inst.rarity) if (RARITY_VERY_COMMON) l_vc += E if (RARITY_COMMON) l_c += E if (RARITY_UNCOMMON) l_u += E if (RARITY_RARE) l_r += E if (RARITY_VERY_RARE) l_vr += E var/list/used = list() var/list/vc = list() var/list/cp = list() var/list/cu = list() var/list/up = list() var/list/uu = list() var/list/rp = list() var/list/ru = list() var/list/vrp = list() var/list/vru = list() for (var/T in (typesof(/datum/suppressant) - /datum/suppressant)) var/r do r = num2hex(rand(0, 4095), 3) while (r in used) suppressant_to_UID[T] = r UID_to_suppressant[r] = T path_to_suppressant[T] = new T() used += r /*for (var/T in typesof(/datum/pathogen_carrier)) var/r do r = num2hex(rand(0, 4095), 3) while (r in used) carrier_to_UID[T] = r UID_to_carrier[r] = new T() used += r*/ // Assemble VERY_COMMON for (var/T in l_vc) var/r do r = num2hex(rand(0, 4095), 3) while (r in used) symptom_to_UID[T] = r UID_to_symptom[r] = T used += r vc += r // Create COMMON possibilities for (var/p1 in vc) for (var/p2 in vc) if (!((p1 + p2) in cp)) cp += p1 + p2 if (!((p2 + p1) in cp)) cp += p2 + p1 // Assemble COMMON for (var/T in l_c) var/r if (cp.len) r = pick(cp) else do r = pick(vc) + num2hex(rand(0, 4095), 3) while (r in cu) cp -= r symptom_to_UID[T] = r UID_to_symptom[r] = T cu += r // Create UNCOMMON possibilities for (var/p1 in cu) for (var/p2 in vc) if (!((p1 + p2) in cp)) up += p1 + p2 if (!((p2 + p1) in cp)) up += p2 + p1 // Assemble UNCOMMON for (var/T in l_u) var/r if (up.len) r = pick(up) else do r = pick(cu) + num2hex(rand(0, 4095), 3) while (r in uu) up -= r symptom_to_UID[T] = r UID_to_symptom[r] = T uu += r // Create RARE possibilities for (var/p1 in uu) for (var/p2 in vc) if (!((p1 + p2) in cp)) rp += p1 + p2 if (!((p2 + p1) in cp)) rp += p2 + p1 // Assemble RARE for (var/T in l_r) var/r if (rp.len) r = pick(rp) else do r = pick(uu) + num2hex(rand(0, 4095), 3) while (r in ru) rp -= r symptom_to_UID[T] = r UID_to_symptom[r] = T ru += r // Create VERY_RARE possibilities for (var/p1 in ru) for (var/p2 in vc) if (!((p1 + p2) in cp)) vrp += p1 + p2 if (!((p2 + p1) in cp)) vrp += p2 + p1 // Assemble VERY_RARE for (var/T in l_vr) var/r if (vrp.len) r = pick(vrp) else do r = pick(ru) + num2hex(rand(0, 4095), 3) while (r in vru) vrp -= r symptom_to_UID[T] = r UID_to_symptom[r] = T vru += r for (var/i = 1, i <= 99, i++) lnums += "[i]" for (var/i = text2ascii("A"), i <= text2ascii("Z"), i++) lalph += ascii2text(i) var/global/datum/controller/pathogen/pathogen_controller = new() // A choice assistant datum datum/choice var/target var/min = 0 var/max = 10 // todo: remove this, port. // A wrapper record returned by the onshocked event of a pathogen symptom. datum/shockparam var/amt var/wattage var/skipsupp // A pathogen. How surprising. datum/pathogen var/name // The full 'scientific' name for the pathogen (eg. H5N1) var/name_base // The 'scientific' name without the mutation part (eg. H5N) var/pathogen_uid // The unique identifier of the pathogen family. All pathogens with the same UID are cured by the same vaccine. var/mutation // The mutation identifier of the pathogen (eg. for H5N1: 1). Unique for each mutation. Sequential. var/desc // What a scientist might see when he looks at this pathogen through a microscope (eg. blue stringy viruses) var/stages // How far the pathogen may advance? Higher stages allow for more malicious/benevolent effects of symptoms. (3 to 5) // The amount of stages is determined by the body type. The most potent of all are viruses and parasites. var/list/carriers = list() // A list of carriers to this pathogen. Currently unused. var/list/effects = list() // A list of symptoms exhibited by those infected with this pathogen. var/stage // The current stage of the pathogen. var/advance_speed // The speed at which this pathogen advances stages. An advance speed of N means a flat N% chance to advance each tick. var/mutativeness // The speed at which this pathogen mutates. A mutativeness of N means that it has a flat N% chance to mutate upon infection. var/maliciousness // The maliciousness of mutations. The higher this value, the more likely it is that the pathogen will mutate in a malevolent way. var/mutation_speed // The rate at which the pathogen mutates. This value defines how many different mutations will occur during a single mutation session. // Mutation Speed is on a log3 scale of mutations. // This means that to achieve the next mutation count (as in, mutate one more time compared to the current state), one needs to tripe // the mutation speed of the pathogen. 1 mutation will occur for a speed of 0 to 8, 2 for 9 to 26, 3 for 27 to 80, etc. No mutation will // occur if this value is less than 0. var/base_mutation // Currently unused. var/datum/microbody/body_type // The body type of the pathogen, which determines the base mutativeness and the method of synthesizing a cure. var/mob/infected // The mob that is infected with this pathogen. var/cooldown = 3 // An internal 'cooldown' so that the pathogen doesn't instantly advance to stage 5. var/suppression_threshold // The pathogen's resistance to suppression. The higher this value, the more extreme conditions are required to suppress the pathogen. var/list/mutex = list() // These symptoms are explicitly disallowed by a mutex. var/symptomatic = 1 // If 0, the pathogen is mostly dormant on the mob. Symptoms may still decide to ignore this. var/generation = 1 // Higher generation pathogens may replace lower generation pathogens on mobs. var/datum/pathogendna/dnasample = null // A reference of what the pathogen's DNA looks like. This reference is passed around // and copied only when coming into contact with something that directly works with // the DNA itself. var/datum/suppressant/suppressant // The method of suppression for the pathogen. This is picked from all children of /datum/suppressant with an equal // probability. I might try to work out a system for rarities once, but it's very low on the priority list. To add a suppression method, // just define a child for /datum/suppressant and please make sure it's not an already existing colour. var/suppressed = 0 // A suppression indicator. After every roll for advancement, suppression is reset to 0 and a cooldown is set. Processes of the pathogen // and the symptoms both may decide to set this flag during this cooldown. The pathogen immediately fails the advance roll if it is suppressed. // With this being available, symptoms may define their own resistances and vulnerabilities. Setting this to -1 will make all current symptoms' // vulnerability checks immediately fail - ie. the symptoms' weaknesses will not suppress the pathogen. On the flipside, setting this to 2 will // make all current symptoms' resistance check immediately fail, ie. the symptoms' resistances will not prevent suppression. It would be good // practice to build all symptoms consistently with this concept. // Each disease has their primary suppression method, which provides their colour. The primary suppression method is relevant only if after // all the symptoms acting, suppressed does not equal -1. Primary suppression methods may suppress the pathogen further: Even if a symptom // has a weakness powerful enough to force it back a stage, a primary suppression method is also such a weakness that it may be pushed back // yet another stage. // A pathogen that cannot be currently suppressed (ie. is strengthened somehow) may advance regardless of advance speed. // Be sensible when defining suppressions for symptoms. It shouldn't cure the pathogen, and it seldom should push the pathogen back below stage 3. // TL;DR // -1: Cannot be suppressed. May cause a negative advance speed pathogen to advance anyway. // 0: Will not be suppressed. // 1: Will be suppressed. // 2: Will surely be suppressed. var/in_remission = 0 // Pathogens in remission are being cured by the body. Set by the curing reagent. var/forced_microbody = null // If not null, this pathogen will be generated with a specific microbody. var/curable_by_suppression = 0 // If not 0, represents a probability of becoming regressive through suppression. If negative, randomly generated. var/rads = 0 // The pathogen may mutate inside someone according to rads. var/rad_mutate_cooldown = 0 // The amount of ticks to wait before we can mutate again due to radiation. var/ticked = 0 var/list/symptom_data = list() // Symptom data container. disposing() clear() proc/clear() name = "" name_base = "" pathogen_uid = 0 mutation = 0 desc = "" stages = 1 carriers = list() effects = list() stage = 1 generation = 1 symptomatic = 1 advance_speed = 0 mutativeness = 0 maliciousness = 0 mutation_speed = 0 base_mutation = 0 body_type = null infected = null cooldown = 3 suppression_threshold = 0 mutex = list() dnasample = null suppressant = null suppressed = 0 in_remission = 0 rads = 0 rad_mutate_cooldown = 0 ticked = 0 symptom_data = list() forced_microbody = initial(forced_microbody) curable_by_suppression = initial(curable_by_suppression) proc/clone() var/datum/pathogen/P = unpool(/datum/pathogen) P.setup(0, src, 0) return P proc/do_prefab(var/strength = 0) clear() var/cdc = generate_name() generate_components(cdc) generate_attributes(strength) New() setup(0, null, 0) unpooled() clear() setup(0, null, 0) proc/create_weak() randomize(0) proc/cdc_announce(var/mob/M) var/datum/pathogen_cdc/CDC = null if (name_base in pathogen_controller.pathogen_trees) CDC = pathogen_controller.pathogen_trees[name_base] else CDC = new /datum/pathogen_cdc(pathogen_uid) pathogen_controller.pathogen_trees[name_base] = CDC pathogen_controller.next_mutation[pathogen_uid] = mutation + 1 CDC.microbody_type = body_type CDC.mutations += name CDC.mutations[name] = clone() return proc/generate_name() src.mutation = pick(pathogen_controller.lnums) do src.name_base = pick(pathogen_controller.lalph) + pick(pathogen_controller.lnums) + pick(pathogen_controller.lalph) while (src.name_base in pathogen_controller.pathogen_trees) src.name = name_base + mutation src.mutation = text2num(mutation) src.base_mutation = 0 src.pathogen_uid = "[pathogen_controller.next_uid]" pathogen_controller.next_uid++ pathogen_controller.pathogen_trees += src.name_base var/datum/pathogen_cdc/cdc = new /datum/pathogen_cdc(src.pathogen_uid) pathogen_controller.pathogen_trees[src.name_base] = cdc pathogen_controller.next_mutation[src.pathogen_uid] = mutation + 1 // if (ticker) // if (ticker.current_state == GAME_STATE_PLAYING) // message_admins("Pathogen tree [src.name_base] entering play.") return cdc proc/generate_components(var/datum/pathogen_cdc/cdc, var/strength) var/supp_t = pick(pathogen_controller.path_to_suppressant) suppressant = pathogen_controller.path_to_suppressant[supp_t] suppressant.onadd(src) if (!forced_microbody) src.body_type = pathogen_controller.get_microbody(strength + 5) cdc.microbody_type = "[src.body_type]" else src.body_type = pathogen_controller.path_to_microbody[forced_microbody] cdc.microbody_type = "[src.body_type]" proc/generate_randomized_effects(var/strength) var/adj_strength = strength - 8 if (strength != -1) var/effcount = pick(1, prob(50); 2, prob(25); 3, prob(10); 4, prob(10); 5) for (var/i = 0, i < effcount, i++) var/val = rand(adj_strength, adj_strength + 8) if (val < 6) generate_weak_effect() else if (val < 14) generate_effect() else generate_strong_effect() proc/generate_attributes(var/strength) var/adj_strength = strength - 8 src.maliciousness = rand(-2, 6) + rand(adj_strength - 8, adj_strength + 8) src.mutation_speed = rand(-2, 10) + rand(adj_strength - 8, adj_strength + 8) src.suppression_threshold += rand(1,3) * maliciousness + rand(-5, 10) + rand(adj_strength - 8, adj_strength + 8) src.advance_speed = rand(-2, 7) + rand(adj_strength - 8, adj_strength + 8) src.mutativeness = src.body_type.mutativeness src.maliciousness *= src.body_type.maliciousness_multiplier src.mutation_speed *= src.body_type.mutation_speed_multiplier if (src.curable_by_suppression < 0 && strength < 10) src.curable_by_suppression = rand(-10 + strength, 10 - strength) if (src.curable_by_suppression < 0) src.curable_by_suppression = 0 else src.curable_by_suppression = 0 src.stages = src.body_type.stages var/shape = pick("stringy", "snake", "blob", "spherical", "tetrahedral", "star shaped", "tesselated") src.desc = "[src.suppressant.color] [shape] [src.body_type.plural]" src.symptomatic = 1 src.generation = 1 src.stage = 1 proc/randomize(var/strength) var/datum/pathogen_cdc/cdc = generate_name() cdc.mutations += src.name cdc.mutations[src.name] = src generate_randomized_effects(strength) generate_components(cdc, strength) generate_attributes(strength) logTheThing("pathology", null, null, "Pathogen [name] created by randomization.") proc/setup(status, var/datum/pathogen/origin, may_mutate, var/datum/pathogendna/sample = null) if (status == 0 && !origin) return src.in_remission = 0 if (origin) src.mutation = origin.mutation src.name = origin.name src.name_base = origin.name_base src.stages = origin.stages src.desc = origin.desc src.carriers = list() src.effects = origin.effects.Copy() for (var/datum/pathogeneffects/E in src.effects) E.onadd(src) src.pathogen_uid = origin.pathogen_uid src.suppressant = new origin.suppressant.type() src.suppressant.onadd(src) src.stage = 1 src.generation = origin.generation src.symptomatic = origin.symptomatic src.advance_speed = origin.advance_speed src.mutativeness = origin.mutativeness src.mutation_speed = origin.mutation_speed src.body_type = origin.body_type src.maliciousness = origin.maliciousness src.suppression_threshold = origin.suppression_threshold if (src.mutativeness && may_mutate) if (prob(src.mutativeness)) mutate() else if (sample) src.dnasample = sample else src.dnasample = origin.dnasample else if (sample) src.dnasample = sample else src.dnasample = origin.dnasample src.curable_by_suppression = origin.curable_by_suppression else if (status == 1) src.randomize(8) if (sample) src.dnasample = sample else src.dnasample = new/datum/pathogendna(src) else if (!origin && status == 2) src.do_prefab() if (sample) src.dnasample = sample else src.dnasample = new/datum/pathogendna(src) proc/generate_weak_effect() switch(rand(1,100)) if (1 to 70) return src.add_new_symptom(pathogen_controller.l_vc) if (71 to 97) return src.add_new_symptom(pathogen_controller.l_c) if (98 to 100) return src.add_new_symptom(pathogen_controller.l_u) proc/generate_effect() switch(rand(1,100)) if (1 to 60) // 60% return src.add_new_symptom(pathogen_controller.l_vc) if (61 to 85) // 25% return src.add_new_symptom(pathogen_controller.l_c) if (86 to 94) // 8% return src.add_new_symptom(pathogen_controller.l_u) if (95 to 98) // 4% return src.add_new_symptom(pathogen_controller.l_r) if (99 to 100) // 2% return src.add_new_symptom(pathogen_controller.l_vr) proc/generate_strong_effect() switch(rand(1,100)) if (1 to 40) // 40% return src.add_new_symptom(pathogen_controller.l_vc) if (41 to 70) // 30% return src.add_new_symptom(pathogen_controller.l_c) if (71 to 85) // 15% return src.add_new_symptom(pathogen_controller.l_u) if (86 to 93) // 8% return src.add_new_symptom(pathogen_controller.l_r) if (94 to 100) // 7% return src.add_new_symptom(pathogen_controller.l_vr) // Invoked when the pathogen mutates. This will change the active instance of the pathogen accordingly. // Does not occur randomly, only upon infection. // In the future, applying radiation to infected people may mutate the pathogen. proc/mutate() base_mutation = mutation mutation = pathogen_controller.next_mutation[src.pathogen_uid] pathogen_controller.next_mutation[src.pathogen_uid] += 1 name = name_base + "[mutation]" mutativeness = round(mutativeness / 1.66) logTheThing("pathology", null, null, "Pathogen strain [name_base] mutated creating [name].") var/count = mutation_speed if (count < 0) return if (count > 0 && count < 2) count = 1 if (count > 3) count = round(log(3, count)) var/list/used_mutations = list() var/retries = 10 for (var/i = 1, i <= count, i++) var/T = pick(pathogen_controller.path_to_mutation) var/datum/pathogen_mutation/mut = pathogen_controller.path_to_mutation[T] if (T in used_mutations) if (used_mutations[T] >= mut.session_maximum) continue else used_mutations[T]++ else used_mutations[T] = 1 if (mut.may_occur(src)) mut.mutate(src) logTheThing("pathology", null, null, "[mut] occurred on [name].") else if (retries) i-- retries-- else logTheThing("pathology", null, null, "[mut] could not occur on [name].") dnasample = new(src) proc/process() disease_act() if (rads) if (rads < 1) rads = 0 else rads /= 2 if (infected) var/mob/living/carbon/human/M = infected if (istype(M)) var/rad = M.get_radiation() rads += rad if (M.reagents) var/datum/reagent/R = M.reagents.get_reagent("mutagen") if (istype(R)) rads += R.volume if (rads && suppressed <= 0) if (prob(rads)) logTheThing("pathology", infected, null, "'s infection of [name] mutated due to radiation levels of [rads].") mutate() rad_mutate_cooldown = 26 if (ticked) ticked = 0 suppressed = 0 if (rad_mutate_cooldown > 0) rad_mutate_cooldown-- else if (rad_mutate_cooldown < 0) //?? rad_mutate_cooldown = 0 // This is the real thing, wrapped by process(). proc/disease_act() var/list/acted = list() var/order = pick(0,1) if (order) for (var/datum/effect in src.effects) if (effect.type in acted) continue acted += effect.type if (prob(body_type.activity[stage])) effect:disease_act(infected, src) else for (var/i = src.effects.len, i > 0, i--) var/datum/effect = src.effects[i] if (effect.type in acted) continue acted += effect.type if (prob(body_type.activity[stage])) effect:disease_act(infected, src) if (!cooldown) if (in_remission) if (prob(abs(advance_speed))) if (stage == 1) infected.cured(src) else reduce() return if (suppressed != -1) var/result = suppressant.suppress_act(src) if (suppressed == 0) suppressed = result if (advance_speed > 0) if (prob(min(advance_speed, 4))) if (suppressed < 1) advance() else if (stage > 3) reduce() else if (advance_speed < 0) if (suppressed == -1) if (prob(4)) advance() else if (prob(-advance_speed)) reduce() if (suppressed > 0) if (curable_by_suppression && prob(curable_by_suppression)) in_remission = 1 ticked = 1 else cooldown-- // A safe method for advancing the pathogen's stage. proc/advance() if (stage != stages) stage++ cooldown = COOLDOWN_MULTIPLIER * 3 + 2 * stage // The polar opposite of advance(). It causes the pathogen to safely reduce a stage if it can. proc/reduce() if (stage > 1) stage-- cooldown = COOLDOWN_MULTIPLIER * 3 + 2 * stage else infected.cured(src) // Carrier query. Currently unused. proc/is_carried_by(var/reagent) return (reagent in pathogen_controller.pathogen_affected_reagents) proc/remission() in_remission = 1 //============================================================================= // Events //============================================================================= // In the following chapter you will encounter the definition for event handlers. // Event handlers are available for both pathogens and symptoms. // // Defining new events // --------------------- // 1) Add your event handler here. The event handler should call the event handlers of all symptoms. // 2) Define a default event handler in /datum/pathogeneffects. This is necessary so that all symptoms continue working, even if they don't respond to that event. // 3) Define a default event handler in /datum/suppressant. This is necessary so that all suppression methods continue working, even if they don't respond to that event. // 4) Override the event handler in the symptoms where you want it to react. // 5) Call each affecting pathogen's event handler when the event is triggered. // // Defining existing events for symptoms // --------------------------------------- // All events are structured, so that if they take X arguments in the pathogen, they take X+2 arguments in the pathogen effect, so the first argument is always the // affected mob, while the last argument is always the affecting pathogen. The equivalent event of the pathogen symptoms has the same name as the pathogen's wrapper // event. // A good practice is to follow these standards. // To define an event for an effect, simply override the appropriate event handler. The pathogen code automatically handles calling these events at the appropriate time. // // Act when grabbing a mob. Does not return anything, the grab always happens. // This event is only fired when the PASSIVE grab comes into play. // @TODO: Extend this event to all grab levels. Add the possibility of vetoing. proc/ongrab(var/mob/target as mob) for (var/effect in src.effects) effect:ongrab(infected, target, src) suppressant.ongrab(target, src) // Act when punched by a mob. Returns a multiplier for the damage done by the punch. // A hardened skin symptom might make good use of it one day (AT THE TIME OF WRITING THIS COMMENT THAT DID NOT EXIST OKAY) proc/onpunched(var/mob/origin as mob, zone) var/ret = 1 for (var/effect in src.effects) ret *= effect:onpunched(infected, origin, zone, src) suppressant.onpunched(origin, zone, src) return ret // Act when punching a mob. Returns a multipier for the damage done by the punch. // This opens up the availability for both hulk (quad-damage anyone?) and muscle deficiency diseases. // Returning 0 from any symptom vetoes the punch. proc/onpunch(var/mob/target as mob, zone) var/ret = 1 for (var/effect in src.effects) ret *= effect:onpunch(infected, target, zone, src) suppressant.onpunch(target, zone, src) return ret // Act when successfully disarming or pushing down a mob. Returns whether this may happen. // This indicates that ondisarm is a veto event - any of the symptoms has a right to veto the occurrence of the disarm or pushdown. // Think of it this way. Suppose you have a muscle disease that makes you weak. When your puny body finally hits the target... // ...nothing actually happens because you're a weak mess and failed to even scratch him. // Returning 0 from ANY of the symptoms' disarm events will make disarming fail. proc/ondisarm(var/mob/target as mob, isPushDown) var/ret = 1 for (var/effect in src.effects) ret = min(effect:ondisarm(infected, target, isPushDown, src), ret) suppressant.ondisarm(target, isPushDown, src) return ret // Act when shocked. Returns the amount of damage the shocked mob should actually take (which leaves place for both amplification and suppression) // The return system here is more complex than for most other events. The symptoms' onshocked may not only modify the amount of shock damage, but // also decide that the presence of the symptom makes the a muscle-event vulnerable pathogen resistant to suppression through shocking. proc/onshocked(var/amt, var/wattage) var/datum/shockparam/ret = new ret.amt = amt ret.wattage = wattage ret.skipsupp = 0 for (var/effect in src.effects) ret = effect:onshocked(infected, ret, src) suppressant.onshocked(ret, src) return ret.amt // Act when saying something. Returns the message that should be said after the diseases make the appropriate modifications. proc/onsay(message) for (var/effect in src.effects) message = effect:onsay(infected, message, src) suppressant.onsay(message, src) return message // Act on emoting. Vetoing available by returning 0. proc/onemote(act) suppressant.onemote(infected, act, src) for (var/effect in src.effects) . *= effect:onemote(infected, act, src) proc/add_new_symptom(var/list/allowed, var/allow_duplicates = 0) for (var/i = 0, i < 10, i++) var/T = pick(allowed) var/datum/pathogeneffects/E = pathogen_controller.path_to_symptom[T] if (add_symptom(E, allow_duplicates)) return 1 return 0 proc/add_symptom(var/datum/pathogeneffects/E, var/allow_duplicates = 0) if (allow_duplicates || !(E in effects)) for (var/mutex in E.mutex) for (var/T in typesof(mutex)) if (!(T in mutex)) mutex += T effects += E E.onadd(src) return 1 return 0 proc/remove_symptom(var/datum/pathogeneffects/E, var/all = 0) if (all) var/rem = 0 while (E in src.effects) src.effects -= E rem = 1 if (rem) rebuild_mutex() else if (E in src.effects) src.effects -= E rebuild_mutex() proc/rebuild_mutex() src.mutex = list() for (var/datum/pathogeneffects/E in src.effects) for (var/mutex in E.mutex) for (var/T in typesof(mutex)) if (!(T in mutex)) mutex += T proc/dig2hex(num) switch (num) if (0 to 9) return num if (10) return "A" if (11) return "B" if (12) return "C" if (13) return "D" if (14) return "E" if (15) return "F" else return "" // One's complement num2hex - converts numbers to their hexadecimal one's complement representation (along with the padding). proc/num2hexoc(num, pad) if (pad == null) pad = 4 if (pad <= 0) return "" var/max = 1 var/neg = 0 if (num < 0) num = -num neg = 1 for (var/i = 1; i < pad; i++) max *= 16 max *= 8 max -= 1 var/ret = "" if (num > max) if (neg) for (var/i = 1; i < pad; i++) ret = "0[ret]" return "8[ret]" else for (var/i = 1; i < pad; i++) ret = "F[ret]" return "7[ret]" else var/digs = 1 var/cnum = num while (cnum) if (digs != pad) var/digit = cnum % 16 if (neg) digit = 15 - digit ret = "[dig2hex(digit)][ret]" cnum = round(cnum / 16) digs++ else var/digit = num if (digit > 7) logTheThing("pathology", null, null, "Num2hexoc error: overflow on [num].") if (neg) digit += 8 return "[dig2hex(digit)][ret]" while (digs <= pad) if (neg) ret = "F[ret]" else ret = "0[ret]" digs++ return ret // One's complement reverse engineering of a hexadecimal one's complement representation to a base 10 signed number proc/hex2numoc(var/num) var/len = length(num) var/max = 7 for (var/i = len - 1, i > 0, i--) max = max * 16 + 15 var/rnum = hex2num(num) if (rnum > max) rnum = rnum - (16 ** len - 1) return rnum // generates a random 3-sequence (rand(0, 4095) is unreliable) proc/rand3seq() return num2hex(rand(0, 15), 1) + num2hex(rand(0, 15), 1) + num2hex(rand(0, 15), 1)
NameSuppression reagents
[S][supp]