///////////////IMMUNITY SCANNER///////////////
/obj/item/device/antibody_scanner
name = "immunity scanner"
desc = "A hand-held body scanner able to evaluate the immune system of the subject."
inhand_states = list("left_hand" = 'icons/mob/in-hand/left/misc_tools.dmi', "right_hand" = 'icons/mob/in-hand/right/misc_tools.dmi')
icon_state = "antibody"
item_state = "immunity"
flags = FPRINT
siemens_coefficient = 1
slot_flags = SLOT_BELT
throwforce = 3
w_class = W_CLASS_TINY
throw_speed = 5
starting_materials = list(MAT_IRON = 200)
w_type = RECYK_ELECTRONIC
melt_temperature = MELTPOINT_PLASTIC
origin_tech = Tc_MAGNETS + "=1;" + Tc_BIOTECH + "=1"
attack_delay = 0
/obj/item/device/antibody_scanner/attack(var/mob/living/L, var/mob/user)
if(!istype(L))
//to_chat(user, "Incompatible object, scan aborted.")
return
if (issilicon(L))
to_chat(user, "Incompatible with silicon lifeforms, scan aborted.")
return
playsound(user, 'sound/items/detscan.ogg', 50, 1)
var/info = ""
var/icon/scan = icon('icons/virology.dmi',"immunitybg")
var/display_width = scan.Width()
var/list/antigens_that_matter = list()
if (L.immune_system)
finding_antigens:
for (var/antibody in L.immune_system.antibodies)
if (L.immune_system.antibodies[antibody] > 0)
antigens_that_matter += antibody
continue
if (L.virus2.len)
for (var/ID in L.virus2)
if(ID in virusDB)
var/datum/disease2/disease/D = L.virus2[ID]
if (antibody in D.antigen)
antigens_that_matter += antibody
continue finding_antigens
var/bar_spacing = round(display_width/antigens_that_matter.len)
var/bar_width = round(bar_spacing/2)
var/bar_offset = round(bar_width/4)
var/x_adjustment = 5//Sometimes you have to adjust things manually so they look good. This var moves all the gauges and graduations on the x axis.
if (L.immune_system)
var/immune_system = L.immune_system.GetImmunity()
var/immune_str = immune_system[1]
var/list/antibodies = immune_system[2]
info += "Immune System Status: [round(immune_str*100)]%"
info += "
Antibody Concentrations:"
var/i = 0
for (var/antibody in antigens_that_matter)
var/rgb = "#FFFFFF"
switch (antibody)
if ("O","A","B","Rh")
rgb = "#80DEFF"
if ("Q","U","V")
rgb = "#81FF9F"
if ("M","N","P")
rgb = "#E6FF81"
if ("X","Y","Z")
rgb = "#FF9681"
if ("C")
rgb = "#F54B4B"
//add colors for new special antigens here
scan.DrawBox(rgb,i*bar_spacing+bar_offset+x_adjustment,6,i*bar_spacing+bar_width+bar_offset+x_adjustment,6+antibodies[antibody]*3*immune_str)
i++
if (L.virus2.len)
for (var/ID in L.virus2)
var/datum/disease2/disease/D = L.virus2[ID]
scan.DrawBox("#FF0000",6,6+D.strength*3,display_width-5,6+D.strength*3)
if(ID in virusDB)
var/subdivision = (D.strength - ((D.robustness * D.strength) / 100)) / D.max_stage
var/i = 0
for (var/antigen in antigens_that_matter)
if (antigen in D.antigen)
var/box_size = 3
scan.DrawBox("#FF0000",bar_width-box_size+bar_spacing*i,6+D.strength*3-3,bar_width+box_size+bar_spacing*i,6+D.strength*3+3)
scan.DrawBox("#FF0000",bar_width+bar_spacing*i,6+D.strength*3,bar_width+bar_spacing*i,6+round(D.strength - D.max_stage * subdivision)*3)
var/stick_out = 6//how far the graduations go left and right of the gauge
for (var/j = 1 to D.max_stage)
var/alt = round(D.strength - j * subdivision)
scan.DrawBox("#FF0000",i*bar_spacing+bar_offset-stick_out+x_adjustment,6+alt*3,i*bar_spacing+bar_offset+bar_width+stick_out+x_adjustment,6+alt*3)
i++
info += "
"
info += "
"
info += "
"
info += ""
if (L.immune_system)
for (var/antibody in antigens_that_matter)
info += "| [antibody] | "
info += "
"
info += ""
if (L.immune_system)
for (var/antibody in antigens_that_matter)
info += "| [round(L.immune_system.antibodies[antibody]*L.immune_system.strength)]%"
info += " |
"
info += "
"
if (L.virus2.len)
for (var/ID in L.virus2)
var/datum/disease2/disease/D = L.virus2[ID]
if(ID in virusDB)
var/datum/data/record/V = virusDB[ID]
info += "
[V.fields["name"]][V.fields["nickname"] ? " \"[V.fields["nickname"]]\"" : ""] detected. Strength: [D.strength]. Robustness: [D.robustness]. Antigen: [D.get_antigen_string()]"
else
info += "
Unknown [D.form] detected. Strength: [D.strength]"
var/datum/browser/popup = new(user, "\ref[src]", name, 600, 600, src)
popup.set_content(info)
popup.open()
/obj/item/device/antibody_scanner/preattack(var/atom/A, var/mob/user, proximity_flag)
if(proximity_flag != 1)
return
if (isitem(A))
var/obj/item/I = A
playsound(user, 'sound/items/detscan.ogg', 50, 1)
var/span = "warning"
if(I.sterility <= 0)
span = "danger"
else if (I.sterility >= 100)
span = "notice"
to_chat(user,"Scanning \the [I]...sterility level = [I.sterility]%")
if (istype(I,/obj/item/weapon/virusdish))
var/obj/item/weapon/virusdish/dish = I
if (dish.open && dish.contained_virus)
to_chat(user,"However, since its lid has been openned, unprotected contact with the dish can result in infection.")
. = ..()
///////////////VIRUS DISH///////////////
var/list/virusdishes = list()
/obj/item/weapon/virusdish
name = "growth dish"
desc = "A petri dish fit to contain viral, bacteriologic, parasitic, or any other kind of pathogenic culture."
inhand_states = list("left_hand" = 'icons/mob/in-hand/left/misc_tools.dmi', "right_hand" = 'icons/mob/in-hand/right/misc_tools.dmi')
icon = 'icons/obj/virology.dmi'
icon_state = "virusdish"
item_state = "virusdish"
w_class = W_CLASS_SMALL
sterility = 100//the outside of the dish is sterile.
var/growth = 0
var/info = ""
var/analysed = FALSE
var/datum/disease2/disease/contained_virus
var/open = FALSE
var/cloud_delay = 8 SECONDS//similar to a mob's breathing
var/last_cloud_time = 0
var/mob/last_openner
/obj/item/weapon/virusdish/New(loc)
..()
reagents = new(10)
reagents.my_atom = src
virusdishes.Add(src)
/obj/item/weapon/virusdish/Destroy()
contained_virus = null
processing_objects.Remove(src)
virusdishes.Remove(src)
..()
/obj/item/weapon/virusdish/clean_blood()
..()
if (open)
contained_virus = null
growth = 0
if (analysed)
info = ""
analysed = FALSE
visible_message("The info sticker falls of \the [src].")
update_icon()
/obj/item/weapon/virusdish/update_icon()
overlays.len = 0
if (!contained_virus)
if (open)
icon_state = "virusdish1"
else
icon_state = "virusdish"
return
icon_state = "virusdish-outline"
var/image/I1 = image(icon,src,"virusdish-bottom")
I1.color = contained_virus.color
var/image/I2 = image(icon,src,"pattern-[contained_virus.pattern]")
I2.color = contained_virus.pattern_color
var/image/I3 = image(icon,src,"virusdish-[open?"open":"closed"]")
I3.color = contained_virus.color
overlays += I1
if (open)
overlays += I3
I2.alpha = growth*255/200+127
overlays += I2
else
overlays += I2
overlays += I3
I2.alpha = (growth*255/200+127)*60/100
overlays += I2
var/image/I4 = image(icon,src,"virusdish-reflection")
overlays += I4
if (analysed)
overlays += "virusdish-label"
else if (info != "" && copytext(info, 1, 9) == "OUTDATED")
overlays += "virusdish-outdated"
/obj/item/weapon/virusdish/attack_hand(var/mob/user)
..()
infection_attempt(user,contained_virus,"attack_hand infection")
/obj/item/weapon/virusdish/attack_self(var/mob/user)
open = !open
update_icon()
to_chat(user,"You [open?"open":"close"] dish's lid.")
if (open)
last_openner = user
if (contained_virus)
contained_virus.log += "
[timestamp()] Containment Dish openned by [key_name(user)]."
processing_objects.Add(src)
else
if (contained_virus)
contained_virus.log += "
[timestamp()] Containment Dish closed by [key_name(user)]."
processing_objects.Remove(src)
infection_attempt(user,contained_virus,"attack_self infection")
/obj/item/weapon/virusdish/attackby(var/obj/item/weapon/W as obj,var/mob/living/carbon/user as mob)
..()
if(istype(W,/obj/item/weapon/hand_labeler))
return
if(user.a_intent == I_HURT && W.force)
visible_message("The virus dish is smashed to bits!")
shatter(user)
/obj/item/weapon/virusdish/is_open_container()
return open
/obj/item/weapon/virusdish/afterattack(var/atom/A, var/mob/user, var/adjacency_flag, var/click_params)
. = ..()
if(.)
return
if (!adjacency_flag)
return
if (open)
if (istype(A,/obj/structure/reagent_dispensers))
var/obj/structure/reagent_dispensers/S = A
if(S.can_transfer(src, user))
var/tx_amount = transfer_sub(A, src, S.amount_per_transfer_from_this, user)
if (tx_amount > 0)
to_chat(user, "You fill \the [src] with [tx_amount] units of the contents of \the [A].")
return tx_amount
if (istype(A,/obj/item/weapon/reagent_containers))
var/success = 0
var/obj/container = A
if (!container.is_open_container() && istype(container,/obj/item/weapon/reagent_containers) && !istype(container,/obj/item/weapon/reagent_containers/food/snacks))
return
if(A.is_open_container())
success = transfer_sub(src, A, 10, user, log_transfer = TRUE)
if (success > 0)
to_chat(user, "You transfer [success] units of the solution to \the [A].")
if (istype(A,/obj/structure/toilet))
var/obj/structure/toilet/T = A
if (T.open)
empty(user,A)
if (istype(A,/obj/structure/urinal)||istype(A,/obj/structure/sink))
empty(user,A)
/obj/item/weapon/virusdish/proc/empty(var/mob/user,var/atom/A)
if (user && A)
to_chat(user,"You empty \the [src]'s reagents into \the [A].")
reagents.clear_reagents()
/obj/item/weapon/virusdish/process()
if (!contained_virus || !(contained_virus.spread & SPREAD_AIRBORNE))
processing_objects.Remove(src)
return
if(world.time - last_cloud_time >= cloud_delay)
last_cloud_time = world.time
var/list/L = list()
L["[contained_virus.uniqueID]-[contained_virus.subID]"] = contained_virus
new /obj/effect/pathogen_cloud/core(get_turf(src), last_openner, virus_copylist(L), FALSE)
/obj/item/weapon/virusdish/random
name = "growth dish"
/obj/item/weapon/virusdish/random/New(loc)
..(loc)
if (loc)//because fuck you /datum/subsystem/supply_shuttle/Initialize()
contained_virus = get_random_weighted_disease(WDISH)
var/list/anti = list(
ANTIGEN_BLOOD = 1,
ANTIGEN_COMMON = 1,
ANTIGEN_RARE = 0,
ANTIGEN_ALIEN = 0,
)
var/list/bad = list(
EFFECT_DANGER_HELPFUL = 1,
EFFECT_DANGER_FLAVOR = 2,
EFFECT_DANGER_ANNOYING = 2,
EFFECT_DANGER_HINDRANCE = 2,
EFFECT_DANGER_HARMFUL = 2,
EFFECT_DANGER_DEADLY = 0,
)
contained_virus.makerandom(list(50,90),list(10,100),anti,bad,src)
growth = rand(5, 50)
name = "growth dish (Unknown [contained_virus.form])"
update_icon()
else
virusdishes.Remove(src)
/obj/item/weapon/virusdish/open
icon_state = "virusdish1"
/obj/item/weapon/virusdish/open/New(loc)
..()
open = TRUE
update_icon()
/obj/item/weapon/virusdish/random/open
icon_state = "virusdish1"
/obj/item/weapon/virusdish/random/open/New(loc)
..()
open = TRUE
update_icon()
processing_objects.Add(src)
/obj/item/weapon/virusdish/throw_impact(atom/hit_atom, var/speed, mob/user)
..()
if(isturf(hit_atom))
visible_message("The virus dish shatters on impact!")
shatter(user)
/obj/item/weapon/virusdish/proc/incubate(var/mutatechance=5,var/growthrate=3)
if (contained_virus)
if(!reagents.remove_reagent(VIRUSFOOD,0.2))
growth = min(growth + growthrate, 100)
if(!reagents.remove_reagent(WATER,0.2))
growth = max(growth - growthrate, 0)
contained_virus.incubate(src,mutatechance)
/obj/item/weapon/virusdish/on_reagent_change()
if (contained_virus)
var/datum/reagent/blood/blood = locate() in reagents.reagent_list
if (blood)
var/list/L = list()
L["[contained_virus.uniqueID]-[contained_virus.subID]"] = contained_virus
blood.data["virus2"] |= filter_disease_by_spread(virus_copylist(L),required = SPREAD_BLOOD)
..()
/obj/item/weapon/virusdish/proc/shatter(var/mob/user)
var/obj/effect/decal/cleanable/virusdish/dish = new(get_turf(src))
dish.pixel_x = pixel_x
dish.pixel_y = pixel_y
if (contained_virus)
dish.contained_virus = contained_virus.getcopy()
dish.last_openner = key_name(user)
src.transfer_fingerprints_to(dish)
playsound(src, "shatter", 70, 1)
var/image/I1
var/image/I2
if (contained_virus)
I1 = image(icon,src,"brokendish-color")
I1.color = contained_virus.color
I2 = image(icon,src,"pattern-[contained_virus.pattern]b")
I2.color = contained_virus.pattern_color
else
I1 = image(icon,src,"brokendish")
dish.overlays += I1
if (contained_virus)
dish.overlays += I2
contained_virus.log += "
[timestamp()] Containment Dish shattered by [key_name(user)]."
if (contained_virus.spread & SPREAD_AIRBORNE)
var/strength = contained_virus.infectionchance
var/list/L = list()
L["[contained_virus.uniqueID]-[contained_virus.subID]"] = contained_virus
while (strength > 0)
new /obj/effect/pathogen_cloud/core(get_turf(src), user, virus_copylist(L), FALSE)
strength -= 40
qdel(src)
/obj/item/weapon/virusdish/examine(var/mob/user)
..()
if(!contained_virus)
to_chat(user, "This one appears to have been disinfected.")
if(open)
to_chat(user, "Its lid is open!")
else
to_chat(user, "Its lid is closed!")
if(info)
to_chat(user, "There is a sticker with some printed information on it. (Read it)")
/obj/item/weapon/virusdish/Topic(href, href_list)
if (!isobserver(usr))
if(..())
return TRUE
if(href_list["examine"])
var/datum/browser/popup = new(usr, "\ref[src]", name, 600, 300, src)
popup.set_content(info)
popup.open()
/obj/item/weapon/virusdish/infection_attempt(var/mob/living/perp,var/datum/disease2/disease/D)
if (open)//If the dish is open, we may get infected by the disease inside on top of those that might be stuck on it.
var/block = 0
var/bleeding = 0
if(attempt_colony(perp,contained_virus, "from exposure to \a [src]."))
//Spacesuits cover feet, torso, and hands, but are ideal for a colony.
else if (src in perp.held_items)
block = perp.check_contact_sterility(HANDS)
bleeding = perp.check_bodypart_bleeding(HANDS)
if (!block)
if (contained_virus.spread & SPREAD_CONTACT)
perp.infect_disease2(contained_virus, notes="(Contact, from picking up \a [src])")
else if (bleeding && (contained_virus.spread & SPREAD_BLOOD))
perp.infect_disease2(contained_virus, notes="(Blood, from picking up \a [src])")
else if (isturf(loc) && loc == perp.loc)//is our perp standing over the open dish?
if (perp.lying)
block = perp.check_contact_sterility(FULL_TORSO)
bleeding = perp.check_bodypart_bleeding(FULL_TORSO)
else
block = perp.check_contact_sterility(FEET)
bleeding = perp.check_bodypart_bleeding(FEET)
if (!block)
if (contained_virus.spread & SPREAD_CONTACT)
perp.infect_disease2(contained_virus, notes="(Contact, from [perp.lying?"lying":"standing"] over a virus dish[last_openner ? " openned by [key_name(last_openner)]" : ""])")
else if (bleeding && (contained_virus.spread & SPREAD_BLOOD))
perp.infect_disease2(contained_virus, notes="(Blood, from [perp.lying?"lying":"standing"] over a virus dish[last_openner ? " openned by [key_name(last_openner)]" : ""])")
..(perp,D)
///////////////GNA DISK///////////////
/obj/item/weapon/disk/disease
name = "blank GNA disk"
desc = "A disk for storing the structure of a pathogen's Glycol Nucleic Acid pertaining to a specific symptom."
icon = 'icons/obj/datadisks.dmi'
icon_state = "disk_virus"
var/datum/disease2/effect/effect = null
var/stage = 1
/obj/item/weapon/disk/disease/premade/New()
name = "blank GNA disk (stage: [stage])"
effect = new /datum/disease2/effect
/obj/item/weapon/disk/disease/examine(var/mob/user)
..()
if(effect)
to_chat(user, "Strength: [effect.multiplier]")
to_chat(user, "Occurrence: [effect.chance]")
/////////////TRAITOR STUFF//////////////////
/obj/item/weapon/storage/lockbox/diskettebox/syndisease/New()
..()
new /obj/item/weapon/disk/disease/invisible(src)
new /obj/item/weapon/disk/disease/spoof/premade(src)
var/list/potential_deadly_symptoms = list()
for (var/diseasetype in subtypesof(/datum/disease2/effect))
var/datum/disease2/effect/E = diseasetype
if (initial(E.restricted))
continue
if (initial(E.stage) == 4 && initial(E.badness) == EFFECT_DANGER_DEADLY)
potential_deadly_symptoms += diseasetype
for(var/i = 1 to 3)
if (potential_deadly_symptoms.len < 1)
break
var/obj/item/weapon/disk/disease/syndisk = new(src)
var/effect_type = pick(potential_deadly_symptoms)
syndisk.effect = new effect_type()
syndisk.name = "\improper [syndisk.effect.name] GNA disk (Stage: [syndisk.effect.stage])"
syndisk.stage = syndisk.effect.stage
potential_deadly_symptoms -= effect_type
update_icon()
/obj/item/weapon/disk/disease/spoof
desc = "A disk for storing the structure of a pathogen's Glycol Nucleic Acid pertaining to a specific symptom. This one has some strange wiring on its back."
/obj/item/weapon/disk/disease/spoof/premade/New()
..()
var/list/potential_nice_symptoms = list()
for (var/diseasetype in subtypesof(/datum/disease2/effect))
var/datum/disease2/effect/E = diseasetype
if (initial(E.restricted))
continue
if (initial(E.stage) == 4 && initial(E.badness) <= EFFECT_DANGER_FLAVOR)
potential_nice_symptoms += diseasetype
if (potential_nice_symptoms.len < 1)
return
var/effect_type = pick(potential_nice_symptoms)
effect = new effect_type()
name = "\improper [effect.name] GNA disk (Stage: [effect.stage])"
stage = effect.stage
/obj/item/weapon/disk/disease/spoof/afterattack(atom/target as mob|obj|turf|area, mob/user as mob)
if(istype(target,/obj/item/weapon/disk/disease))
var/obj/item/weapon/disk/disease/D = target
effect = D.effect
to_chat(user,"Effect copied.")
name = "\improper [D.effect.name] GNA disk (Stage: [D.effect.stage])"
stage = D.effect.stage
effect.spoof = 1
/obj/item/weapon/disk/disease/invisible
name = "\improper Waiting Syndrome GNA disk (Stage 1)"
effect = new /datum/disease2/effect/invisible
stage = 1
/obj/item/weapon/disk/disease/zombie
name = "\improper Stubborn Brain Syndrome GNA disk (Stage 4)"
effect = new /datum/disease2/effect/zombie
stage = 4