diff --git a/code/datums/diseases/gastrolisis.dm b/code/datums/diseases/gastrolisis.dm index 9f1ba1be626d..051bb85838a5 100644 --- a/code/datums/diseases/gastrolisis.dm +++ b/code/datums/diseases/gastrolisis.dm @@ -66,7 +66,7 @@ if(isopenturf(OT)) OT.MakeSlippery(TURF_WET_LUBE, 100) -/datum/disease/gastrolosis/cure() +/datum/disease/gastrolosis/cure(add_resistance = TRUE) . = ..() if(!is_species(affected_mob, /datum/species/snail)) //undo all the snail fuckening var/mob/living/carbon/human/H = affected_mob diff --git a/code/datums/diseases/parrotpossession.dm b/code/datums/diseases/parrotpossession.dm index 0715a7748dd3..988cc360b97e 100644 --- a/code/datums/diseases/parrotpossession.dm +++ b/code/datums/diseases/parrotpossession.dm @@ -23,7 +23,7 @@ if(parrot.speech_buffer.len) affected_mob.say(pick(parrot.speech_buffer), forced = "parrot possession") -/datum/disease/parrot_possession/cure() +/datum/disease/parrot_possession/cure(add_resistance = TRUE) if(parrot && parrot.loc == affected_mob) parrot.forceMove(affected_mob.drop_location()) affected_mob.visible_message(span_danger("[parrot] is violently driven out of [affected_mob]!"), span_userdanger("[parrot] bursts out of your chest!")) diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm index 5f1c86f4260e..9e80c87252fd 100644 --- a/code/datums/diseases/transformation.dm +++ b/code/datums/diseases/transformation.dm @@ -138,7 +138,7 @@ if(prob(3)) affected_mob.say(pick("Eeek, ook ook!", "Eee-eeek!", "Eeee!", "Ungh, ungh."), forced = "jungle fever") -/datum/disease/transformation/jungle_fever/cure() +/datum/disease/transformation/jungle_fever/cure(add_resistance = TRUE) remove_monkey(affected_mob.mind) ..() @@ -147,7 +147,7 @@ disease_flags = CAN_CARRY //no vaccines! no cure! cure_text = "Clown's Tears." cures = list(/datum/reagent/consumable/clownstears) - + /datum/disease/transformation/jungle_fever/monkeymode/after_add() if(affected_mob && !is_monkey_leader(affected_mob.mind)) visibility_flags = NONE @@ -286,7 +286,7 @@ stage5 = list(span_danger("You have become a morph.")) new_form = /mob/living/simple_animal/hostile/morph infectable_biotypes = list(MOB_ORGANIC, MOB_INORGANIC, MOB_UNDEAD) //magic! - + /datum/disease/transformation/ghost name = "Spectral Curse" cure_text = "Holy Water" diff --git a/code/game/objects/items/sentient_disease_injector.dm b/code/game/objects/items/sentient_disease_injector.dm new file mode 100644 index 000000000000..b3a06026c280 --- /dev/null +++ b/code/game/objects/items/sentient_disease_injector.dm @@ -0,0 +1,172 @@ +/obj/item/sentient_disease_injector + name = "\improper CVS recipient injector" + desc = "It doesn't look like it prints receipts..." + + icon = 'yogstation/icons/obj/syringe.dmi' + icon_state = "cvs" + + var/uses = 3 + + var/obj/item/reagent_containers/glass/bottle/vial/stored_vial + + resistance_flags = ACID_PROOF + slot_flags = ITEM_SLOT_BELT + +/obj/item/sentient_disease_injector/Initialize() + . = ..() + update_icon() + +/obj/item/sentient_disease_injector/update_icon() + + . = ..() + + cut_overlays() + + if(uses > 0) + add_overlay( + image( + icon = icon, + icon_state = "[icon_state]_virus[min(uses,3)]" + ) + ) + + if(stored_vial) + if(stored_vial.reagents.total_volume > 0) + var/mutable_appearance/filling = mutable_appearance(icon,"[icon_state]_reagents") + filling.color = mix_color_from_reagents(stored_vial.reagents.reagent_list) + add_overlay(filling) + add_overlay( + image( + icon = icon, + icon_state = "[icon_state]_vial]" + ) + ) + +/obj/item/sentient_disease_injector/examine(mob/user) + . = ..() + if(stored_vial) + . += span_notice("It has a [stored_vial] inserted.") + if(uses > 0) + . += span_notice("It has [uses] [uses == 1 ? "use" : "uses"] remaining.") + else + . += span_notice("It is spent.") + +/obj/item/sentient_disease_injector/attackby(obj/item/I, mob/user, params) + + if(!istype(I,/obj/item/reagent_containers)) + return ..() //Something else. + + if(stored_vial) //Already exists. + to_chat(user, span_warning("There is already \a [stored_vial] inside.")) + return + + if(!istype(I, /obj/item/reagent_containers/glass/bottle/vial)) + to_chat(user, span_warning("\The [stored_vial] won't fit inside.")) + return + + var/datum/reagent/R = I.reagents.get_master_reagent() + + if(!R) + to_chat(user, span_warning("\The [I] is empty!")) + return + + if(!length(R.data) || !length(R.data["viruses"])) + to_chat(user, span_warning("\The [src] can't seem to detect any viruses inside \the [I]...")) + return + + stored_vial = I + stored_vial.forceMove(src) + + to_chat(user, span_notice("You insert \the [I] into \the [src].")) + + update_icon() + + return TRUE + +/obj/item/sentient_disease_injector/attack_self(mob/user) + + if(!stored_vial) + return + + stored_vial.forceMove(user.loc) + user.put_in_hands(stored_vial) + to_chat(user, span_notice("You eject \the [stored_vial] from \the [src].")) + stored_vial = null + + update_icon() + + return TRUE + +/obj/item/sentient_disease_injector/attack(obj/item/I, mob/user, params) + return //Prevents damage. + +/obj/item/sentient_disease_injector/afterattack(atom/target, mob/user, proximity) + + if(!proximity || !iscarbon(target)) + return ..() + + if(uses <= 0) + to_chat(user, span_warning("\The [src] is spent!")) + return + + var/mob/living/carbon/C = target + + if(!C.can_inject(user, 1, user.zone_selected, TRUE)) + to_chat(user, span_warning("You can't seem to inject \the [C] that way!")) + + if(ishuman(C)) + var/obj/item/bodypart/affecting = C.get_bodypart(check_zone(user.zone_selected)) + if(!affecting) + to_chat(user, span_warning("\The [src] can't inject a missing limb!")) + return + if(affecting.status != BODYPART_ORGANIC) + to_chat(user, span_warning("\The [src] won't work on a robotic limb!")) + return + + to_chat(user, span_notice("You stealthily inject \the [C] with \the [src].")) + + uses -= 1 + + for(var/datum/disease/D as anything in C.diseases) //Cure all existing diseases + D.cure(add_resistance = FALSE) + + if(stored_vial && stored_vial.reagents.total_volume) //If there is a stored vial, inject. + var/list/injected = list() + for(var/datum/reagent/R as anything in stored_vial.reagents.reagent_list) + injected += R.name + log_combat(user, C, "attempted to inject", src, "([english_list(injected)])") + stored_vial.reagents.reaction(C, INJECT, 1) + stored_vial.reagents.trans_to(C, stored_vial.reagents.total_volume, transfered_by = user) + else + log_combat(user, C, "attempted to inject", src) + + if(length(C.diseases)) + INVOKE_ASYNC(src, PROC_REF(create_sentient_virus), target, user) + + update_icon() + + return TRUE + +/obj/item/sentient_disease_injector/Destroy() + QDEL_NULL(stored_vial) + . = ..() + +/obj/item/sentient_disease_injector/proc/create_sentient_virus(mob/living/carbon/target,mob/user) + + var/list/candidates = pollGhostCandidates("Do you wish to be considered for the special role of 'custom sentient disease'?", ROLE_ALIEN, null, ROLE_ALIEN) + if(!length(candidates)) + return FALSE //No candidates. + + var/mob/dead/observer/selected = pick_n_take(candidates) + var/mob/camera/disease/virus = new/mob/camera/disease(get_turf(target)) + virus.key = selected.key + message_admins("[ADMIN_LOOKUPFLW(virus)] has been made into a sentient disease by [ADMIN_LOOKUPFLW(usr)]'s [src].") + log_game("[key_name(virus)] was spawned as a sentient disease by [ADMIN_LOOKUPFLW(usr)]'s [src].") + //Mix and cure all existing diseases. + for(var/datum/disease/D as anything in target.diseases) + if(D == virus) + continue + virus.disease_template.Mix(D) + D.cure(add_resistance = FALSE) + + return virus.force_infect(target) diff --git a/code/modules/antagonists/revenant/revenant_blight.dm b/code/modules/antagonists/revenant/revenant_blight.dm index 05e972caeaa9..bdc958fdc707 100644 --- a/code/modules/antagonists/revenant/revenant_blight.dm +++ b/code/modules/antagonists/revenant/revenant_blight.dm @@ -15,7 +15,7 @@ var/stagedamage = 0 //Highest stage reached. var/finalstage = 0 //Because we're spawning off the cure in the final stage, we need to check if we've done the final stage's effects. -/datum/disease/revblight/cure() +/datum/disease/revblight/cure(add_resistance = TRUE) if(affected_mob) affected_mob.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, "#1d2953") if(affected_mob.dna && affected_mob.dna.species) diff --git a/yogstation.dme b/yogstation.dme index 2afe45aa9dd8..8e8d08383aab 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -1099,6 +1099,7 @@ #include "code\game\objects\items\RPD.dm" #include "code\game\objects\items\RSF.dm" #include "code\game\objects\items\scrolls.dm" +#include "code\game\objects\items\sentient_disease_injector.dm" #include "code\game\objects\items\sharpener.dm" #include "code\game\objects\items\shields.dm" #include "code\game\objects\items\shooting_range.dm" diff --git a/yogstation/code/modules/uplink/uplink_item.dm b/yogstation/code/modules/uplink/uplink_item.dm index 7294f8940c10..92d94f43e470 100644 --- a/yogstation/code/modules/uplink/uplink_item.dm +++ b/yogstation/code/modules/uplink/uplink_item.dm @@ -28,6 +28,18 @@ category = "Conspicuous Weapons" include_objectives = list(/datum/objective/hijack, /datum/objective/martyr, /datum/objective/nuclear) +/datum/uplink_item/stealthy_weapons/sentient_disease_injector + name = "CVS recipient injector" + desc = "The Contagion Viral Supplementor injector is a state of the art Syndicate hyposyringe that can inject the target with a \ + sentient virus. A vial can be inserted with a virus sample to give that sentient virus those symptoms. Single use. Doesn't come with a miniprinter." + item = /obj/item/sentient_disease_injector + cost = 20 + surplus = 0 //Hijack-only, don't let this exist in surplus + cant_discount = TRUE + include_objectives = list(/datum/objective/hijack) //Hijack only. + exclude_modes = list(/datum/game_mode/infiltration) // yogs: infiltration + restricted_roles = list("Virologist","Chief Medical Officer") + /datum/uplink_item/stealthy_weapons/soap_clusterbang category = "Conspicuous Weapons" diff --git a/yogstation/icons/obj/syringe.dmi b/yogstation/icons/obj/syringe.dmi index 04d67369d352..036f1bcc9749 100644 Binary files a/yogstation/icons/obj/syringe.dmi and b/yogstation/icons/obj/syringe.dmi differ