Move all the non-weapons out of code/game/objects/weapons (#29820)

This commit is contained in:
Charlie Nolan
2025-08-06 01:37:56 +00:00
committed by GitHub
parent 379a368ccd
commit 8ffefd8777
64 changed files with 63 additions and 63 deletions
@@ -0,0 +1,229 @@
/**
* # Implants
*
* Code for implants that can be inserted into a person and have some sort of passive or triggered action.
*
*/
/obj/item/bio_chip
name = "bio-chip"
icon = 'icons/obj/bio_chips.dmi'
icon_state = "generic" //Shows up as a auto surgeon, used as a placeholder when a implant doesn't have a sprite
origin_tech = "materials=2;biotech=3;programming=2"
actions_types = list(/datum/action/item_action/hands_free/activate)
item_color = "black"
flags = DROPDEL // By default, don't let implants be harvestable.
///which implant overlay should be used for implant cases. This should point to a state in bio_chips.dmi
var/implant_state = "implant-default"
/// How the implant is activated.
var/activated = BIOCHIP_ACTIVATED_ACTIVE
/// Whether the implant is implanted. Null if it's never been inserted, TRUE if it's currently inside someone, or FALSE if it's been removed.
var/implanted
/// Who the implant is inside of.
var/mob/living/imp_in
/// Whether multiple implants of this same type can be inserted into someone.
var/allow_multiple = FALSE
/// Amount of times that the implant can be triggered by the user. If the implant can't be used, it can't be inserted.
var/uses = -1
/// List of emote keys that activate this implant when used.
var/list/trigger_emotes
/// What type of action will trigger this emote. Bitfield of IMPLANT_EMOTE_* defines.
var/trigger_causes
/// Whether this implant has already triggered on death or not, to prevent it firing multiple times.
var/has_triggered_on_death = FALSE
///the implant_fluff datum attached to this implant, purely cosmetic "lore" information
var/datum/implant_fluff/implant_data = /datum/implant_fluff
/obj/item/bio_chip/Initialize(mapload)
. = ..()
if(ispath(implant_data))
implant_data = new implant_data
/obj/item/bio_chip/Destroy()
if(imp_in)
removed(imp_in)
QDEL_NULL(implant_data)
return ..()
/obj/item/bio_chip/proc/unregister_emotes()
if(imp_in && LAZYLEN(trigger_emotes))
for(var/emote in trigger_emotes)
UnregisterSignal(imp_in, COMSIG_MOB_EMOTED(emote))
/**
* Set the emote that will trigger the implant.
* * user - User who is trying to associate the implant to themselves.
* * emote_key - Key of the emote that should trigger the implant.
* * on_implant - Whether this proc is being called during the implantation of the implant.
* * silent - If true, the user won't get any to_chat messages if an implantation fails.
*/
/obj/item/bio_chip/proc/set_trigger(mob/user, emote_key, on_implant = FALSE, silent = TRUE)
if(imp_in != user)
return FALSE
if(!emote_key)
return FALSE
if(LAZYIN(trigger_emotes, emote_key) && !on_implant)
if(!silent)
to_chat(user, "<span class='warning'>You've already registered [emote_key]!")
return FALSE
if(emote_key == "me" || emote_key == "custom")
if(!silent)
to_chat(user, "<span class='warning'>You can't trigger [src] with a custom emote.")
return FALSE
if(!(emote_key in user.usable_emote_keys(trigger_causes & BIOCHIP_EMOTE_TRIGGER_INTENTIONAL)))
if(!silent)
to_chat(user, "<span class='warning'>You can't trigger [src] with that emote! Try *help to see emotes you can use.</span>")
return FALSE
if(!(emote_key in user.usable_emote_keys(trigger_causes & BIOCHIP_EMOTE_TRIGGER_UNINTENTIONAL)))
CRASH("User was given an bio-chip for an unintentional emote that they can't use.")
LAZYADD(trigger_emotes, emote_key)
RegisterSignal(user, COMSIG_MOB_EMOTED(emote_key), PROC_REF(on_emote))
/obj/item/bio_chip/proc/on_emote(mob/living/user, datum/emote/fired_emote, key, emote_type, message, intentional)
SIGNAL_HANDLER
if(!implanted || !imp_in)
return
if(!(intentional && (trigger_causes & BIOCHIP_EMOTE_TRIGGER_INTENTIONAL)) && !(!intentional && (trigger_causes & BIOCHIP_EMOTE_TRIGGER_UNINTENTIONAL)))
return
add_attack_logs(user, user, "[intentional ? "intentionally" : "unintentionally"] [src] was [intentional ? "intentionally" : "unintentionally"] triggered with the emote [fired_emote].")
emote_trigger(key, user, intentional)
/obj/item/bio_chip/proc/on_death(mob/source, gibbed)
SIGNAL_HANDLER
if(!implanted || !imp_in)
return
if(gibbed && (trigger_causes & BIOCHIP_TRIGGER_NOT_WHEN_GIBBED))
return
// This should help avoid infinite recursion for things like dust that call death()
if(has_triggered_on_death && (trigger_causes & BIOCHIP_TRIGGER_DEATH_ONCE))
return
has_triggered_on_death = TRUE
add_attack_logs(source, source, "had their [src] bio-chip triggered on [gibbed ? "gib" : "death"].")
death_trigger(source, gibbed)
/obj/item/bio_chip/proc/emote_trigger(emote, mob/source, force)
return
/obj/item/bio_chip/proc/death_trigger(mob/source, gibbed)
return
/obj/item/bio_chip/proc/activate(cause)
SEND_SIGNAL(src, COMSIG_IMPLANT_ACTIVATED, cause, imp_in)
return
/obj/item/bio_chip/ui_action_click()
activate("action_button")
/**
* Try to implant ourselves into a mob.
*
* * source - The person the implant is being administered to.
* * user - The person who is doing the implanting.
*
* Returns
* 1 if the implant injects successfully
* -1 if the implant fails to inject
* 0 if there's no room for the implant.
*/
/obj/item/bio_chip/proc/implant(mob/source, mob/user, force)
if(!force && !can_implant(source, user))
return
var/obj/item/bio_chip/imp_e = locate(type) in source
if(!allow_multiple && imp_e && imp_e != src)
if(imp_e.uses < initial(imp_e.uses)*2)
if(uses == -1)
imp_e.uses = -1
else
imp_e.uses = min(imp_e.uses + uses, initial(imp_e.uses)*2)
qdel(src)
return 1
else
return 0
loc = source
imp_in = source
implanted = TRUE
if(trigger_emotes)
if(!(trigger_causes & BIOCHIP_EMOTE_TRIGGER_INTENTIONAL | BIOCHIP_EMOTE_TRIGGER_UNINTENTIONAL))
CRASH("Bio-chip [src] has trigger emotes defined but no trigger cause with which to use them!")
if(!activated && (trigger_causes & BIOCHIP_EMOTE_TRIGGER_INTENTIONAL))
CRASH("Bio-chip [src] has intentional emote triggers on a passive bio-chip")
// If you can't activate the implant manually, you shouldn't be able to deliberately activate it with an emote
for(var/emote in trigger_emotes)
set_trigger(source, emote, TRUE, TRUE)
if(activated)
for(var/X in actions)
var/datum/action/A = X
A.Grant(source)
if(trigger_causes & (BIOCHIP_TRIGGER_DEATH_ONCE | BIOCHIP_TRIGGER_DEATH_ANY))
RegisterSignal(source, COMSIG_MOB_DEATH, PROC_REF(on_death))
if(ishuman(source))
var/mob/living/carbon/human/H = source
H.sec_hud_set_implants()
if(user)
add_attack_logs(user, source, "Chipped with [src]")
SEND_SIGNAL(src, COMSIG_IMPLANT_IMPLANTED, source, user, force)
return 1
/**
* Check that we can actually implant this before implanting it
* * source - The person being implanted
* * user - The person doing the implanting
*
* Returns
* TRUE - I could care less, implant it, maybe don't. I don't care.
* FALSE - Don't implant!
*/
/obj/item/bio_chip/proc/can_implant(mob/source, mob/user)
return TRUE
/**
* Clean up when an implant is removed.
* * source - the user who the implant was removed from.
*/
/obj/item/bio_chip/proc/removed(mob/source)
loc = null
imp_in = null
implanted = FALSE
for(var/X in actions)
var/datum/action/A = X
A.Remove(source)
if(ishuman(source))
var/mob/living/carbon/human/H = source
H.sec_hud_set_implants()
if(trigger_causes & (BIOCHIP_TRIGGER_DEATH_ONCE | BIOCHIP_TRIGGER_DEATH_ANY))
UnregisterSignal(source, COMSIG_MOB_DEATH)
unregister_emotes()
SEND_SIGNAL(src, COMSIG_IMPLANT_REMOVED, source)
return TRUE
/obj/item/bio_chip/dropped(mob/user)
. = TRUE
..()
@@ -0,0 +1,61 @@
/obj/item/bio_chip/abductor
name = "recall bio-chip"
desc = "Returns you to the mothership."
icon = 'icons/obj/abductor.dmi'
icon_state = "implant"
origin_tech = "materials=2;biotech=7;magnets=4;bluespace=4;abductor=5"
implant_data = /datum/implant_fluff/abductor
implant_state = "implant-alien"
var/obj/machinery/abductor/pad/home
var/cooldown = 30
var/total_cooldown = 30
/obj/item/bio_chip/abductor/activate()
if(cooldown == total_cooldown)
if(imp_in.has_status_effect(STATUS_EFFECT_ABDUCTOR_COOLDOWN))
to_chat(imp_in, "<span class='warning'>The teleporter will not activate yet to prevent potential damage!</span>")
return
home.Retrieve(imp_in, 1)
cooldown = 0
START_PROCESSING(SSobj, src)
else
to_chat(imp_in, "<span class='warning'>You must wait [(total_cooldown - cooldown) * 2] seconds to use [src] again!</span>")
/obj/item/bio_chip/abductor/process()
if(cooldown < total_cooldown)
cooldown++
if(cooldown == total_cooldown)
STOP_PROCESSING(SSobj, src)
/obj/item/bio_chip/abductor/implant(mob/source, mob/user)
if(..())
var/obj/machinery/abductor/console/console
if(ishuman(source))
var/mob/living/carbon/human/H = source
if(isabductor(H))
var/datum/species/abductor/S = H.dna.species
console = get_team_console(S.team)
home = console.pad
if(!home)
console = get_team_console(pick(1, 2, 3, 4))
home = console.pad
return TRUE
/obj/item/bio_chip/abductor/proc/get_team_console(team)
var/obj/machinery/abductor/console/console
for(var/obj/machinery/abductor/console/c in GLOB.abductor_equipment)
if(c.team == team)
console = c
break
return console
/obj/item/bio_chip_implanter/abductor
name = "bio-chip implanter (abductor)"
implant_type = /obj/item/bio_chip/abductor
/obj/item/bio_chip_case/abductor
name = "bio-chip case - 'abductor'"
desc = "A glass case containing an abductor bio-chip."
implant_type = /obj/item/bio_chip/abductor
@@ -0,0 +1,101 @@
/obj/item/bio_chip/adrenalin
name = "adrenal bio-chip"
desc = "Removes all stuns and knockdowns."
icon_state = "adrenal"
origin_tech = "materials=2;biotech=4;combat=3;syndicate=4"
uses = 3
implant_data = /datum/implant_fluff/adrenaline
implant_state = "implant-syndicate"
/obj/item/bio_chip/adrenalin/activate()
uses--
to_chat(imp_in, "<span class='notice'>You feel a sudden surge of energy!</span>")
imp_in.SetStunned(0)
imp_in.SetWeakened(0)
imp_in.SetKnockDown(0)
imp_in.SetParalysis(0)
imp_in.adjustStaminaLoss(-75)
imp_in.stand_up(TRUE)
SEND_SIGNAL(imp_in, COMSIG_LIVING_CLEAR_STUNS)
imp_in.reagents.add_reagent("synaptizine", 10)
imp_in.reagents.add_reagent("omnizine_no_addiction", 10)
imp_in.reagents.add_reagent("stimulative_agent", 10)
if(!uses)
qdel(src)
/obj/item/bio_chip_implanter/adrenalin
name = "bio-chip implanter (adrenalin)"
implant_type = /obj/item/bio_chip/adrenalin
/obj/item/bio_chip_case/adrenaline
name = "bio-chip case - 'Adrenaline'"
desc = "A glass case containing an adrenaline bio-chip."
implant_type = /obj/item/bio_chip/adrenalin
/obj/item/bio_chip/basic_adrenalin
name = "basic adrenal bio-chip"
desc = "Removes all stuns and knockdowns."
icon_state = "adrenal"
origin_tech = "materials=2;biotech=4;combat=3;syndicate=3"
uses = 1
implant_data = /datum/implant_fluff/basic_adrenalin
implant_state = "implant-syndicate"
/obj/item/bio_chip/basic_adrenalin/activate()
uses--
to_chat(imp_in, "<span class='notice'>You feel a sudden surge of energy!</span>")
imp_in.SetStunned(0)
imp_in.SetWeakened(0)
imp_in.SetKnockDown(0)
imp_in.SetParalysis(0)
imp_in.adjustStaminaLoss(-75)
imp_in.stand_up(TRUE)
SEND_SIGNAL(imp_in, COMSIG_LIVING_CLEAR_STUNS)
imp_in.reagents.add_reagent("synaptizine", 7.5)
imp_in.reagents.add_reagent("weak_omnizine", 7.5)
imp_in.reagents.add_reagent("stimulative_agent", 7.5)
if(!uses)
qdel(src)
/obj/item/bio_chip_implanter/basic_adrenalin
name = "bio-chip implanter (basic adrenalin)"
implant_type = /obj/item/bio_chip/basic_adrenalin
/obj/item/bio_chip_case/basic_adrenalin
name = "bio-chip case - 'Basic Adrenaline'"
desc = "A glass case containing an smaller than normal adrenaline bio-chip."
implant_type = /obj/item/bio_chip/basic_adrenalin
/obj/item/bio_chip/proto_adrenalin
name = "proto-adrenal bio-chip"
desc = "Removes all stuns and knockdowns."
icon_state = "adrenal"
origin_tech = "materials=2;biotech=4;combat=3;syndicate=2"
uses = 1
implant_data = /datum/implant_fluff/proto_adrenaline
implant_state = "implant-syndicate"
/obj/item/bio_chip/proto_adrenalin/activate()
uses--
to_chat(imp_in, "<span class='notice'>You feel a sudden surge of energy!</span>")
imp_in.SetStunned(0)
imp_in.SetWeakened(0)
imp_in.SetKnockDown(0)
imp_in.SetParalysis(0)
imp_in.setStaminaLoss(0) //Since it doesn't have a good followup like adrenals, and getting batoned the moment after triggering it will stamina crit you, will set to zero over - 75
imp_in.stand_up(TRUE)
SEND_SIGNAL(imp_in, COMSIG_LIVING_CLEAR_STUNS)
imp_in.reagents.add_reagent("stimulative_cling", 1)
if(!uses)
qdel(src)
/obj/item/bio_chip_implanter/proto_adrenalin
name = "bio-chip implanter (proto-adrenalin)"
implant_type = /obj/item/bio_chip/proto_adrenalin
/obj/item/bio_chip_case/proto_adrenalin
name = "bio-chip case - 'proto-adrenalin'"
desc = "A glass case containing an proto-adrenalin bio-chip."
implant_type = /obj/item/bio_chip/proto_adrenalin
@@ -0,0 +1,68 @@
/obj/item/bio_chip_case
name = "bio-chip case"
desc = "A glass case containing a bio-chip."
icon = 'icons/obj/bio_chips.dmi'
icon_state = "implantcase"
item_state = "implantcase"
throw_range = 5
w_class = WEIGHT_CLASS_TINY
origin_tech = "materials=1;biotech=2"
container_type = OPENCONTAINER | INJECTABLE | DRAWABLE
materials = list(MAT_GLASS = 500)
var/obj/item/bio_chip/imp
var/obj/item/bio_chip/implant_type
/obj/item/bio_chip_case/Initialize(mapload)
. = ..()
if(!implant_type)
return
imp = new implant_type(src)
update_state()
/obj/item/bio_chip_case/Destroy()
if(imp)
QDEL_NULL(imp)
return ..()
/obj/item/bio_chip_case/proc/update_state()
if(imp)
origin_tech = imp.origin_tech
flags = imp.flags & ~DROPDEL
reagents = imp.reagents
else
origin_tech = initial(origin_tech)
flags = initial(flags)
reagents = null
update_icon(UPDATE_OVERLAYS)
/obj/item/bio_chip_case/update_overlays()
. = ..()
if(imp)
var/image/implant_overlay = image('icons/obj/bio_chips.dmi', imp.implant_state)
. += implant_overlay
/obj/item/bio_chip_case/attackby__legacy__attackchain(obj/item/W, mob/user)
..()
if(is_pen(W))
rename_interactive(user, W)
else if(istype(W, /obj/item/bio_chip_implanter))
var/obj/item/bio_chip_implanter/I = W
if(I.imp)
if(imp || I.imp.implanted)
return
I.imp.forceMove(src)
imp = I.imp
I.imp = null
update_state()
I.update_icon(UPDATE_ICON_STATE)
else
if(imp)
if(I.imp)
return
imp.loc = I
I.imp = imp
imp = null
update_state()
I.update_icon(UPDATE_ICON_STATE)
@@ -0,0 +1,52 @@
/obj/item/bio_chip/chem
name = "chem bio-chip"
desc = "Injects things."
icon_state = "reagents"
origin_tech = "materials=3;biotech=4"
container_type = OPENCONTAINER
trigger_causes = BIOCHIP_TRIGGER_DEATH_ANY
implant_data = /datum/implant_fluff/chem
implant_state = "implant-nanotrasen"
/obj/item/bio_chip/chem/Initialize(mapload)
. = ..()
create_reagents(50)
GLOB.tracked_implants += src
/obj/item/bio_chip/chem/Destroy()
GLOB.tracked_implants -= src
return ..()
/obj/item/bio_chip/chem/death_trigger(mob/victim, gibbed)
activate(reagents.total_volume)
/obj/item/bio_chip/chem/activate(cause)
if(!cause || !imp_in)
return FALSE
var/mob/living/carbon/R = imp_in
var/injectamount
var/list/implant_chems = list()
for(var/datum/reagent/chems in reagents.reagent_list)
implant_chems += chems.name
var/contained_chemicals = english_list(implant_chems)
if(cause == "action_button")
injectamount = reagents.total_volume
else
injectamount = cause
reagents.trans_to(R, injectamount)
add_attack_logs(usr, R, "Chem bio-chip activated injecting [injectamount]u of [contained_chemicals]")
to_chat(R, "<span class='italics'>You hear a faint beep.</span>")
if(!reagents.total_volume)
to_chat(R, "<span class='italics'>You hear a faint click from your chest.</span>")
qdel(src)
/obj/item/bio_chip_implanter/chem
name = "bio-chip implanter (chem)"
implant_type = /obj/item/bio_chip/chem
/obj/item/bio_chip_case/chem
name = "bio-chip case - 'Remote Chemical'"
desc = "A glass case containing a remote chemical bio-chip."
implant_type = /obj/item/bio_chip/chem
@@ -0,0 +1,68 @@
/obj/item/bio_chip/death_alarm
name = "death alarm bio-chip"
desc = "An alarm which monitors host vital signs and transmits a radio message upon death."
activated = BIOCHIP_ACTIVATED_PASSIVE
trigger_causes = BIOCHIP_TRIGGER_DEATH_ANY
implant_data = /datum/implant_fluff/death_alarm
implant_state = "implant-nanotrasen"
var/mobname = "Unknown"
var/static/list/stealth_areas = typecacheof(list(/area/syndicate_mothership, /area/shuttle/syndicate_elite))
/// Tracking to prevent multiple EMPs in the same tick from flooding radio.
COOLDOWN_DECLARE(emp_spam_lock)
/obj/item/bio_chip/death_alarm/implant(mob/target)
. = ..()
if(.)
mobname = target.real_name
/obj/item/bio_chip/death_alarm/activate(cause) // Death signal sends name followed by the gibbed / not gibbed check
var/mob/M = imp_in
var/area/t = get_area(M)
var/obj/item/radio/headset/a = new /obj/item/radio/headset(src)
a.follow_target = M
switch(cause)
if("gib")
a.autosay("[mobname] has died-zzzzt in-in-in...", "[mobname]'s Death Alarm")
qdel(src)
if("emp")
if(!COOLDOWN_FINISHED(src, emp_spam_lock))
return
var/name = prob(50) ? t.name : pick(SSmapping.teleportlocs)
a.autosay("[mobname] has died in [name]!", "[mobname]'s Death Alarm")
COOLDOWN_START(src, emp_spam_lock, 0.1 SECONDS)
else
if(is_type_in_typecache(t, stealth_areas))
//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(src)
qdel(a)
/obj/item/bio_chip/death_alarm/emp_act(severity) //for some reason alarms stop going off in case they are emp'd, even without this
activate("emp") //let's shout that this dude is dead
/obj/item/bio_chip/death_alarm/death_trigger(mob/source, gibbed)
if(gibbed)
activate("gib")
else
activate("death")
/obj/item/bio_chip/death_alarm/removed(mob/target)
if(..())
UnregisterSignal(target, COMSIG_MOB_DEATH)
return TRUE
return FALSE
/obj/item/bio_chip_implanter/death_alarm
name = "bio-chip implanter (Death Alarm)"
implant_type = /obj/item/bio_chip/death_alarm
/obj/item/bio_chip_case/death_alarm
name = "bio-chip Case - 'Death Alarm'"
desc = "A case containing a death alarm bio-chip."
implant_type = /obj/item/bio_chip/death_alarm
@@ -0,0 +1,76 @@
/datum/deathrattle_group
var/name
var/list/implants = list()
/datum/deathrattle_group/New(name)
if(name)
src.name = name
else
// Give the group a unique name for debugging, and possible future
// use for making custom linked groups.
src.name = "[rand(100, 999)] [pick(GLOB.phonetic_alphabet)]"
/*
* Proc called by new implant being added to the group. Listens for the
* implant being implanted, removed and destroyed.
*
* If implant is already implanted in a person, then trigger the implantation
* code.
*/
/datum/deathrattle_group/proc/register(obj/item/bio_chip/deathrattle/implant)
if(implant in implants)
return
RegisterSignal(implant, COMSIG_PARENT_QDELETING, PROC_REF(on_implant_destruction))
RegisterSignal(implant, COMSIG_IMPLANT_ACTIVATED, PROC_REF(on_user_death))
implants += implant
/datum/deathrattle_group/proc/on_implant_destruction(obj/item/bio_chip/implant)
SIGNAL_HANDLER
implants -= implant
/datum/deathrattle_group/proc/on_user_death(obj/item/bio_chip/implant, source, mob/owner)
SIGNAL_HANDLER
var/victim_name = owner.mind ? owner.mind.name : owner.real_name
// All "hearers" hear the same sound.
var/sound = pick(
'sound/items/knell1.ogg',
'sound/items/knell2.ogg',
'sound/items/knell3.ogg',
'sound/items/knell4.ogg',
)
for(var/obj/item/bio_chip/deathrattle/other_implant as anything in implants)
// Skip the unfortunate soul, and any unimplanted implants
if(implant == other_implant || !implant.imp_in)
continue
var/mob/living/recipient = other_implant.imp_in
to_chat(recipient, "<i>You hear a strange, robotic voice in your head...</i> <span class='robot'>\"<b>[victim_name]</b> has died...\"</span>")
recipient.playsound_local(get_turf(recipient), sound, vol = 75, vary = FALSE, pressure_affected = FALSE, use_reverb = FALSE)
qdel(implant)
/obj/item/bio_chip/deathrattle
name = "deathrattle implant"
desc = "Hope no one else dies, prepare for when they do."
activated = BIOCHIP_ACTIVATED_PASSIVE
trigger_causes = BIOCHIP_TRIGGER_DEATH_ONCE
implant_data = /datum/implant_fluff/deathrattle
implant_state = "implant-nanotrasen"
actions_types = null
/obj/item/bio_chip/deathrattle/emp_act(severity)
activate("emp")
/obj/item/bio_chip/deathrattle/death_trigger(mob/source, gibbed)
activate("death")
/obj/item/bio_chip_case/deathrattle
name = "implant case - 'Deathrattle'"
desc = "A glass case containing a deathrattle implant."
implant_type = /obj/item/bio_chip/deathrattle
@@ -0,0 +1,34 @@
// Dust implant, for CC officers. Prevents gear theft if they die.
/obj/item/bio_chip/dust
name = "duster bio-chip"
desc = "A remote controlled bio-chip that will dust the user upon activation (or death of user)."
icon_state = "dust"
actions_types = list(/datum/action/item_action/hands_free/activate/always)
trigger_causes = BIOCHIP_TRIGGER_DEATH_ONCE | BIOCHIP_TRIGGER_NOT_WHEN_GIBBED
implant_data = /datum/implant_fluff/dust
implant_state = "implant-nanotrasen"
/obj/item/bio_chip/dust/death_trigger(mob/source, force)
activate("death")
/obj/item/bio_chip/dust/activate(cause)
if(!cause || !imp_in || cause == "emp")
return FALSE
if(cause == "action_button" && alert(imp_in, "Are you sure you want to activate your dusting bio-chip? This will turn you to ash!", "Dusting Confirmation", "Yes", "No") != "Yes")
return FALSE
to_chat(imp_in, "<span class='notice'>Your dusting bio-chip activates!</span>")
imp_in.visible_message("<span class = 'warning'>[imp_in] burns up in a flash!</span>")
imp_in.dust()
/obj/item/bio_chip/dust/emp_act(severity)
return
/obj/item/bio_chip_implanter/dust
name = "bio-chip implanter (Dust-on-death)"
implant_type = /obj/item/bio_chip/dust
/obj/item/bio_chip_case/dust
name = "bio-chip case - 'Dust'"
desc = "A glass case containing a dust bio-chip."
implant_type = /obj/item/bio_chip/dust
@@ -0,0 +1,23 @@
/obj/item/bio_chip/emp
name = "emp bio-chip"
desc = "Triggers an EMP."
icon_state = "emp"
origin_tech = "biotech=3;magnets=4;syndicate=1"
uses = 2
implant_data = /datum/implant_fluff/emp
implant_state = "implant-syndicate"
/obj/item/bio_chip/emp/activate()
uses--
INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(empulse), get_turf(imp_in), 3, 5, 1)
if(!uses)
qdel(src)
/obj/item/bio_chip_implanter/emp
name = "bio-chip implanter (EMP)"
implant_type = /obj/item/bio_chip/emp
/obj/item/bio_chip_case/emp
name = "bio-chip case - 'EMP'"
desc = "A glass case containing an EMP bio-chip."
implant_type = /obj/item/bio_chip/emp
@@ -0,0 +1,147 @@
/obj/item/bio_chip/explosive
name = "microbomb bio-chip"
desc = "And boom goes the weasel."
icon_state = "explosive"
origin_tech = "materials=2;combat=3;biotech=4;syndicate=4"
actions_types = list(/datum/action/item_action/hands_free/activate/always)
trigger_causes = BIOCHIP_TRIGGER_DEATH_ONCE // Not surviving that
implant_data = /datum/implant_fluff/explosive
implant_state = "implant-syndicate"
var/detonating = FALSE
var/weak = 2
var/medium = 0.8
var/heavy = 0.4
var/delay = 7
/obj/item/bio_chip/explosive/death_trigger(mob/source, gibbed)
activate("death")
/obj/item/bio_chip/explosive/activate(cause)
if(!cause || !imp_in)
return FALSE
if(cause == "action_button" && alert(imp_in, "Are you sure you want to activate your microbomb bio-chip? This will cause you to explode!", "Microbomb Bio-chip Confirmation", "Yes", "No") != "Yes")
return FALSE
if(detonating)
return FALSE
heavy = round(heavy)
medium = round(medium)
weak = round(weak)
detonating = TRUE
to_chat(imp_in, "<span class='danger'>You activate your microbomb bio-chip.</span>")
//If the delay is short, just blow up already jeez
if(delay <= 7)
self_destruct()
return
timed_explosion()
/// Gib the implantee and delete their destructible contents.
/obj/item/bio_chip/explosive/proc/self_destruct()
if(!imp_in)
return
explosion(src, heavy, medium, weak, weak, flame_range = weak, cause = name)
// In case something happens to the implantee between now and the
// self-destruct
var/current_location = get_turf(imp_in)
var/list/destructed_items = list()
// Iterate over the implantee's contents and take out indestructible
// things to avoid having to worry about containers and recursion
for(var/obj/item/I in imp_in.get_contents())
if(I == src) // Don't delete ourselves prematurely
continue
// Drop indestructible items on the ground first, to avoid them
// getting deleted when destroying the rest of the items, which we
// track in a list to qdel afterwards
if(I.resistance_flags & INDESTRUCTIBLE)
I.forceMove(current_location)
else
destructed_items += I
QDEL_LIST_CONTENTS(destructed_items)
imp_in.gib()
qdel(src)
/obj/item/bio_chip/explosive/implant(mob/source)
var/obj/item/bio_chip/explosive/imp_e = locate(type) in source
if(imp_e && imp_e != src)
imp_e.heavy += heavy
imp_e.medium += medium
imp_e.weak += weak
imp_e.delay += delay
qdel(src)
return TRUE
return ..()
/obj/item/bio_chip/explosive/proc/timed_explosion()
imp_in.visible_message("<span class = 'warning'>[imp_in] starts beeping ominously!</span>")
playsound(loc, 'sound/items/timer.ogg', 30, 0)
var/wait_delay = delay / 4
sleep(wait_delay)
if(imp_in && imp_in.stat)
imp_in.visible_message("<span class = 'warning'>[imp_in] doubles over in pain!</span>")
imp_in.Weaken(14 SECONDS)
playsound(loc, 'sound/items/timer.ogg', 30, 0)
sleep(wait_delay)
playsound(loc, 'sound/items/timer.ogg', 30, 0)
sleep(wait_delay)
playsound(loc, 'sound/items/timer.ogg', 30, 0)
sleep(wait_delay)
self_destruct()
/obj/item/bio_chip/explosive/macro
name = "macrobomb bio-chip"
desc = "And boom goes the weasel. And everything else nearby."
origin_tech = "materials=3;combat=5;biotech=4;syndicate=5"
weak = 16
medium = 8
heavy = 4
delay = 3 SECONDS
implant_data = new /datum/implant_fluff/explosive_macro
/obj/item/bio_chip/explosive/macro/activate(cause)
if(!cause || !imp_in)
return FALSE
if(cause == "action_button" && alert(imp_in, "Are you sure you want to activate your macrobomb bio-chip? This will cause you to explode and gib!", "Macrobomb Bio-chip Confirmation", "Yes", "No") != "Yes")
return FALSE
to_chat(imp_in, "<span class='notice'>You activate your macrobomb bio-chip.</span>")
timed_explosion()
/obj/item/bio_chip/explosive/macro/implant(mob/source)
var/obj/item/bio_chip/explosive/imp_e = locate(type) in source
if(imp_e && imp_e != src)
return FALSE
imp_e = locate(/obj/item/bio_chip/explosive) in source
if(imp_e && imp_e != src)
heavy += imp_e.heavy
medium += imp_e.medium
weak += imp_e.weak
delay += imp_e.delay
qdel(imp_e)
return ..()
/obj/item/bio_chip_implanter/explosive
name = "bio-chip implanter (explosive)"
implant_type = /obj/item/bio_chip/explosive
/obj/item/bio_chip_case/explosive
name = "bio-chip case - 'Micro Explosive'"
desc = "A glass case containing a micro explosive bio-chip."
implant_type = /obj/item/bio_chip/explosive
/obj/item/bio_chip_implanter/explosive_macro
name = "bio-chip implanter (macro-explosive)"
implant_type = /obj/item/bio_chip/explosive/macro
/obj/item/bio_chip_case/explosive_macro
name = "bio-chip case - 'Macro Explosive'"
desc = "A glass case containing a macro explosive bio-chip."
implant_type = /obj/item/bio_chip/explosive/macro
@@ -0,0 +1,26 @@
/// Dumb path but easier to search for admins
/obj/item/bio_chip/gorilla_rampage
name = "magillitis serum bio-chip"
desc = "An experimental biochip which causes irreversable rapid muscular growth in Hominidae. Side-affects may include hypertrichosis, violent outbursts, and an unending affinity for bananas."
icon_state = "gorilla_rampage"
origin_tech = "combat=5;biotech=5;syndicate=2"
uses = 1
implant_data = /datum/implant_fluff/gorilla_rampage
implant_state = "implant-syndicate"
/obj/item/bio_chip/gorilla_rampage/activate()
if(!iscarbon(imp_in))
return
var/mob/living/carbon/target = imp_in
target.visible_message("<span class='userdanger'>[target] swells and their hair grows rapidly. Uh oh!.</span>","<span class='userdanger'>You feel your muscles swell and your hair grow as you return to monke.</span>", "<span class='userdanger'>You hear angry gorilla noises.</span>")
target.gorillize(TRUE)
/obj/item/bio_chip_implanter/gorilla_rampage
name = "bio-chip implanter (magillitis serum)"
implant_type = /obj/item/bio_chip/gorilla_rampage
/obj/item/bio_chip_case/gorilla_rampage
name = "bio-chip case - 'magillitis serum'"
desc = "A glass case containing a magillitis bio-chip."
implant_type = /obj/item/bio_chip/gorilla_rampage
@@ -0,0 +1,27 @@
/obj/item/bio_chip/krav_maga
name = "krav maga bio-chip"
desc = "Teaches you the arts of Krav Maga in 5 short instructional videos beamed directly into your eyeballs."
icon = 'icons/obj/wizard.dmi'
icon_state ="scroll2"
origin_tech = "materials=2;biotech=4;combat=5;syndicate=4"
implant_data = /datum/implant_fluff/krav_maga
var/datum/martial_art/krav_maga/style = new
/obj/item/bio_chip/krav_maga/activate()
var/mob/living/carbon/human/H = imp_in
if(!ishuman(H) || !H.mind)
return
if(istype(H.mind.martial_art, /datum/martial_art/krav_maga))
style.remove(H)
else
style.teach(H, TRUE)
/obj/item/bio_chip_implanter/krav_maga
name = "bio-chip implanter (krav maga)"
implant_type = /obj/item/bio_chip/krav_maga
/obj/item/bio_chip_case/krav_maga
name = "bio-chip case - 'Krav Maga'"
desc = "A glass case containing a bio-chip that can teach the user the art of Krav Maga."
implant_type = /obj/item/bio_chip/krav_maga
@@ -0,0 +1,43 @@
/obj/item/bio_chip/mindshield
name = "mindshield bio-chip"
desc = "Stops people messing with your mind."
origin_tech = "materials=2;biotech=4;programming=4"
activated = BIOCHIP_ACTIVATED_PASSIVE
implant_data = /datum/implant_fluff/mindshield
implant_state = "implant-nanotrasen"
/obj/item/bio_chip/mindshield/can_implant(mob/source, mob/user)
if(source.mind?.has_antag_datum(/datum/antagonist/rev/head))
source.visible_message("<span class='biggerdanger'>[source] seems to resist [src]!</span>",
"<span class='warning'>You feel something interfering with your mental conditioning, but you resist it!</span>")
return FALSE
return ..()
/obj/item/bio_chip/mindshield/implant(mob/target)
if(!..())
return FALSE
if(target.mind)
if(target.mind.has_antag_datum(/datum/antagonist/rev))
SSticker.mode.remove_revolutionary(target.mind)
if(IS_CULTIST(target))
to_chat(target, "<span class='warning'>You feel the corporate tendrils of Nanotrasen try to invade your mind!</span>")
return TRUE
to_chat(target, "<span class='notice'>Your mind feels hardened - more resistant to brainwashing.</span>")
return TRUE
/obj/item/bio_chip/mindshield/removed(mob/target, silent = 0)
if(..())
if(target.stat != DEAD && !silent)
to_chat(target, "<span class='boldnotice'>Your mind softens. You feel susceptible to the effects of brainwashing once more.</span>")
return TRUE
return FALSE
/obj/item/bio_chip_implanter/mindshield
name = "bio-chip implanter (mindshield)"
implant_type = /obj/item/bio_chip/mindshield
/obj/item/bio_chip_case/mindshield
name = "bio-chip case - 'mindshield'"
desc = "A glass case containing a mindshield bio-chip."
implant_type = /obj/item/bio_chip/mindshield
@@ -0,0 +1,120 @@
/obj/item/bio_chip_pad
name = "bio-chip pad"
desc = "Used to modify bio-chips."
icon = 'icons/obj/bio_chips.dmi'
icon_state = "implantpad-off"
item_state = "electronic"
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
var/obj/item/bio_chip_case/case
var/static/list/cached_base64_icons = list()
/obj/item/bio_chip_pad/Destroy()
if(case)
eject_case()
return ..()
/obj/item/bio_chip_pad/examine(mob/user)
. = ..()
. += "<span class='notice'>You can <b>Alt-Click</b> [src] to remove it's stored implant.</span>"
/obj/item/bio_chip_pad/update_icon_state()
if(case)
icon_state = "implantpad-on"
else
icon_state = "implantpad-off"
/obj/item/bio_chip_pad/attack_self__legacy__attackchain(mob/user)
ui_interact(user)
/obj/item/bio_chip_pad/attackby__legacy__attackchain(obj/item/bio_chip_case/C, mob/user)
if(istype(C))
addcase(user, C)
else
return ..()
/obj/item/bio_chip_pad/proc/addcase(mob/user, obj/item/bio_chip_case/C)
if(!user || !C)
return
if(case)
to_chat(user, "<span class='warning'>There's already a bio-chip in the pad!</span>")
return
user.unequip(C)
C.forceMove(src)
case = C
update_icon(UPDATE_ICON_STATE)
SStgui.update_uis(src)
/obj/item/bio_chip_pad/proc/eject_case(mob/user)
if(!case)
return
if(user)
if(user.put_in_hands(case))
add_fingerprint(user)
case.add_fingerprint(user)
case = null
update_icon(UPDATE_ICON_STATE)
SStgui.update_uis(src)
/obj/item/bio_chip_pad/AltClick(mob/user)
if(user.stat || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || !Adjacent(user))
return
eject_case(user)
/obj/item/bio_chip_pad/ui_state(mob/user)
return GLOB.default_state
/obj/item/bio_chip_pad/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "BioChipPad", name)
ui.set_autoupdate(FALSE)
ui.open()
/obj/item/bio_chip_pad/ui_data(mob/user)
var/list/data = list()
data["contains_case"] = case ? TRUE : FALSE
if(case && case.imp)
var/datum/implant_fluff/implant_data = case.imp.implant_data
var/icon/base64icon = cached_base64_icons["[initial(case.imp.icon)][initial(case.imp.icon_state)]"]
if(!base64icon)
base64icon = "[icon2base64(icon(initial(case.imp.icon), initial(case.imp.icon_state), SOUTH, 1))]"
cached_base64_icons["[initial(case.imp.icon)][initial(case.imp.icon_state)]"] = base64icon
data["implant"] = list(
"name" = implant_data.name,
"life" = implant_data.life,
"notes" = implant_data.notes,
"function" = implant_data.function,
"image" = "[icon2base64(icon(initial(case.imp.icon), initial(case.imp.icon_state), SOUTH, 1))]",
)
if(istype(case.imp, /obj/item/bio_chip/tracking))
var/obj/item/bio_chip/tracking/T = case.imp
data["gps"] = T
data["tag"] = T.gpstag
else
data["gps"] = null
data["tag"] = null
else
// Sanity check in the case that a pad is used for multiple types of implants.
data["gps"] = null
data["tag"] = null
return data
/obj/item/bio_chip_pad/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
. = TRUE
switch(action)
if("eject_case")
eject_case(ui.user)
if("tag")
var/obj/item/bio_chip/tracking/T = case.imp
var/newtag = params["newtag"] || ""
newtag = uppertext(paranoid_sanitize(copytext_char(newtag, 1, 5)))
if(!length(newtag) || T.gpstag == newtag)
return
T.gpstag = newtag
@@ -0,0 +1,47 @@
/obj/item/bio_chip/grey_autocloner
name = "technocracy cloning bio-chip"
desc = "Allows for advanced instantanious cloning!"
origin_tech = "materials=3;combat=5;syndicate=2"
activated = FALSE
trigger_causes = BIOCHIP_TRIGGER_DEATH_ANY
implant_state = "implant-alien"
var/obj/machinery/grey_autocloner/linked
var/datum/dna2_record/our_record
/obj/item/bio_chip/grey_autocloner/Destroy()
linked = null
our_record = null
return ..()
/obj/item/bio_chip/grey_autocloner/death_trigger(mob/source, gibbed)
imp_in.ghostize(TRUE)
if(linked)
linked.growclone(our_record)
/obj/item/bio_chip/grey_autocloner/implant(mob/source, mob/user, force)
if(!linked)
to_chat(user, "<span class='warning'>Please link the implanter with a Technocracy cloning pod!</span>")
return FALSE
. = ..()
if(!. || !ishuman(imp_in))
return FALSE
our_record = new /datum/dna2_record()
our_record.ckey = imp_in.ckey
var/obj/item/organ/B = imp_in.get_int_organ(/obj/item/organ/internal/brain)
B.dna.check_integrity()
our_record.dna = B.dna.Clone()
our_record.id = copytext(md5(B.dna.real_name), 2, 6)
our_record.name = B.dna.real_name
our_record.types = DNA2_BUF_UI|DNA2_BUF_UE|DNA2_BUF_SE
our_record.languages = imp_in.languages
if(imp_in.mind) //Save that mind so traitors can continue traitoring after cloning.
our_record.mind = imp_in.mind.UID()
/obj/item/bio_chip_implanter/grey_autocloner
name = "bio-chip implanter (Technocracy cloning)"
implant_type = /obj/item/bio_chip/grey_autocloner
/obj/item/bio_chip_case/grey_autocloner
name = "bio-chip case - 'Technocracy cloning'"
desc = "A glass case containing an Technocracy bio-chip."
implant_type = /obj/item/bio_chip/grey_autocloner
@@ -0,0 +1,27 @@
/obj/item/bio_chip/sad_trombone
name = "sad trombone bio-chip"
activated = FALSE
trigger_emotes = list("deathgasp")
// If something forces the clown to fake death, it's pretty funny to still see the sad trombone played
trigger_causes = BIOCHIP_EMOTE_TRIGGER_UNINTENTIONAL | BIOCHIP_TRIGGER_DEATH_ANY
implant_data = /datum/implant_fluff/sad_trombone
implant_state = "implant-honk"
/obj/item/bio_chip/sad_trombone/emote_trigger(emote, mob/source, force)
activate(emote)
/obj/item/bio_chip/sad_trombone/death_trigger(mob/user, gibbed)
activate(gibbed)
/obj/item/bio_chip/sad_trombone/activate()
playsound(loc, 'sound/misc/sadtrombone.ogg', 50, FALSE)
/obj/item/bio_chip_implanter/sad_trombone
name = "bio-chip implanter (sad trombone)"
implant_type = /obj/item/bio_chip/sad_trombone
/obj/item/bio_chip_case/sad_trombone
name = "bio-chip case - 'Sad Trombone'"
desc = "A glass case containing a sad trombone bio-chip."
implant_type = /obj/item/bio_chip/sad_trombone
@@ -0,0 +1,46 @@
/obj/item/bio_chip/shock
name = "power bio-chip"
desc = "A shockingly effective bio-chip for stunning or killing all those in your way. Do it."
icon_state = "lighting_bolt"
item_color = "r"
origin_tech = "combat=5;magnets=3;biotech=4;syndicate=2"
implant_data = /datum/implant_fluff/shock
implant_state = "implant-syndicate"
var/enabled = FALSE
var/old_mclick_override
var/datum/middle_click_override/shock_implant/mclick_override = new /datum/middle_click_override/shock_implant
COOLDOWN_DECLARE(last_shocked)
var/shock_delay = 3 SECONDS
var/unlimited_power = FALSE // Does this really need explanation?
var/shock_range = 7
/obj/item/bio_chip/shock/activate()
enabled = !enabled
to_chat(imp_in, "<span class='notice'>You toggle the implant [enabled? "on" : "off"].</span>")
if(enabled)
if(imp_in.middleClickOverride)
old_mclick_override = imp_in.middleClickOverride
imp_in.middleClickOverride = mclick_override
else
if(old_mclick_override)
imp_in.middleClickOverride = old_mclick_override
old_mclick_override = null
else
imp_in.middleClickOverride = null
/obj/item/bio_chip/shock/removed()
if(old_mclick_override)
imp_in.middleClickOverride = old_mclick_override
old_mclick_override = null
else
imp_in.middleClickOverride = null
return ..()
/obj/item/bio_chip_implanter/shock
name = "bio-chip implanter (power)"
implant_type = /obj/item/bio_chip/shock
/obj/item/bio_chip_case/shock
name = "bio-chip case - 'power'"
desc = "A glass case containing a power bio-chip."
implant_type = /obj/item/bio_chip/shock
@@ -0,0 +1,144 @@
/**
* # Stealth Implant
*
* Implant which allows you to summon an MGS-style cardboard box that turns you invisble after a short delay.
*/
/obj/item/bio_chip/stealth
name = "S3 bio-chip"
desc = "Allows you to be hidden in plain sight."
implant_state = "implant-syndicate"
implant_data = /datum/implant_fluff/stealth
actions_types = list(/datum/action/item_action/agent_box)
/obj/item/bio_chip_implanter/stealth
name = "bio-chip implanter (stealth)"
implant_type = /obj/item/bio_chip/stealth
/datum/action/item_action/agent_box
name = "Deploy Box"
desc = "Find inner peace, here, in the box."
check_flags = AB_CHECK_HANDS_BLOCKED | AB_CHECK_IMMOBILE | AB_CHECK_CONSCIOUS | AB_CHECK_STUNNED
background_icon_state = "bg_agent"
button_icon_state = "deploy_box"
/// If TRUE, the box can't be deployed
var/on_cooldown = FALSE
/datum/action/item_action/agent_box/Trigger(trigger_flags, left_click)
. = ..()
if(!.)
return FALSE
if(istype(owner.loc, /obj/structure/closet/cardboard/agent))
var/obj/structure/closet/cardboard/agent/box = owner.loc
if(box.open())
owner.playsound_local(box, 'sound/misc/box_deploy.ogg', 50, TRUE)
recall_box_animation()
return
// Box closing from here on out.
if(!isturf(owner.loc)) //Don't let the player use this to escape mechs/welded closets.
to_chat(owner, "<span class='warning'>You need more space to activate this implant!</span>")
return
owner.playsound_local(owner, 'sound/misc/box_deploy.ogg', 50, TRUE)
spawn_box()
/datum/action/item_action/agent_box/proc/spawn_box()
// Do the box's fade in spawn animation with an image so it follows the owner.
var/image/fake_box = image('icons/obj/cardboard_boxes.dmi', owner, "agentbox", ABOVE_MOB_LAYER)
flick_overlay_view(fake_box, owner, 0.4 SECONDS)
fake_box.alpha = 0
fake_box.pixel_z = 30
animate(fake_box, pixel_z = fake_box.pixel_z - 30, alpha = fake_box.alpha + 255, time = 3, loop = 1)
sleep(3)
// Spawn the actual box
var/obj/structure/closet/cardboard/agent/box = new(get_turf(owner), owner)
// Slightly shorter time since we needed 0.3s to to do the spawn animation.
INVOKE_ASYNC(box, TYPE_PROC_REF(/obj/structure/closet/cardboard/agent, go_invisible), 1.7 SECONDS)
owner.forceMove(box)
owner.overlay_fullscreen("agent_box", /atom/movable/screen/fullscreen/center/agent_box)
RegisterSignal(box, COMSIG_PARENT_QDELETING, PROC_REF(start_cooldown))
/datum/action/item_action/agent_box/proc/start_cooldown(datum/source)
SIGNAL_HANDLER
on_cooldown = TRUE
addtimer(CALLBACK(src, PROC_REF(end_cooldown)), 10 SECONDS)
owner.clear_fullscreen("agent_box")
build_all_button_icons()
/datum/action/item_action/agent_box/proc/end_cooldown()
on_cooldown = FALSE
build_all_button_icons()
/datum/action/item_action/agent_box/IsAvailable()
if(..() && !on_cooldown)
return TRUE
return FALSE
/datum/action/item_action/agent_box/proc/recall_box_animation()
var/image/fake_box = image('icons/obj/cardboard_boxes.dmi', owner, "agentbox", ABOVE_MOB_LAYER)
flick_overlay_view(fake_box, owner, 0.4 SECONDS)
animate(fake_box, pixel_z = fake_box.pixel_z + 30, alpha = fake_box.alpha - 255, time = 3, loop = 1)
/datum/action/item_action/agent_box/Grant(mob/grant_to)
. = ..()
if(owner)
RegisterSignal(owner, COMSIG_HUMAN_SUICIDE_ACT, PROC_REF(suicide_act))
/datum/action/item_action/agent_box/Remove(mob/M)
if(owner)
UnregisterSignal(owner, COMSIG_HUMAN_SUICIDE_ACT)
return ..()
/datum/action/item_action/agent_box/proc/suicide_act(datum/source)
SIGNAL_HANDLER
if(!istype(owner.loc, /obj/structure/closet/cardboard/agent))
return
var/obj/structure/closet/cardboard/agent/box = owner.loc
owner.visible_message("<span class='suicide'>[owner] falls out of [box]! It looks like [owner.p_they()] committed suicide!</span>")
owner.playsound_local(box, 'sound/misc/box_deploy.ogg', 50, TRUE)
INVOKE_ASYNC(box, TYPE_PROC_REF(/obj/structure/closet/cardboard/agent, open))
INVOKE_ASYNC(owner, TYPE_PROC_REF(/atom/movable, throw_at), get_turf(owner))
return OXYLOSS
// Stealth implant box
/obj/structure/closet/cardboard/agent
name = "inconspicious box"
desc = "It's so normal that you didn't notice it before."
icon_state = "agentbox"
max_integrity = 1
move_speed_multiplier = 0.5 // You can move at run speed while in this box.
material_drop = null
/obj/structure/closet/cardboard/agent/attackby__legacy__attackchain(obj/item/I, mob/living/user)
return
/obj/structure/closet/cardboard/agent/open()
. = ..()
if(!.)
return FALSE
qdel(src)
// When the box is opened, it's deleted, so we never need to update this.
/obj/structure/closet/cardboard/agent/update_icon_state()
return
/obj/structure/closet/cardboard/agent/proc/go_invisible(invis_time = 2 SECONDS)
animate(src, alpha = 0, time = invis_time)
sleep(invis_time)
// This is so people can't locate the box by spamming right click everywhere.
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/obj/structure/closet/cardboard/agent/proc/reveal()
alpha = 255
mouse_opacity = MOUSE_OPACITY_OPAQUE
addtimer(CALLBACK(src, PROC_REF(go_invisible)), 1 SECONDS, TIMER_OVERRIDE|TIMER_UNIQUE)
/obj/structure/closet/cardboard/agent/Bump(atom/A)
. = ..()
if(isliving(A))
reveal()
/obj/structure/closet/cardboard/agent/Bumped(atom/movable/A)
. = ..()
if(isliving(A))
reveal()
@@ -0,0 +1,74 @@
/obj/item/storage/hidden_implant
name = "bluespace pocket"
storage_slots = 2
max_w_class = WEIGHT_CLASS_NORMAL
max_combined_w_class = WEIGHT_CLASS_GIGANTIC
w_class = WEIGHT_CLASS_BULKY
cant_hold = list(/obj/item/disk/nuclear)
w_class_override = list(/obj/item/storage/belt)
silent = TRUE
/obj/item/bio_chip/storage
name = "storage bio-chip"
desc = "Stores up to two big items in a bluespace pocket."
icon_state = "storage"
origin_tech = "materials=2;magnets=4;bluespace=5;syndicate=4"
item_color = "r"
implant_data = /datum/implant_fluff/storage
implant_state = "implant-syndicate"
var/obj/item/storage/hidden_implant/storage
/obj/item/bio_chip/storage/Initialize(mapload)
. = ..()
storage = new /obj/item/storage/hidden_implant(src)
/obj/item/bio_chip/storage/emp_act(severity)
..()
storage.emp_act(severity)
/obj/item/bio_chip/storage/activate()
if(!length(storage.mobs_viewing))
storage.MouseDrop(imp_in)
else
for(var/mob/to_close in storage.mobs_viewing)
storage.close(to_close)
/obj/item/bio_chip/storage/removed(source)
if(..())
for(var/mob/M in range(1))
if(M.s_active == storage)
storage.close(M)
for(var/obj/item/I in storage)
storage.remove_from_storage(I, get_turf(source))
return TRUE
/obj/item/bio_chip/storage/implant(mob/source)
var/obj/item/bio_chip/storage/imp_e = locate(type) in source
if(imp_e)
imp_e.storage.storage_slots += storage.storage_slots
imp_e.storage.max_combined_w_class += storage.max_combined_w_class
imp_e.storage.contents += storage.contents
for(var/mob/M in range(1))
if(M.s_active == storage)
storage.close(M)
storage.show_to(source)
qdel(src)
return TRUE
return ..()
/obj/item/bio_chip/storage/proc/get_contents() //Used for swiftly returning a list of the implant's contents i.e. for checking a theft objective's completion.
if(storage && storage.contents)
return storage.contents
/obj/item/bio_chip_implanter/storage
name = "bio-chip implanter (storage)"
implant_type = /obj/item/bio_chip/storage
/obj/item/bio_chip_case/storage
name = "bio-chip case - 'Storage'"
desc = "A glass case containing a storage bio-chip."
implant_type = /obj/item/bio_chip/storage
@@ -0,0 +1,34 @@
/obj/item/bio_chip/supercharge
name = "supercharge bio-chip"
desc = "Removes all stuns and knockdowns."
icon_state = "adrenal"
origin_tech = "materials=3;combat=5;syndicate=4"
uses = 3
implant_data = /datum/implant_fluff/adrenaline
implant_state = "implant-syndicate"
/obj/item/bio_chip/supercharge/activate()
uses--
to_chat(imp_in, "<span class='notice'>You feel an electric sensation as your components enter overdrive!</span>")
imp_in.SetStunned(0)
imp_in.SetWeakened(0)
imp_in.SetKnockDown(0)
imp_in.SetParalysis(0)
imp_in.adjustStaminaLoss(-75)
imp_in.stand_up(TRUE)
SEND_SIGNAL(imp_in, COMSIG_LIVING_CLEAR_STUNS)
imp_in.reagents.add_reagent("recal", 10)
imp_in.reagents.add_reagent("surge_plus", 10)
imp_in.reagents.add_reagent("synthetic_omnizine_no_addiction", 10)
if(!uses)
qdel(src)
/obj/item/bio_chip_implanter/supercharge
name = "bio-chip implanter (supercharge)"
implant_type = /obj/item/bio_chip/supercharge
/obj/item/bio_chip_case/supercharge
name = "bio-chip case - 'supercharge'"
desc = "A glass case containing a supercharge bio-chip."
implant_type = /obj/item/bio_chip/supercharge
@@ -0,0 +1,52 @@
/obj/item/bio_chip/tracking
name = "tracking bio-chip"
desc = "Track with this."
activated = BIOCHIP_ACTIVATED_PASSIVE
origin_tech = "materials=2;magnets=2;programming=2;biotech=2"
implant_data = /datum/implant_fluff/tracking
implant_state = "implant-nanotrasen"
var/warn_cooldown = 0
var/obj/item/gps/internal_gps
var/gpstag = "TRACK0"
var/internal_gps_path = /obj/item/gps/internal/tracking_implant
/obj/item/bio_chip/tracking/Initialize(mapload)
. = ..()
GLOB.tracked_implants += src
/obj/item/bio_chip/tracking/Destroy()
QDEL_NULL(internal_gps)
GLOB.tracked_implants -= src
return ..()
/obj/item/bio_chip/tracking/implant(mob/target)
if(ishuman(target))
var/mob/living/carbon/human/H = target
var/obj/item/organ/internal/cyberimp/chest/bluespace_anchor/anchor = H.get_int_organ(/obj/item/organ/internal/cyberimp/chest/bluespace_anchor)
if(anchor)
target.visible_message("<span class='danger'>[src] sparks out, disrupted by [anchor] inside [H]!</span>")
qdel(src)
return FALSE
. = ..()
if(!.)
return
internal_gps = new internal_gps_path(src)
if(gpstag)
internal_gps.gpstag = gpstag
/obj/item/bio_chip/tracking/removed(mob/target)
. = ..()
if(.)
QDEL_NULL(internal_gps)
/obj/item/gps/internal/tracking_implant
local = FALSE
/obj/item/bio_chip_implanter/tracking
name = "bio-chip implanter (tracking)"
implant_type = /obj/item/bio_chip/tracking
/obj/item/bio_chip_case/tracking
name = "bio-chip case - 'Tracking'"
desc = "A glass case containing a tracking bio-chip."
implant_type = /obj/item/bio_chip/tracking
@@ -0,0 +1,55 @@
/obj/item/bio_chip/traitor
name = "Mindslave Bio-chip"
desc = "Divide and Conquer!"
origin_tech = "programming=5;biotech=5;syndicate=8"
activated = FALSE
implant_data = /datum/implant_fluff/traitor
implant_state = "implant-syndicate"
/// The UID of the mindslave's `mind`. Stored to solve GC race conditions and ensure we can remove their mindslave status even when they're deleted or gibbed.
var/mindslave_UID
/obj/item/bio_chip/traitor/implant(mob/living/carbon/human/mindslave_target, mob/living/carbon/human/user)
// Check `activated` here so you can't just keep taking it out and putting it back into other people.
if(activated || !istype(mindslave_target) || !istype(user)) // Both the target and the user need to be human.
return FALSE
// If the target is catatonic or doesn't have a mind, return.
if(!mindslave_target.mind)
to_chat(user, "<span class='warning'><i>This person doesn't have a mind for you to slave!</i></span>")
return FALSE
// Fails if they're already a mindslave of someone, or if they're mindshielded.
if(IS_MINDSLAVE(mindslave_target) || ismindshielded(mindslave_target))
mindslave_target.visible_message(
"<span class='warning'>[mindslave_target] seems to resist the bio-chip!</span>", \
"<span class='warning'>You feel a strange sensation in your head that quickly dissipates.</span>")
qdel(src)
return FALSE
// Mindslaving yourself.
if(mindslave_target == user)
to_chat(user, "<span class='notice'>Making yourself loyal to yourself was a great idea! Perhaps even the best idea ever! Actually, you just feel like an idiot.</span>")
user.adjustBrainLoss(20)
qdel(src)
return FALSE
// Create a new mindslave datum for the target with the user as their master.
mindslave_target.mind.add_antag_datum(new /datum/antagonist/mindslave/implant(user.mind))
mindslave_UID = mindslave_target.mind.UID()
log_admin("[key_name_admin(user)] has mind-slaved [key_name_admin(mindslave_target)].")
return ..()
/obj/item/bio_chip/traitor/removed(mob/target)
. = ..()
var/datum/mind/M = locateUID(mindslave_UID)
M.remove_antag_datum(/datum/antagonist/mindslave/implant)
/obj/item/bio_chip_implanter/traitor
name = "bio-chip implanter (Mindslave)"
implant_type = /obj/item/bio_chip/traitor
/obj/item/bio_chip_case/traitor
name = "bio-chip case - 'Mindslave'"
desc = "A glass case containing a mindslave bio-chip."
implant_type = /obj/item/bio_chip/traitor
@@ -0,0 +1,62 @@
/obj/item/bio_chip/uplink
name = "uplink bio-chip"
desc = "Summon things."
icon = 'icons/obj/radio.dmi'
icon_state = "radio"
origin_tech = "materials=4;magnets=4;programming=4;biotech=4;syndicate=5;bluespace=5"
implant_data = /datum/implant_fluff/uplink
implant_state = "implant-syndicate"
/obj/item/bio_chip/uplink/Initialize(mapload)
. = ..()
hidden_uplink = new(src)
hidden_uplink.uses = 50
/obj/item/bio_chip/uplink/nuclear/Initialize(mapload)
. = ..()
if(hidden_uplink)
hidden_uplink.update_uplink_type(UPLINK_TYPE_NUCLEAR)
/obj/item/bio_chip/uplink/sit/Initialize(mapload)
. = ..()
if(hidden_uplink)
hidden_uplink.update_uplink_type(UPLINK_TYPE_SIT)
/obj/item/bio_chip/uplink/admin/Initialize(mapload)
. = ..()
if(hidden_uplink)
hidden_uplink.update_uplink_type(UPLINK_TYPE_ADMIN)
/obj/item/bio_chip/uplink/implant(mob/source)
var/obj/item/bio_chip/imp_e = locate(type) in source
if(imp_e && imp_e != src)
imp_e.hidden_uplink.uses += hidden_uplink.uses
qdel(src)
return TRUE
if(..())
hidden_uplink.uplink_owner="[source.key]"
return TRUE
return FALSE
/obj/item/bio_chip/uplink/activate()
if(hidden_uplink)
hidden_uplink.check_trigger(imp_in)
/obj/item/bio_chip_implanter/uplink
name = "bio-chip implanter (uplink)"
implant_type = /obj/item/bio_chip/uplink
/obj/item/bio_chip_case/uplink
name = "bio-chip case - 'Syndicate Uplink'"
desc = "A glass case containing an uplink bio-chip."
implant_type = /obj/item/bio_chip/uplink
/obj/item/bio_chip_implanter/nuclear
name = "bio-chip implanter (Nuclear Agent Uplink)"
implant_type = /obj/item/bio_chip/uplink/nuclear
/obj/item/bio_chip_case/nuclear
name = "bio-chip case - 'Nuclear Agent Uplink'"
implant_type = /obj/item/bio_chip/uplink/nuclear
@@ -0,0 +1,55 @@
/obj/item/bio_chip_implanter
name = "bio-chip implanter"
desc = "A sterile automatic bio-chip injector."
icon = 'icons/obj/bio_chips.dmi'
icon_state = "implanter0"
item_state = "syringe_0"
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
origin_tech = "materials=2;biotech=3"
materials = list(MAT_METAL = 600, MAT_GLASS = 200)
var/obj/item/bio_chip/imp
var/obj/item/bio_chip/implant_type
/obj/item/bio_chip_implanter/update_icon_state()
if(imp)
icon_state = "implanter1"
origin_tech = imp.origin_tech
else
icon_state = "implanter0"
origin_tech = initial(origin_tech)
/obj/item/bio_chip_implanter/attack__legacy__attackchain(mob/living/carbon/M, mob/user)
if(!iscarbon(M))
return
if(user && imp)
if(M != user)
M.visible_message("<span class='warning'>[user] is attempting to bio-chip [M].</span>")
var/turf/T = get_turf(M)
if(T && (M == user || do_after(user, 50 * toolspeed, target = M)))
if(user && M && (get_turf(M) == T) && src && imp)
if(imp.implant(M, user))
if(M == user)
to_chat(user, "<span class='notice'>You bio-chip yourself.</span>")
else
M.visible_message("[user] has implanted [M].", "<span class='notice'>[user] bio-chips you.</span>")
imp = null
update_icon(UPDATE_ICON_STATE)
/obj/item/bio_chip_implanter/attackby__legacy__attackchain(obj/item/W, mob/user, params)
..()
if(is_pen(W))
rename_interactive(user, W)
/obj/item/bio_chip_implanter/Initialize(mapload)
. = ..()
if(!implant_type)
return
imp = new implant_type()
update_icon(UPDATE_ICON_STATE)
/obj/item/bio_chip_implanter/Destroy()
QDEL_NULL(imp)
. = ..()