From 0db705d678c439189fc55915847b78502560f681 Mon Sep 17 00:00:00 2001 From: Cody Brittain Date: Sun, 24 Sep 2023 18:41:02 -0400 Subject: [PATCH] Implant Improvements (#16905) * Modernize and improve implant code * Lint fix * Fix initialize hint in implant cases * fix tabulations --------- Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> --- aurorastation.dme | 18 +- code/__defines/_macros.dm | 1 + code/_onclick/hud/action.dm | 26 + code/datums/mind.dm | 2 +- code/datums/uplink/implants.dm | 13 +- code/game/machinery/body_scanner.dm | 13 +- code/game/machinery/cloning.dm | 17 - .../items/devices/uplink_random_lists.dm | 2 +- .../objects/items/weapons/implants/implant.dm | 793 ++---------------- .../items/weapons/implants/implantcase.dm | 223 ++--- .../items/weapons/implants/implanter.dm | 144 +--- .../items/weapons/implants/implantfreedom.dm | 74 -- .../items/weapons/implants/implantpad.dm | 40 +- .../weapons/implants/implants/adrenaline.dm | 41 + .../weapons/implants/implants/aggression.dm | 67 ++ .../weapons/implants/implants/anti-augment.dm | 44 + .../items/weapons/implants/implants/chem.dm | 84 ++ .../circuit.dm} | 3 +- .../implants/implants/compressed_matter.dm | 69 ++ .../weapons/implants/implants/death_alarm.dm | 83 ++ .../items/weapons/implants/implants/emp.dm | 23 + .../weapons/implants/implants/explosive.dm | 320 +++++++ .../weapons/implants/implants/freedom.dm | 77 ++ .../implants/implants/health_tracker.dm | 22 + .../weapons/implants/implants/loyalty.dm | 104 +++ .../weapons/implants/implants/mindshield.dm | 75 ++ .../weapons/implants/implants/tracking.dm | 70 ++ .../{implantuplink.dm => implants/uplink.dm} | 9 + .../objects/items/weapons/storage/boxes.dm | 3 +- .../objects/items/weapons/storage/lockbox.dm | 4 +- .../items/weapons/storage/uplink_kits.dm | 19 +- .../objects/items/weapons/teleportation.dm | 4 +- code/modules/awaymissions/exile.dm | 2 +- code/modules/customitems/item_defines.dm | 2 +- code/modules/mob/living/carbon/human/life.dm | 6 +- .../programs/command/teleporter.dm | 2 +- .../designs/protolathe/implant_designs.dm | 14 +- code/modules/surgery/encased.dm | 3 + code/modules/surgery/generic.dm | 6 +- code/modules/surgery/implant.dm | 2 +- code/stylesheet.dm | 1 + html/changelogs/GeneralCamo - Implant.yml | 50 ++ icons/obj/action_buttons/implants.dmi | Bin 0 -> 9593 bytes icons/obj/item/implants.dmi | Bin 0 -> 2751 bytes icons/obj/item/reagent_containers/syringe.dmi | Bin 17897 -> 15092 bytes 45 files changed, 1445 insertions(+), 1130 deletions(-) delete mode 100644 code/game/objects/items/weapons/implants/implantfreedom.dm create mode 100644 code/game/objects/items/weapons/implants/implants/adrenaline.dm create mode 100644 code/game/objects/items/weapons/implants/implants/aggression.dm create mode 100644 code/game/objects/items/weapons/implants/implants/anti-augment.dm create mode 100644 code/game/objects/items/weapons/implants/implants/chem.dm rename code/game/objects/items/weapons/implants/{implantcircuits.dm => implants/circuit.dm} (96%) create mode 100644 code/game/objects/items/weapons/implants/implants/compressed_matter.dm create mode 100644 code/game/objects/items/weapons/implants/implants/death_alarm.dm create mode 100644 code/game/objects/items/weapons/implants/implants/emp.dm create mode 100644 code/game/objects/items/weapons/implants/implants/explosive.dm create mode 100644 code/game/objects/items/weapons/implants/implants/freedom.dm create mode 100644 code/game/objects/items/weapons/implants/implants/health_tracker.dm create mode 100644 code/game/objects/items/weapons/implants/implants/loyalty.dm create mode 100644 code/game/objects/items/weapons/implants/implants/mindshield.dm create mode 100644 code/game/objects/items/weapons/implants/implants/tracking.dm rename code/game/objects/items/weapons/implants/{implantuplink.dm => implants/uplink.dm} (86%) create mode 100644 html/changelogs/GeneralCamo - Implant.yml create mode 100644 icons/obj/action_buttons/implants.dmi create mode 100644 icons/obj/item/implants.dmi diff --git a/aurorastation.dme b/aurorastation.dme index 78288be2a19..0f7cec43c83 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -1133,11 +1133,23 @@ #include "code\game\objects\items\weapons\grenades\spawnergrenade.dm" #include "code\game\objects\items\weapons\implants\implant.dm" #include "code\game\objects\items\weapons\implants\implantcase.dm" -#include "code\game\objects\items\weapons\implants\implantcircuits.dm" #include "code\game\objects\items\weapons\implants\implanter.dm" -#include "code\game\objects\items\weapons\implants\implantfreedom.dm" #include "code\game\objects\items\weapons\implants\implantpad.dm" -#include "code\game\objects\items\weapons\implants\implantuplink.dm" +#include "code\game\objects\items\weapons\implants\implants\adrenaline.dm" +#include "code\game\objects\items\weapons\implants\implants\aggression.dm" +#include "code\game\objects\items\weapons\implants\implants\anti-augment.dm" +#include "code\game\objects\items\weapons\implants\implants\chem.dm" +#include "code\game\objects\items\weapons\implants\implants\circuit.dm" +#include "code\game\objects\items\weapons\implants\implants\compressed_matter.dm" +#include "code\game\objects\items\weapons\implants\implants\death_alarm.dm" +#include "code\game\objects\items\weapons\implants\implants\emp.dm" +#include "code\game\objects\items\weapons\implants\implants\explosive.dm" +#include "code\game\objects\items\weapons\implants\implants\freedom.dm" +#include "code\game\objects\items\weapons\implants\implants\health_tracker.dm" +#include "code\game\objects\items\weapons\implants\implants\loyalty.dm" +#include "code\game\objects\items\weapons\implants\implants\mindshield.dm" +#include "code\game\objects\items\weapons\implants\implants\tracking.dm" +#include "code\game\objects\items\weapons\implants\implants\uplink.dm" #include "code\game\objects\items\weapons\material\ashtray.dm" #include "code\game\objects\items\weapons\material\bats.dm" #include "code\game\objects\items\weapons\material\caltrops.dm" diff --git a/code/__defines/_macros.dm b/code/__defines/_macros.dm index 4e69dac1985..62c88d2a9f8 100644 --- a/code/__defines/_macros.dm +++ b/code/__defines/_macros.dm @@ -21,6 +21,7 @@ #define SPAN_SUBTLE(X) ("" + X + "") #define SPAN_SOGHUN(X) ("" + X + "") #define SPAN_VOTE(X) ("" + X + "") +#define SPAN_HEAR(X) ("" + X + "") #define SPAN_SIZE(size, text) ("" + text + "") diff --git a/code/_onclick/hud/action.dm b/code/_onclick/hud/action.dm index acba5cca978..2c7a2b09f53 100644 --- a/code/_onclick/hud/action.dm +++ b/code/_onclick/hud/action.dm @@ -228,6 +228,32 @@ /datum/action/item_action/hands_free check_flags = AB_CHECK_ALIVE|AB_CHECK_INSIDE +/datum/action/item_action/hands_free/activate + name = "Activate" + +/datum/action/item_action/hands_free/activate/implant + action_type = AB_ITEM_USE_ICON + button_icon = 'icons/obj/action_buttons/implants.dmi' + button_icon_state = "default" + +/datum/action/item_action/hands_free/activate/implant/adrenaline + button_icon_state = "adrenal" + +/datum/action/item_action/hands_free/activate/implant/chemical + button_icon_state = "reagents" + +/datum/action/item_action/hands_free/activate/implant/compressed + button_icon_state = "storage" + +/datum/action/item_action/hands_free/activate/implant/emp + button_icon_state = "emp" + +/datum/action/item_action/hands_free/activate/implant/explosive + button_icon_state = "explosive" + +/datum/action/item_action/hands_free/activate/implant/freedom + button_icon_state = "freedom" + /datum/action/item_action/organ action_type = AB_ITEM_USE_ICON button_icon = 'icons/obj/action_buttons/organs.dmi' diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 22531ab2c27..8248b6c5434 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -358,7 +358,7 @@ switch(href_list["implant"]) if("remove") - for(var/obj/item/implant/mindshield/I in H.contents) + for(var/obj/item/implant/mindshield/loyalty/I in H.contents) for(var/obj/item/organ/external/organs in H.organs) if(I in organs.implants) qdel(I) diff --git a/code/datums/uplink/implants.dm b/code/datums/uplink/implants.dm index 14300bef4d3..26abc434bd3 100644 --- a/code/datums/uplink/implants.dm +++ b/code/datums/uplink/implants.dm @@ -7,18 +7,19 @@ /datum/uplink_item/item/implants/imp_freedom name = "Freedom Implant" telecrystal_cost = 1 + desc = "A box containing a freedom implant case and implanter." path = /obj/item/storage/box/syndie_kit/imp_freedom -/datum/uplink_item/item/implants/imp_compress - name = "Compressed Matter Implant" - desc = "A box containing a single implanter and matter cartridge. To remove an unintended target, use the implanter in-hand then open the cartridge with a screwdriver." - bluecrystal_cost = 1 - path = /obj/item/storage/box/syndie_kit/imp_compress +/datum/uplink_item/item/implants/imp_emp + name = "EMP Implant" + telecrystal_cost = 1 + desc = "A box containing an EMP implant case and implanter." + path = /obj/item/storage/box/syndie_kit/imp_emp /datum/uplink_item/item/implants/imp_explosive name = "Explosive Implant (DANGER!)" bluecrystal_cost = 3 - desc = "A box containing an explosive implant and implanter. Use the implant in-hand to set the explosion size and trigger phrase." + desc = "A box containing an explosive implant case and implanter. Use the implant case with the implant pad to set the explosion size, trigger phrase, and trigger code." path = /obj/item/storage/box/syndie_kit/imp_explosive /datum/uplink_item/item/implants/imp_deadman diff --git a/code/game/machinery/body_scanner.dm b/code/game/machinery/body_scanner.dm index 85f14d6089b..d1f1860a84f 100644 --- a/code/game/machinery/body_scanner.dm +++ b/code/game/machinery/body_scanner.dm @@ -736,9 +736,16 @@ if (e.implants.len) var/unk = 0 var/list/organic = list() - for(var/atom/movable/I in e.implants) - if(is_type_in_list(I, known_implants)) - wounds += "\a [I.name] implanted:" + var/imp + for(var/I in e.implants) + if(istype(I, /obj/item/implant)) + var/obj/item/implant/A = I + if (A.hidden) + return + else if(A.known) + imp += "[I] implanted:" + else + unk += 1 else if(istype(I, /obj/effect/spider)) organic += I else diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 627b7c42884..2ca6594e149 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -376,23 +376,6 @@ else if (mess) icon_state = "pod_g" -//Health Tracker Implant - -/obj/item/implant/health - name = "health implant" - var/healthstring = "" - -/obj/item/implant/health/proc/sensehealth() - if(!implanted) - return "ERROR" - else - if(isliving(implanted)) - var/mob/living/L = implanted - healthstring = "[round(L.getOxyLoss())] - [round(L.getFireLoss())] - [round(L.getToxLoss())] - [round(L.getBruteLoss())]" - if(!healthstring) - healthstring = "ERROR" - return healthstring - //Disk stuff. //The return of data disks?? Just for transferring between genetics machine/cloning machine. //TO-DO: Make the genetics machine accept them. diff --git a/code/game/objects/items/devices/uplink_random_lists.dm b/code/game/objects/items/devices/uplink_random_lists.dm index 1089a4f81cb..af954589f94 100644 --- a/code/game/objects/items/devices/uplink_random_lists.dm +++ b/code/game/objects/items/devices/uplink_random_lists.dm @@ -70,7 +70,7 @@ var/datum/uplink_random_selection/default_uplink_selection = new/datum/uplink_ra items += new/datum/uplink_random_item(/datum/uplink_item/item/tools/ai_module, 25, 0) items += new/datum/uplink_random_item(/datum/uplink_item/item/implants/imp_freedom) - items += new/datum/uplink_random_item(/datum/uplink_item/item/implants/imp_compress) + items += new/datum/uplink_random_item(/datum/uplink_item/item/implants/imp_emp) items += new/datum/uplink_random_item(/datum/uplink_item/item/implants/imp_explosive) items += new/datum/uplink_random_item(/datum/uplink_item/item/medical/sinpockets, reselect_propbability = 20) diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index 3891f3b8244..6118816a08c 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -3,44 +3,120 @@ /obj/item/implant + abstract_type = /obj/item/implant name = "implant" - icon = 'icons/obj/device.dmi' - icon_state = "implant" + icon = 'icons/obj/item/implants.dmi' w_class = ITEMSIZE_TINY + /** + * This gives the user an action button that allows them to activate the implant. + * If the implant needs no action button, then null this out. + * Or, if you want to add a unique action button, then replace this. + */ + default_action_type = /datum/action/item_action/hands_free/activate/implant + action_button_name = "Activate Implant" var/implanted = null + ///The mob that has been implanted with this var/mob/imp_in = null + ///The organ/limb that has been implanted with this var/obj/item/organ/external/part = null - var/implant_color = "b" - var/allow_reagents = 0 + ///Implant icon name, used for getting the name of the implant for usage in the implant case name. + var/implant_icon = null + ///Implant color, used for overlaying the implant into an implanter. + var/implant_color = null var/malfunction = 0 + ///If advanced scanners would name these in results + var/known + ///If scanners can locate this implant at all + var/hidden /obj/item/implant/Initialize() . = ..() implants += src -/obj/item/implant/proc/trigger(emote, source as mob) +/obj/item/implant/proc/trigger(emote, source) + return + +/obj/item/implant/ui_action_click() + INVOKE_ASYNC(src, PROC_REF(activate), "action_button") + +/obj/item/implant/item_action_slot_check(slot, mob/user) + return user = imp_in + +/obj/item/implant/proc/hear(message) return /obj/item/implant/proc/activate() return - // What does the implant do upon injection? - // return 0 if the implant fails (ex. Revhead and loyalty implant.) - // return 1 if the implant succeeds (ex. Nonrevhead and loyalty implant.) -/obj/item/implant/proc/implanted(var/mob/source, mob/user) - return 1 +/** + * What does the implant do upon injection? + * return FALSE if the implant fails (ex. Revhead and loyalty implant.) + * return TRUE if the implant succeeds (ex. Nonrevhead and loyalty implant.) +*/ +/obj/item/implant/proc/implanted(mob/source) + return TRUE +/obj/item/implant/proc/canImplant(mob/M, mob/user, target_zone) + var/mob/living/carbon/human/H = M + if(istype(H) && !H.get_organ(target_zone)) + to_chat(user, SPAN_WARNING("\The [M] is missing that body part!")) + return FALSE + return TRUE + +/obj/item/implant/proc/implantInMob(mob/M, target_zone) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/affected = H.get_organ(target_zone) + if(affected) + affected.implants += src + part = affected + + forceMove(M) + imp_in = M + implanted = TRUE + implanted(M) + + return TRUE + +///Remove implant from mob. +/obj/item/implant/proc/removed() + imp_in = null + if(part) + part.implants -= src + part = null + implanted = FALSE + +///Called in surgery when incision is retracted open / ribs are opened - basically before you can take the implant out +/obj/item/implant/proc/exposed() + return + +///Get implant specifications for the implant pad /obj/item/implant/proc/get_data() return "No information available" -/obj/item/implant/proc/hear(message, source as mob) - return +/obj/item/implant/interact(user) + var/datum/browser/popup = new(user, capitalize(name), capitalize(name), 300, 700, src) + var/dat = "Implant Mini-Computer:
" + dat += get_data() + if(malfunction) + popup.title = "??? Implant" + dat = stars(dat,10) + popup.set_content(dat) + popup.open() -/obj/item/implant/proc/islegal() - return 0 +/** + * Determines if the implant is known as a legal implant or not. + * + * If TRUE, increases the chance of removal during surgery + */ +/obj/item/implant/proc/isLegal() + return FALSE -/obj/item/implant/proc/meltdown() //breaks it down, making implant unrecongizible - to_chat(imp_in, "You feel something melting inside [part ? "your [part.name]" : "you"]!") +///Breaks the implant down, making it unrecognizable +/obj/item/implant/proc/meltdown() + if(malfunction == MALFUNCTION_PERMANENT) + return + to_chat(imp_in, SPAN_DANGER("You feel something melting inside [part ? "your [part.name]" : "you"]!")) if (part) part.take_damage(burn = 15, used_weapon = "Electronics meltdown") else @@ -59,690 +135,5 @@ implants -= src return ..() -/obj/item/implant/proc/removed() - imp_in = null - if(part) - part.implants -= src - part = null - implanted = 0 - -/obj/item/implant/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/implanter)) - var/obj/item/implanter/implanter = I - if(implanter.imp) - to_chat(user, SPAN_NOTICE("\The [implanter] already has an implant loaded.")) - return // It's full. - user.drop_from_inventory(src) - forceMove(implanter) - implanter.imp = src - implanter.update() - else - ..() - -/obj/item/implant/tracking - name = "tracking implant" - desc = "Track with this." - var/id = 1.0 - -/obj/item/implant/tracking/Initialize() - var/list/tracking_list = list() - for(var/obj/item/implant/tracking/T in implants) - tracking_list += T - id = length(tracking_list) + 1 - . = ..() - -/obj/item/implant/tracking/get_data() - . = {"Implant Specifications:
-Name: Tracking Beacon
-Life: 10 minutes after death of host
-Important Notes: None
-
-Implant Details:
-Function: Continuously transmits low power signal. Useful for tracking.
-Special Features:
-Neuro-Safe- Specialized shell absorbs excess voltages self-destructing the chip if -a malfunction occurs thereby securing safety of subject. The implant will melt and -disintegrate into bio-safe elements.
-Integrity: Gradient creates slight risk of being overcharged and frying the -circuitry. As a result neurotoxins can cause massive damage.
-Implant Specifics:
"} - -/obj/item/implant/tracking/emp_act(severity) - if (malfunction) //no, dawg, you can't malfunction while you are malfunctioning - return - malfunction = MALFUNCTION_TEMPORARY - - var/delay = 20 - switch(severity) - if(1) - if(prob(60)) - meltdown() - if(2) - delay = rand(5*60*10,15*60*10) //from 5 to 15 minutes of free time - - spawn(delay) - malfunction-- - -//BS12 Explosive -/obj/item/implant/explosive - name = "explosive implant" - desc = "A military grade micro bio-explosive. Highly dangerous." - var/elevel = "Localized Limb" - var/phrase - var/setup_done = FALSE //Have we set this yet? - var/uses_codewords = TRUE - var/list/possible_explosions = list("Localized Limb", "Destroy Body") - icon_state = "implant_evil" - -/obj/item/implant/explosive/Initialize() - . = ..() - if(uses_codewords) - phrase = "You are [pick(adjectives)]" - -/obj/item/implant/explosive/get_data() - . = {" -Implant Specifications:
-Name: Robust Corp RX-78 Intimidation Class Implant
-Life: Activates upon codephrase.
-Important Notes: Explodes
-
-Implant Details:
-Function: Contains a compact, electrically detonated explosive that detonates upon receiving a specially encoded signal or upon host death.
-Special Features: Explodes. Explosion severity can be altered.
-Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} - -/obj/item/implant/explosive/attackby(obj/item/I, mob/user) - if(uses_codewords) - if(istype(I, /obj/item/implanter)) - var/obj/item/implanter/implanter = I - if(implanter.imp) - to_chat(user, SPAN_NOTICE("\The [implanter] already has an implant loaded.")) - return // It's full. - if(!setup_done) - var/choice = alert("\The [src]'s default settings have not been changed. Continue?", "Ready for Implantation?", "Yes", "Cancel") - if(choice == "Cancel") - return - to_chat(user, "You load \the [src] into \the [I]. The current setting is \"[elevel]\" and the current phrase is \"[phrase]\".") - user.drop_from_inventory(src) - forceMove(implanter) - implanter.imp = src - implanter.update() - else - ..() - -/obj/item/implant/explosive/hear_talk(mob/M, msg) - hear(msg) - -/obj/item/implant/explosive/hear(var/msg) - var/list/replacechars = list("\"" = "",">" = "","<" = "","(" = "",")" = "") - msg = replace_characters(msg, replacechars) - if(findtext(msg,phrase)) - activate() - -/obj/item/implant/explosive/activate() - if(malfunction == MALFUNCTION_PERMANENT) - return - - if(!imp_in) - small_countdown() - return - - message_admins("Explosive implant triggered in [imp_in] ([imp_in.key]). (JMP) ") - log_game("Explosive implant triggered in [imp_in] ([imp_in.key]).") - if(ishuman(imp_in)) - var/mob/living/carbon/human/T = imp_in - if(elevel == "Localized Limb" && part) - small_countdown() - return //to avoid hotspot_expose. - if(elevel == "Destroy Body") - explosion(get_turf(T), -1, 0, 2, 6) - T.gib() - if(elevel == "Full Explosion") - explosion_spread(get_turf(T), rand(8,13)) - T.gib() - else if(ismob(imp_in)) - var/mob/M = imp_in - M.gib() - - var/turf/F = get_turf(imp_in) - if(F) - F.hotspot_expose(3500,125) - qdel(src) - -/obj/item/implant/explosive/proc/small_countdown() - if(!imp_in) - visible_message(SPAN_WARNING("Something begins beeping...")) - if(ishuman(imp_in)) - var/message = "Something beeps inside of [imp_in][part ? "'s [part.name]" : ""]..." //for some reason SPAN_X and span() both hate having this in-line - imp_in.visible_message(SPAN_WARNING(message)) - else if(ismob(imp_in)) - imp_in.visible_message(SPAN_WARNING("Something beeps inside of [imp_in]...")) - playsound(loc, 'sound/items/countdown.ogg', 75, 1, -3) - addtimer(CALLBACK(src, PROC_REF(small_boom)), 25) - -/obj/item/implant/explosive/proc/small_boom() - if(!imp_in) - explosion(get_turf(src), -1, 0, 2, 4) - if(ishuman(imp_in) && part) - //No tearing off these parts since it's pretty much killing. Mangle them. - if(part.vital && !istype(part, /obj/item/organ/external/head)) //Head explodes - part.createwound(BRUISE, 70) - part.add_pain(50) - imp_in.visible_message(SPAN_WARNING("[imp_in]'s [part.name] bursts open with a horrible ripping noise!"), - SPAN_DANGER("Your [part.name] bursts open with a horrible ripping noise!"), - SPAN_WARNING("You hear a horrible ripping noise.")) - else - part.droplimb(0,DROPLIMB_BLUNT) - playsound(get_turf(imp_in), BP_IS_ROBOTIC(part) ? 'sound/effects/meteorimpact.ogg' : 'sound/effects/splat.ogg') - else if(ismob(imp_in)) - var/mob/M = imp_in - M.gib() //Simple mobs just get got - qdel(src) - -/proc/explosion_spread(turf/epicenter, power, adminlog = 1, z_transfer = UP|DOWN) - var/datum/explosiondata/data = new - data.epicenter = epicenter - data.rec_pow = power - data.spreading = TRUE - data.adminlog = adminlog - data.z_transfer = z_transfer - SSexplosives.queue(data) - -/obj/item/implant/explosive/implanted(mob/source, mob/user) - if(user.mind) - user.mind.store_memory("\The [src] in [source] can be activated by saying something containing the phrase ''[phrase]'', say [phrase] to attempt to activate.", 0, 0) - to_chat(usr, "\The [src] in [source] can be activated by saying something containing the phrase ''[phrase]'', say [phrase] to attempt to activate.") - return TRUE - -/obj/item/implant/explosive/attack_self(mob/user) - elevel = input(user, "What sort of explosion would you prefer?", "Implant Intent") as null|anything in possible_explosions - phrase = input("Choose activation phrase:") as text - var/list/replacechars = list("\"" = "",">" = "","<" = "","(" = "",")" = "") - phrase = replace_characters(phrase, replacechars) - user.mind.store_memory("\The [src] can be activated by saying something containing the phrase ''[phrase]'', say [phrase] to attempt to activate.", 0, 0) - to_chat(user, "\The [src] can be activated by saying something containing the phrase ''[phrase]'', say [phrase] to attempt to activate.") - setup_done = TRUE - -/obj/item/implant/explosive/emp_act(severity) - if(malfunction) - return - malfunction = MALFUNCTION_TEMPORARY - switch (severity) - if(2.0) //Weak EMP will make implant tear limbs off. - if(prob(50)) - small_countdown() - if(1.0) //strong EMP will melt implant either making it go off, or disarming it - if(prob(70)) - if(prob(50)) - small_countdown() - else - if(prob(50)) - activate() //50% chance of bye bye - else - meltdown() //50% chance of implant disarming - addtimer(CALLBACK(src, PROC_REF(self_correct)), 20) - -/obj/item/implant/explosive/proc/self_correct() - malfunction-- - -/obj/item/implant/explosive/islegal() - return FALSE - -/obj/item/implant/explosive/New() - ..() - become_hearing_sensitive(ROUNDSTART_TRAIT) - -/obj/item/implant/explosive/Destroy() - return ..() - -/obj/item/implant/explosive/full - possible_explosions = list("Localized Limb", "Destroy Body", "Full Explosion") - -/obj/item/implant/explosive/deadman - name = "deadman explosive" - desc = "A military grade micro bio-explosive that detonates upon death." - icon_state = "implant_evil" - uses_codewords = FALSE - -/obj/item/implant/explosive/deadman/get_data() - . = {" -Implant Specifications:
-Name: Robust Corp RX-78 Employee Management Implant
-Life: Activates upon death.
-Important Notes: Explodes
-
-Implant Details:
-Function: Contains a compact, electrically detonated explosive that detonates upon receiving a specially encoded signal or upon host death.
-Special Features: Explodes
-Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} - -/obj/item/implant/explosive/deadman/attack_self(mob/user) - return - -/obj/item/implant/explosive/deadman/hear(var/msg) - return - -/obj/item/implant/explosive/deadman/process() - if(malfunction) - STOP_PROCESSING(SSprocessing, src) - return - if (!implanted) - return - var/mob/M = imp_in - - if(M.stat == DEAD) - activate() - -/obj/item/implant/explosive/deadman/activate(var/cause) - small_countdown(src) - STOP_PROCESSING(SSprocessing, src) - -/obj/item/implant/explosive/deadman/small_boom() - if(imp_in) - explosion(get_turf(src), -1, 0, 1, 6) - imp_in.gib() - qdel(src) - -/obj/item/implant/explosive/deadman/implanted(mob/source) - START_PROCESSING(SSprocessing, src) - return TRUE - -/obj/item/implant/explosive/deadman/emp_act(severity) - if(malfunction) - return - malfunction = MALFUNCTION_TEMPORARY - switch (severity) - if(3.0) - if(prob(1)) - small_countdown() - else if(prob(5)) - meltdown() - if(2.0) - if(prob(5)) - small_countdown() - else if (prob(10)) - meltdown() - if(1.0) - if(prob(10)) - small_countdown() - else if (prob(30)) - meltdown() - -/obj/item/implant/chem - name = "chemical implant" - desc = "Injects things." - allow_reagents = 1 - -/obj/item/implant/chem/get_data() - . = {" -Implant Specifications:
-Name: Robust Corp MJ-420 Prisoner Management Implant
-Life: Deactivates upon death but remains within the body.
-Important Notes: Due to the system functioning off of nutrients in the implanted subject's body, the subject
-will suffer from an increased appetite.

-
-Implant Details:
-Function: Contains a small capsule that can contain various chemicals. Upon receiving a specially encoded signal
-the implant releases the chemicals directly into the blood stream.
-Special Features: -Micro-Capsule- Can be loaded with any sort of chemical agent via the common syringe and can hold 50 units.
-Can only be loaded while still in its original case.
-Integrity: Implant will last so long as the subject is alive. However, if the subject suffers from malnutrition,
-the implant may become unstable and either pre-maturely inject the subject or simply break."} - - -/obj/item/implant/chem/New() - ..() - var/datum/reagents/R = new/datum/reagents(50) - reagents = R - R.my_atom = src - - -/obj/item/implant/chem/trigger(emote, source as mob) - if(emote == "deathgasp") - src.activate(src.reagents.total_volume) - return - - -/obj/item/implant/chem/activate(var/cause) - if((!cause) || (!src.imp_in)) return 0 - var/mob/living/carbon/R = src.imp_in - src.reagents.trans_to_mob(R, cause, CHEM_BLOOD) - to_chat(R, "You hear a faint *beep*.") - if(!src.reagents.total_volume) - to_chat(R, "You hear a faint click from your chest.") - spawn(0) - qdel(src) - -/obj/item/implant/chem/emp_act(severity) - if (malfunction) - return - malfunction = MALFUNCTION_TEMPORARY - - switch(severity) - if(1) - if(prob(60)) - activate(20) - if(2) - if(prob(30)) - activate(5) - - spawn(20) - malfunction-- - -/obj/item/implant/mindshield - name = "mind shield implant" - desc = "A controversial and debatably unethical neurostimulator and autohypnosis device. When implanted against the amygdala, it ensures the host maintains a consistent personality, preventing outside interference through brainwashing or hypnotic suggestion." - -/obj/item/implant/mindshield/get_data() - . = {" -Implant Specifications:
-Name: [current_map.company_name] Employee Management Implant
-Life: Ten years.
-Important Notes: Personnel injected with this device tend to be much more resistant to brain washing and other external influences.
-
-Implant Details:
-Function: Contains a small pod of nanobots that manipulate the host's mental functions.
-Special Features: Will prevent and cure most forms of brainwashing.
-Integrity: Implant will last so long as the nanobots are inside the bloodstream."} - -/obj/item/implant/mindshield/emp_act(severity) - if (malfunction) - return - malfunction = MALFUNCTION_TEMPORARY - - activate("emp") - if(severity == 1) - if(prob(50)) - meltdown() - else if (prob(50)) - malfunction = MALFUNCTION_PERMANENT - return - spawn(20) - malfunction-- - -/obj/item/implant/mindshield/ipc - name = "software protection chip" - desc = "A dedicated processor core designed to identify and terminate malignant software, ensuring a synthetics protection from outside hacking." - -/obj/item/implant/mindshield/ipc/implanted(mob/M) - if (!isipc(M)) - return - - ..() - -/obj/item/implant/mindshield/sol - name = "loyalty implant" - desc = "Makes you loyal to the Sol Alliance, or to a certain individual." - -/obj/item/implant/mindshield/sol/implanted(mob/M) - if(!istype(M, /mob/living/carbon/human)) return 0 - var/mob/living/carbon/human/H = M - var/datum/antagonist/antag_data = get_antag_data(H.mind.special_role) - if(antag_data && (antag_data.flags & ANTAG_IMPLANT_IMMUNE)) - H.visible_message("[H] seems to resist the implant!", "You feel the tendrils of the Sol Alliance try to invade your mind!") - return 0 - else - clear_antag_roles(H.mind, 1) - to_chat(H, "You feel a surge of loyalty towards Admiral Michael Frost.") - return 1 - -/obj/item/implant/adrenalin - name = "adrenalin" - desc = "Removes all stuns and knockdowns." - var/uses - -/obj/item/implant/adrenalin/get_data() - . = {" -Implant Specifications:
-Name: Cybersun Industries Adrenalin Implant
-Life: Five days.
-Important Notes: Illegal
-
-Implant Details: Subjects injected with implant can activate a massive injection of adrenalin.
-Function: Contains nanobots to stimulate body to mass-produce Adrenalin.
-Special Features: Will prevent and cure most forms of brainwashing.
-Integrity: Implant can only be used three times before the nanobots are depleted."} - - -/obj/item/implant/adrenalin/trigger(emote, mob/source as mob) - if (src.uses < 1) - return 0 - if (emote == "pale") - src.uses-- - to_chat(source, "You feel a sudden surge of energy!") - source.SetStunned(0) - source.SetWeakened(0) - source.SetParalysis(0) - - -/obj/item/implant/adrenalin/implanted(mob/source) - source.mind.store_memory("A implant can be activated by using the pale emote, say *pale to attempt to activate.", 0, 0) - to_chat(source, "The implanted freedom implant can be activated by using the pale emote, say *pale to attempt to activate.") - return 1 - - -/obj/item/implant/death_alarm - name = "death alarm implant" - desc = "An alarm which monitors host vital signs and transmits a radio message upon death." - var/mobname = "Will Robinson" - -/obj/item/implant/death_alarm/get_data() - . = {" -Implant Specifications:
-Name: [current_map.company_name] \"Profit Margin\" Class Employee Lifesign Sensor
-Life: Activates upon death.
-Important Notes: Alerts crew to crewmember death.
-
-Implant Details:
-Function: Contains a compact radio signaler that triggers when the host's lifesigns cease.
-Special Features: Alerts crew to crewmember death.
-Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} - -/obj/item/implant/death_alarm/process() - if (!implanted) - return - var/mob/M = imp_in - - if(QDELETED(M)) // If the mob got gibbed - M = null - activate() - else if(M.stat == 2) - activate("death") - -/obj/item/implant/death_alarm/activate(var/cause) - var/mob/M = imp_in - var/area/t = get_area(M) - switch (cause) - if("death") - var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset(null) - if(istype(t, /area/antag) || istype(t, /area/shuttle/mercenary) || istype(t, /area/shuttle/syndicate_elite) ) - //give the syndies a bit of stealth - a.autosay("[mobname] has died in Space!", "[mobname]'s Death Alarm") - else - a.autosay("[mobname] has died in [t.name]!", "[mobname]'s Death Alarm") - qdel(a) - STOP_PROCESSING(SSprocessing, src) - if ("emp") - var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset(null) - var/name = prob(50) ? t.name : pick(the_station_areas) - a.autosay("[mobname] has died in [name]!", "[mobname]'s Death Alarm") - qdel(a) - else - var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset(null) - a.autosay("[mobname] has died-zzzzt in-in-in...", "[mobname]'s Death Alarm") - qdel(a) - STOP_PROCESSING(SSprocessing, src) - -/obj/item/implant/death_alarm/emp_act(severity) //for some reason alarms stop going off in case they are emp'd, even without this - if (malfunction) //so I'm just going to add a meltdown chance here - return - malfunction = MALFUNCTION_TEMPORARY - - activate("emp") //let's shout that this dude is dead - if(severity == 1) - if(prob(40)) //small chance of obvious meltdown - meltdown() - else if (prob(60)) //but more likely it will just quietly die - malfunction = MALFUNCTION_PERMANENT - STOP_PROCESSING(SSprocessing, src) - - spawn(20) - malfunction-- - -/obj/item/implant/death_alarm/implanted(mob/source as mob) - mobname = source.real_name - START_PROCESSING(SSprocessing, src) - return 1 - -/obj/item/implant/compressed - name = "compressed matter implant" - desc = "Based on compressed matter technology, can store a single item." - icon_state = "implant_evil" - var/activation_emote = "sigh" - var/obj/item/scanned = null - -/obj/item/implant/compressed/attackby(var/obj/item/T, mob/user) - if(T.isscrewdriver()) - if(!scanned) - to_chat(user, SPAN_NOTICE("There is nothing to remove from the implant.")) - else - to_chat(user, SPAN_NOTICE("You remove \the [scanned] from the implant.")) - user.put_in_hands(scanned) - scanned = null - if(istype(T, /obj/item/implanter)) - var/obj/item/implanter/implanter = T - if(implanter.imp) - to_chat(user, SPAN_NOTICE("\The [implanter] already has an implant loaded.")) - return - user.drop_from_inventory(src) - forceMove(implanter) - implanter.imp = src - implanter.update() - else - ..() - -/obj/item/implant/compressed/get_data() - . = {" -Implant Specifications:
-Name: [current_map.company_name] \"Profit Margin\" Class Employee Lifesign Sensor
-Life: Activates upon death.
-Important Notes: Alerts crew to crewmember death.
-
-Implant Details:
-Function: Contains a compact radio signaler that triggers when the host's lifesigns cease.
-Special Features: Alerts crew to crewmember death.
-Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} - -/obj/item/implant/compressed/trigger(emote, mob/source as mob) - if (src.scanned == null) - return 0 - - if (emote == src.activation_emote) - to_chat(source, "The air glows as \the [src.scanned.name] uncompresses.") - activate() - -/obj/item/implant/compressed/activate() - var/turf/t = get_turf(src) - if (imp_in) - imp_in.put_in_hands(scanned) - else - scanned.forceMove(t) - qdel(src) - -/obj/item/implant/compressed/implanted(mob/source as mob) - src.activation_emote = input("Choose activation emote:") in list("blink", "blink_r", "eyebrow", "chuckle", "twitch", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") - if (source.mind) - source.mind.store_memory("Compressed matter implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.", 0, 0) - to_chat(source, "The implanted compressed matter implant can be activated by using the [src.activation_emote] emote, say *[src.activation_emote] to attempt to activate.") - return 1 - -/obj/item/implant/compressed/islegal() - return 0 - -/obj/item/implant/aggression - name = "aggression implant" - desc = "An implant that microdoses its user with chemicals that induce anger." - -/obj/item/implant/aggression/get_data() - . = {" - Implant Specifications:
- Name: Aggression Implant
- Life: N/A.
- Important Notes: Users injected with this device get increasingly angry to a breaking point. Users tend to expire before the implant does.
-
- Implant Details:
- Function: Contains a small pod of nanobots that manipulate the host's mental functions.
- Integrity: Implant will last so long as the nanobots are inside the bloodstream."} - -/obj/item/implant/aggression/implanted(mob/M) - if(!istype(M, /mob/living/carbon/human)) - return FALSE - - var/mob/living/carbon/human/H = M - - for(var/obj/item/implant/mindshield/I in H) - if(I.implanted) - to_chat(H, SPAN_DANGER("Rage surges through your body, but the nanobots from your mind shield implant stop it soon after it starts!")) - return TRUE - - var/datum/antagonist/antag_data = get_antag_data(H.mind.special_role) - if(antag_data?.flags & ANTAG_IMPLANT_IMMUNE) - H.visible_message("[H] seems to resist the implant!", "You feel rage overtake your body, but you manage to fend it off by sheer will!") - log_and_message_admins("[key_name(H)] was implanted by an aggression implant, but was not effected.", H) - else if(antag_data?.id == MODE_LOYALIST) - clear_antag_roles(H.mind, 1) - to_chat(H, SPAN_DANGER("You feel a surge of rage override your loyalty!")) - log_and_message_admins("[key_name(H)] was implanted by an aggression implant, clearing their loyalist status!", H) - else - to_chat(H, SPAN_DANGER("You feel a surge of rage course through your body and very soul!")) - log_and_message_admins("[key_name(H)] was implanted by an aggression implant!", H) - return TRUE - -/obj/item/implant/aggression/emp_act(severity) - if(malfunction) - return - malfunction = MALFUNCTION_TEMPORARY - - activate("emp") - if(severity == 1) - if(prob(50)) - meltdown() - else if(prob(50)) - malfunction = MALFUNCTION_PERMANENT - return - spawn(20) - malfunction-- - -/obj/item/implant/anti_augment - name = "augmentation disrupter implant" - desc = "An implant that emits signals able to disrupt the use of commonly used augments." - -/obj/item/implant/anti_augment/get_data() - . = {" -Implant Specifications:
-Name: Augmentation Disrupter Implant
-Life: Three Months.
-Important Notes: Emits a signal able to block most augments from functioning..
-
-Implant Details:
-Function: Emits a short radio wave that will block most augments.
-Special Features: Will stop the host from using any augment they might have.
-Integrity: Implant will last so long as it inside the host."} - -/obj/item/implant/anti_augment/emp_act(severity) - switch(severity) - if(1.0) - if (prob(75)) - qdel(src) - if(2.0) - if (prob(50)) - qdel(src) - if(3.0) - if (prob(25)) - qdel(src) - return - - #undef MALFUNCTION_TEMPORARY #undef MALFUNCTION_PERMANENT diff --git a/code/game/objects/items/weapons/implants/implantcase.dm b/code/game/objects/items/weapons/implants/implantcase.dm index 49b2f572cb4..4ccb03863e6 100644 --- a/code/game/objects/items/weapons/implants/implantcase.dm +++ b/code/game/objects/items/weapons/implants/implantcase.dm @@ -1,183 +1,86 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - +/** + * Item used to store implants. Can be renamed with a pen. Implants are moved between these and implanters when a mob uses an implanter on the case. + */ /obj/item/implantcase - name = "glass case" - desc = "A case containing an implant." - icon = 'icons/obj/items.dmi' - icon_state = "implantcase-0" + name = "implant case" + desc = "An aluminium case, which can safely contain an implant." + icon = 'icons/obj/item/implants.dmi' + icon_state = "implantcase" item_state = "implantcase" throw_speed = 1 throw_range = 5 w_class = ITEMSIZE_TINY + ///The implant within the case var/obj/item/implant/imp = null -/obj/item/implantcase/proc/update() - if (src.imp) - src.icon_state = text("implantcase-[]", src.imp.implant_color) - else - src.icon_state = "implantcase-0" - return +/obj/item/implantcase/Initialize(mapload) + . = ..() + if(ispath(imp)) + imp = new imp(src) + update_description() + update_icon() -/obj/item/implantcase/attackby(obj/item/I as obj, mob/user as mob) - ..() +/obj/item/implantcase/proc/update_description() + if(imp) + desc = "An aluminium case, containing \a [imp]." + origin_tech = imp.origin_tech + else + desc = "An aluminium case, which can safely contain an implant." + origin_tech.Cut() + + +/obj/item/implantcase/update_icon() + cut_overlays() + if (imp) + var/overlay_icon_state = "implantstorage_[imp.implant_icon]" + var/mutable_appearance/overlay_implant_icon = mutable_appearance(icon, overlay_icon_state) + add_overlay(overlay_implant_icon) + +/obj/item/implantcase/attackby(obj/item/I, mob/user) if (I.ispen()) - var/t = input(user, "What would you like the label to be?", text("[]", src.name), null) as text + var/t = input(user, "What would you like the label to be?", text("[]", src.name), null) if (user.get_active_hand() != I) return - if((!in_range(src, usr) && src.loc != user)) + if((!in_range(src, usr) && loc != user)) return t = sanitizeSafe(t, MAX_NAME_LEN) if(t) - src.name = text("Glass Case - '[]'", t) + src.name = text("implant case - '[]'", t) + desc = "An aluminium case, containing \a [t] implant." else - src.name = "Glass Case" + src.name = "implant case" + desc = "An aluminium case, which can safely contain an implant." else if(istype(I, /obj/item/reagent_containers/syringe)) - if(!src.imp) return - if(!src.imp.allow_reagents) return - if(src.imp.reagents.total_volume >= src.imp.reagents.maximum_volume) - to_chat(user, "\The [src] is full.") - else - var/trans = I.reagents.trans_to_obj(src.imp, 5) - if (trans > 0) - to_chat(user, "You inject [trans] units of the solution. The syringe now contains [I.reagents.total_volume] units.") + imp.attackby(I, user) else if (istype(I, /obj/item/implanter)) var/obj/item/implanter/M = I - if (M.imp) - if ((src.imp || M.imp.implanted)) - return + if (M.imp && !imp && !M.imp.implanted) M.imp.forceMove(src) - src.imp = M.imp + imp = M.imp M.imp = null - src.update() - M.update() + else if (imp && !M.imp) + imp.forceMove(M) + M.imp = src.imp + imp = null + update_description() + update_icon() + M.update_icon() + else if (istype(I, /obj/item/implant)) + if(imp == null) + to_chat(user, SPAN_NOTICE("You slide \the [I] into \the [src].")) + user.drop_from_inventory(I,src) + imp = I else - if (src.imp) - if (M.imp) - return - src.imp.forceMove(M) - M.imp = src.imp - src.imp = null - update() - M.update() - return - - -/obj/item/implantcase/tracking - name = "glass case - 'tracking'" - desc = "A case containing a tracking implant." - icon_state = "implantcase-b" - -/obj/item/implantcase/tracking/New() - src.imp = new /obj/item/implant/tracking( src ) + to_chat(user, SPAN_WARNING("\The [src] already has an implant inside of it!")) + update_description() + update_icon() + else if(istype(I, /obj/item/implantpad)) + var/obj/item/implantpad/pad = I + if(!pad.case) + user.drop_from_inventory(src,pad) + pad.case = src + pad.update_icon() + else + to_chat(user, SPAN_WARNING("\The [pad] already has an implant case attached to it!")) ..() - return - -/obj/item/implantcase/explosive - name = "glass case - 'explosive'" - desc = "A case containing an explosive implant." - icon_state = "implantcase-r" - -/obj/item/implantcase/explosive/New() - src.imp = new /obj/item/implant/explosive( src ) - ..() - return - - -/obj/item/implantcase/chem - name = "glass case - 'chem'" - desc = "A case containing a chemical implant." - icon_state = "implantcase-b" - -/obj/item/implantcase/chem/New() - src.imp = new /obj/item/implant/chem( src ) - ..() - return - - -/obj/item/implantcase/loyalty - name = "glass case - 'mind shield'" - desc = "A case containing a mind shield implant." - icon_state = "implantcase-r" - -/obj/item/implantcase/loyalty/New() - src.imp = new /obj/item/implant/mindshield( src ) - ..() - return - - -/obj/item/implantcase/death_alarm - name = "glass case - 'death alarm'" - desc = "A case containing a death alarm implant." - icon_state = "implantcase-b" - -/obj/item/implantcase/death_alarm/New() - src.imp = new /obj/item/implant/death_alarm( src ) - ..() - return - - -/obj/item/implantcase/freedom - name = "glass case - 'freedom'" - desc = "A case containing a freedom implant." - icon_state = "implantcase-r" - -/obj/item/implantcase/freedom/New() - src.imp = new /obj/item/implant/freedom( src ) - ..() - return - - -/obj/item/implantcase/adrenalin - name = "glass case - 'adrenalin'" - desc = "A case containing an adrenalin implant." - icon_state = "implantcase-b" - -/obj/item/implantcase/adrenalin/New() - src.imp = new /obj/item/implant/adrenalin( src ) - ..() - return - - -/obj/item/implantcase/explosive/deadman - name = "glass case - 'explosive'" - desc = "A case containing an explosive." - icon_state = "implantcase-r" - -/obj/item/implantcase/explosive/deadman/New() - src.imp = new /obj/item/implant/explosive/deadman( src ) - ..() - return - - -/obj/item/implantcase/health - name = "glass case - 'health'" - desc = "A case containing a health tracking implant." - icon_state = "implantcase-b" - -/obj/item/implantcase/health/New() - src.imp = new /obj/item/implant/health( src ) - ..() - return - - -/obj/item/implantcase/aggression - name = "glass case - 'aggression'" - desc = "A case containing an aggression inducing implant." - icon_state = "implantcase-b" - -/obj/item/implantcase/aggression/New() - src.imp = new /obj/item/implant/aggression(src) - ..() - return - - -/obj/item/implantcase/anti_augment - name = "glass case - 'augmentation disrupter'" - desc = "A case containing an augmentation disrupter implant." - icon_state = "implantcase-b" - -/obj/item/implantcase/anti_augment/New() - src.imp = new /obj/item/implant/anti_augment(src) - ..() - return diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm index 6dfc7b56764..abcd38e60e6 100644 --- a/code/game/objects/items/weapons/implants/implanter.dm +++ b/code/game/objects/items/weapons/implants/implanter.dm @@ -1,32 +1,35 @@ /obj/item/implanter name = "implanter" - icon = 'icons/obj/item/reagent_containers/syringe.dmi' + icon = 'icons/obj/item/implants.dmi' contained_sprite = TRUE - icon_state = "implanter0" - item_state = "syringe_0" + icon_state = "implanter-0" throw_speed = 1 throw_range = 5 w_class = ITEMSIZE_SMALL matter = list(DEFAULT_WALL_MATERIAL = 320, MATERIAL_GLASS = 800) var/obj/item/implant/imp = null -/obj/item/implanter/attack_self(var/mob/user) - if(!imp) - return ..() - imp.forceMove(get_turf(src)) - user.put_in_hands(imp) - to_chat(user, "You remove \the [imp] from \the [src].") - name = "implanter" - imp = null - update() - return +/obj/item/implanter/New() + if(ispath(imp)) + imp = new imp(src) + ..() + update_icon() -/obj/item/implanter/proc/update() +/obj/item/implanter/update_icon() + cut_overlays() + icon_state = "implanter-[imp ? "1" : "0"]" if (imp) - icon_state = "implanter1" + var/mutable_appearance/overlay_implant_icon = mutable_appearance(icon, "implanter-overlay") + overlay_implant_icon.color = imp.implant_color + add_overlay(overlay_implant_icon) + +/obj/item/implanter/attackby(obj/item/I, mob/user) + if(!imp && istype(I, /obj/item/implant) && user.unEquip(I,src)) + to_chat(usr, SPAN_NOTICE("You slide \the [I] into \the [src].")) + imp = I + update_icon() else - icon_state = "implanter0" - return + ..() /obj/item/implanter/attack(mob/living/carbon/human/M, mob/user, var/target_zone) if(!istype(M)) @@ -35,15 +38,15 @@ var/obj/item/organ/external/affected = M.get_organ(target_zone) if(user && imp && affected) - M.visible_message("[user] is attempting to implant [M] in \the [affected.name].") + M.visible_message(SPAN_WARNING("[user] is attempting to implant [M] in \the [affected.name].")) user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) user.do_attack_animation(M) var/turf/T1 = get_turf(M) - if (T1 && ((M == user) || do_after(user, 50))) + if (T1 && ((M == user) || do_after(user, 5 SECONDS))) if(user && M && (get_turf(M) == T1) && src && imp) - M.visible_message("[M] has been implanted by [user] in the [affected.name].") + M.visible_message(SPAN_WARNING("[M] has been implanted by [user] in the [affected.name].")) admin_attack_log(user, M, "Implanted using \the [name] ([imp.name])", "Implanted with \the [name] ([imp.name])", "used an implanter, [name] ([imp.name]), on") @@ -54,101 +57,12 @@ affected.implants += imp imp.part = affected BITSET(M.hud_updateflag, IMPLOYAL_HUD) - if(istype(imp, /obj/item/implanter/loyalty)) - to_chat(M, "") imp = null - update() + update_icon() return -/obj/item/implanter/loyalty - name = "implanter-loyalty" - -/obj/item/implanter/loyalty/New() - imp = new /obj/item/implant/mindshield(src) - ..() - update() - return - -/obj/item/implanter/explosive - name = "implanter (E)" - -/obj/item/implanter/explosive/New() - imp = new /obj/item/implant/explosive(src) - ..() - update() - return - -/obj/item/implanter/adrenalin - name = "implanter-adrenalin" - -/obj/item/implanter/adrenalin/New() - imp = new /obj/item/implant/adrenalin(src) - ..() - update() - return - -/obj/item/implanter/compressed - name = "implanter (C)" - -/obj/item/implanter/compressed/New() - imp = new /obj/item/implant/compressed( src ) - ..() - update() - return - -/obj/item/implanter/compressed/attack(mob/M as mob, mob/user as mob) - var/obj/item/implant/compressed/c = imp - if (!c) return - if (c.scanned == null) - to_chat(user, "Please scan an object with the implanter first.") - return - ..() - -/obj/item/implanter/compressed/afterattack(atom/A, mob/user as mob, proximity) - if(!proximity) - return - if(istype(A,/obj/item) && imp) - var/obj/item/implant/compressed/c = imp - if(istype(A,/obj/item/implant/compressed)) - to_chat(user, SPAN_NOTICE("The implant is loaded into the implanter.")) - return - if (c.scanned) - to_chat(user, SPAN_WARNING("Something is already scanned inside the implant!")) - return - c.scanned = A - if(istype(A.loc,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = A.loc - H.remove_from_mob(A) - else if(istype(A.loc,/obj/item/storage)) - var/obj/item/storage/S = A.loc - S.remove_from_storage(A) - A.loc.contents.Remove(A) - update() - -/obj/item/implanter/freedom/Initialize() - imp = new /obj/item/implant/freedom( src ) - . = ..() - update() - -/obj/item/implanter/uplink - name = "implanter (U)" - -/obj/item/implanter/uplink/Initialize() - imp = new /obj/item/implant/uplink( src ) - . = ..() - update() - -/obj/item/implanter/anti_augment - name = "implanter-augmentation disrupter" - -/obj/item/implanter/anti_augment/New() - imp = new /obj/item/implant/anti_augment(src) - ..() - update() - return - /obj/item/implanter/ipc_tag name = "IPC tag implanter" desc = "A special implanter used for implanting synthetics with a special tag." @@ -157,9 +71,9 @@ /obj/item/implanter/ipc_tag/Initialize() . = ..() ipc_tag = new /obj/item/organ/internal/ipc_tag(src) - update() + update_icon() -/obj/item/implanter/ipc_tag/update() +/obj/item/implanter/ipc_tag/update_icon() if(ipc_tag) icon_state = "cimplanter1" else @@ -195,7 +109,7 @@ ipc_tag.serial_number = uppertext(dd_limittext(md5(M.real_name), 12)) ipc_tag = null - update() + update_icon() /obj/item/implanter/ipc_tag/attackby(obj/item/I, mob/user) if(I.isscrewdriver()) @@ -206,7 +120,7 @@ ipc_tag.forceMove(get_turf(user)) user.put_in_hands(ipc_tag) ipc_tag = null - update() + update_icon() return if(istype(I, /obj/item/organ/internal/ipc_tag)) if(ipc_tag) @@ -214,6 +128,6 @@ return ipc_tag = I user.drop_from_inventory(I, src) - update() + update_icon() return ..() diff --git a/code/game/objects/items/weapons/implants/implantfreedom.dm b/code/game/objects/items/weapons/implants/implantfreedom.dm deleted file mode 100644 index 20ce9ea08ab..00000000000 --- a/code/game/objects/items/weapons/implants/implantfreedom.dm +++ /dev/null @@ -1,74 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/obj/item/implant/freedom - name = "freedom implant" - desc = "Use this to escape from those evil Red Shirts." - implant_color = "r" - var/activation_emote = "chuckle" - var/uses = 1 - -/obj/item/implant/freedom/New() - uses = rand(1, 5) - ..() - -/obj/item/implant/freedom/trigger(emote, mob/living/carbon/source) - if(!activation_emote) - return - if(uses < 1) - to_chat(source, SPAN_WARNING("\The [src] gives a faint beep inside your head, indicating that it's out of uses!")) - activation_emote = null //Disable this to allow them to emote normally - return - if(emote == activation_emote) - uses-- - to_chat(source, "You feel a faint click.") - if(source.handcuffed) - var/obj/item/W = source.handcuffed - source.handcuffed = null - if(source.buckled_to && source.buckled_to.buckle_require_restraints) - source.buckled_to.unbuckle() - source.update_inv_handcuffed() - if(source.client) - source.client.screen -= W - if(W) - W.forceMove(source.loc) - dropped(source) - if (W) - W.layer = initial(W.layer) - if(source.legcuffed) - var/obj/item/W = source.legcuffed - source.legcuffed = null - source.update_inv_legcuffed() - if(source.client) - source.client.screen -= W - if(W) - W.forceMove(source.loc) - dropped(source) - if(W) - W.layer = initial(W.layer) - return - - -/obj/item/implant/freedom/implanted(mob/living/carbon/source) - activation_emote = input("Choose activation emote:") in list("blink", "blink_r", "eyebrow", "chuckle", "twitch", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") - if(source.mind) - source.mind.store_memory("\The [src] can be activated by using the [activation_emote] emote, say *[activation_emote] to attempt to activate.") - to_chat(source, "The implanted [src] can be activated by using the [activation_emote] emote, say *[activation_emote] to attempt to activate.") - return TRUE - - -/obj/item/implant/freedom/get_data() - var/dat = {" -Implant Specifications:
-Name: Freedom Beacon
-Life: optimum 5 uses
-Important Notes: Illegal
-
-Implant Details:
-Function: Transmits a specialized cluster of signals to override handcuff locking -mechanisms
-Special Features:
-Neuro-Scan- Analyzes certain shadow signals in the nervous system
-Integrity: The battery is extremely weak and commonly after injection its -life can drive down to only 1 use.
-No Implant Specifics"} - return dat diff --git a/code/game/objects/items/weapons/implants/implantpad.dm b/code/game/objects/items/weapons/implants/implantpad.dm index f0bd1cbcd44..a2ffd62317d 100644 --- a/code/game/objects/items/weapons/implants/implantpad.dm +++ b/code/game/objects/items/weapons/implants/implantpad.dm @@ -1,7 +1,7 @@ /obj/item/implantpad name = "implantpad" desc = "A device used to modify implants." - icon = 'icons/obj/items.dmi' + icon = 'icons/obj/item/implants.dmi' icon_state = "implantpad-0" item_state = "electronic" throw_speed = 1 @@ -12,16 +12,23 @@ var/listening = TRUE /obj/item/implantpad/update_icon() + cut_overlays() icon_state = "implantpad-[case ? "1" : "0"]" + if(case.imp) + var/obj/item/implant/caseimplant = case.imp + var/implant_overlay_icon_state = "implantstorage_[caseimplant.implant_icon]" + var/mutable_appearance/implant_case_implant_overlay = mutable_appearance(icon, implant_overlay_icon_state) + add_overlay(implant_case_implant_overlay) + /obj/item/implantpad/attack_hand(mob/user) - if(src.case && (user.l_hand == src || user.r_hand == src)) + if(case && (user.l_hand == src || user.r_hand == src)) user.put_in_active_hand(case) - src.case.add_fingerprint(user) - src.case = null + case.add_fingerprint(user) + case = null - src.add_fingerprint(user) + add_fingerprint(user) update_icon() return return ..() @@ -30,28 +37,17 @@ if(istype(C, /obj/item/implantcase)) if(!case) user.drop_from_inventory(C,src) - src.case = C + case = C update_icon() else - to_chat(user, SPAN_WARNING("\The [src] already has an implant case inside it!")) - return + to_chat(user, SPAN_WARNING("\The [src] already has an implant case attached to it!")) ..() /obj/item/implantpad/attack_self(mob/user) - user.set_machine(src) - var/dat = "Implant Mini-Computer:
" - if (src.case) - if(src.case.imp) - if(istype(src.case.imp, /obj/item/implant)) - dat += src.case.imp.get_data() - else - dat += "The implant casing is empty." + if(case.imp) + case.imp.interact(user) else - dat += "Please insert an implant casing!" - - var/datum/browser/implantpad_win = new(user, "implantpad", capitalize_first_letters(name)) - implantpad_win.set_content(dat) - implantpad_win.open() + to_chat(user, SPAN_WARNING("There's no implant loaded in \the [src]!")) /obj/item/implantpad/Topic(href, href_list) ..() @@ -68,4 +64,4 @@ src.attack_self(M) src.add_fingerprint(usr) else - usr << browse(null, "window=implantpad") \ No newline at end of file + usr << browse(null, "window=implantpad") diff --git a/code/game/objects/items/weapons/implants/implants/adrenaline.dm b/code/game/objects/items/weapons/implants/implants/adrenaline.dm new file mode 100644 index 00000000000..5f3ff7dea20 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/adrenaline.dm @@ -0,0 +1,41 @@ +/obj/item/implant/adrenaline + name = "adrenaline implant" + desc = "Removes all stuns and knockdowns." + icon_state = "implant_chem" //Temporary, this is currently unused so no need for a custom sprite + implant_icon = "chem" //Ditto + implant_color = "#eba7eb" //Ditto + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_ILLEGAL = 2) + default_action_type = /datum/action/item_action/hands_free/activate/implant/adrenaline + action_button_name = "Activate Adrenaline Implant" + var/uses = 3 + +/obj/item/implant/adrenaline/get_data() + . = {" +Implant Specifications:
+Name: Kumar Arms ZV-16 Combat Readiness Implant
+Life: Five days.
+Important Notes: Illegal for non-licensed personnel in Biesel space.
+
+Implant Details: Subjects injected with implant can activate a massive injection of adrenaline.
+Function: Contains nanobots to stimulate body to mass-produce Adrenaline.
+Integrity: Implant can only be used three times before the nanobots are depleted."} + +/obj/item/implant/adrenaline/activate() + if (malfunction || !imp_in) + return + if (uses < 1) + to_chat(imp_in, SPAN_WARNING("\The [src] gives a faint beep inside your head, indicating that it's out of uses!")) + return + uses-- + to_chat(imp_in, SPAN_NOTICE("You feel a sudden surge of energy!")) + imp_in.SetStunned(0) + imp_in.SetWeakened(0) + imp_in.SetParalysis(0) + +/obj/item/implantcase/adrenaline + name = "glass case - 'adrenalin'" + imp = /obj/item/implant/adrenaline + +/obj/item/implanter/adrenaline + name = "implanter-adrenaline" + imp = /obj/item/implant/adrenaline diff --git a/code/game/objects/items/weapons/implants/implants/aggression.dm b/code/game/objects/items/weapons/implants/implants/aggression.dm new file mode 100644 index 00000000000..b77ee2e408b --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/aggression.dm @@ -0,0 +1,67 @@ +#define MALFUNCTION_TEMPORARY 1 +#define MALFUNCTION_PERMANENT 2 + +/obj/item/implant/aggression + name = "aggression implant" + desc = "An implant that microdoses its user with chemicals that induce anger." + icon_state = "implant_chem" //Temporary + implant_icon = "chem" //Ditto + implant_color = "#eba7eb" //Ditto + default_action_type = null + +/obj/item/implant/aggression/get_data() + . = {" + Implant Specifications:
+ Name: Aggression Implant
+ Life: N/A.
+ Important Notes: Users injected with this device get increasingly angry to a breaking point. Users tend to expire before the implant does.
+
+ Implant Details:
+ Function: Contains a small pod of nanobots that manipulate the host's mental functions.
+ Integrity: Implant will last so long as the nanobots are inside the bloodstream."} + +/obj/item/implant/aggression/implanted(mob/M) + if(!istype(M, /mob/living/carbon/human)) + return FALSE + + var/mob/living/carbon/human/H = M + + for(var/obj/item/implant/mindshield/I in H) + if(I.implanted) + to_chat(H, SPAN_DANGER("Rage surges through your body, but the nanobots from your mind shield implant stop it soon after it starts!")) + return TRUE + + var/datum/antagonist/antag_data = get_antag_data(H.mind.special_role) + if(antag_data?.flags & ANTAG_IMPLANT_IMMUNE) + H.visible_message("[H] seems to resist the implant!", "You feel rage overtake your body, but you manage to fend it off by sheer will!") + log_and_message_admins("[key_name(H)] was implanted by an aggression implant, but was not affected.", H) + else if(antag_data?.id == MODE_LOYALIST) + clear_antag_roles(H.mind, 1) + to_chat(H, SPAN_DANGER("You feel a surge of rage override your loyalty!")) + log_and_message_admins("[key_name(H)] was implanted by an aggression implant, clearing their loyalist status!", H) + else + to_chat(H, SPAN_DANGER("You feel a surge of rage course through your body and very soul!")) + log_and_message_admins("[key_name(H)] was implanted by an aggression implant!", H) + return TRUE + +/obj/item/implant/aggression/emp_act(severity) + if(malfunction) + return + malfunction = MALFUNCTION_TEMPORARY + + activate("emp") + if(severity == 1) + if(prob(50)) + meltdown() + else if(prob(50)) + malfunction = MALFUNCTION_PERMANENT + return + spawn(20) + malfunction-- + +#undef MALFUNCTION_TEMPORARY +#undef MALFUNCTION_PERMANENT + +/obj/item/implantcase/aggression + name = "glass case - 'aggression'" + imp = /obj/item/implant/aggression diff --git a/code/game/objects/items/weapons/implants/implants/anti-augment.dm b/code/game/objects/items/weapons/implants/implants/anti-augment.dm new file mode 100644 index 00000000000..9267f9f9b07 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/anti-augment.dm @@ -0,0 +1,44 @@ +/obj/item/implant/anti_augment + name = "augmentation disrupter implant" + desc = "An implant that emits signals able to disrupt the use of commonly used augments." + icon_state = "implant_excel" //Temporary + implant_icon = "excel" //Ditto + implant_color = "#ffd079" //Ditto + default_action_type = null + known = TRUE + +/obj/item/implant/anti_augment/get_data() + . = {" +Implant Specifications:
+Name: Hephaestus Industries HP-152 Augmentation Disrupter Implant
+Life: Three Months.
+Important Notes: Emits a signal able to block most augments from functioning.
+
+Implant Details:
+Function: Emits a short radio wave that will block most augments.
+Special Features: Will stop the host from using any augment they might have.
+Integrity: Implant will last so long as it inside the host."} + +/obj/item/implant/anti_augment/isLegal() + return TRUE + +/obj/item/implant/anti_augment/emp_act(severity) + switch(severity) + if(1.0) + if (prob(75)) + qdel(src) + if(2.0) + if (prob(50)) + qdel(src) + if(3.0) + if (prob(25)) + qdel(src) + return + +/obj/item/implantcase/anti_augment + name = "glass case - 'augmentation disrupter'" + imp = /obj/item/implant/anti_augment + +/obj/item/implanter/anti_augment + name = "implanter-augmentation disrupter" + imp = /obj/item/implant/anti_augment diff --git a/code/game/objects/items/weapons/implants/implants/chem.dm b/code/game/objects/items/weapons/implants/implants/chem.dm new file mode 100644 index 00000000000..9281e1289f1 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/chem.dm @@ -0,0 +1,84 @@ +#define MALFUNCTION_TEMPORARY 1 + +/obj/item/implant/chem + name = "chemical implant" + desc = "Injects things." + icon_state = "implant_chem" + implant_icon = "chem" + implant_color = "#eba7eb" + origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 3) + default_action_type = /datum/action/item_action/hands_free/activate/implant/chemical + action_button_name = "Dispense Reagents from Chemical Implant" + known = TRUE + +/obj/item/implant/chem/get_data() + . = {" +Implant Specifications:
+Name: Ingkom ZV-02 Prisoner Management Implant
+Life: Deactivates upon death but remains within the body.
+Important Notes: Due to the system functioning off of nutrients in the implanted subject's body, the subject
+will suffer from an increased appetite.

+
+Implant Details:
+Function: Contains a small capsule that can contain various chemicals. Upon receiving a specially encoded signal
+the implant releases the chemicals directly into the blood stream.
+Special Features: +Micro-Capsule- Can be loaded with any sort of chemical agent via the common syringe and can hold 50 units.
+Can only be loaded while still in its original case.
+Integrity: Implant will last so long as the subject is alive. However, if the subject suffers from malnutrition,
+the implant may become unstable and either pre-maturely inject the subject or simply break."} + +/obj/item/implant/chem/New() + ..() + var/datum/reagents/R = new/datum/reagents(50) + reagents = R + R.my_atom = src + +/obj/item/implant/chem/trigger(emote, source as mob) + if(emote == "deathgasp") + src.activate(src.reagents.total_volume) + return + +/obj/item/implant/chem/activate(cause) + if((malfunction) || (!iscarbon(imp_in))) + return 0 + if(!cause) + cause = rand(1, 25) + var/mob/living/carbon/R = imp_in + src.reagents.trans_to_mob(R, cause, CHEM_BLOOD) + to_chat(R, SPAN_HEAR("You hear a faint *beep*.")) + if(!reagents.total_volume) + to_chat(R, SPAN_WARNING("You hear a faint *click*.")) + +/obj/item/implant/chem/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/reagent_containers/syringe)) + if(reagents.total_volume >= reagents.maximum_volume) + to_chat(user, SPAN_WARNING("\The [src] is full.")) + else + if(do_after(user, 0.5 SECONDS, src)) + I.reagents.trans_to_obj(src, 5) + to_chat(user, SPAN_NOTICE("You inject 5 units of the solution. The syringe now contains [I.reagents.total_volume] units.")) + else + ..() + +/obj/item/implant/chem/emp_act(severity) + if (malfunction) + return + malfunction = MALFUNCTION_TEMPORARY + + switch(severity) + if(1) + if(prob(60)) + activate(20) + if(2) + if(prob(30)) + activate(5) + + spawn(20) + malfunction-- + +#undef MALFUNCTION_TEMPORARY + +/obj/item/implantcase/chem + name = "glass case - 'chem'" + imp = /obj/item/implant/chem diff --git a/code/game/objects/items/weapons/implants/implantcircuits.dm b/code/game/objects/items/weapons/implants/implants/circuit.dm similarity index 96% rename from code/game/objects/items/weapons/implants/implantcircuits.dm rename to code/game/objects/items/weapons/implants/implants/circuit.dm index 6231c27149a..09c2a77c20b 100644 --- a/code/game/objects/items/weapons/implants/implantcircuits.dm +++ b/code/game/objects/items/weapons/implants/implants/circuit.dm @@ -3,9 +3,10 @@ desc = "It's a case, for building very tiny electronics with." icon = 'icons/obj/assemblies/electronic_setups.dmi' icon_state = "setup_implant" + known = TRUE var/obj/item/device/electronic_assembly/implant/IC = null -/obj/item/implant/integrated_circuit/islegal() +/obj/item/implant/integrated_circuit/isLegal() return TRUE /obj/item/implant/integrated_circuit/Initialize() diff --git a/code/game/objects/items/weapons/implants/implants/compressed_matter.dm b/code/game/objects/items/weapons/implants/implants/compressed_matter.dm new file mode 100644 index 00000000000..674d4872853 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/compressed_matter.dm @@ -0,0 +1,69 @@ +/obj/item/implant/compressed //TODO: This code is awful, and this implant is difficult to use. Port atom storage, and make the implant its own storage item + name = "compressed matter implant" + desc = "Based on compressed matter technology, can store a single item." + icon_state = "implant_storage" + implant_icon = "storage" + implant_color = "#143464" + origin_tech = list(TECH_MATERIAL = 4, TECH_BIO = 2, TECH_ILLEGAL = 2) + default_action_type = /datum/action/item_action/hands_free/activate/implant/compressed + action_button_name = "Retrieve Item from Compressed Implant" + hidden = TRUE + var/obj/item/scanned = null + +/obj/item/implant/compressed/attackby(var/obj/item/T, mob/user) + if(T.isscrewdriver()) + if(!scanned) + to_chat(user, SPAN_NOTICE("There is nothing to remove from the implant.")) + else + to_chat(user, SPAN_NOTICE("You remove \the [scanned] from the implant.")) + user.put_in_hands(scanned) + scanned = null + if(istype(T, /obj/item/implanter)) + var/obj/item/implanter/implanter = T + if(implanter.imp) + to_chat(user, SPAN_NOTICE("\The [implanter] already has an implant loaded.")) + return + user.drop_from_inventory(src) + forceMove(implanter) + implanter.imp = src + implanter.update_icon() + else + ..() + +/obj/item/implant/compressed/get_data() + . = {" +Implant Specifications:
+Name: NT-06 Covert Insertion Implant
+Life: Up to 6 months.
+Important Notes: Uses a localized pocket of bluespace to store an item, that cannot be detected from most external sources.
+
+Implant Details:
+Function: Can store one item, that can be retrieved at will.
+Special Features:
+Neuro-Scan- Analyzes certain shadow signals in the nervous system
+Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} + +/obj/item/implant/compressed/trigger(emote, mob/source as mob) + if (src.scanned == null) + return FALSE + + to_chat(source, SPAN_NOTICE("The air glows as \the [src.scanned.name] uncompresses.")) + activate() + +/obj/item/implant/compressed/activate() + var/turf/t = get_turf(src) + if (imp_in) + imp_in.put_in_hands(scanned) + else + scanned.forceMove(t) + qdel(src) + +/obj/item/implant/compressed/implanted(mob/source as mob) + return TRUE + +/obj/item/implant/compressed/isLegal() + return FALSE + +/obj/item/implanter/compressed + name = "implanter (C)" + imp = /obj/item/implant/compressed diff --git a/code/game/objects/items/weapons/implants/implants/death_alarm.dm b/code/game/objects/items/weapons/implants/implants/death_alarm.dm new file mode 100644 index 00000000000..75733b37ff4 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/death_alarm.dm @@ -0,0 +1,83 @@ +#define MALFUNCTION_TEMPORARY 1 +#define MALFUNCTION_PERMANENT 2 + +/obj/item/implant/death_alarm + name = "death alarm implant" + desc = "An alarm which monitors host vital signs and transmits a radio message upon death." + icon_state = "implant_deathalarm" + implant_icon = "deathalarm" + implant_color = "#9cdb43" + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 3, TECH_DATA = 2) + default_action_type = null + known = TRUE + var/mobname = "Will Robinson" + +/obj/item/implant/death_alarm/get_data() + . = {" +Implant Specifications:
+Name: Idris Incorporated ID-15 \"Profit Margin\" Class Sapient Lifesign Sensor
+Life: Activates upon death.
+Important Notes: Alerts crew to crewmember death.
+
+Implant Details:
+Function: Contains a compact radio signaler that triggers when the host's lifesigns cease.
+Special Features: Alerts crew to crewmember death.
+Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} + +/obj/item/implant/death_alarm/process() + if (!implanted) + return + var/mob/M = imp_in + + if(QDELETED(M)) // If the mob got gibbed + M = null + activate(null) + else if(M.stat == DEAD) + activate("death") + +/obj/item/implant/death_alarm/activate(cause = "emp") + if (malfunction) + return + var/mob/M = imp_in + var/area/A = get_area(M) + var/location = A.name + if(cause == "emp" && prob(50)) + location = pick(teleportbeacons) + if(!A.requires_power) // We assume areas that don't use power are special zones + var/area/default = world.area + location = initial(default.name) + var/death_message = "[mobname] has died in [location]!" + if(!cause) + death_message = "[mobname] has died-zzzzt in-in-in..." + STOP_PROCESSING(SSprocessing, src) + + for(var/channel in list("Security", "Medical", "Command")) + global_announcer.autosay(death_message, "[mobname]'s Death Alarm", channel) + +/obj/item/implant/death_alarm/emp_act(severity) //for some reason alarms stop going off in case they are emp'd, even without this + if (malfunction) //so I'm just going to add a meltdown chance here + return + malfunction = MALFUNCTION_TEMPORARY + + activate("emp") //let's shout that this dude is dead + if(severity == 1) + if(prob(40)) //small chance of obvious meltdown + meltdown() + else if (prob(60)) //but more likely it will just quietly die + malfunction = MALFUNCTION_PERMANENT + STOP_PROCESSING(SSprocessing, src) + + spawn(20) + malfunction-- + +/obj/item/implant/death_alarm/implanted(mob/source as mob) + mobname = source.real_name + START_PROCESSING(SSprocessing, src) + return TRUE + +#undef MALFUNCTION_TEMPORARY +#undef MALFUNCTION_PERMANENT + +/obj/item/implantcase/death_alarm + name = "glass case - 'death alarm'" + imp = /obj/item/implant/death_alarm diff --git a/code/game/objects/items/weapons/implants/implants/emp.dm b/code/game/objects/items/weapons/implants/implants/emp.dm new file mode 100644 index 00000000000..9d34bf79c79 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/emp.dm @@ -0,0 +1,23 @@ +/obj/item/implant/emp + name = "\improper EMP implant" + desc = "Triggers an EMP." + icon_state = "implant_emp" + implant_icon = "emp" + implant_color = "#249fde" + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_ILLEGAL = 2) + default_action_type = /datum/action/item_action/hands_free/activate/implant/emp + action_button_name = "Activate EMP Implant" + var/uses = 3 + +/obj/item/implant/emp/activate() + if (malfunction || !imp_in) + return + if (uses < 1) + to_chat(imp_in, SPAN_WARNING("\The [src] gives a faint beep inside your head, indicating that it's out of uses!")) + return + uses-- + empulse(imp_in, 3, 5) + +/obj/item/implantcase/emp + name = "implant case - 'EMP'" + imp = /obj/item/implant/emp diff --git a/code/game/objects/items/weapons/implants/implants/explosive.dm b/code/game/objects/items/weapons/implants/implants/explosive.dm new file mode 100644 index 00000000000..a0356ebefc0 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/explosive.dm @@ -0,0 +1,320 @@ +#define MALFUNCTION_TEMPORARY 1 +#define MALFUNCTION_PERMANENT 2 + +//BS12 Explosive +/obj/item/implant/explosive + name = "explosive implant" + desc = "A military grade micro bio-explosive. Highly dangerous." + icon_state = "implant_explosive" + implant_icon = "explosive" + implant_color = "#e46b5d" + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_ILLEGAL = 3) + default_action_type = /datum/action/item_action/hands_free/activate/implant/explosive + action_button_name = "Activate Explosive Implant" + hidden = TRUE + var/elevel = "Localized Limb" + var/explodes_on_death = FALSE + var/phrase + var/code = 13 + var/frequency = 1443 + var/datum/radio_frequency/radio_connection + var/list/possible_explosions = list("Localized Limb", "Destroy Body") + var/warning_message = "Tampering detected. Tampering detected." + +/obj/item/implant/explosive/Initialize() + . = ..() + setFrequency(frequency) + +/obj/item/implant/explosive/get_data() + . = {" +Implant Specifications:
+Name: Kumar Arms ZX-01 \"Obscuration\" Class Implant
+Life: Activates upon codephrase.
+Important Notes: Explodes
+
+Implant Details:
+Function: Contains a compact, electrically detonated explosive that detonates upon receiving a specially encoded signal or upon host death.
+Special Features: Explodes. Explosion severity can be altered.
+Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} + if(!malfunction) + . += {" +
Explosion yield mode: + [elevel ? elevel : "NONE SET"]
+ Activation phrase:
+ [phrase ? phrase : "NONE SET"]
+ Frequency:
+ - + - + [format_frequency(src.frequency)] + + + +
+ Code:
+ - + - + [src.code] + + + +
+ Tampering warning message:
+ This will be broadcasted on radio if the implant is exposed during surgery.
+ [warning_message ? warning_message : "NONE SET"] + "} + +/obj/item/implant/explosive/Topic(href, href_list) + ..() + if(href_list["freq"]) + var/new_frequency = frequency + text2num(href_list["freq"]) + new_frequency = sanitize_frequency(new_frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) + setFrequency(new_frequency) + interact(usr) + if(href_list["code"]) + var/adj = text2num(href_list["code"]) + if(!adj) + code = input("Set radio activation code","Radio activation") as num + else + code += adj + code = clamp(code,1,100) + interact(usr) + if(href_list["mode"]) + var/mod = input("Set explosion mode", "Explosion mode") as null|anything in possible_explosions + if(mod) + elevel = mod + interact(usr) + if(href_list["msg"]) + var/msg = input("Set tampering message, or leave blank for no broadcasting.", "Anti-tampering", warning_message) as text|null + if(msg) + warning_message = msg + interact(usr) + if(href_list["phrase"]) + var/talk = input("Set activation phrase", "Audio activation", phrase) as text|null + if(talk) + phrase = sanitizePhrase(talk) + interact(usr) + +/obj/item/implant/explosive/receive_signal(datum/signal/signal) + if(signal && signal.encryption == code) + activate() + +/obj/item/implant/explosive/proc/setFrequency(new_frequency) + if(!frequency) + return + SSradio.remove_object(src, frequency) + frequency = new_frequency + radio_connection = SSradio.add_object(src, frequency, RADIO_CHAT) + +/obj/item/implant/explosive/hear_talk(mob/M, msg) + hear(msg) + +/obj/item/implant/explosive/hear(var/msg) + if(!phrase) + return + if(findtext(sanitizePhrase(msg),phrase)) + activate() + qdel(src) + +/obj/item/implant/explosive/exposed() + if(warning_message) + global_announcer.autosay(warning_message, "Anti-Tampering System") + +/obj/item/implant/explosive/proc/sanitizePhrase(phrase) + var/list/replacechars = list("'" = "", "\"" = "", ">" = "", "<" = "", "(" = "", ")" = "") + return replace_characters(phrase, replacechars) + +/obj/item/implant/explosive/activate() + if(malfunction) + return + + if(!imp_in) + small_countdown() + return + + message_admins("Explosive implant triggered in [imp_in] ([imp_in.key]). (JMP) ") + log_game("Explosive implant triggered in [imp_in] ([imp_in.key]).") + if(!elevel) + elevel = "Localized Limb" + switch(elevel) + if("Localized Limb") + if(part) + small_countdown() + return + if("Destroy Body") + explosion(get_turf(imp_in), -1, 0, 2, 6) + if(ismob(imp_in)) + imp_in.gib() + if("Full Explosion") + explosion_spread(get_turf(imp_in), rand(8,13)) + if(ismob(imp_in)) + imp_in.gib() + + var/turf/F = get_turf(imp_in) + if(F) + F.hotspot_expose(3500,125) + qdel(src) + +/obj/item/implant/explosive/proc/small_countdown() + if(!imp_in) + audible_message(SPAN_WARNING("[src] beeps ominously!")) + if(ishuman(imp_in)) + var/message = "Something beeps inside of [imp_in][part ? "'s [part.name]" : ""]..." //for some reason SPAN_X and span() both hate having this in-line + imp_in.audible_message(SPAN_WARNING(message)) + else if(ismob(imp_in)) + imp_in.audible_message(SPAN_WARNING("Something beeps inside of [imp_in]...")) + playsound(loc, 'sound/items/countdown.ogg', 75, 1, -3) + addtimer(CALLBACK(src, PROC_REF(small_boom)), 25) + +/obj/item/implant/explosive/proc/small_boom() + if(!imp_in) + explosion(get_turf(src), -1, 0, 2, 4) + if(ishuman(imp_in) && part) + //No tearing off these parts since it's pretty much killing. Mangle them. + if(part.vital && !istype(part, /obj/item/organ/external/head)) //Head explodes + part.createwound(BRUISE, 70) + part.add_pain(50) + imp_in.visible_message(SPAN_WARNING("\The [imp_in]'s [part.name] bursts open with a horrible ripping noise!"), + SPAN_DANGER("Your [part.name] bursts open with a horrible ripping noise!"), + SPAN_WARNING("You hear a horrible ripping noise.")) + else + part.droplimb(0,DROPLIMB_BLUNT) + playsound(get_turf(imp_in), BP_IS_ROBOTIC(part) ? 'sound/effects/meteorimpact.ogg' : 'sound/effects/splat.ogg') + else if(ismob(imp_in)) + var/mob/M = imp_in + M.gib() //Simple mobs just get got + qdel(src) + +/proc/explosion_spread(turf/epicenter, power, adminlog = 1, z_transfer = UP|DOWN) + var/datum/explosiondata/data = new + data.epicenter = epicenter + data.rec_pow = power + data.spreading = TRUE + data.adminlog = adminlog + data.z_transfer = z_transfer + SSexplosives.queue(data) + +/obj/item/implant/explosive/implanted(mob/source, mob/user) + var/memo = "\The [src] in [source] can be activated by saying something containing the phrase ''[phrase]'', say [phrase] to attempt to activate. It can also be triggered with a radio signal on frequency [format_frequency(src.frequency)] with code [code]." + if(user.mind) + user.mind.store_memory(memo, 0, 0) + to_chat(usr, memo) + return TRUE + +/obj/item/implant/explosive/emp_act(severity) + if(malfunction) + return + malfunction = MALFUNCTION_TEMPORARY + switch (severity) + if(2.0) //Weak EMP will make implant tear limbs off. + if(prob(50)) + small_countdown() + if(1.0) //strong EMP will melt implant either making it go off, or disarming it + if(prob(70)) + if(prob(50)) + small_countdown() + else + if(prob(50)) + activate() //50% chance of bye bye + else + meltdown() //50% chance of implant disarming + addtimer(CALLBACK(src, PROC_REF(self_correct)), 20) + +/obj/item/implant/explosive/proc/self_correct() + malfunction-- + +/obj/item/implant/explosive/isLegal() + return FALSE + +/obj/item/implant/explosive/New() + ..() + become_hearing_sensitive(ROUNDSTART_TRAIT) + +/obj/item/implant/explosive/Destroy() + return ..() + +/obj/item/implant/explosive/full + possible_explosions = list("Localized Limb", "Destroy Body", "Full Explosion") + +/obj/item/implant/explosive/deadman + name = "deadman explosive" + desc = "A military grade micro bio-explosive that detonates upon death." + icon_state = "implant_evil" + +/obj/item/implant/explosive/deadman/get_data() + . = {" +Implant Specifications:
+Name: Kumar Arms ZX-01a \"Obscuration\" Class Implant
+Life: Activates upon death.
+Important Notes: Explodes
+
+Implant Details:
+Function: Contains a compact, electrically detonated explosive that detonates upon receiving a specially encoded signal or upon host death.
+Special Features: Explodes
+Integrity: Implant will occasionally be degraded by the body's immune system and thus will occasionally malfunction."} + +/obj/item/implant/explosive/deadman/attack_self(mob/user) + return + +/obj/item/implant/explosive/deadman/hear(var/msg) + return + +/obj/item/implant/explosive/deadman/process() + if(malfunction) + STOP_PROCESSING(SSprocessing, src) + return + if (!implanted) + return + var/mob/M = imp_in + + if(M.stat == DEAD) + activate() + +/obj/item/implant/explosive/deadman/activate(var/cause) + small_countdown(src) + STOP_PROCESSING(SSprocessing, src) + +/obj/item/implant/explosive/deadman/small_boom() + if(imp_in) + explosion(get_turf(src), -1, 0, 1, 6) + imp_in.gib() + qdel(src) + +/obj/item/implant/explosive/deadman/implanted(mob/source) + START_PROCESSING(SSprocessing, src) + return TRUE + +/obj/item/implant/explosive/deadman/emp_act(severity) + if(malfunction) + return + malfunction = MALFUNCTION_TEMPORARY + switch (severity) + if(3.0) + if(prob(1)) + small_countdown() + else if(prob(5)) + meltdown() + if(2.0) + if(prob(5)) + small_countdown() + else if (prob(10)) + meltdown() + if(1.0) + if(prob(10)) + small_countdown() + else if (prob(30)) + meltdown() + +#undef MALFUNCTION_TEMPORARY +#undef MALFUNCTION_PERMANENT + +/obj/item/implantcase/explosive + name = "implant case - 'explosive'" + imp = /obj/item/implant/explosive + +/obj/item/implantcase/explosive/deadman + name = "glass case - 'deadman'" + imp = /obj/item/implant/explosive/deadman + +/obj/item/implanter/explosive + name = "implanter (E)" + imp = /obj/item/implant/explosive + +/obj/item/implanter/explosive/deadman + name = "implanter (D)" + imp = /obj/item/implant/explosive/deadman diff --git a/code/game/objects/items/weapons/implants/implants/freedom.dm b/code/game/objects/items/weapons/implants/implants/freedom.dm new file mode 100644 index 00000000000..7fd50279779 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/freedom.dm @@ -0,0 +1,77 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/obj/item/implant/freedom + name = "freedom implant" + desc = "Use this to escape from those evil Red Shirts." + icon_state = "implant_freedom" + implant_icon = "freedom" + implant_color = "#88f2e0" + origin_tech = list(TECH_MATERIAL = 1, TECH_ILLEGAL = 2, TECH_BIO = 3) + default_action_type = /datum/action/item_action/hands_free/activate/implant/freedom + action_button_name = "Activate Freedom Implant" + hidden = TRUE + var/uses = 1 + +/obj/item/implant/freedom/New() + uses = rand(1, 5) + ..() + +/obj/item/implant/freedom/activate(cause) + if(malfunction || !imp_in) + return + if(uses < 1) + to_chat(imp_in, SPAN_WARNING("\The [src] gives a faint beep inside your [part], indicating that it's out of uses!")) + return + uses-- + to_chat(imp_in, SPAN_HEAR("You feel a faint click.")) + if(iscarbon(imp_in)) + var/mob/living/carbon/C_imp_in = imp_in + if(C_imp_in.handcuffed) + var/obj/item/W = C_imp_in.handcuffed + C_imp_in.handcuffed = null + if(C_imp_in.buckled_to && C_imp_in.buckled_to.buckle_require_restraints) + C_imp_in.buckled_to.unbuckle() + C_imp_in.update_inv_handcuffed() + if(C_imp_in.client) + C_imp_in.client.screen -= W + if(W) + W.forceMove(C_imp_in.loc) + dropped(C_imp_in) + if (W) + W.layer = initial(W.layer) + if(C_imp_in.legcuffed) + var/obj/item/W = C_imp_in.legcuffed + C_imp_in.legcuffed = null + C_imp_in.update_inv_legcuffed() + if(C_imp_in.client) + C_imp_in.client.screen -= W + if(W) + W.forceMove(C_imp_in.loc) + dropped(C_imp_in) + if(W) + W.layer = initial(W.layer) + +/obj/item/implant/freedom/get_data() + var/dat = {" +Implant Specifications:
+Name: Freedom Beacon
+Life: optimum 5 uses
+Important Notes: Illegal
+
+Implant Details:
+Function: Transmits a specialized cluster of signals to override handcuff locking +mechanisms
+Special Features:
+Neuro-Scan- Analyzes certain shadow signals in the nervous system
+Integrity: The battery is extremely weak and commonly after injection its +life can drive down to only 1 use.
+No Implant Specifics"} + return dat + +/obj/item/implantcase/freedom + name = "glass case - 'freedom'" + imp = /obj/item/implant/freedom + +/obj/item/implanter/freedom + name = "implanter (F)" + imp = /obj/item/implant/freedom diff --git a/code/game/objects/items/weapons/implants/implants/health_tracker.dm b/code/game/objects/items/weapons/implants/implants/health_tracker.dm new file mode 100644 index 00000000000..53cfb6ea8fc --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/health_tracker.dm @@ -0,0 +1,22 @@ +//Health Tracker Implant +/obj/item/implant/health + name = "health implant" + icon_state = "implant_health" + implant_icon = "deathalarm" //This is intentionally the same as the death alarm + implant_color = "#9cdb43" //This is intentionally the same as the death alarm + var/healthstring = "" + +/obj/item/implant/health/proc/sensehealth() + if(!implanted) + return "ERROR" + else + if(isliving(implanted)) + var/mob/living/L = implanted + healthstring = "[round(L.getOxyLoss())] - [round(L.getFireLoss())] - [round(L.getToxLoss())] - [round(L.getBruteLoss())]" + if(!healthstring) + healthstring = "ERROR" + return healthstring + +/obj/item/implantcase/health + name = "glass case - 'health'" + imp = /obj/item/implant/health diff --git a/code/game/objects/items/weapons/implants/implants/loyalty.dm b/code/game/objects/items/weapons/implants/implants/loyalty.dm new file mode 100644 index 00000000000..2052c6e2f98 --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/loyalty.dm @@ -0,0 +1,104 @@ +/obj/item/implant/mindshield/loyalty + name = "loyalty implant" + desc = "A controversial device, these were replaced with mindshield implants by the corporations of the spur. However, they still find usage with several entities across the spur." + ///The entity that the implantee should be loyal to + var/loyal_entity + ///Whether this implant will override mindshield implants. These are supposed to be older versions of mindshields, so only specially modified versions should do so. + var/mindshield_override = FALSE + +/obj/item/implant/mindshield/loyalty/get_data() + . = {" +Implant Specifications:
+Name: Solarian Corporate Authority NT-02 Employee Management Implant Mk.I
+Life: Ten years.
+Important Notes: Personnel injected with this device tend to be much more loyal to the entity provided.
+
+Implant Details:
+Function: Contains a small pod of nanobots that manipulate the host's mental functions, to ensure no harmful thoughts are present against an entity.
+Special Features: Will prevent and cure most forms of brainwashing.
+Integrity: Implant will last so long as the nanobots are inside the bloodstream." +Loyal entity:
+This is the entity that the implantee will align their thoughts to benefit.
+[loyal_entity ? loyal_entity : "NONE SET"] +"} + +/obj/item/implant/mindshield/loyalty/Topic(href, href_list) + ..() + if(href_list["loyal"]) + var/entity = input("Set loyalty target.", "Loyalty", loyal_entity) as text|null + if(entity) + loyal_entity = entity + interact(usr) + +/obj/item/implant/mindshield/loyalty/implanted(mob/M) + if(!istype(M, /mob/living/carbon/human)) + return FALSE + + var/mob/living/carbon/human/H = M + + for(var/obj/item/implant/mindshield/I in H) + if(I.implanted && !mindshield_override) + to_chat(H, SPAN_DANGER("You almost feel your loyalties shifting, but nanobots from your mindshield implant stop it soon after it starts!")) + meltdown() + return FALSE + else if(I.implanted && mindshield_override) + to_chat(H, SPAN_DANGER("You hear a buzzing sound as your mindshield implant struggles to defend against the new implant.")) + I.meltdown() + + to_chat(H, SPAN_GOOD("You feel a sudden surge of loyalty to \the [loyal_entity]!")) + log_and_message_admins("[key_name(H)] was implanted by an loyalty implant, set to [loyal_entity]!", H) + return TRUE + +/obj/item/implant/mindshield/loyalty/sol + name = "loyalty implant - Sol Alliance" + desc = "A device used by the Sol Alliance, to ensure loyalty to the only human government in the spur." + loyal_entity = "\improper Sol Alliance" + +/obj/item/implant/mindshield/loyalty/nralakk + name = "loyalty implant - Nralakk Federation" + desc = "A device used by the Nralakk Federation, to ensure loyalty to its ideals and to the best caretaker of the skrellian people." + loyal_entity = "\improper Nralakk Federation" + +/obj/item/implant/mindshield/loyalty/scc + name = "loyalty implant - Stellar Corporate Conglomerate" + desc = "A device that is allegedly used by the Stellar Corporate Conglomerate, which is allegedly used to enforce loyalty to the corporate agenda for its emergency response teams and high-ranking officers." + loyal_entity = "\improper Stellar Corporate Conglomerate" + +/obj/item/implant/mindshield/loyalty/nt + name = "loyalty implant - NanoTrasen" + desc = "A device that is allegedly used by NanoTrasen, which is allegedly used to enforce loyalty to the corporate agenda for its emergency response teams and high-ranking officers." + loyal_entity = "NanoTrasen" + //They made them originally, they would know how to override them. + mindshield_override = TRUE + +/obj/item/implantcase/loyalty + name = "glass case - 'loyalty'" + imp = /obj/item/implant/mindshield/loyalty + +/obj/item/implanter/loyalty + name = "implanter-loyalty" + imp = /obj/item/implant/mindshield/loyalty + +/obj/item/implantcase/loyalty/sol + name = "glass case - 'loyalty - Sol Alliance'" + imp = /obj/item/implant/mindshield/loyalty/sol + +/obj/item/implanter/loyalty/sol + name = "implanter-loyalty - Sol Alliance" + imp = /obj/item/implant/mindshield/loyalty/sol + +/obj/item/implantcase/loyalty/nralakk + name = "glass case - 'loyalty - Nralakk Federation'" + imp = /obj/item/implant/mindshield/loyalty/nralakk + +/obj/item/implanter/loyalty/nralakk + name = "implanter-loyalty - Nralakk Federation" + imp = /obj/item/implant/mindshield/loyalty/nralakk + +/obj/item/implantcase/loyalty/scc + name = "glass case - 'loyalty - Stellar Corporate Conglomerate'" + imp = /obj/item/implant/mindshield/loyalty/scc + +/obj/item/implanter/loyalty/scc + name = "implanter-loyalty - Stellar Corporate Conglomerate" + imp = /obj/item/implant/mindshield/loyalty/scc diff --git a/code/game/objects/items/weapons/implants/implants/mindshield.dm b/code/game/objects/items/weapons/implants/implants/mindshield.dm new file mode 100644 index 00000000000..e394ed9ee8e --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/mindshield.dm @@ -0,0 +1,75 @@ +#define MALFUNCTION_TEMPORARY 1 +#define MALFUNCTION_PERMANENT 2 + +/obj/item/implant/mindshield + name = "mind shield implant" + desc = "A neurostimulator and autohypnosis device. These replaced older, controversial loyalty implants for the corporations of the spur. When implanted against the amygdala, it ensures the host maintains a consistent personality, preventing outside interference through brainwashing or hypnotic suggestion." + icon_state = "implant_excel" + implant_icon = "excel" + implant_color = "#ffd079" + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_ILLEGAL = 3) + default_action_type = null + known = TRUE + +/obj/item/implant/mindshield/get_data() + . = {" +Implant Specifications:
+Name: NanoTrasen NT-02 Employee Management Implant Mk.II
+Life: Ten years.
+Important Notes: Personnel injected with this device tend to be much more resistant to brain washing and other external influences.
+
+Implant Details:
+Function: Contains a small pod of nanobots that observe the host's mental functions, and will destroy and interfere with common techniques of intrusion.
+Special Features: Will prevent and cure most forms of brainwashing.
+Integrity: Implant will last so long as the nanobots are inside the bloodstream."} + +/obj/item/implant/mindshield/implanted(mob/M) + to_chat(M, SPAN_SUBTLE("You feel a weird feeling, as the implant's nanobots disperse through your brain.")) + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + for(var/obj/item/implant/mindshield/loyalty/I in H) + if(I.implanted && !I.mindshield_override) + to_chat(H, SPAN_DANGER("The new mindshield implant activates, destroying your loyalty implant.")) + I.meltdown() + continue + else if(I.implanted && I.mindshield_override) + to_chat(H, SPAN_DANGER("You hear a buzzing sound as your loyalty implant defends itself against the new implant.")) + meltdown() + return FALSE + return TRUE + +/obj/item/implant/mindshield/emp_act(severity) + if (malfunction) + return + malfunction = MALFUNCTION_TEMPORARY + + activate("emp") + if(severity == 1) + if(prob(50)) + meltdown() + else if (prob(50)) + malfunction = MALFUNCTION_PERMANENT + return + spawn(20) + malfunction-- + +/obj/item/implant/mindshield/ipc + name = "software protection chip" + desc = "A dedicated processor core designed to identify and terminate malignant software, ensuring a synthetics protection from outside hacking." + +/obj/item/implant/mindshield/ipc/implanted(mob/M) + if (!isipc(M)) + return + + ..() + +#undef MALFUNCTION_TEMPORARY +#undef MALFUNCTION_PERMANENT + +/obj/item/implantcase/mindshield + name = "glass case - 'mind shield'" + imp = /obj/item/implant/mindshield + +/obj/item/implanter/mindshield + name = "implanter-mindshield" + imp = /obj/item/implant/mindshield diff --git a/code/game/objects/items/weapons/implants/implants/tracking.dm b/code/game/objects/items/weapons/implants/implants/tracking.dm new file mode 100644 index 00000000000..fe6657a01bd --- /dev/null +++ b/code/game/objects/items/weapons/implants/implants/tracking.dm @@ -0,0 +1,70 @@ +#define MALFUNCTION_TEMPORARY 1 + +/obj/item/implant/tracking + name = "tracking implant" + desc = "Track with this." + icon_state = "implant_freedom" + implant_icon = "freedom" + implant_color = "#eadb83" + origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_BLUESPACE = 2) + default_action_type = null + known = TRUE + var/id = 1.0 + var/lifespan_postmortem = 10 MINUTES + +/obj/item/implant/tracking/Initialize() + var/list/tracking_list = list() + for(var/obj/item/implant/tracking/T in implants) + tracking_list += T + id = length(tracking_list) + 1 + . = ..() + +/obj/item/implant/tracking/process() + if(!imp_in) + return + if(iscarbon(imp_in)) + var/mob/living/carbon/R = imp_in + if(R.chem_effects[CE_NEUROTOXIC]) + if(prob(5)) + meltdown() + +/obj/item/implant/tracking/get_data() + . = {"Implant Specifications:
+Name: Ingkom ZV-01 Tracking Beacon
+Life: 10 minutes after death of host
+Important Notes: None
+
+Implant Details:
+Function: Continuously transmits a low power signal. Useful for tracking subjects.
+Special Features:
+Neuro-Safe- Specialized shell absorbs excess voltages self-destructing the chip if +a malfunction occurs thereby securing safety of subject. The implant will melt and +disintegrate into bio-safe elements.
+Integrity: Gradient creates slight risk of being overcharged and frying the +circuitry. As a result neurotoxins can cause massive damage.
+Implant Specifics:
"} + +/obj/item/implant/tracking/isLegal() + return TRUE + +/obj/item/implant/tracking/emp_act(severity) + if (malfunction) //no, dawg, you can't malfunction while you are malfunctioning + return + malfunction = MALFUNCTION_TEMPORARY + + var/delay = 20 + switch(severity) + if(1) + if(prob(60)) + meltdown() + if(2) + delay = rand(5*60*10,15*60*10) //from 5 to 15 minutes of free time + + spawn(delay) + malfunction-- + +#undef MALFUNCTION_TEMPORARY + +/obj/item/implantcase/tracking + name = "glass case - 'tracking'" + imp = /obj/item/implant/tracking diff --git a/code/game/objects/items/weapons/implants/implantuplink.dm b/code/game/objects/items/weapons/implants/implants/uplink.dm similarity index 86% rename from code/game/objects/items/weapons/implants/implantuplink.dm rename to code/game/objects/items/weapons/implants/implants/uplink.dm index f22f5a62df5..a2ac8925f2a 100644 --- a/code/game/objects/items/weapons/implants/implantuplink.dm +++ b/code/game/objects/items/weapons/implants/implants/uplink.dm @@ -1,7 +1,12 @@ /obj/item/implant/uplink name = "uplink" desc = "Summon things." + icon_state = "implant_uplink" + implant_icon = "uplink" + implant_color = "#ffd4a3" var/activation_emote = "chuckle" + default_action_type = null + hidden = TRUE /obj/item/implant/uplink/New() activation_emote = pick("blink", "blink_r", "eyebrow", "chuckle", "twitch", "frown", "nod", "blush", "giggle", "grin", "groan", "shrug", "smile", "pale", "sniff", "whimper", "wink") @@ -23,3 +28,7 @@ if(hidden_uplink && usr == source) // Let's not have another people activate our uplink hidden_uplink.check_trigger(source, emote, activation_emote) return + +/obj/item/implanter/uplink + name = "implanter (U)" + imp = /obj/item/implant/uplink diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index a99c6f56e48..c5ca35588eb 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -530,7 +530,7 @@ name = "death alarm kit" desc = "Box of stuff used to implant death alarms." illustration = "implant" - starts_with = list(/obj/item/implanter = 1, /obj/item/implantcase/death_alarm = 6) + starts_with = list(/obj/item/implanter = 1, /obj/item/implantcase/death_alarm = 6, /obj/item/implantpad = 1) /obj/item/storage/box/condimentbottles name = "box of condiment bottles" @@ -1221,3 +1221,4 @@ /obj/item/storage/box/produce/fill() . = ..() make_exact_fit() + diff --git a/code/game/objects/items/weapons/storage/lockbox.dm b/code/game/objects/items/weapons/storage/lockbox.dm index 1ceed545796..6addf763f9b 100644 --- a/code/game/objects/items/weapons/storage/lockbox.dm +++ b/code/game/objects/items/weapons/storage/lockbox.dm @@ -79,8 +79,8 @@ name = "lockbox of mind shield implants" req_access = list(access_security) starts_with = list( - /obj/item/implantcase/loyalty = 3, - /obj/item/implanter/loyalty = 1 + /obj/item/implantcase/mindshield = 3, + /obj/item/implanter/mindshield = 1 ) /obj/item/storage/lockbox/anti_augment diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm index 629b49efbe6..40f5be5b039 100644 --- a/code/game/objects/items/weapons/storage/uplink_kits.dm +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -6,26 +6,23 @@ /obj/item/storage/box/syndie_kit/imp_freedom name = "box (F)" - starts_with = list(/obj/item/implanter/freedom = 1) - -/obj/item/storage/box/syndie_kit/imp_freedom/fill() - ..() - var/obj/item/implanter/O = new(src) - O.imp = new /obj/item/implant/freedom(O) - O.update() - return + starts_with = list(/obj/item/implantpad = 1, /obj/item/implanter = 1, /obj/item/implantcase/freedom = 1) /obj/item/storage/box/syndie_kit/imp_compress name = "box (C)" - starts_with = list(/obj/item/implanter/compressed = 1) + starts_with = list(/obj/item/implantpad = 1, /obj/item/implanter/compressed = 1) /obj/item/storage/box/syndie_kit/imp_explosive name = "box (E)" - starts_with = list(/obj/item/implanter = 1, /obj/item/implant/explosive = 1) + starts_with = list(/obj/item/implantpad = 1, /obj/item/implanter = 1, /obj/item/implantcase/explosive = 1) + +/obj/item/storage/box/syndie_kit/imp_emp + name = "box (M)" + starts_with = list(/obj/item/implantpad = 1, /obj/item/implanter = 1, /obj/item/implantcase/emp = 1) /obj/item/storage/box/syndie_kit/imp_deadman name = "box (D)" - starts_with = list(/obj/item/implanter = 1, /obj/item/implant/explosive/deadman = 1) + starts_with = list(/obj/item/implantpad = 1, /obj/item/implanter = 1, /obj/item/implantcase/explosive/deadman = 1) /obj/item/storage/box/syndie_kit/imp_uplink diff --git a/code/game/objects/items/weapons/teleportation.dm b/code/game/objects/items/weapons/teleportation.dm index 2923b8a5bae..56513894de9 100644 --- a/code/game/objects/items/weapons/teleportation.dm +++ b/code/game/objects/items/weapons/teleportation.dm @@ -99,8 +99,8 @@ Frequency: continue else var/mob/M = W.loc - if (M.stat == 2) - if (M.timeofdeath + 6000 < world.time) + if (M.stat == DEAD) + if (M.timeofdeath + W.lifespan_postmortem < world.time) continue var/turf/tr = get_turf(W) diff --git a/code/modules/awaymissions/exile.dm b/code/modules/awaymissions/exile.dm index fadbc540c23..7db07f94a00 100644 --- a/code/modules/awaymissions/exile.dm +++ b/code/modules/awaymissions/exile.dm @@ -7,7 +7,7 @@ /obj/item/implanter/exile/New() src.imp = new /obj/item/implant/exile( src ) ..() - update() + update_icon() return diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm index c12e806be3a..451d39ff0ce 100644 --- a/code/modules/customitems/item_defines.dm +++ b/code/modules/customitems/item_defines.dm @@ -23,7 +23,7 @@ All custom items with worn sprites must follow the contained sprite system: http if (!implant_type) return imp = new implant_type(src) - update() + update_icon() return diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 9a616a821a9..e30dbd62985 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1347,8 +1347,8 @@ hud_list[WANTED_HUD] = holder if ( BITTEST(hud_updateflag, IMPLOYAL_HUD) \ - || BITTEST(hud_updateflag, IMPCHEM_HUD) \ - || BITTEST(hud_updateflag, IMPTRACK_HUD)) + || BITTEST(hud_updateflag, IMPCHEM_HUD) \ + || BITTEST(hud_updateflag, IMPTRACK_HUD)) var/image/holder1 = hud_list[IMPTRACK_HUD] var/image/holder2 = hud_list[IMPLOYAL_HUD] @@ -1361,7 +1361,7 @@ if(I.implanted) if(istype(I,/obj/item/implant/tracking)) holder1.icon_state = "hud_imp_tracking" - if(istype(I,/obj/item/implant/mindshield)) + if(istype(I,/obj/item/implant/mindshield) && !istype(I,/obj/item/implant/mindshield/loyalty)) holder2.icon_state = "hud_imp_loyal" if(istype(I,/obj/item/implant/chem)) holder3.icon_state = "hud_imp_chem" diff --git a/code/modules/modular_computers/file_system/programs/command/teleporter.dm b/code/modules/modular_computers/file_system/programs/command/teleporter.dm index 5260a61da3e..6f230b8a181 100644 --- a/code/modules/modular_computers/file_system/programs/command/teleporter.dm +++ b/code/modules/modular_computers/file_system/programs/command/teleporter.dm @@ -83,7 +83,7 @@ else var/mob/M = I.loc if(M.stat == DEAD) - if(M.timeofdeath + 6000 < world.time) + if(M.timeofdeath + I.lifespan_postmortem < world.time) continue var/turf/IT = get_turf(M) if(!IT) diff --git a/code/modules/research/designs/protolathe/implant_designs.dm b/code/modules/research/designs/protolathe/implant_designs.dm index 7aba0b48bbc..be6c0b9c2ac 100644 --- a/code/modules/research/designs/protolathe/implant_designs.dm +++ b/code/modules/research/designs/protolathe/implant_designs.dm @@ -2,12 +2,22 @@ materials = list(DEFAULT_WALL_MATERIAL = 50, MATERIAL_GLASS = 50) p_category = "Implantable Biocircuit Designs" +/datum/design/item/implant/adrenaline + name = "Adrenaline" + req_tech = list(TECH_MATERIAL = 1, TECH_ILLEGAL = 2, TECH_BIO = 3) + build_path = /obj/item/implantcase/adrenaline + /datum/design/item/implant/chemical name = "Chemical" req_tech = list(TECH_MATERIAL = 2, TECH_BIO = 3) build_path = /obj/item/implantcase/chem +/datum/design/item/implant/death_alarm + name = "Death Alarm" + req_tech = list(TECH_MATERIAL = 1, TECH_BIO = 3, TECH_DATA = 2) + build_path = /obj/item/implantcase/death_alarm + /datum/design/item/implant/freedom name = "Freedom" - req_tech = list(TECH_ILLEGAL = 2, TECH_BIO = 3) - build_path = /obj/item/implantcase/freedom \ No newline at end of file + req_tech = list(TECH_MATERIAL = 1, TECH_ILLEGAL = 2, TECH_BIO = 3) + build_path = /obj/item/implantcase/freedom diff --git a/code/modules/surgery/encased.dm b/code/modules/surgery/encased.dm index ff2089cb6f6..7c5821b0abc 100644 --- a/code/modules/surgery/encased.dm +++ b/code/modules/surgery/encased.dm @@ -103,6 +103,9 @@ affected.open = ORGAN_ENCASED_RETRACTED + for(var/obj/item/implant/I in affected.implants) + I.exposed() + /singleton/surgery_step/open_encased/retract/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) if(!ishuman(target)) return diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm index 1226e58e6c1..dd4b2d09025 100644 --- a/code/modules/surgery/generic.dm +++ b/code/modules/surgery/generic.dm @@ -183,7 +183,7 @@ /singleton/surgery_step/generic/cut_open_vaurca/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] has drilled into [target]'s [affected.name] carapace with \the [tool].", \ - SPAN_NOTICE("You have drilled into [target]'s [affected.name] carapace with \the [tool]."),) + SPAN_NOTICE("You have drilled into [target]'s [affected.name] carapace with \the [tool]."),) affected.open = ORGAN_OPEN_INCISION if(istype(target) && !(target.species.flags & NO_BLOOD)) @@ -281,6 +281,10 @@ user.visible_message(msg, self_msg) affected.open = ORGAN_OPEN_RETRACTED + if(!affected.encased) + for(var/obj/item/implant/I in affected.implants) + I.exposed() + /singleton/surgery_step/generic/retract_skin/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) var/msg = SPAN_WARNING("[user]'s hand slips, tearing the edges of the incision on [target]'s [affected.name] with \the [tool]!") diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm index f71b7be2ae0..15089f651d9 100644 --- a/code/modules/surgery/implant.dm +++ b/code/modules/surgery/implant.dm @@ -192,7 +192,7 @@ if(istype(obj,/obj/item/implant)) var/obj/item/implant/imp = obj - if(imp.islegal()) + if(imp.isLegal()) find_prob += 60 else find_prob += 40 diff --git a/code/stylesheet.dm b/code/stylesheet.dm index 9080664a316..13d3a80d191 100644 --- a/code/stylesheet.dm +++ b/code/stylesheet.dm @@ -85,6 +85,7 @@ h1.alert, h2.alert {color: #000000;} .rose {color: #ff5050;} .info {color: #0000CC;} .notice {color: #000099;} +.hear {color: #000099; font-style: italic;} .subtle {color: #000099; font-size: 75%; font-style: italic;} .alium {color: #00ff00;} .cult {color: #800080; font-weight: bold; font-style: italic;} diff --git a/html/changelogs/GeneralCamo - Implant.yml b/html/changelogs/GeneralCamo - Implant.yml new file mode 100644 index 00000000000..fac947cf362 --- /dev/null +++ b/html/changelogs/GeneralCamo - Implant.yml @@ -0,0 +1,50 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# balance +# admin +# backend +# security +# refactor +################################# + +# Your name. +author: GeneralCamo + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - refactor: "Refactored implants to be easier to modify in the future." + - refactor: "Refactored the known implant system to use an implant's variable rather than a list in the body scanner, and allowed for implants completely hidden from all scanners." + - tweak: "Replaced the sprites for implanters, implant cases, implants, and implant pads. Sprites by Wowzewow (Wezzy)." + - tweak: "Implant pads are now used by placing the case onto them (or vice versa), and implanters now directly take implants from cases." + - rscadd: "Added the EMP implant, which will emit a burst of EMP when activated." + - rscdel: "Temporarily removed the compressed matter implant from the uplink, as it is difficult to use and needs new logic to fix up." + - rscadd: "Explosive implants now have an anti-tamper system that will warn if it is exposed in surgery, and can be triggered via radio signal as well as a custom phrase set in an implant pad." + - tweak: "Completely removed the emote triggering system from all implants, in favor of an action button-based system." + - rscadd: "Re-added loyalty implants, which still exist in the canon. These are currently unused, but variants exist for staff and event usage." + - bugfix: "Mindshield implants, when implanted, will no longer give the old loyalty implant messages. These are exclusive to loyalty implants." diff --git a/icons/obj/action_buttons/implants.dmi b/icons/obj/action_buttons/implants.dmi new file mode 100644 index 0000000000000000000000000000000000000000..a6aaeef180a800049856ed38aeb48a85c3cad7aa GIT binary patch literal 9593 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 FV1iQ;OqBot literal 0 HcmV?d00001 diff --git a/icons/obj/item/reagent_containers/syringe.dmi b/icons/obj/item/reagent_containers/syringe.dmi index b30a98cb38a83a6892922aee049c0b5efc743922..df8d5e2ac968e53611d64f1fd44c8863e925cfd4 100644 GIT binary patch literal 15092 zcmcJ$cT`hb*DoC4ASxmj6cr&J1yQOV=?FnV5fD(iv>?c#386?$NKkA@(@+9Z0@9?0 z-bp|yQY7>ap@m3?P(woUZ9LC?zdyd`z2EbWJ1%1|*z7&`Tx-oW=WornLmugA@*KTz z6a)hCXg$y{0D;&h4}K3H0`3I%;bTA`c0_=Y*$WMOFFQ{s_ZLnuHxS4#F(&S(+w={- zH-oK)X3KIHVnAub&u)FWP~-@0@H~z2YxcO@!q=UJy~o~Y{E2u{;3FQ6sDyOB(Ojp~ zh)m-p>uuV*?X>x%uZ?pphRI0}Pn$mu@s4-MmwPAo5Zs*d>THak-^M;>q--2OIv=J@AJy)B)>QX#K;%H>}~-6hAq#E`gCJX|B; z+hGp+{@WiNW|#{~!tLFD-r9G|E*u&czL~2U1BvL_&Pnx1{}ZnPB3EjJ1^f7-i&{(W zTX>(1*)@)C%DJ}s`quF*(6`B&qJc{F9@{6;_nt)i&uz6<&UMb;;WR|y%Ici*KhV4l zAGLJpC-u^wv0>cz#6lc}F&?0g?e=PWmp?cT5I<~P(X;}q+&J_2Bnxx>pjX6FccSWDdCpXoM}!g+_by;?Ip#uBWh118;agrEJcp{!o+@T-`+eXe%(HP zyDt4@sis2KapAxa4zHTVm)Ta6(Oy!LmL@^zYLe{RhlcnZRII;P!1W=~a#80b7Z`(Viiq@g!> zvXTHy@5M_Eehg{aP~A*LJ6v$l_QD%!!k`JDLRo zT>@!o+%fV?Tpoub_yB(Et3efMekb0))u}veebo7l?HlZ6fvWwrSMu5?Uv88bL_RV~ zKapyXeb26}`+Jet>zpC4FP4p8&xJbmeSEZePUQXNbfKfd!mm$!;!Ew%d4@zah9nef z$<^H2So#~XI@pexEhoi0_+Vkl!^7dmj~-nDfhKW2nere|kcI{u2gnA*c}ygOVxC#? z=ZVATNQXdcQB7X;Akc2)nHwV#CjB7W^PI=@{`mu&W#TfQ#3FfNeH8+NzghZw!Q zXwut!<;9AYSs#$vHNL|3hx*&mP^-CUk}4E#vLkFINA4WCP6(XX^#iHd74Q|_s*3+S zYkQrfL6hy=sA0VFdKeA;%9!Hc?6s&u^oG(Vb`{&04SyGi`3*~&rM_1 zBD8e;b%-d*2zYU)gmIUgwLf~!UWITMg*cHOCaQ(h3n+?40n@3Ap=)k2nI~vv)T5nX8u^%LX#yGQiZXzbu{1FeEs2ffl_ zO@^z2G^Q&ZVf9bEAM~to@68uq_Z`@?QZ0&xeF281KS5@0ytBHQI84PTQBcQYZDnqtaz@RTDJ=nM)B+NR=|AOMS zm{!lhEPaQgl>_}(Zgw9qZt!DP?N>Wfw@!zLv!aMnj~}ngCHa{18@mOzR3NnW7IJY* zYM1J@1=KVy2OL+ZM94iK_wU$10!ydveG}-VeJ_Z6M2GoyJ_e=|;Xl!hV|dZMjR7wE zj&rxK%wV@+b~3cR5T)f(sS(pE3uVaIES%X6b2HhI65Lv2j0U!27TSC_e{~1Ugv$$S zi6*+g!tt{dX>Z=VsjWTw-Y{QkvYFgVr>h%nKmG(G)--A34Urr;>>M1w(cZFpcHHYB zjTR534gaZSVA9Nu5-qTxm{_T`J-srA3>jDDAt4rSJ>< zl$T{*rDhC?Lwjk_kP}rVP)=9x`OGiVk=`RtR){2qod{tm?Xv4fnYBHq`x{B9gw7rM z2fJQcJ4PC|27|Oq-{05|*LbpUK7Hi<3^R)i8d@W5E$yWatPg|8|PSyL64ZK>ahuLk`~hJ!BRA53PZ+*G*ck zo;W--m7IDcHz=tUXF=Q+v#!yPJS(`q^;7DHDCwDM*98JXY*Yx?)_WG;^crdbg;Q}~ z+>H~9pSx{r^t5KZT~p`$x`JHzo4}*ho?c~Q@;bolH>p>-W}{$#fe#OIR76xDX-4HL zcJ+(s+%GR^p_CzJo%DgbN>DcFU>@R}^L+R(ZZM~l> zFqvxs&y&S+3W*EJ=@p)=U&gORC))PYIv0|KaqZo>i(1L{W}KXy)?-p#nN8|9@708_ z7e;38-jsurnAvqN=w|{Z2i84&kNvM*Tkx3gO?In+Dq0J2A3X=M?RfPrxv-Z)67p>t zjf2vs>?1H0Kku1=PN$W)0TGg|8L2RHKK?kD#AISHjLjVT| zhAR z!O6WpKed@ohbw?Uq`&-A4KJU;1&0=bfE62d{ddar&&HFi!ZM;-@aAC1Cybng1DK}1%Bg@2*@;BR!VoCUy>zbWaZnpySe!V zucxal8A?*Fv|Z6+wM&ms1Qeh*B{S{7Mg^TX(1Lf+F8wD&To+)6zWbQRz?wiZ)7~`g z1BK^7P$N$-m!bsHcr1JaOz@`w>8No~k{SBqGlY#7iy!&)aW7KuUlQ`1T7Nv0FB&4B(Ks!@T~Q3QD@v27L4enH+v|i1A&O;!0d8y4Y9#`NEbm?HP3AbRcUcJeM;OQ!#nQ7N*GLL1`hito5(^KjleF zZ9HUheuYCP!#8jhPWcsTwOqD=lAllK@P^JP+JLN&CZl`?k!gZW7B33RP0$eH%R>}? zLA0v0zrHMVFa`@IzP!4}Y!Np#sqdULUCuSw*1;`o-sog%~%;pt9u?| z?JXjOwJyj8JlvnuPyXvu1J~sF-VI(_2dn#oA7{rT$Bm{<&9$p@ViK%=iG$rT_I@a*5sN z5G$kw`%zfZYVS3(_Gy|h@VMfi$MDqttQ5^~p)?HCzle$6FcV~`z_+WZ%rv)gJ&W0v zp~l5sc-{EAl2rF!Dy)x0#%g9E_ipck^FCRcmAe|adQpWoySnA%?cH%4X+04DpZ(GI zl?z5puG{|cDZ8!R0&E(U1a11Yb-<{`n{~^Zo*E~GI9TqwJj-`1(A8*XIHCr(gkZec_F8+;W^7hKKVGn6J6X1NtxUEsfm`7?06QTj}4yJkzF zUit-zk^STEz;>r`GplQR3cDVOf|-$T=4tO3yNRq(<8&7WIqO$fyo*I$zMwDE#R12v zaW*{b7l4Ho1wjJVHoAGN~`64n*_jV-V`{K;x z*0SWW>hA*y|@L^$#`bIMWJYTiVjnp8-e1oYMNzLq2>|5TzMXHy zBH9M^`ECTo*#uBUvD7UA{-k?e(by9|!N~tI{+$4jn5zbrS-3GF4So z_cwr_n8d{A!l+iXNV)x!YHFK!xF9RHpjtaC(euM6MtZvNXt6|E3qc1Xb>XjP?~C@O z#l=JYSWnnEPJVbpy_JN;Vqu$@NCpE@1|vuYNli|QqQ#qKXT zG$Uyb^z`In34wGU(`}O2wQKH9Q9+H9(b!h%r)RZ{Q(L8Q0|Rs&iiNbBIaob>>f4)U z6MSY12kIDkF+QiZb}QMQ z_Gt?6iMI~SCRvaR2ZQiINgAO;97PW*ziN_#*b>NHKp!Z=8{7=KrdsUH} zvMsJM2G$o8cD?DY^JXBm!b<#MZcvb4Q~Sq*GxUFU&irpw&Qf|32=_K4vl2SFK31Z8 zyy8(OGVfnOc`EOw`t20CSG5KvH-`pjQaB+R|aq#lSqM$FcIaBvlzP`@T~p3nwO?E9+n#Py-y^qe(x*#u1zqrvK>B z3tIfaM6W?L#HZQitbllnO<1ap-|hX^AYBZ09(XO3`ohoDnLe z@K?_R+UJgcmYDx!2Ksf`PdKZAp-#JeD&L$6}y4m zSkGIRzIcoE2>;$_NZf`}x;ku!mbGuEnENxH@&wLs+e4;Tog54S5fMK@d2(aY)1j2| z+$x6$%foft0v(W0)h~#XRfQ(?dbAh}#>sPdT&Z-2``}GiWctV;RW^oX4mmeOa)S+4 z7F#VZU!Zew&|Ah-o7o}FSA|+gKj~13**LjL1~_N%^KeTCw@0oAx1KAx1v5(_0(* zd9gTQ-DHK4ewqWdvD?k{vos?S^+hlNSlYdNtBY%?&VjoP$~k#?1L@f%2uVmUEx*5R zP)*#OMGJ77 zP({%*7ej{?Pa^_5z-BiFe6-7f@ae&M5eeJ)##L+)dQ1mXtI%^%5gj3cJ{L5{H5%FN>_qkCE zoEz;klco{#cAuh?U93u2;UlI|niWy$pW$!&VlkK|#1S3u7BV(IFgiANV8NsP$B#n& zMC%Kf9hM_-^teUn4#Dot*W!w^0dNFox2aexC9A+Is)O3w+ou=giOrXXSKWd5!SyLa z&{~j-;Q3G}6fl&<@@-VUmCt6L57*hSvZx-f{K!n7{1`rd&ZQr~2o{F-^Y@u%!sxO_CP!2E&c6oNqvNHU43{eTha%>>A#s553 zTQi9UO`-$o+x-M9`wF-5yk;=Hj7QJp3pqiEH85vb51M=hJRO#w@Uz=*$u-GWnzO^{ z)DOQk&NUfEM?ate(2GXs-QfrdHOV*k?l>T!A~**sL7zv2PScP}D1fPiXs!ny{J9AV3 zX>o?#*0*Rn58ROobbYq(#s@a?wZ9b;suE0shR zLjvOuaz!PJp<+`RamvjiLP*8A0!B)nIsewL<|qbHLgTw}yJ&v=HvLPg9U`d|$Q@W& zTIOBRjCgcbiZ-E08H(4zhEh^l~M4Z0uu8)`)7_excq$8reGoP)- zPV9ACv@kAa<-S}iWWR5DtB$(=lu$5YWu4u?pNuOll^G?T5(0QB`K{RmBHfQ@PXFpo z<3XmLyI~X5xk!SdWo#SY?-4DU3|dMu)WcN?D3YpHPdOUBH<}vuGV^i$dyA{>@{*E2 zRmstYrB$1T#wN%d=?Ljw<~}`8aw>eZeUprV4p3IbSVpa_ttZC^UWUkzj_c9P_vP?7 zR}m2<917)KN2pm6@wVD)JgxsL#?<ZrVf9Z!Kj!*A#b^fOjAYd9RGc7i(Ik2A!;U2!IHWK$isUJ7WPmqT9WSqD`_m>VxOSATC_P)!9DFo40}E*oNbD;zHr;my@cd7 z`{UCOj)Q=#Q4-STySF*tV!8BUAv;TK{`JTq@h*HI-5Eub8Z@n+n$xUd7otr+c+%8^ zzaE2LV3M|&D>>B_2K1ffUhhFGQv&;OaeD5+i{M;A*jnK`slj;$)fc1A^9rSTTe`i!b%!>wyAX*p@&2Y@J zBjcjGp?URT7r>3%V&NxWaVtn3lSyql;|{NBM*jMg6%!kKR-QLKEbJJZIfiXpln-7L z=lWZbJjWmuIZ7cuT!ri&b(AkpTjw-vFuj9o?JQs+fQXX2P$^bM!h$P<`*qgvnKj@5 zC}p`n!CS+-JsWnam*9R8)&7jWNG8hDyizBQ zEQT+-6=@QR$EvsSMhR5T%Y(Dme^Hf{T-r8?WqxDSN<@&PP(}0SV*AW}Vn?TeIfBwi zFAAy|vm_(y82-6crB;khko_sy`sRSCn%uwt zHtY0zjG`;q?2?bwunR7NU|$?agQted?N&W?*jgkFu(|S^-r+dXp%{*^nf~e1vj8!} z5HQX-LgjpKTO#t%*vv9H0c88x@QYS1%SJHHucVGS&7PYbb0Zg8Zw15!hnB{FqLTWh zCyyUJ7nHtg(!hC|JFl;w$Fw02$+iRJUl!hoO-)kmx40|c0a=lYSNa6p9@Nesn!Nfu zd7!|_^WSCJbeXd04}gFG$K+&;S9_OSKrQ(Qfk5j&`q?KcVAwz)jXQvbBuXZNxOC+(5a-XgHYwf=Uh(4^3kDKVcZA5?WN&zVJq(jldYuy z&tP1P>ApH@Ea0WE)B1E%a^k{OEFy{q8aWO%sdtN6Um7l1F4@~Q#;FEwwji8nWFAtM z+(tO}Z)jTehMyAthy3gyiF@Q{Zi<(u=aR=v^Am&d*K)RvhshL5u1=O7Ivqfpg^@Cs zU~G0yPLKaSeev6!;AkusH=pLaFwOKXde>DGaJ*B}t6v9WRWd}cxfEq-#9 zm6v(HeRV8jM|)we-wTH*>*suanbhk2I*MT5es&zbTDL`z(D+PJP)=k_E;&-w?JJ^z zf6$CfPm4Bam8boW(a^scY{JI}p9Xyj%;N|1lhN9tZohC);C%xt#piT13x@V8h zmVCYd3_RZk*BdD9#%iNG!=o6F-kjBA9>~sdBSEY*mYPJlpVrD7BdCXu5_CcuR!Nfe zKg+akQ<+>Tu0R&ny%0c_(PhBeNW67loL{>90!||*C#N*4)TnN6^G_^8 z?$ZHz!px|5+HBriy`smGf4nnXSMc&IJ#&B&NV?)C$S|hui%DUFV z>Z-K$XxJ~$u_=X1pWHrfTvMXHDZ)r7Q&sTp1;!0L%*=+wP zWLEkk_AX)OQK3|llE3FdS*sfuWR&>VAHvSxovgJ0`!i8sJ57bVX1EwLB%;+ef!Q-(oiGBmoNP*!1B{K}00q z@V+uSZ_;kcN3R3Ig_ugYv#_~r!Fpq0XgD+f&%!O*<3YU4Wf)0sBF(#3H&Di@M_4)0 z)pBPNvT5CFXujTgeW5=qQpIgd!DUX+*X&?2@A4x%qaq=0yytFQ`m*oFL%~GL`^GxY zD6cx!2eB<6Mw|+s`TLI|4^K2FCSHUC_kZD$Fvs!W*yC01^zI3QMMD3s*=^eHO!-Fp z8v)w@PKo~fyQ=ik1BIyQ5^5!Ef#mIh63^TD!hAL^>*L=Kky(h9 zmvqQD=|UfjcHFL!J&1ylxW<9NCs{ufEhYyRegKj%TnnW9B&RJUTj~2O=bMdw^YCdz zuyHu5NQ>5+&9xxmG#%~REcV$fKS(Elof4|3#Q9gOI6cvw`&13lMPdA9jvUhUO8I)?**~j&V=bJke zeO6Vhyr)vU$|}Cx7VKn#iRObd6X6RRJK6!;{xE8=R}zu-2`pBTjS!5T?PhX>yk)=tAXw8X zhojwhAz~QP3vj+hCtuVupq_V-*~Rbo_w%Su?D~9C^~0H=BWSF->2Z%wtIw1xM1eBU zKsVcoXq_X_XXEz=0zsE;!pE_h3v5gankjvmjFp?SGk(X^4a z6b_(#5>{w+6O}U#YgAK_msK|`?s;KjnsGeF#LyJg2-G`74|)L>MWNf>UuRbq7@_Br z^~z^OeN?*!*7VE{>#WU+XERx71eVdNUyDeQ{1VhH2JjHpvO}p1x~zMuI?{5;)^e3zU495*f^(v++WOI>_oJyDK*Yo(MvOb1qU zHfDJwzadR3AKsD<6MYKUzWr$4cpFkNtLaGLbrE~GE5%i2Myr%ADCK}ChIV$#wU7HM zY*5ShqobniDqcujvyqwqKr>v92wa#5D11J+vWH1g$OQw8jB$`?`#Q5I@ZIJ1fw@SS`F^_yF?uSS|cdMm;eVtmadrsahachpL9j?71 zL|wFe{pRe!UP)?ozENl(vZ3{ndGM(M`0_xl(ZVDwb_BM93!@W;`hcu81~b!Z(yVF; z;KJO)#^VH08|rCgu%pZG>dquktN3>{p6>vNSE2bpr%nJ)^<kK{rabO-;cYW#KS>Ei{^_pl&c8Y=#zs)}}Y?@KpO13ip%V-a7fZ zxXMqSHrrx}ycY5i`|H}|-!JBSns)kOU&ygBD`?@m?dkRw#7}=UWfl>ssM+d}_?Q(0 zV+6)zkkR;rYp)auF9}ry19U09%i(4c1Tgi{C;q#?FD%dxXO)LTVhMztoIB+tT6oER zoBj*F8(~V19?P@IsQwhu`i*uZmBJ*VEdIw8@tveY;7B|T(=s-YdN0zYkyckqPm637 z#WK#d9=vJ$?R$LgB5SLPb_3$TnZMxx}Y4voe(6@GObw+KD!*)Aaqn=DUkryMp?@m2LZQW5} zO+&EKS^=xYk>5M@UjVt0#>72wby3D<94;niMQN_#qVp-mQru=7md86olr|d$wxET) zX20K24Jb|xiC0r*cdT<~V=Kxqa`0au7P}D`jv5H(QU<7DQjn8Cx%pm?_w@295Qu516JdD1#+r;(@<;J8V($_(fgheViBtafa6095S=#c`UlK3 zXK>&wK>vpK;X7-y^4Q6Sp}*Iq#6m9hdFe+q!=MK?x7{yqx!4M09n6eH>uzgpEfSAd z6?zQe+|ivIxt!!Xowe6Hffq}x=t9m;-78pyHi}OUg4>F%^IA=}+Z8VWcI01l>bOuC zzYBG1PyNYFkD#d}@ywqUnh$rgfjx9yJM~tbuB~o8G_?&Q{UavFpGg&6%-)I9-V-5M zF)!E0xpb$+>4(d4Rci4rp)!6$*OnoH@AXFN9$QD__{d)M`eE^Qf(1EU5%Jum-X572 zqejH@Vc(6<1lV?5Y?Ht92V}KxY>_L8gcsLox7uG$_^oQ-a7`iWXGx{-v~8@aM)13E zgSn9}CR@G04hMLlGE7u%j4ycj)nt*ytK83QR(j0j@lR9_3dM|#hc7$TpAQ3bS$VuG zU;N;-;Y!(h-3jm0cHXX7T?q`R-W!D+sKr&1WaRDIAD@BqWjw7NqYbyI-uh-WwPQ$u zb`&BR%LLeG_i*pt*DkfAkE%BR62>v}jMi)}-TZ?PMDo`Z%3k3OlxJE?C&Mpe5!9dL z8WF$#3+<@wkArMi{#GE^D@!lwYXdgqx<03i9h#(%BUk=qL+|}WB^vW4eTO_I&LL68 z#=)!WRN8rJt0>75dHJ8pyze*m|4F_6-};rDK&c>qZ}AaeP?uge1apCJ5`lc2jqXhk@T2_hpg*tHrE}$*pbs|+# zECBj0@?v*l75C;Cjo;CaWnnJy6mXY=4$DZ9yomF;ZEeosfw^*dXKox6D!a71V{r#9 zfn8#5(Z4Uu{{*-@FSomnnBxV=;=kKT4tfRKc~z|GOFM)D*~hPdbq-i*l5Ty5xG=cO zh&xQzzJDmM{((s}#0TS+GgUG&suzF3lQA|kjG73%DIADvnyC)qs8l(MSa!fDWh9Pj zZbTMeSDKV_0lbmz5~B2Ab46$$!I#%A%LUY!1;|6Zg0wJFH1Ew_mQ6xsmTwHVF5t;u z-zMUp#E|<9T0#TcQNP09Icw^S^kqjmJ3E)=r)wyY2#kZIee!tCBg1k;K}-vHpi2h~|#rzZV5tWn@h0pOAzctUXCc7ek|K=f4sUvuEX6zaVD5o*_M5^*cY zPLbT3?*J!nTUgaFx@OAS^dGkfvAzs)ndgjI=36LDoHVAD%ArP6?kLHUk6A@0Ny1L}?j|Mb*zjXT61=S_*3Icx9@>9(5#{ewk0D}T)3(IyY zwY*O5zysaxxJ|D;4KW5lg&6TBd*)a@{GdkAvXVID2BkeVb}KOPCl)E?!l296ey@(N zC@eYA4?$ z`2heP{PxX!U|WuR3LI-KZB$f$a!=15#j?)YzdRbUgw~PSs>dQ~*sJM0B`9rdBddqP-}Rr6~9Ad(}?gWCyr?$6X?|R|+}_aZ?L6f{dRA^q>1Nd+VqP zSiadtPMv@6)xo1Z?W1lw)B6e>j!%HvrtIDfD<`HFvOH?QEYy*Dtg9P-pF(lzPr1{k zy+=rf=>s$|%Eeas!h`Lm({(9qpr7t02}lfVhS3dXnJ!z=x3$pa+W4do+nxty4z&(1 zlkZn{mN&NiZKMy3snRAuc17-Y0P82N{cpX-|MaG%v<(Gk3<@H}p-$*qN>2U@LCl5z z05Q&TZxFYyL)=cIuJSV7^Mej*O9y7rd5t99%gYW5$yjH2r7D%}zy(G|Ww(L)?T9M5 zef?3i1iiD))F? zZ7qql_UVe!P9pxG_%~GHJSu2*BewS@=yq=(D9y+-({ZYU4pmW$qWO#Si&4IT(0*v>XiJ`lEGGy-h zXtOxfXE7+GxLZ!csJ_UZ!u2uE_9-(JG4I2?-RBmMf}#mO4Y0g|iPzqbKLm7_DaOIc^M@>w*CX)Rx!QK8$K#8Az>z z?waG#eL#ISx3;z;@@wT3B`ywWJT>hA4(U{%`30A&*}xFJdidT!D$jt&PT7(Di<;N0Bef*L zX>^$6`*_!oGuDwIAvYu6&?sL7uw_7jx{Mm0(c&lpA77f}Vilzl#?V2S1jQxMvu{DLe-n8fj>v@1YF_v$uzcVkW+stg0 zbGeo;2xuUy0IVvv<(1a5s!@0m#C`IY5VzUXm$F@5 zp8v2%@WAJ=+{AGi&}!xnb8{XuEvs;eLwqb`ZmH#{{6aVlVy{0f4P$?s8)2R#p?xmI z5hx05Uy&Y9@2-gKsb@ytFu%|C-5b!RflS{G1Qr2w#Ez$`b6r*0bpt4U?%jKnlbgF0 z3}&cVXs6>bXUsAyxQoKs--=3IP--4*6$P4ynwpxFJZImpMop+I!_qcSn*mjnV5+3J zcpBpL!%HXLJ04F7I=S-@^Se1h*@0aoF-TiSXSuev_7GXwuK8HopysDoYyu77b8=sT zGpzFOVuTJr&|2;{vAMf{ z_FSGP@obF)aYD)2n~FGgDzH}h#V?zLfHkci4&K`~36`|D36=(tvKs|<#piM&{I(y~ zqcjSoTs#{y&chNTg!F{2{g&963Q-36@XkL24@=lIMfhcTYNGg&|zL_Kwtg`J)-~C z=lpMO4%ufLMvP=uuz^m{ui5Zt=qWlc&Yq0E0ZO^YSEw_PZ{a|aVVs`_(|TI3MDL~P z0#AhBt6l0^P$c|3<9_KxAt0Se7h1kWMQ6d+uaCUF%b06w{#Hk@GVf0v`gr1?nOcjj zDhcK+kT^ClR|6#Qc!Q##|5VP+koK`alLTfp`nuufm=`g7wEMa@H2w8UIqBH8mPU4A zKaws*$KW;@OqsjS$IoBm?RAnux5E4T`}4Hs-=a>QU?39~H}NjJb!Z zz-I{eS19445QpPb7a>PW)vFsBtJ@^$SxwBUHe13qpwHxI%qnn>ls)}^=uE9bFxB<@ zD=^~f(f8Dlqn$(bhYK`Cn;U(l6PqKE~pj`tmhyX@}D`q7c_Ha0SPfbOP-$MmAs11O?E&;e9cU}yOFG%k(-hBMly*K(J+iekax`+HmH zj(mhJuJ*@ovPcO?4*T2E7xM-dr?QgRK>2q87u!ZH0e)L4{ZKv9{=4220dD-{_gm8grM?LUY^8gw=df; zzl5kddVm-%lE5A5LApXI0<%#srL5d->O`TOxs`uR5ZOXI(%WA}hvy64I-=Qxd5g!9Zsj z@HtQSJ+lV#&T3N=Pn&d~cJDFA6;_X|fx4Ck9_L z)P@5H0jQ7qrph^O3O&g|+ipI3;qTF;Tzx0N{7EX+6)0jWoV zA=Vb<&mRK|SS33s5z0(()~?e2uxugtQqk9|;VnY&4r}T}Po)?e;cA<5fzsmvR|6oE z?ywW=cM;WEM~CVF?SB%Ba`WGwNgLwTkEG>0tzXVl^qL#$jA_2AO?-h&2Uy*tXE;eO zzI7-V%zIK|UN_#&taZxH&Mr44|0268PX{vgCzyUJ6PB+zqrRE5B}f5S@F`B#CD!}< ztwEQ;0>b^xjT)bQSvOHswww2C(}$)=YRoi>kyghlGpPl`>RcQqp;yA@^o9;d}^;`(O)X*=}oeSPF~9*~rNU8Xct>A?||amUqz zVd2H%n8bb*x9J5$0amlM0roB8$v@KpzO75W^Iw-4ci15No3}E{)zKO>cF?JN!R%5J mvz{mrh;gF(px+qOO=Ah06s=In=UE`&N9&%RM!{X1SN{(#Jb@?x literal 17897 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 a9<{f|;-QOhJ{)W*q^7KSzwq9(SN|7iG=)n5