mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-21 12:08:55 +01:00
## About The Pull Request stop forgetting to include mapload, if you don't include it then every single subtype past it by default doesn't include it for example, `obj/item` didn't include mapload so every single item by default didn't fill in mapload  ## Regex used: procs without args, not even regex `/Initialize()` procs with args `\/Initialize\((?!mapload)((.)*\w)?` cleanup of things i didn't want to mapload: `\/datum\/(.)*\/Initialize\(mapload`
301 lines
12 KiB
Plaintext
301 lines
12 KiB
Plaintext
/obj/item/organ/cyberimp/arm
|
|
name = "arm-mounted implant"
|
|
desc = "You shouldn't see this! Adminhelp and report this as an issue on github!"
|
|
zone = BODY_ZONE_R_ARM
|
|
icon_state = "implant-toolkit"
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
actions_types = list(/datum/action/item_action/organ_action/toggle)
|
|
///A ref for the arm we're taking up. Mostly for the unregister signal upon removal
|
|
var/obj/hand
|
|
//A list of typepaths to create and insert into ourself on init
|
|
var/list/items_to_create = list()
|
|
/// Used to store a list of all items inside, for multi-item implants.
|
|
var/list/items_list = list()// I would use contents, but they shuffle on every activation/deactivation leading to interface inconsistencies.
|
|
/// You can use this var for item path, it would be converted into an item on New().
|
|
var/obj/item/active_item
|
|
/// Sound played when extending
|
|
var/extend_sound = 'sound/mecha/mechmove03.ogg'
|
|
/// Sound played when retracting
|
|
var/retract_sound = 'sound/mecha/mechmove03.ogg'
|
|
|
|
/obj/item/organ/cyberimp/arm/Initialize(mapload)
|
|
. = ..()
|
|
if(ispath(active_item))
|
|
active_item = new active_item(src)
|
|
items_list += WEAKREF(active_item)
|
|
|
|
for(var/typepath in items_to_create)
|
|
var/atom/new_item = new typepath(src)
|
|
items_list += WEAKREF(new_item)
|
|
|
|
update_appearance()
|
|
SetSlotFromZone()
|
|
|
|
/obj/item/organ/cyberimp/arm/Destroy()
|
|
hand = null
|
|
active_item = null
|
|
for(var/datum/weakref/ref in items_list)
|
|
var/obj/item/to_del = ref.resolve()
|
|
if(!to_del)
|
|
continue
|
|
qdel(to_del)
|
|
items_list.Cut()
|
|
return ..()
|
|
|
|
/obj/item/organ/cyberimp/arm/proc/SetSlotFromZone()
|
|
switch(zone)
|
|
if(BODY_ZONE_L_ARM)
|
|
slot = ORGAN_SLOT_LEFT_ARM_AUG
|
|
if(BODY_ZONE_R_ARM)
|
|
slot = ORGAN_SLOT_RIGHT_ARM_AUG
|
|
else
|
|
CRASH("Invalid zone for [type]")
|
|
|
|
/obj/item/organ/cyberimp/arm/update_icon()
|
|
. = ..()
|
|
transform = (zone == BODY_ZONE_R_ARM) ? null : matrix(-1, 0, 0, 0, 1, 0)
|
|
|
|
/obj/item/organ/cyberimp/arm/examine(mob/user)
|
|
. = ..()
|
|
if(status == ORGAN_ROBOTIC)
|
|
. += span_info("[src] is assembled in the [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm configuration. You can use a screwdriver to reassemble it.")
|
|
|
|
/obj/item/organ/cyberimp/arm/screwdriver_act(mob/living/user, obj/item/screwtool)
|
|
. = ..()
|
|
if(.)
|
|
return TRUE
|
|
screwtool.play_tool_sound(src)
|
|
if(zone == BODY_ZONE_R_ARM)
|
|
zone = BODY_ZONE_L_ARM
|
|
else
|
|
zone = BODY_ZONE_R_ARM
|
|
SetSlotFromZone()
|
|
to_chat(user, span_notice("You modify [src] to be installed on the [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm."))
|
|
update_appearance()
|
|
|
|
/obj/item/organ/cyberimp/arm/Insert(mob/living/carbon/arm_owner, special = FALSE, drop_if_replaced = TRUE)
|
|
. = ..()
|
|
var/side = zone == BODY_ZONE_R_ARM? RIGHT_HANDS : LEFT_HANDS
|
|
hand = arm_owner.hand_bodyparts[side]
|
|
if(hand)
|
|
RegisterSignal(hand, COMSIG_ITEM_ATTACK_SELF, .proc/on_item_attack_self) //If the limb gets an attack-self, open the menu. Only happens when hand is empty
|
|
RegisterSignal(arm_owner, COMSIG_KB_MOB_DROPITEM_DOWN, .proc/dropkey) //We're nodrop, but we'll watch for the drop hotkey anyway and then stow if possible.
|
|
|
|
/obj/item/organ/cyberimp/arm/Remove(mob/living/carbon/arm_owner, special = 0)
|
|
Retract()
|
|
if(hand)
|
|
UnregisterSignal(hand, COMSIG_ITEM_ATTACK_SELF)
|
|
UnregisterSignal(arm_owner, COMSIG_KB_MOB_DROPITEM_DOWN)
|
|
..()
|
|
|
|
/obj/item/organ/cyberimp/arm/proc/on_item_attack_self()
|
|
SIGNAL_HANDLER
|
|
INVOKE_ASYNC(src, .proc/ui_action_click)
|
|
|
|
/obj/item/organ/cyberimp/arm/emp_act(severity)
|
|
. = ..()
|
|
if(. & EMP_PROTECT_SELF || status == ORGAN_ROBOTIC)
|
|
return
|
|
if(prob(15/severity) && owner)
|
|
to_chat(owner, span_warning("The electromagnetic pulse causes [src] to malfunction!"))
|
|
// give the owner an idea about why his implant is glitching
|
|
Retract()
|
|
|
|
/**
|
|
* Called when the mob uses the "drop item" hotkey
|
|
*
|
|
* Items inside toolset implants have TRAIT_NODROP, but we can still use the drop item hotkey as a
|
|
* quick way to store implant items. In this case, we check to make sure the user has the correct arm
|
|
* selected, and that the item is actually owned by us, and then we'll hand off the rest to Retract()
|
|
**/
|
|
/obj/item/organ/cyberimp/arm/proc/dropkey(mob/living/carbon/host)
|
|
SIGNAL_HANDLER
|
|
if(!host)
|
|
return //How did we even get here
|
|
if(hand != host.hand_bodyparts[host.active_hand_index])
|
|
return //wrong hand
|
|
Retract()
|
|
|
|
/obj/item/organ/cyberimp/arm/proc/Retract()
|
|
if(!active_item || (active_item in src))
|
|
return
|
|
|
|
owner?.visible_message(span_notice("[owner] retracts [active_item] back into [owner.p_their()] [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm."),
|
|
span_notice("[active_item] snaps back into your [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm."),
|
|
span_hear("You hear a short mechanical noise."))
|
|
|
|
owner.transferItemToLoc(active_item, src, TRUE)
|
|
active_item = null
|
|
playsound(get_turf(owner), retract_sound, 50, TRUE)
|
|
|
|
/obj/item/organ/cyberimp/arm/proc/Extend(obj/item/augment)
|
|
if(!(augment in src))
|
|
return
|
|
|
|
active_item = augment
|
|
|
|
active_item.resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
|
ADD_TRAIT(active_item, TRAIT_NODROP, HAND_REPLACEMENT_TRAIT)
|
|
active_item.slot_flags = null
|
|
active_item.set_custom_materials(null)
|
|
|
|
var/side = zone == BODY_ZONE_R_ARM? RIGHT_HANDS : LEFT_HANDS
|
|
var/hand = owner.get_empty_held_index_for_side(side)
|
|
if(hand)
|
|
owner.put_in_hand(active_item, hand)
|
|
else
|
|
var/list/hand_items = owner.get_held_items_for_side(side, all = TRUE)
|
|
var/success = FALSE
|
|
var/list/failure_message = list()
|
|
for(var/i in 1 to hand_items.len) //Can't just use *in* here.
|
|
var/hand_item = hand_items[i]
|
|
if(!owner.dropItemToGround(hand_item))
|
|
failure_message += span_warning("Your [hand_item] interferes with [src]!")
|
|
continue
|
|
to_chat(owner, span_notice("You drop [hand_item] to activate [src]!"))
|
|
success = owner.put_in_hand(active_item, owner.get_empty_held_index_for_side(side))
|
|
break
|
|
if(!success)
|
|
for(var/i in failure_message)
|
|
to_chat(owner, i)
|
|
return
|
|
owner.visible_message(span_notice("[owner] extends [active_item] from [owner.p_their()] [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm."),
|
|
span_notice("You extend [active_item] from your [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm."),
|
|
span_hear("You hear a short mechanical noise."))
|
|
playsound(get_turf(owner), extend_sound, 50, TRUE)
|
|
|
|
/obj/item/organ/cyberimp/arm/ui_action_click()
|
|
if((organ_flags & ORGAN_FAILING) || (!active_item && !contents.len))
|
|
to_chat(owner, span_warning("The implant doesn't respond. It seems to be broken..."))
|
|
return
|
|
|
|
if(!active_item || (active_item in src))
|
|
active_item = null
|
|
if(contents.len == 1)
|
|
Extend(contents[1])
|
|
else
|
|
var/list/choice_list = list()
|
|
for(var/datum/weakref/augment_ref in items_list)
|
|
var/obj/item/augment_item = augment_ref.resolve()
|
|
if(!augment_item)
|
|
items_list -= augment_ref
|
|
continue
|
|
choice_list[augment_item] = image(augment_item)
|
|
var/obj/item/choice = show_radial_menu(owner, owner, choice_list)
|
|
if(owner && owner == usr && owner.stat != DEAD && (src in owner.internal_organs) && !active_item && (choice in contents))
|
|
// This monster sanity check is a nice example of how bad input is.
|
|
Extend(choice)
|
|
else
|
|
Retract()
|
|
|
|
|
|
/obj/item/organ/cyberimp/arm/gun/emp_act(severity)
|
|
. = ..()
|
|
if(. & EMP_PROTECT_SELF)
|
|
return
|
|
if(prob(30/severity) && owner && !(organ_flags & ORGAN_FAILING))
|
|
Retract()
|
|
owner.visible_message(span_danger("A loud bang comes from [owner]\'s [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm!"))
|
|
playsound(get_turf(owner), 'sound/weapons/flashbang.ogg', 100, TRUE)
|
|
to_chat(owner, span_userdanger("You feel an explosion erupt inside your [zone == BODY_ZONE_R_ARM ? "right" : "left"] arm as your implant breaks!"))
|
|
owner.adjust_fire_stacks(20)
|
|
owner.IgniteMob()
|
|
owner.adjustFireLoss(25)
|
|
organ_flags |= ORGAN_FAILING
|
|
|
|
|
|
/obj/item/organ/cyberimp/arm/gun/laser
|
|
name = "arm-mounted laser implant"
|
|
desc = "A variant of the arm cannon implant that fires lethal laser beams. The cannon emerges from the subject's arm and remains inside when not in use."
|
|
icon_state = "arm_laser"
|
|
items_to_create = list(/obj/item/gun/energy/laser/mounted/augment)
|
|
|
|
/obj/item/organ/cyberimp/arm/gun/laser/l
|
|
zone = BODY_ZONE_L_ARM
|
|
|
|
/obj/item/organ/cyberimp/arm/gun/taser
|
|
name = "arm-mounted taser implant"
|
|
desc = "A variant of the arm cannon implant that fires electrodes and disabler shots. The cannon emerges from the subject's arm and remains inside when not in use."
|
|
icon_state = "arm_taser"
|
|
items_to_create = list(/obj/item/gun/energy/e_gun/advtaser/mounted)
|
|
|
|
/obj/item/organ/cyberimp/arm/gun/taser/l
|
|
zone = BODY_ZONE_L_ARM
|
|
|
|
/obj/item/organ/cyberimp/arm/toolset
|
|
name = "integrated toolset implant"
|
|
desc = "A stripped-down version of the engineering cyborg toolset, designed to be installed on subject's arm. Contain advanced versions of every tool."
|
|
items_to_create = list(/obj/item/screwdriver/cyborg, /obj/item/wrench/cyborg, /obj/item/weldingtool/largetank/cyborg,
|
|
/obj/item/crowbar/cyborg, /obj/item/wirecutters/cyborg, /obj/item/multitool/cyborg)
|
|
|
|
/obj/item/organ/cyberimp/arm/toolset/l
|
|
zone = BODY_ZONE_L_ARM
|
|
|
|
/obj/item/organ/cyberimp/arm/toolset/emag_act(mob/user)
|
|
for(var/datum/weakref/created_item in items_list)
|
|
var/obj/potential_knife = created_item.resolve()
|
|
if(istype(/obj/item/kitchen/knife/combat/cyborg, potential_knife))
|
|
return FALSE
|
|
|
|
to_chat(user, span_notice("You unlock [src]'s integrated knife!"))
|
|
items_list += WEAKREF(new /obj/item/kitchen/knife/combat/cyborg(src))
|
|
return TRUE
|
|
|
|
/obj/item/organ/cyberimp/arm/esword
|
|
name = "arm-mounted energy blade"
|
|
desc = "An illegal and highly dangerous cybernetic implant that can project a deadly blade of concentrated energy."
|
|
items_to_create = list(/obj/item/melee/energy/blade/hardlight)
|
|
|
|
/obj/item/organ/cyberimp/arm/medibeam
|
|
name = "integrated medical beamgun"
|
|
desc = "A cybernetic implant that allows the user to project a healing beam from their hand."
|
|
items_to_create = list(/obj/item/gun/medbeam)
|
|
|
|
|
|
/obj/item/organ/cyberimp/arm/flash
|
|
name = "integrated high-intensity photon projector" //Why not
|
|
desc = "An integrated projector mounted onto a user's arm that is able to be used as a powerful flash."
|
|
items_to_create = list(/obj/item/assembly/flash/armimplant)
|
|
|
|
/obj/item/organ/cyberimp/arm/flash/Initialize(mapload)
|
|
. = ..()
|
|
for(var/datum/weakref/created_item in items_list)
|
|
var/obj/potential_flash = created_item.resolve()
|
|
if(!istype(potential_flash, /obj/item/assembly/flash/armimplant))
|
|
continue
|
|
var/obj/item/assembly/flash/armimplant/flash = potential_flash
|
|
flash.arm = WEAKREF(src) // Todo: wipe single letter vars out of assembly code
|
|
|
|
/obj/item/organ/cyberimp/arm/flash/Extend()
|
|
. = ..()
|
|
active_item.set_light_range(7)
|
|
active_item.set_light_on(TRUE)
|
|
|
|
/obj/item/organ/cyberimp/arm/flash/Retract()
|
|
active_item.set_light_on(FALSE)
|
|
return ..()
|
|
|
|
/obj/item/organ/cyberimp/arm/baton
|
|
name = "arm electrification implant"
|
|
desc = "An illegal combat implant that allows the user to administer disabling shocks from their arm."
|
|
items_to_create = list(/obj/item/borg/stun)
|
|
|
|
/obj/item/organ/cyberimp/arm/combat
|
|
name = "combat cybernetics implant"
|
|
desc = "A powerful cybernetic implant that contains combat modules built into the user's arm."
|
|
items_to_create = list(/obj/item/melee/energy/blade/hardlight, /obj/item/gun/medbeam, /obj/item/borg/stun, /obj/item/assembly/flash/armimplant)
|
|
|
|
/obj/item/organ/cyberimp/arm/combat/Initialize(mapload)
|
|
. = ..()
|
|
for(var/datum/weakref/created_item in items_list)
|
|
var/obj/potential_flash = created_item.resolve()
|
|
if(!istype(potential_flash, /obj/item/assembly/flash/armimplant))
|
|
continue
|
|
var/obj/item/assembly/flash/armimplant/flash = potential_flash
|
|
flash.arm = WEAKREF(src) // Todo: wipe single letter vars out of assembly code
|
|
|
|
/obj/item/organ/cyberimp/arm/surgery
|
|
name = "surgical toolset implant"
|
|
desc = "A set of surgical tools hidden behind a concealed panel on the user's arm."
|
|
items_to_create = list(/obj/item/retractor/augment, /obj/item/hemostat/augment, /obj/item/cautery/augment, /obj/item/surgicaldrill/augment, /obj/item/scalpel/augment, /obj/item/circular_saw/augment, /obj/item/surgical_drapes)
|