mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-11 10:11:09 +00:00
Generalizes multi-slot implants and makes autosurgeons support them (#89845)
## About The Pull Request Generalized code from #89479 to be applicable to all organs and made autosurgeons respect which hand you're using them in (and what zone you have selected) ## Why It's Good For The Game Allows us to add leg implants with similar behavior easier, gets of placeholder types for left arm slots, and you'd ***expect*** to be able to use autosurgeons to insert implants anywhere but your right arm. ## Changelog 🆑 qol: Autosurgeons now can insert toolkit implants into your left arm when used in the left hand/with left arm zone selected /🆑
This commit is contained in:
@@ -135,9 +135,9 @@ DEFINE_BITFIELD(no_equip_flags, list(
|
||||
//defines for the index of hands
|
||||
#define LEFT_HANDS 1
|
||||
#define RIGHT_HANDS 2
|
||||
/// Checks if the value is "left" - same as ISEVEN, but used primarily for hand or foot index contexts
|
||||
/// Checks if the value is "right" - same as ISEVEN, but used primarily for hand or foot index contexts
|
||||
#define IS_RIGHT_INDEX(value) (value % 2 == 0)
|
||||
/// Checks if the value is "right" - same as ISODD, but used primarily for hand or foot index contexts
|
||||
/// Checks if the value is "left" - same as ISODD, but used primarily for hand or foot index contexts
|
||||
#define IS_LEFT_INDEX(value) (value % 2 != 0)
|
||||
|
||||
//flags for female outfits: How much the game can safely "take off" the uniform without it looking weird
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
to_chat(user, span_userdanger("The mass goes up your arm and goes inside it!"))
|
||||
playsound(user, 'sound/effects/magic/demon_consume.ogg', 50, TRUE)
|
||||
var/index = user.get_held_index_of_item(src)
|
||||
zone = (index == LEFT_HANDS ? BODY_ZONE_L_ARM : BODY_ZONE_R_ARM)
|
||||
SetSlotFromZone()
|
||||
swap_zone(IS_LEFT_INDEX(index) ? BODY_ZONE_L_ARM : BODY_ZONE_R_ARM)
|
||||
user.temporarilyRemoveItemFromInventory(src, TRUE)
|
||||
Insert(user)
|
||||
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
var/list/organ_effects
|
||||
/// String displayed when the organ has decayed.
|
||||
var/failing_desc = "has decayed for too long, and has turned a sickly color. It probably won't work without repairs."
|
||||
/// Assoc list of alternate zones where this can organ be slotted to organ slot for that zone
|
||||
var/list/valid_zones = null
|
||||
|
||||
// Players can look at prefs before atoms SS init, and without this
|
||||
// they would not be able to see external organs, such as moth wings.
|
||||
@@ -198,8 +200,14 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
|
||||
|
||||
/// Returns a line to be displayed regarding valid insertion zones
|
||||
/obj/item/organ/proc/zones_tip()
|
||||
if (!valid_zones)
|
||||
return span_notice("It should be inserted in the [parse_zone(zone)].")
|
||||
|
||||
var/list/fit_zones = list()
|
||||
for (var/valid_zone in valid_zones)
|
||||
fit_zones += parse_zone(valid_zone)
|
||||
return span_notice("It should be inserted in the [english_list(fit_zones, and_text = " or ")].")
|
||||
|
||||
///Used as callbacks by object pooling
|
||||
/obj/item/organ/proc/exit_wardrobe()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
@@ -90,7 +90,22 @@
|
||||
span_notice("You press a button on [src] as it plunges into your body."),
|
||||
)
|
||||
|
||||
stored_organ.Insert(target)//insert stored organ into the user
|
||||
if (stored_organ.valid_zones && user.get_held_index_of_item(src))
|
||||
var/list/checked_zones = list(user.zone_selected)
|
||||
if (IS_RIGHT_INDEX(user.get_held_index_of_item(src)))
|
||||
checked_zones += list(BODY_ZONE_R_ARM, BODY_ZONE_R_LEG)
|
||||
else
|
||||
checked_zones += list(BODY_ZONE_L_ARM, BODY_ZONE_L_LEG)
|
||||
|
||||
for (var/check_zone in checked_zones)
|
||||
if (stored_organ.valid_zones[check_zone])
|
||||
stored_organ.swap_zone(check_zone)
|
||||
break
|
||||
|
||||
if (!stored_organ.Insert(target)) // insert stored organ into the user
|
||||
balloon_alert(user, "insertion failed!")
|
||||
return
|
||||
|
||||
stored_organ = null
|
||||
name = initial(name) //get rid of the organ in the name
|
||||
playsound(target.loc, 'sound/items/weapons/circsawhit.ogg', 50, vary = TRUE)
|
||||
|
||||
@@ -2,9 +2,14 @@
|
||||
name = "arm-mounted implant"
|
||||
desc = "You shouldn't see this! Adminhelp and report this as an issue on github!"
|
||||
zone = BODY_ZONE_R_ARM
|
||||
slot = ORGAN_SLOT_RIGHT_ARM_AUG
|
||||
icon_state = "toolkit_generic"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
actions_types = list(/datum/action/item_action/organ_action/toggle)
|
||||
valid_zones = list(
|
||||
BODY_ZONE_R_ARM = ORGAN_SLOT_RIGHT_ARM_AUG,
|
||||
BODY_ZONE_L_ARM = ORGAN_SLOT_LEFT_ARM_AUG,
|
||||
)
|
||||
///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
|
||||
@@ -17,10 +22,6 @@
|
||||
var/extend_sound = 'sound/vehicles/mecha/mechmove03.ogg'
|
||||
/// Sound played when retracting
|
||||
var/retract_sound = 'sound/vehicles/mecha/mechmove03.ogg'
|
||||
/// Organ slot that the implant occupies for the right arm
|
||||
var/right_arm_organ_slot = ORGAN_SLOT_RIGHT_ARM_AUG
|
||||
/// Organ slot that the implant occupies for the left arm
|
||||
var/left_arm_organ_slot = ORGAN_SLOT_LEFT_ARM_AUG
|
||||
|
||||
/obj/item/organ/cyberimp/arm/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -32,8 +33,6 @@
|
||||
var/atom/new_item = new typepath(src)
|
||||
items_list += WEAKREF(new_item)
|
||||
|
||||
SetSlotFromZone()
|
||||
|
||||
/obj/item/organ/cyberimp/arm/Destroy()
|
||||
hand = null
|
||||
active_item = null
|
||||
@@ -48,28 +47,6 @@
|
||||
/datum/action/item_action/organ_action/toggle/toolkit
|
||||
desc = "You can also activate your empty hand or the tool in your hand to open the tools radial menu."
|
||||
|
||||
/obj/item/organ/cyberimp/arm/proc/SetSlotFromZone()
|
||||
switch(zone)
|
||||
if(BODY_ZONE_L_ARM)
|
||||
slot = left_arm_organ_slot
|
||||
if(BODY_ZONE_R_ARM)
|
||||
slot = right_arm_organ_slot
|
||||
else
|
||||
CRASH("Invalid zone for [type]")
|
||||
update_appearance()
|
||||
|
||||
/obj/item/organ/cyberimp/arm/pre_surgical_insertion(mob/living/user, mob/living/carbon/new_owner, target_zone)
|
||||
// Ensure that in case we're somehow placed elsewhere (HARS-esque bs) we don't break our zone
|
||||
if (target_zone != BODY_ZONE_R_ARM && target_zone != BODY_ZONE_L_ARM)
|
||||
return FALSE
|
||||
|
||||
zone = target_zone
|
||||
SetSlotFromZone()
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/cyberimp/arm/zones_tip()
|
||||
return span_notice("It should be inserted in the [parse_zone(right_arm_organ_slot)] or [parse_zone(left_arm_organ_slot)].")
|
||||
|
||||
/obj/item/organ/cyberimp/arm/on_mob_insert(mob/living/carbon/arm_owner)
|
||||
. = ..()
|
||||
RegisterSignal(arm_owner, COMSIG_CARBON_POST_ATTACH_LIMB, PROC_REF(on_limb_attached))
|
||||
@@ -134,8 +111,8 @@
|
||||
active_item.resistance_flags = active_item::resistance_flags
|
||||
if(owner)
|
||||
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_notice("[owner] retracts [active_item] back into [owner.p_their()] [parse_zone(zone)]."),
|
||||
span_notice("[active_item] snaps back into your [parse_zone(zone)]."),
|
||||
span_hear("You hear a short mechanical noise."),
|
||||
)
|
||||
|
||||
@@ -154,13 +131,12 @@
|
||||
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/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)
|
||||
@@ -180,8 +156,8 @@
|
||||
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."),
|
||||
owner.visible_message(span_notice("[owner] extends [active_item] from [owner.p_their()] [parse_zone(zone)]."),
|
||||
span_notice("You extend [active_item] from your [parse_zone(zone)]."),
|
||||
span_hear("You hear a short mechanical noise."))
|
||||
playsound(get_turf(owner), extend_sound, 50, TRUE)
|
||||
|
||||
@@ -217,40 +193,32 @@
|
||||
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!"))
|
||||
owner.visible_message(span_danger("A loud bang comes from [owner]\'s [parse_zone(zone)]!"))
|
||||
playsound(get_turf(owner), 'sound/items/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!"))
|
||||
to_chat(owner, span_userdanger("You feel an explosion erupt inside your [parse_zone(zone)] as your implant breaks!"))
|
||||
owner.adjust_fire_stacks(20)
|
||||
owner.ignite_mob()
|
||||
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."
|
||||
@@ -265,9 +233,6 @@
|
||||
/obj/item/multitool/cyborg,
|
||||
)
|
||||
|
||||
/obj/item/organ/cyberimp/arm/toolset/l
|
||||
zone = BODY_ZONE_L_ARM
|
||||
|
||||
//The order of the item list for this implant is not alphabetized due to it actually affecting how it shows up playerside when opening the implant
|
||||
/obj/item/organ/cyberimp/arm/paperwork
|
||||
name = "integrated paperwork implant"
|
||||
@@ -284,9 +249,6 @@
|
||||
/obj/item/stamp/denied,
|
||||
)
|
||||
|
||||
/obj/item/organ/cyberimp/arm/paperwork/l
|
||||
zone = BODY_ZONE_L_ARM
|
||||
|
||||
/obj/item/organ/cyberimp/arm/paperwork/emag_act(mob/user, obj/item/card/emag/emag_card)
|
||||
for(var/datum/weakref/created_item in items_list)
|
||||
var/obj/potential_tool = created_item.resolve()
|
||||
@@ -317,7 +279,6 @@
|
||||
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."
|
||||
@@ -407,8 +368,10 @@
|
||||
|
||||
zone = BODY_ZONE_R_ARM
|
||||
slot = ORGAN_SLOT_RIGHT_ARM_MUSCLE
|
||||
right_arm_organ_slot = ORGAN_SLOT_RIGHT_ARM_MUSCLE
|
||||
left_arm_organ_slot = ORGAN_SLOT_LEFT_ARM_MUSCLE
|
||||
valid_zones = list(
|
||||
BODY_ZONE_R_ARM = ORGAN_SLOT_RIGHT_ARM_MUSCLE,
|
||||
BODY_ZONE_L_ARM = ORGAN_SLOT_LEFT_ARM_MUSCLE,
|
||||
)
|
||||
|
||||
actions_types = list()
|
||||
|
||||
@@ -433,9 +396,6 @@
|
||||
///Tracks how soon we can perform another slam attack
|
||||
COOLDOWN_DECLARE(slam_cooldown)
|
||||
|
||||
/obj/item/organ/cyberimp/arm/strongarm/l
|
||||
zone = BODY_ZONE_L_ARM
|
||||
|
||||
/obj/item/organ/cyberimp/arm/strongarm/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/strongarm)
|
||||
|
||||
@@ -290,4 +290,19 @@
|
||||
|
||||
/// Proc that gets called when someone starts surgically inserting the organ
|
||||
/obj/item/organ/proc/pre_surgical_insertion(mob/living/user, mob/living/carbon/new_owner, target_zone)
|
||||
if (!valid_zones)
|
||||
return TRUE
|
||||
|
||||
// Ensure that in case we're somehow placed elsewhere (HARS-esque bs) we don't break our zone
|
||||
if (!valid_zones[target_zone])
|
||||
return FALSE
|
||||
|
||||
swap_zone(target_zone)
|
||||
return TRUE
|
||||
|
||||
/// Readjusts the organ to fit into a different body zone/slot
|
||||
/obj/item/organ/proc/swap_zone(target_zone)
|
||||
if (!valid_zones[target_zone])
|
||||
CRASH("[src]'s ([type]) swap_zone was called with invalid zone [target_zone]")
|
||||
zone = target_zone
|
||||
slot = valid_zones[zone]
|
||||
|
||||
Reference in New Issue
Block a user