From 8baa0568b09cb9516192696ad8b06558c1d3eece Mon Sep 17 00:00:00 2001 From: Atermonera Date: Wed, 23 Dec 2020 15:12:38 -0900 Subject: [PATCH 01/20] Adds (Follow) link to emotes for ghosts --- code/modules/mob/emote.dm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index bff705d0c51..a8b94d602a4 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -37,6 +37,7 @@ var/mob/M = mob spawn(0) // It's possible that it could be deleted in the meantime, or that it runtimes. if(M) +<<<<<<< HEAD //VOREStation edit if(istype(M, /mob/observer/dead/)) var/mob/observer/dead/D = M @@ -45,6 +46,11 @@ else M.show_message(message, m_type) //End VOREStation edit +======= + if(isobserver(M)) + message = "[src] ([ghost_follow_link(src, M)]) [input]" + M.show_message(message, m_type) +>>>>>>> 47c1641... Merge pull request #7796 from Atermonera/ghost_emote for(var/obj in o_viewers) var/obj/O = obj From 327a858b3e72e97c5b423022a70e54b4722e787c Mon Sep 17 00:00:00 2001 From: Riley Date: Fri, 12 Feb 2021 08:10:34 -0500 Subject: [PATCH 02/20] Peacock tails! Application here: https://forum.vore-station.net/viewtopic.php?f=26&t=1914 --- .../vore/appearance/sprite_accessories_vr.dm | 18 ++++++++++++++++++ icons/mob/vore/tails_vr.dmi | Bin 143859 -> 148621 bytes 2 files changed, 18 insertions(+) diff --git a/code/modules/vore/appearance/sprite_accessories_vr.dm b/code/modules/vore/appearance/sprite_accessories_vr.dm index 06bb7a34cca..dac79672083 100644 --- a/code/modules/vore/appearance/sprite_accessories_vr.dm +++ b/code/modules/vore/appearance/sprite_accessories_vr.dm @@ -2101,6 +2101,24 @@ do_colouration = 1 color_blend_mode = ICON_MULTIPLY +/datum/sprite_accessory/tail/peacocktail_red + name = "Peacock tail (vwag)" + desc = "" + icon = "icons/mob/vore/tails_vr.dmi" + icon_state = "peacocktail_red" + ani_state = "peacocktail_red_w" + ckeys_allowed = list("prettiebyrd") + +/datum/sprite_accessory/tail/peacocktail + name = "Peacock tail, colorable (vwag)" + desc = "" + icon = "icons/mob/vore/tails_vr.dmi" + icon_state = "peacocktail" + ani_state = "peacocktail_w" + do_colouration = 1 + color_blend_mode = ICON_MULTIPLY + ckeys_allowed = list("prettiebyrd") + /* //////////////////////////// / =--------------------= / diff --git a/icons/mob/vore/tails_vr.dmi b/icons/mob/vore/tails_vr.dmi index 0ef22dd9ef9fd6cfd5abf4d18ddb592cddec2129..44a960e345c660b8b180e8a1e589c9015c5aa511 100644 GIT binary patch delta 18870 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 G=>G!?`t%+E delta 14071 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 Y-6zXU Date: Fri, 12 Feb 2021 08:14:25 -0500 Subject: [PATCH 03/20] Peacock tails! Added comment in code, they want the tails to be unlocked for public at a later date. --- code/modules/vore/appearance/sprite_accessories_vr.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/vore/appearance/sprite_accessories_vr.dm b/code/modules/vore/appearance/sprite_accessories_vr.dm index dac79672083..7fbf2662b7e 100644 --- a/code/modules/vore/appearance/sprite_accessories_vr.dm +++ b/code/modules/vore/appearance/sprite_accessories_vr.dm @@ -1,4 +1,4 @@ -/* +ing /* Hello and welcome to VOREStation sprite_accessories: For a more general overview please read sprite_accessories.dm. This file is for ears and tails. This is intended to be friendly for people with little to no actual coding experience. @@ -2101,7 +2101,7 @@ do_colouration = 1 color_blend_mode = ICON_MULTIPLY -/datum/sprite_accessory/tail/peacocktail_red +/datum/sprite_accessory/tail/peacocktail_red //this is ckey locked for now, but prettiebyrd wants these tails to be unlocked at a later date name = "Peacock tail (vwag)" desc = "" icon = "icons/mob/vore/tails_vr.dmi" @@ -2109,7 +2109,7 @@ ani_state = "peacocktail_red_w" ckeys_allowed = list("prettiebyrd") -/datum/sprite_accessory/tail/peacocktail +/datum/sprite_accessory/tail/peacocktail //ditto name = "Peacock tail, colorable (vwag)" desc = "" icon = "icons/mob/vore/tails_vr.dmi" From 24f036d0a1abb6d9f59585c47d871b903a363de8 Mon Sep 17 00:00:00 2001 From: Riley Date: Fri, 12 Feb 2021 08:10:34 -0500 Subject: [PATCH 04/20] Peacock tails! Application here: https://forum.vore-station.net/viewtopic.php?f=26&t=1914 --- .../vore/appearance/sprite_accessories_vr.dm | 18 ++++++++++++++++++ icons/mob/vore/tails_vr.dmi | Bin 143859 -> 148621 bytes 2 files changed, 18 insertions(+) diff --git a/code/modules/vore/appearance/sprite_accessories_vr.dm b/code/modules/vore/appearance/sprite_accessories_vr.dm index 06bb7a34cca..dac79672083 100644 --- a/code/modules/vore/appearance/sprite_accessories_vr.dm +++ b/code/modules/vore/appearance/sprite_accessories_vr.dm @@ -2101,6 +2101,24 @@ do_colouration = 1 color_blend_mode = ICON_MULTIPLY +/datum/sprite_accessory/tail/peacocktail_red + name = "Peacock tail (vwag)" + desc = "" + icon = "icons/mob/vore/tails_vr.dmi" + icon_state = "peacocktail_red" + ani_state = "peacocktail_red_w" + ckeys_allowed = list("prettiebyrd") + +/datum/sprite_accessory/tail/peacocktail + name = "Peacock tail, colorable (vwag)" + desc = "" + icon = "icons/mob/vore/tails_vr.dmi" + icon_state = "peacocktail" + ani_state = "peacocktail_w" + do_colouration = 1 + color_blend_mode = ICON_MULTIPLY + ckeys_allowed = list("prettiebyrd") + /* //////////////////////////// / =--------------------= / diff --git a/icons/mob/vore/tails_vr.dmi b/icons/mob/vore/tails_vr.dmi index 0ef22dd9ef9fd6cfd5abf4d18ddb592cddec2129..44a960e345c660b8b180e8a1e589c9015c5aa511 100644 GIT binary patch delta 18870 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 G=>G!?`t%+E delta 14071 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 Y-6zXU Date: Fri, 12 Feb 2021 08:14:25 -0500 Subject: [PATCH 05/20] Peacock tails! Added comment in code, they want the tails to be unlocked for public at a later date. --- code/modules/vore/appearance/sprite_accessories_vr.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/vore/appearance/sprite_accessories_vr.dm b/code/modules/vore/appearance/sprite_accessories_vr.dm index dac79672083..7fbf2662b7e 100644 --- a/code/modules/vore/appearance/sprite_accessories_vr.dm +++ b/code/modules/vore/appearance/sprite_accessories_vr.dm @@ -1,4 +1,4 @@ -/* +ing /* Hello and welcome to VOREStation sprite_accessories: For a more general overview please read sprite_accessories.dm. This file is for ears and tails. This is intended to be friendly for people with little to no actual coding experience. @@ -2101,7 +2101,7 @@ do_colouration = 1 color_blend_mode = ICON_MULTIPLY -/datum/sprite_accessory/tail/peacocktail_red +/datum/sprite_accessory/tail/peacocktail_red //this is ckey locked for now, but prettiebyrd wants these tails to be unlocked at a later date name = "Peacock tail (vwag)" desc = "" icon = "icons/mob/vore/tails_vr.dmi" @@ -2109,7 +2109,7 @@ ani_state = "peacocktail_red_w" ckeys_allowed = list("prettiebyrd") -/datum/sprite_accessory/tail/peacocktail +/datum/sprite_accessory/tail/peacocktail //ditto name = "Peacock tail, colorable (vwag)" desc = "" icon = "icons/mob/vore/tails_vr.dmi" From c00ed7e3b1c5f1714fa91ee0a33d00f474f1ac72 Mon Sep 17 00:00:00 2001 From: Atermonera Date: Tue, 23 Feb 2021 14:16:59 -0800 Subject: [PATCH 06/20] Added verbs/handling for removing and attaching your own robotic bodyparts. --- code/__defines/damage_organs.dm | 6 +- .../carbon/human/human_modular_limbs.dm | 191 ++++++++++++++++++ .../mob/living/carbon/human/human_powers.dm | 2 +- .../carbon/human/species/outsider/event.dm | 2 +- .../living/carbon/human/species/species.dm | 3 + code/modules/organs/organ_external.dm | 6 +- code/modules/organs/robolimbs.dm | 54 +++++ .../cyberlimbs/prosthesis/wooden.dmi | Bin 0 -> 1337 bytes vorestation.dme | 4 + 9 files changed, 264 insertions(+), 4 deletions(-) create mode 100644 code/modules/mob/living/carbon/human/human_modular_limbs.dm create mode 100644 icons/mob/human_races/cyberlimbs/prosthesis/wooden.dmi diff --git a/code/__defines/damage_organs.dm b/code/__defines/damage_organs.dm index c87b9942dfc..db1a71c77a6 100644 --- a/code/__defines/damage_organs.dm +++ b/code/__defines/damage_organs.dm @@ -61,4 +61,8 @@ #define INFECTION_LEVEL_ONE 100 #define INFECTION_LEVEL_TWO 500 #define INFECTION_LEVEL_THREE 1000 -#define INFECTION_LEVEL_MAX 1500 \ No newline at end of file +#define INFECTION_LEVEL_MAX 1500 + +#define MODULAR_BODYPART_INVALID 0 // Cannot be detached or reattached. +#define MODULAR_BODYPART_PROSTHETIC 1 // Can be detached or reattached freely. +#define MODULAR_BODYPART_CYBERNETIC 2 // Can be detached or reattached to compatible parent organs. diff --git a/code/modules/mob/living/carbon/human/human_modular_limbs.dm b/code/modules/mob/living/carbon/human/human_modular_limbs.dm new file mode 100644 index 00000000000..aab466dae72 --- /dev/null +++ b/code/modules/mob/living/carbon/human/human_modular_limbs.dm @@ -0,0 +1,191 @@ +/* + A system for easily and quickly removing your own bodyparts, with a view towards + swapping them out for new ones, or just doing it as a party trick to horrify an + audience. Current implementation only supports robolimbs and uses a modular_bodypart + value on the manufacturer datum, but I have tried to keep it generic for future work. + PS. jesus christ this was meant to be a half an hour port +*/ + +// External organ procs: +// Does this bodypart count as a modular limb, and if so, what kind? +/obj/item/organ/external/proc/get_modular_limb_category() + . = MODULAR_BODYPART_INVALID + if(robotic >= ORGAN_ROBOT && model) + var/datum/robolimb/manufacturer = all_robolimbs[model] + if(!isnull(manufacturer?.modular_bodyparts)) + . = manufacturer.modular_bodyparts + +// Checks if a limb could theoretically be removed. +// Note that this does not currently bother checking if a child or internal organ is vital. +/obj/item/organ/external/proc/can_remove_modular_limb(var/mob/living/carbon/human/user) + if(vital || cannot_amputate) + return FALSE + var/bodypart_cat = get_modular_limb_category() + if(bodypart_cat == MODULAR_BODYPART_CYBERNETIC) + if(!parent_organ) + return FALSE + var/obj/item/organ/external/parent = user?.get_organ(parent_organ) + if(!parent || parent.get_modular_limb_category(user) < MODULAR_BODYPART_CYBERNETIC) + return FALSE + . = (bodypart_cat != MODULAR_BODYPART_INVALID) + +// Note that this proc is checking if the organ can be attached -to-, not attached itself. +/obj/item/organ/external/proc/can_attach_modular_limb_here(var/mob/living/carbon/human/user) + var/list/limb_data = user?.species?.has_limbs[organ_tag] + if(islist(limb_data) && limb_data["has_children"] > 0) + . = (length(children) < limb_data["has_children"]) + +/obj/item/organ/external/proc/can_be_attached_modular_limb(var/mob/living/carbon/user) + var/bodypart_cat = get_modular_limb_category() + if(bodypart_cat == MODULAR_BODYPART_INVALID) + return FALSE + if(!parent_organ) + return FALSE + var/obj/item/organ/external/parent = user?.get_organ(parent_organ) + if(!parent) + return FALSE + if(!parent.can_attach_modular_limb_here(user)) + return FALSE + if(bodypart_cat == MODULAR_BODYPART_CYBERNETIC && parent.get_modular_limb_category(src) < MODULAR_BODYPART_CYBERNETIC) + return FALSE + return TRUE + +// Checks if an organ (or the parent of one) is in a fit state for modular limb stuff to happen. +/obj/item/organ/external/proc/check_modular_limb_damage(var/mob/living/carbon/human/user) + . = damage >= min_broken_damage || (status & ORGAN_BROKEN) || is_stump() // can't use is_broken() as the limb has ORGAN_CUT_AWAY + +// Human mob procs: +// Checks the organ list for limbs meeting a predicate. Way overengineered for such a limited use +// case but I can see it being expanded in the future if meat limbs or doona limbs use it. +/mob/living/carbon/human/proc/get_modular_limbs(var/return_first_found = FALSE, var/validate_proc) + for(var/bp in organs) + var/obj/item/organ/external/E = bp + if(!validate_proc || call(E, validate_proc)(src) > MODULAR_BODYPART_INVALID) + LAZYADD(., E) + if(return_first_found) + return + // Prune children so we can't remove every individual component of an entire prosthetic arm + // piece by piece. Technically a circular dependency here would remove the limb entirely but + // if there's a parent whose child is also its parent, there's something wrong regardless. + for(var/bp in .) + var/obj/item/organ/external/E = bp + if(length(E.children)) + . -= E.children + +// Called in robotize(), replaced() and removed() to update our modular limb verbs. +/mob/living/carbon/human/proc/refresh_modular_limb_verbs() + if(length(get_modular_limbs(return_first_found = TRUE, validate_proc = /obj/item/organ/external/proc/can_attach_modular_limb_here))) + verbs |= .proc/attach_limb_verb + else + verbs -= .proc/attach_limb_verb + if(length(get_modular_limbs(return_first_found = TRUE, validate_proc = /obj/item/organ/external/proc/can_remove_modular_limb))) + verbs |= .proc/detach_limb_verb + else + verbs -= .proc/detach_limb_verb + +// Proc helper for attachment verb. +/mob/living/carbon/human/proc/check_can_attach_modular_limb(var/obj/item/organ/external/E) + if(world.time < last_special + (2 SECONDS) || get_active_hand() != E) + return FALSE + if(incapacitated() || restrained()) + to_chat(src, SPAN_WARNING("You can't do that in your current state!")) + return FALSE + if(QDELETED(E) || !istype(E)) + to_chat(src, SPAN_WARNING("You are not holding a compatible limb to attach.")) + return FALSE + if(!E.can_be_attached_modular_limb(src)) + to_chat(src, SPAN_WARNING("\The [E] cannot be attached to your current body.")) + return FALSE + if(E.get_modular_limb_category() <= MODULAR_BODYPART_INVALID) + to_chat(src, SPAN_WARNING("\The [E] cannot be attached by your own hand.")) + return FALSE + var/install_to_zone = E.organ_tag + if(!isnull(get_organ(install_to_zone))) + to_chat(src, SPAN_WARNING("There is already a limb attached at that part of your body.")) + return FALSE + if(E.check_modular_limb_damage(src)) + to_chat(src, SPAN_WARNING("\The [E] is too damaged to be attached.")) + return FALSE + var/obj/item/organ/external/parent = E.parent_organ && get_organ(E.parent_organ) + if(!parent) + to_chat(src, SPAN_WARNING("\The [E] needs an existing limb to be attached to.")) + return FALSE + if(parent.check_modular_limb_damage(src)) + to_chat(src, SPAN_WARNING("Your [parent.name] is too damaged to have anything attached.")) + return FALSE + return TRUE + +// Proc helper for detachment verb. +/mob/living/carbon/human/proc/check_can_detach_modular_limb(var/obj/item/organ/external/E) + if(world.time < last_special + (2 SECONDS)) + return FALSE + if(incapacitated() || restrained()) + to_chat(src, SPAN_WARNING("You can't do that in your current state!")) + return FALSE + if(!istype(E) || QDELETED(src) || QDELETED(E) || E.owner != src || E.loc != src) + return FALSE + if(E.check_modular_limb_damage(src)) + to_chat(src, SPAN_WARNING("That limb is too damaged to be removed!")) + return FALSE + var/obj/item/organ/external/parent = E.parent_organ && get_organ(E.parent_organ) + if(!parent) + return FALSE + if(parent.check_modular_limb_damage(src)) + to_chat(src, SPAN_WARNING("Your [parent.name] is too damaged to detach anything from it.")) + return FALSE + return (E in get_modular_limbs(return_first_found = FALSE, validate_proc = /obj/item/organ/external/proc/can_remove_modular_limb)) + +// Verbs below: +// Add or remove robotic limbs; check refresh_modular_limb_verbs() above. +/mob/living/carbon/human/proc/attach_limb_verb() + set name = "Attach Limb" + set category = "Object" + set desc = "Attach a replacement limb." + set usr = src + + var/obj/item/organ/external/E = get_active_hand() + if(!check_can_attach_modular_limb(E)) + return FALSE + if(!do_after(src, 2 SECONDS, src)) + return FALSE + if(!check_can_attach_modular_limb(E)) + return FALSE + + last_special = world.time + drop_from_inventory(E) + E.replaced(src) + E.status &= ~ORGAN_CUT_AWAY + var/datum/gender/G = gender_datums[gender] + visible_message( + SPAN_NOTICE("\The [src] attaches \the [E] to [G.his] body!"), + SPAN_NOTICE("You attach \the [E] to your body!")) + regenerate_icons() // Not sure why this isn't called by removed(), but without it we don't update our limb appearance. + return TRUE + +/mob/living/carbon/human/proc/detach_limb_verb() + set name = "Remove Limb" + set category = "Object" + set desc = "Detach one of your limbs." + set usr = src + + var/list/detachable_limbs = get_modular_limbs(return_first_found = FALSE, validate_proc = /obj/item/organ/external/proc/can_remove_modular_limb) + if(!length(detachable_limbs)) + to_chat(src, SPAN_WARNING("You have no detachable limbs.")) + return FALSE + var/obj/item/organ/external/E = input(usr, "Which limb do you wish to detach?", "Limb Removal") as null|anything in detachable_limbs + if(!check_can_detach_modular_limb(E)) + return FALSE + if(!do_after(src, 2 SECONDS, src)) + return FALSE + if(!check_can_detach_modular_limb(E)) + return FALSE + + last_special = world.time + E.removed(src) + E.dropInto(loc) + put_in_hands(E) + var/datum/gender/G = gender_datums[gender] + visible_message( + SPAN_NOTICE("\The [src] detaches [G.his] [E.name]!"), + SPAN_NOTICE("You detach your [E.name]!")) + return TRUE diff --git a/code/modules/mob/living/carbon/human/human_powers.dm b/code/modules/mob/living/carbon/human/human_powers.dm index d63b866e6fa..d7c66d52895 100644 --- a/code/modules/mob/living/carbon/human/human_powers.dm +++ b/code/modules/mob/living/carbon/human/human_powers.dm @@ -366,7 +366,7 @@ return var/datum/robolimb/robohead = all_robolimbs[E.model] if(!robohead.monitor_styles || !robohead.monitor_icon) - to_chat(src,"Your head doesn't have a monitor or it doens't support to be changed!") + to_chat(src,"Your head doesn't have a monitor, or it doesn't support being changed!") return var/list/states if(!states) diff --git a/code/modules/mob/living/carbon/human/species/outsider/event.dm b/code/modules/mob/living/carbon/human/species/outsider/event.dm index 3566010050b..3604e201f39 100644 --- a/code/modules/mob/living/carbon/human/species/outsider/event.dm +++ b/code/modules/mob/living/carbon/human/species/outsider/event.dm @@ -122,7 +122,7 @@ Variables you may want to make use of are: has_limbs = list( BP_TORSO = list("path" = /obj/item/organ/external/chest), BP_GROIN = list("path" = /obj/item/organ/external/groin), - BP_HEAD = list("path" = /obj/item/organ/external/head), + BP_HEAD = list("path" = /obj/item/organ/external/head), BP_L_ARM = list("path" = /obj/item/organ/external/arm), BP_R_ARM = list("path" = /obj/item/organ/external/arm/right), BP_L_LEG = list("path" = /obj/item/organ/external/leg), diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 9860b0c0113..bc0e1eddbe3 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -347,6 +347,9 @@ var/limb_path = organ_data["path"] var/obj/item/organ/O = new limb_path(H) organ_data["descriptor"] = O.name + if(O.parent_organ) + organ_data = has_limbs[O.parent_organ] + organ_data["has_children"] = organ_data["has_children"]+1 for(var/organ_tag in has_organ) var/organ_type = has_organ[organ_tag] diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index ab8a91f721d..d9b21f6ceca 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -235,6 +235,7 @@ owner.organs |= src for(var/obj/item/organ/organ in src) organ.replaced(owner,src) + owner.refresh_modular_limb_verbs() if(parent_organ) parent = owner.organs_by_name[src.parent_organ] @@ -1129,6 +1130,8 @@ Note that amputating the affected organ does in fact remove the infection from t if(R.lifelike) robotic = ORGAN_LIFELIKE name = "[initial(name)]" + else if(R.modular_bodyparts == MODULAR_BODYPART_PROSTHETIC) + name = "prosthetic [initial(name)]" else name = "robotic [initial(name)]" desc = "[R.desc] It looks like it was produced by [R.company]." @@ -1160,7 +1163,7 @@ Note that amputating the affected organ does in fact remove the infection from t while(null in owner.internal_organs) owner.internal_organs -= null - + owner.refresh_modular_limb_verbs() return 1 /obj/item/organ/external/proc/mutate() @@ -1261,6 +1264,7 @@ Note that amputating the affected organ does in fact remove the infection from t qdel(spark_system) qdel(src) + victim.refresh_modular_limb_verbs() victim.update_icons_body() /obj/item/organ/external/proc/disfigure(var/type = "brute") diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm index e7be5f4912a..5a769091895 100644 --- a/code/modules/organs/robolimbs.dm +++ b/code/modules/organs/robolimbs.dm @@ -47,6 +47,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ var/icon = 'icons/mob/human_races/robotic.dmi' // Icon base to draw from. var/monitor_icon = 'icons/mob/monitor_icons.dmi' // Where it draws the monitor icon from. var/unavailable_at_chargen // If set, not available at chargen. +<<<<<<< HEAD var/unavailable_to_build // If set, can't be constructed. var/lifelike // If set, appears organic. var/skin_tone // If set, applies skin tone rather than part color Overrides color. @@ -63,6 +64,26 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ var/robo_brute_mod = 1 // Multiplier for incoming brute damage. var/robo_burn_mod = 1 // As above for burn. +======= + var/unavailable_to_build // If set, can't be constructed. + var/lifelike // If set, appears organic. + var/skin_tone // If set, applies skin tone rather than part color Overrides color. + var/skin_color // If set, applies skin color rather than part color. + var/blood_color = SYNTH_BLOOD_COLOUR // Colour for blood splatters. + var/blood_name = "oil" // Descriptor for blood splatters. + var/list/monitor_styles // If empty, the model of limbs offers a head compatible with monitors. + var/parts = BP_ALL // Defines what parts said brand can replace on a body. + var/health_hud_intensity = 1 // Intensity modifier for the health GUI indicator. + var/suggested_species = "Human" // If it should make the torso a species + var/speech_bubble_appearance = "synthetic" // What icon_state to use for speech bubbles when talking. Check talk.dmi for all the icons. + var/modular_bodyparts = MODULAR_BODYPART_INVALID // Whether or not this limb allows attaching/detaching, and whether or not it checks its parent as well. + var/robo_brute_mod = 1 // Multiplier for incoming brute damage. + var/robo_burn_mod = 1 // As above for burn. + // Species in this list cannot take these prosthetics. + var/list/species_cannot_use = list(SPECIES_TESHARI, SPECIES_PROMETHEAN, SPECIES_DIONA) + // "Species Name" = "Robolimb Company", List, when initialized, will become "Species Name" = RobolimbDatum, used for alternate species sprites. + var/list/species_alternates = list(SPECIES_TAJ = "Unbranded - Tajaran", SPECIES_UNATHI = "Unbranded - Unathi") +>>>>>>> c31a3e7... Merge pull request #7905 from MistakeNot4892/beepboop /datum/robolimb/unbranded_monitor company = "Unbranded Monitor" @@ -77,12 +98,14 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ desc = "A simple robotic limb with retro design. Seems rather stiff." icon = 'icons/mob/human_races/cyberlimbs/unbranded/unbranded_alt1.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/unbranded_alt2 company = "Unbranded - Mantis Prosis" desc = "This limb has a casing of sleek black metal and repulsive insectile design." icon = 'icons/mob/human_races/cyberlimbs/unbranded/unbranded_alt2.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/unbranded_tajaran company = "Unbranded - Tajaran" @@ -91,6 +114,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ desc = "A simple robotic limb with feline design. Seems rather stiff." icon = 'icons/mob/human_races/cyberlimbs/unbranded/unbranded_tajaran.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/unbranded_unathi company = "Unbranded - Unathi" @@ -99,6 +123,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ desc = "A simple robotic limb with reptilian design. Seems rather stiff." icon = 'icons/mob/human_races/cyberlimbs/unbranded/unbranded_unathi.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/unbranded_teshari company = "Unbranded - Teshari" @@ -107,12 +132,20 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ desc = "A simple robotic limb with a small, raptor-like design. Seems rather stiff." icon = 'icons/mob/human_races/cyberlimbs/unbranded/unbranded_teshari.dmi' unavailable_to_build = 0 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC + parts = list(BP_HEAD, BP_TORSO, BP_GROIN) + +/datum/robolimb/unbranded_teshari/limbs + company = "Unbranded - Teshari (Limbs)" + parts = list(BP_L_ARM, BP_R_ARM, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT) + modular_bodyparts = MODULAR_BODYPART_PROSTHETIC /datum/robolimb/nanotrasen company = "NanoTrasen" desc = "A simple but efficient robotic limb, created by NanoTrasen." icon = 'icons/mob/human_races/cyberlimbs/nanotrasen/nanotrasen_main.dmi' species_alternates = list(SPECIES_TAJ = "NanoTrasen - Tajaran", SPECIES_UNATHI = "NanoTrasen - Unathi") + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/nanotrasen_tajaran company = "NanoTrasen - Tajaran" @@ -122,6 +155,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ desc = "A simple but efficient robotic limb, created by NanoTrasen." icon = 'icons/mob/human_races/cyberlimbs/nanotrasen/nanotrasen_tajaran.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/nanotrasen_unathi company = "NanoTrasen - Unathi" @@ -131,6 +165,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ desc = "A simple but efficient robotic limb, created by NanoTrasen." icon = 'icons/mob/human_races/cyberlimbs/nanotrasen/nanotrasen_unathi.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/cenilimicybernetics_teshari company = "Cenilimi Cybernetics" @@ -140,6 +175,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ desc = "Made by a Teshari-owned company, for Teshari." icon = 'icons/mob/human_races/cyberlimbs/cenilimicybernetics/cenilimicybernetics_teshari.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/bishop company = "Bishop" @@ -187,18 +223,21 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ desc = "This limb is grey and rough, with little in the way of aesthetic." icon = 'icons/mob/human_races/cyberlimbs/cybersolutions/cybersolutions_main.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/cybersolutions_alt2 company = "Cyber Solutions - Outdated" desc = "This limb is of severely outdated design; there's no way it's comfortable or very functional to use." icon = 'icons/mob/human_races/cyberlimbs/cybersolutions/cybersolutions_alt2.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/cybersolutions_alt1 company = "Cyber Solutions - Wight" desc = "This limb has cheap plastic panels mounted on grey metal." icon = 'icons/mob/human_races/cyberlimbs/cybersolutions/cybersolutions_alt1.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/cybersolutions_alt3 company = "Cyber Solutions - Array" @@ -212,6 +251,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ desc = "This limb is lightweight with a sleek design." icon = 'icons/mob/human_races/cyberlimbs/einstein/einstein_main.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/grayson company = "Grayson" @@ -223,6 +263,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ green=grayson_green;\ blue=grayson_blue;\ rgb=grayson_rgb" + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/grayson_alt1 company = "Grayson - Reinforced" @@ -286,6 +327,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ icon = 'icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi' unavailable_to_build = 1 monitor_styles = standard_monitor_styles + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/morpheus_alt1 company = "Morpheus - Zenith" @@ -334,6 +376,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ desc = "This limb features sleek black and white polymers." icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/wardtakahashi_alt1 company = "Ward-Takahashi - Shroud" @@ -361,6 +404,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ desc = "This limb has a minimalist black and red casing." icon = 'icons/mob/human_races/cyberlimbs/xion/xion_main.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/xion_alt1 company = "Xion - Breach" @@ -379,12 +423,14 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ green=xion_green;\ blue=xion_blue;\ rgb=xion_rgb" + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/xion_alt3 company = "Xion - Whiteout" desc = "This limb has a minimalist black and white casing." icon = 'icons/mob/human_races/cyberlimbs/xion/xion_alt3.dmi' unavailable_to_build = 1 + modular_bodyparts = MODULAR_BODYPART_CYBERNETIC /datum/robolimb/xion_alt4 company = "Xion - Breach - Whiteout" @@ -409,6 +455,14 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ unavailable_to_build = 1 skin_tone = 1 +/datum/robolimb/wooden + company = "Morgan Trading Co" + desc = "A simplistic, metal-banded, wood-panelled prosthetic." + icon = 'icons/mob/human_races/cyberlimbs/prosthesis/wooden.dmi' + modular_bodyparts = MODULAR_BODYPART_PROSTHETIC + parts = list(BP_L_ARM, BP_R_ARM, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT) + modular_bodyparts = MODULAR_BODYPART_PROSTHETIC + /obj/item/weapon/disk/limb name = "Limb Blueprints" desc = "A disk containing the blueprints for prosthetics." diff --git a/icons/mob/human_races/cyberlimbs/prosthesis/wooden.dmi b/icons/mob/human_races/cyberlimbs/prosthesis/wooden.dmi new file mode 100644 index 0000000000000000000000000000000000000000..5dbf1ee175688a0f81b4c995568f4e3eba9fd242 GIT binary patch literal 1337 zcmV-91;+Y`P)&N=l}trd?fK#l^+)m^JskegDdpz`($F4Q&Ac0004WQchCV=-0C=2@(!C19AP~UuS)W3Zz4UACQW8pr<`qQn{D4Hu zDaq?Mi9@I2ZFlgy{~)&F*}sNSbnk&LfXT-o9^!sFbGCY&-L~AWoH_8;<+7x#GHhdm zQsLZirah+ph%tlevlx9K z^opzZ94Jl59jspaAS@o%f36k%*d1T*3$hHhXSG%HTL1tA14%?dRCt{2ozHI5KoG{) zI40s&qljFKiNrO;={<2HaZRMg%c>z!#gEPDVPlugW_0H@c$6Xs&;`^zG zjG6iTc}ZQ_-dPI)007`gaB}p<<3#F~dZ)Urugi~qGOkuB^YwZZeU1w5EYFU$1925X9Po_^iy>R4bPG20cc)EY0ZUgU@BgF(dGhZ_uO2BjC@q zDc*TK0}uHIJtqUl3~EgSvZUeH_R%MTx`hA$000000002+67BW$%enq@QDMzD=+TV> z=_Xu1-02GTL;dHRo;BZ~H#4gDg|=YV*MB}#*z!$!Ms=~%7sy++8K!)_9z}Z$00000 z000000O$_?RNeNbriPra)3X~GDVuu4fS*KU7KtC7({!4z>P>n5h{hvjlFF1BpaY^B zm{J2=j~NgXni2e13P$>!BwUeD1h;&y5Xo2d(p$Ra1Ith+U(qefM52i@0%LO|_<*Wo zRAoR+xB+Dkb^|^)z~Y$iU-&f*(0oPD*#J-QYZ~BNlzIRF000000002|_jG=PLhX+W zK9VqH|NNZa2BZ0^9ur{l-5US^0I^=$ut03VHlEWzg`%MIGY+2XeA zMK7Wg@)dz+^m_iq@1Kp<3z5+L{Q900^b#iU=NDCQt>?>H@SDk%xYh#z002ik>EusF z>pm&9)>q!oAMpGCNmT23KvlgMz8aE(VYcNlz5jomkw-4B_1%v^=LV`CspK(#1XJsg zOjSJq000000002@>w8z6FD_kizP@**^AQ-VFHWp++XljPbz+N$*`ECuY@5BlckK^w z#kD`cmB;l5G`OPB*>>>>>> c31a3e7... Merge pull request #7905 from MistakeNot4892/beepboop:polaris.dme #include "code\modules\mob\living\carbon\human\human_movement.dm" #include "code\modules\mob\living\carbon\human\human_organs.dm" #include "code\modules\mob\living\carbon\human\human_powers.dm" From ec94beed6b42c236b2f58e7f1695c3176201af82 Mon Sep 17 00:00:00 2001 From: Schnayy Date: Fri, 26 Feb 2021 08:58:53 -0600 Subject: [PATCH 07/20] Removes ping subsystem that was breaking chat --- code/__defines/subsystems.dm | 3 + code/game/verbs/advanced_who.dm | 4 + code/game/verbs/who.dm | 191 ++++++++++++++++++++++++++++++ code/modules/client/verbs/ping.dm | 12 ++ 4 files changed, 210 insertions(+) create mode 100644 code/modules/client/verbs/ping.dm diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index d0a5d72c86f..0f927bb4946 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -57,7 +57,10 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define INIT_ORDER_SKYBOX 30 #define INIT_ORDER_MAPPING 25 #define INIT_ORDER_DECALS 20 +<<<<<<< HEAD #define INIT_ORDER_PLANTS 18 // Must initialize before atoms. +======= +>>>>>>> ebc5263... Merge pull request #7920 from Atermonera/ping_verb_fix #define INIT_ORDER_JOB 17 #define INIT_ORDER_ALARM 16 // Must initialize before atoms. #define INIT_ORDER_ATOMS 15 diff --git a/code/game/verbs/advanced_who.dm b/code/game/verbs/advanced_who.dm index 4498136b2b3..221939cd50c 100644 --- a/code/game/verbs/advanced_who.dm +++ b/code/game/verbs/advanced_who.dm @@ -85,6 +85,10 @@ entry += " - In Lobby
" else entry += " - Playing
" +<<<<<<< HEAD:code/game/verbs/advanced_who.dm +======= + +>>>>>>> ebc5263... Merge pull request #7920 from Atermonera/ping_verb_fix:code/modules/client/verbs/advanced_who.dm Lines += entry msg += "" diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm index 3cb25b702e4..5c6f1e15452 100644 --- a/code/game/verbs/who.dm +++ b/code/game/verbs/who.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD:code/game/verbs/who.dm /client/verb/who() set name = "Who" @@ -206,3 +207,193 @@ msg += "\nAdminhelps are also sent to Discord. If no admins are available in game try anyway and an admin on Discord may see it and respond." return msg +======= + +/client/verb/who() + set name = "Who" + set category = "OOC" + + var/msg = "Current Players:\n" + + var/list/Lines = list() + + if(holder && (R_ADMIN & holder.rights || R_MOD & holder.rights)) + for(var/client/C in GLOB.clients) + var/entry = "\t[C.key]" + if(C.holder && C.holder.fakekey) + entry += " (as [C.holder.fakekey])" + entry += " - Playing as [C.mob.real_name]" + switch(C.mob.stat) + if(UNCONSCIOUS) + entry += " - Unconscious" + if(DEAD) + if(isobserver(C.mob)) + var/mob/observer/dead/O = C.mob + if(O.started_as_observer) + entry += " - Observing" + else + entry += " - DEAD" + else + entry += " - DEAD" + + var/age + if(isnum(C.player_age)) + age = C.player_age + else + age = 0 + + if(age <= 1) + age = "[age]" + else if(age < 10) + age = "[age]" + + entry += " - [age]" + + if(is_special_character(C.mob)) + entry += " - Antagonist" + + if(C.is_afk()) + var/seconds = C.last_activity_seconds() + entry += " (AFK - " + entry += "[round(seconds / 60)] minutes, " + entry += "[seconds % 60] seconds)" + + entry += " (?)" + Lines += entry + else + for(var/client/C in GLOB.clients) + var/entry + if(C.holder && C.holder.fakekey) + entry = C.holder.fakekey + else + entry = C.key + Lines += entry + + for(var/line in sortList(Lines)) + msg += "[line]\n" + + msg += "Total Players: [length(Lines)]" + to_chat(src,msg) + +/client/verb/staffwho() + set category = "Admin" + set name = "Staffwho" + + var/msg = "" + var/modmsg = "" + var/devmsg = "" + var/eventMmsg = "" + var/num_mods_online = 0 + var/num_admins_online = 0 + var/num_devs_online = 0 + var/num_event_managers_online = 0 + if(holder) + for(var/client/C in admins) + if(R_ADMIN & C.holder.rights || (!R_MOD & C.holder.rights && !R_EVENT & C.holder.rights)) //Used to determine who shows up in admin rows + + if(C.holder.fakekey && (!R_ADMIN & holder.rights && !R_MOD & holder.rights)) //Event Managerss can't see stealthmins + continue + + msg += "\t[C] is a [C.holder.rank]" + + if(C.holder.fakekey) + msg += " (as [C.holder.fakekey])" + + if(isobserver(C.mob)) + msg += " - Observing" + else if(istype(C.mob,/mob/new_player)) + msg += " - Lobby" + else + msg += " - Playing" + + if(C.is_afk()) + var/seconds = C.last_activity_seconds() + msg += " (AFK - " + msg += "[round(seconds / 60)] minutes, " + msg += "[seconds % 60] seconds)" + msg += "\n" + + num_admins_online++ + else if(R_MOD & C.holder.rights) //Who shows up in mod rows. + modmsg += "\t[C] is a [C.holder.rank]" + + if(isobserver(C.mob)) + modmsg += " - Observing" + else if(istype(C.mob,/mob/new_player)) + modmsg += " - Lobby" + else + modmsg += " - Playing" + + if(C.is_afk()) + var/seconds = C.last_activity_seconds() + modmsg += " (AFK - " + modmsg += "[round(seconds / 60)] minutes, " + modmsg += "[seconds % 60] seconds)" + modmsg += "\n" + num_mods_online++ + + else if(R_SERVER & C.holder.rights) + devmsg += "\t[C] is a [C.holder.rank]" + if(isobserver(C.mob)) + devmsg += " - Observing" + else if(istype(C.mob,/mob/new_player)) + devmsg += " - Lobby" + else + devmsg += " - Playing" + + if(C.is_afk()) + var/seconds = C.last_activity_seconds() + devmsg += "(AFK - " + devmsg += "[round(seconds / 60)] minutes, " + devmsg += "[seconds % 60] seconds)" + devmsg += "\n" + num_devs_online++ + + else if(R_EVENT & C.holder.rights) + eventMmsg += "\t[C] is a [C.holder.rank]" + if(isobserver(C.mob)) + eventMmsg += " - Observing" + else if(istype(C.mob,/mob/new_player)) + eventMmsg += " - Lobby" + else + eventMmsg += " - Playing" + + if(C.is_afk()) + var/seconds = C.last_activity_seconds() + eventMmsg += " (AFK - " + eventMmsg += "[round(seconds / 60)] minutes, " + eventMmsg += "[seconds % 60] seconds)" + eventMmsg += "\n" + num_event_managers_online++ + + else + for(var/client/C in admins) + if(R_ADMIN & C.holder.rights || (!R_MOD & C.holder.rights && !R_EVENT & C.holder.rights)) + if(!C.holder.fakekey) + msg += "\t[C] is a [C.holder.rank]\n" + num_admins_online++ + else if (R_MOD & C.holder.rights) + modmsg += "\t[C] is a [C.holder.rank]\n" + num_mods_online++ + else if (R_SERVER & C.holder.rights) + devmsg += "\t[C] is a [C.holder.rank]\n" + num_devs_online++ + else if (R_EVENT & C.holder.rights) + eventMmsg += "\t[C] is a [C.holder.rank]\n" + num_event_managers_online++ + + if(config.admin_irc) + to_chat(src, "Adminhelps are also sent to IRC. If no admins are available in game try anyway and an admin on IRC may see it and respond.") + msg = "Current Admins ([num_admins_online]):\n" + msg + + if(config.show_mods) + msg += "\n Current Moderators ([num_mods_online]):\n" + modmsg + + if(config.show_devs) + msg += "\n Current Developers ([num_devs_online]):\n" + devmsg + + if(config.show_event_managers) + msg += "\n Current Event Managers ([num_event_managers_online]):\n" + eventMmsg + + to_chat(src,msg) +>>>>>>> ebc5263... Merge pull request #7920 from Atermonera/ping_verb_fix:code/modules/client/verbs/who.dm diff --git a/code/modules/client/verbs/ping.dm b/code/modules/client/verbs/ping.dm new file mode 100644 index 00000000000..8213daa7505 --- /dev/null +++ b/code/modules/client/verbs/ping.dm @@ -0,0 +1,12 @@ +/client/proc/pingfromtime(time) + return ((world.time+world.tick_lag*world.tick_usage/100)-time)*100 + +/client/verb/display_ping(time as num) + set instant = TRUE + set name = ".display_ping" + to_chat(src, "Round trip ping took [round(pingfromtime(time),1)]ms") + +/client/verb/ping() + set name = "Ping" + set category = "OOC" + winset(src, null, "command=.display_ping+[world.time+world.tick_lag*world.tick_usage/100]") \ No newline at end of file From 0adc1f2d112724be0a74bf759ef79795bd8125a5 Mon Sep 17 00:00:00 2001 From: Schnayy Date: Fri, 26 Feb 2021 09:09:56 -0600 Subject: [PATCH 08/20] Properly cleared ORGAN_CUT_AWAY for prosthetics. --- .../carbon/human/human_modular_limbs.dm | 196 ++++++++++++++++++ code/modules/surgery/limb_reattach.dm | 7 + 2 files changed, 203 insertions(+) create mode 100644 code/modules/mob/living/carbon/human/human_modular_limbs.dm diff --git a/code/modules/mob/living/carbon/human/human_modular_limbs.dm b/code/modules/mob/living/carbon/human/human_modular_limbs.dm new file mode 100644 index 00000000000..471e8a42cd8 --- /dev/null +++ b/code/modules/mob/living/carbon/human/human_modular_limbs.dm @@ -0,0 +1,196 @@ +/* + A system for easily and quickly removing your own bodyparts, with a view towards + swapping them out for new ones, or just doing it as a party trick to horrify an + audience. Current implementation only supports robolimbs and uses a modular_bodypart + value on the manufacturer datum, but I have tried to keep it generic for future work. + PS. jesus christ this was meant to be a half an hour port +*/ + +// External organ procs: +// Does this bodypart count as a modular limb, and if so, what kind? +/obj/item/organ/external/proc/get_modular_limb_category() + . = MODULAR_BODYPART_INVALID + if(robotic >= ORGAN_ROBOT && model) + var/datum/robolimb/manufacturer = all_robolimbs[model] + if(!isnull(manufacturer?.modular_bodyparts)) + . = manufacturer.modular_bodyparts + +// Checks if a limb could theoretically be removed. +// Note that this does not currently bother checking if a child or internal organ is vital. +/obj/item/organ/external/proc/can_remove_modular_limb(var/mob/living/carbon/human/user) + if(vital || cannot_amputate) + return FALSE + var/bodypart_cat = get_modular_limb_category() + if(bodypart_cat == MODULAR_BODYPART_CYBERNETIC) + if(!parent_organ) + return FALSE + var/obj/item/organ/external/parent = user?.get_organ(parent_organ) + if(!parent || parent.get_modular_limb_category(user) < MODULAR_BODYPART_CYBERNETIC) + return FALSE + . = (bodypart_cat != MODULAR_BODYPART_INVALID) + +// Note that this proc is checking if the organ can be attached -to-, not attached itself. +/obj/item/organ/external/proc/can_attach_modular_limb_here(var/mob/living/carbon/human/user) + var/list/limb_data = user?.species?.has_limbs[organ_tag] + if(islist(limb_data) && limb_data["has_children"] > 0) + . = (length(children) < limb_data["has_children"]) + +/obj/item/organ/external/proc/can_be_attached_modular_limb(var/mob/living/carbon/user) + var/bodypart_cat = get_modular_limb_category() + if(bodypart_cat == MODULAR_BODYPART_INVALID) + return FALSE + if(!parent_organ) + return FALSE + var/obj/item/organ/external/parent = user?.get_organ(parent_organ) + if(!parent) + return FALSE + if(!parent.can_attach_modular_limb_here(user)) + return FALSE + if(bodypart_cat == MODULAR_BODYPART_CYBERNETIC && parent.get_modular_limb_category(src) < MODULAR_BODYPART_CYBERNETIC) + return FALSE + return TRUE + +// Checks if an organ (or the parent of one) is in a fit state for modular limb stuff to happen. +/obj/item/organ/external/proc/check_modular_limb_damage(var/mob/living/carbon/human/user) + . = damage >= min_broken_damage || (status & ORGAN_BROKEN) || is_stump() // can't use is_broken() as the limb has ORGAN_CUT_AWAY + +// Human mob procs: +// Checks the organ list for limbs meeting a predicate. Way overengineered for such a limited use +// case but I can see it being expanded in the future if meat limbs or doona limbs use it. +/mob/living/carbon/human/proc/get_modular_limbs(var/return_first_found = FALSE, var/validate_proc) + for(var/bp in organs) + var/obj/item/organ/external/E = bp + if(!validate_proc || call(E, validate_proc)(src) > MODULAR_BODYPART_INVALID) + LAZYADD(., E) + if(return_first_found) + return + // Prune children so we can't remove every individual component of an entire prosthetic arm + // piece by piece. Technically a circular dependency here would remove the limb entirely but + // if there's a parent whose child is also its parent, there's something wrong regardless. + for(var/bp in .) + var/obj/item/organ/external/E = bp + if(length(E.children)) + . -= E.children + +// Called in robotize(), replaced() and removed() to update our modular limb verbs. +/mob/living/carbon/human/proc/refresh_modular_limb_verbs() + if(length(get_modular_limbs(return_first_found = TRUE, validate_proc = /obj/item/organ/external/proc/can_attach_modular_limb_here))) + verbs |= .proc/attach_limb_verb + else + verbs -= .proc/attach_limb_verb + if(length(get_modular_limbs(return_first_found = TRUE, validate_proc = /obj/item/organ/external/proc/can_remove_modular_limb))) + verbs |= .proc/detach_limb_verb + else + verbs -= .proc/detach_limb_verb + +// Proc helper for attachment verb. +/mob/living/carbon/human/proc/check_can_attach_modular_limb(var/obj/item/organ/external/E) + if(world.time < last_special + (2 SECONDS) || get_active_hand() != E) + return FALSE + if(incapacitated() || restrained()) + to_chat(src, SPAN_WARNING("You can't do that in your current state!")) + return FALSE + if(QDELETED(E) || !istype(E)) + to_chat(src, SPAN_WARNING("You are not holding a compatible limb to attach.")) + return FALSE + if(!E.can_be_attached_modular_limb(src)) + to_chat(src, SPAN_WARNING("\The [E] cannot be attached to your current body.")) + return FALSE + if(E.get_modular_limb_category() <= MODULAR_BODYPART_INVALID) + to_chat(src, SPAN_WARNING("\The [E] cannot be attached by your own hand.")) + return FALSE + var/install_to_zone = E.organ_tag + if(!isnull(get_organ(install_to_zone))) + to_chat(src, SPAN_WARNING("There is already a limb attached at that part of your body.")) + return FALSE + if(E.check_modular_limb_damage(src)) + to_chat(src, SPAN_WARNING("\The [E] is too damaged to be attached.")) + return FALSE + var/obj/item/organ/external/parent = E.parent_organ && get_organ(E.parent_organ) + if(!parent) + to_chat(src, SPAN_WARNING("\The [E] needs an existing limb to be attached to.")) + return FALSE + if(parent.check_modular_limb_damage(src)) + to_chat(src, SPAN_WARNING("Your [parent.name] is too damaged to have anything attached.")) + return FALSE + return TRUE + +// Proc helper for detachment verb. +/mob/living/carbon/human/proc/check_can_detach_modular_limb(var/obj/item/organ/external/E) + if(world.time < last_special + (2 SECONDS)) + return FALSE + if(incapacitated() || restrained()) + to_chat(src, SPAN_WARNING("You can't do that in your current state!")) + return FALSE + if(!istype(E) || QDELETED(src) || QDELETED(E) || E.owner != src || E.loc != src) + return FALSE + if(E.check_modular_limb_damage(src)) + to_chat(src, SPAN_WARNING("That limb is too damaged to be removed!")) + return FALSE + var/obj/item/organ/external/parent = E.parent_organ && get_organ(E.parent_organ) + if(!parent) + return FALSE + if(parent.check_modular_limb_damage(src)) + to_chat(src, SPAN_WARNING("Your [parent.name] is too damaged to detach anything from it.")) + return FALSE + return (E in get_modular_limbs(return_first_found = FALSE, validate_proc = /obj/item/organ/external/proc/can_remove_modular_limb)) + +// Verbs below: +// Add or remove robotic limbs; check refresh_modular_limb_verbs() above. +/mob/living/carbon/human/proc/attach_limb_verb() + set name = "Attach Limb" + set category = "Object" + set desc = "Attach a replacement limb." + set usr = src + + var/obj/item/organ/external/E = get_active_hand() + if(!check_can_attach_modular_limb(E)) + return FALSE + if(!do_after(src, 2 SECONDS, src)) + return FALSE + if(!check_can_attach_modular_limb(E)) + return FALSE + + last_special = world.time + drop_from_inventory(E) + E.replaced(src) + + // Reconnect the organ and children as normally this is done with surgery. + E.status &= ~ORGAN_CUT_AWAY + for(var/obj/item/organ/external/child in E.children) + child.status &= ~ORGAN_CUT_AWAY + + var/datum/gender/G = gender_datums[gender] + visible_message( + SPAN_NOTICE("\The [src] attaches \the [E] to [G.his] body!"), + SPAN_NOTICE("You attach \the [E] to your body!")) + regenerate_icons() // Not sure why this isn't called by removed(), but without it we don't update our limb appearance. + return TRUE + +/mob/living/carbon/human/proc/detach_limb_verb() + set name = "Remove Limb" + set category = "Object" + set desc = "Detach one of your limbs." + set usr = src + + var/list/detachable_limbs = get_modular_limbs(return_first_found = FALSE, validate_proc = /obj/item/organ/external/proc/can_remove_modular_limb) + if(!length(detachable_limbs)) + to_chat(src, SPAN_WARNING("You have no detachable limbs.")) + return FALSE + var/obj/item/organ/external/E = input(usr, "Which limb do you wish to detach?", "Limb Removal") as null|anything in detachable_limbs + if(!check_can_detach_modular_limb(E)) + return FALSE + if(!do_after(src, 2 SECONDS, src)) + return FALSE + if(!check_can_detach_modular_limb(E)) + return FALSE + + last_special = world.time + E.removed(src) + E.dropInto(loc) + put_in_hands(E) + var/datum/gender/G = gender_datums[gender] + visible_message( + SPAN_NOTICE("\The [src] detaches [G.his] [E.name]!"), + SPAN_NOTICE("You detach your [E.name]!")) + return TRUE diff --git a/code/modules/surgery/limb_reattach.dm b/code/modules/surgery/limb_reattach.dm index 9ed0ce520da..ecbf1917418 100644 --- a/code/modules/surgery/limb_reattach.dm +++ b/code/modules/surgery/limb_reattach.dm @@ -59,6 +59,13 @@ "You have attached [target]'s [E.name] to the [E.amputation_point].") user.drop_from_inventory(E) E.replaced(target) + + // Modular bodyparts (like prosthetics) do not need to be reconnected. + if(E.get_modular_limb_category() != MODULAR_BODYPART_INVALID) + E.status &= ~ORGAN_CUT_AWAY + for(var/obj/item/organ/external/child in E.children) + child.status &= ~ORGAN_CUT_AWAY + target.update_icons_body(FALSE) target.updatehealth() target.UpdateDamageIcon() From 4ac86b68c9a2648a14c8577dbf9e2370ecae7d50 Mon Sep 17 00:00:00 2001 From: Novacat <35587478+Novacat@users.noreply.github.com> Date: Fri, 26 Feb 2021 10:16:41 -0500 Subject: [PATCH 09/20] Update subsystems.dm --- code/__defines/subsystems.dm | 3 --- 1 file changed, 3 deletions(-) diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index 0f927bb4946..d0a5d72c86f 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -57,10 +57,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define INIT_ORDER_SKYBOX 30 #define INIT_ORDER_MAPPING 25 #define INIT_ORDER_DECALS 20 -<<<<<<< HEAD #define INIT_ORDER_PLANTS 18 // Must initialize before atoms. -======= ->>>>>>> ebc5263... Merge pull request #7920 from Atermonera/ping_verb_fix #define INIT_ORDER_JOB 17 #define INIT_ORDER_ALARM 16 // Must initialize before atoms. #define INIT_ORDER_ATOMS 15 From a454e11d25188956a10ace4a3ae8e9e64e13ad33 Mon Sep 17 00:00:00 2001 From: Novacat <35587478+Novacat@users.noreply.github.com> Date: Fri, 26 Feb 2021 10:17:31 -0500 Subject: [PATCH 10/20] Update advanced_who.dm --- code/game/verbs/advanced_who.dm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/code/game/verbs/advanced_who.dm b/code/game/verbs/advanced_who.dm index 221939cd50c..8cbf3b638e5 100644 --- a/code/game/verbs/advanced_who.dm +++ b/code/game/verbs/advanced_who.dm @@ -85,10 +85,7 @@ entry += " - In Lobby
" else entry += " - Playing
" -<<<<<<< HEAD:code/game/verbs/advanced_who.dm -======= ->>>>>>> ebc5263... Merge pull request #7920 from Atermonera/ping_verb_fix:code/modules/client/verbs/advanced_who.dm Lines += entry msg += "
" @@ -97,4 +94,4 @@ msg += "
" msg += "Total Players: [length(Lines)]" msg = "" + msg + "" - to_chat(src, msg) \ No newline at end of file + to_chat(src, msg) From e9431e756767f9463b89f0e7c097524721798e2d Mon Sep 17 00:00:00 2001 From: Heroman Date: Mon, 1 Mar 2021 03:52:49 +1000 Subject: [PATCH 11/20] Fixes prommies still having trashcan var on by default --- .../mob/living/carbon/human/species/station/prometheans_vr.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm b/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm index 4e7ac9376c3..f2b233cccf5 100644 --- a/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm +++ b/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm @@ -19,7 +19,6 @@ color_mult = 1 mob_size = MOB_MEDIUM //As of writing, original was MOB_SMALL - Allows normal swapping - trashcan = 1 //They have goopy bodies. They can just dissolve things within them. appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR | HAS_HAIR_COLOR | RADIATION_GLOWS | HAS_UNDERWEAR From 6d063e1dd2f75b254ad55ca0979a2a1379e1b103 Mon Sep 17 00:00:00 2001 From: rboys2 <69563414+rboys2@users.noreply.github.com> Date: Sun, 28 Feb 2021 13:38:05 -0500 Subject: [PATCH 12/20] Apply suggestions from code review Co-authored-by: TheFurryFeline <38586851+TheFurryFeline@users.noreply.github.com> --- code/modules/vore/appearance/sprite_accessories_vr.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/vore/appearance/sprite_accessories_vr.dm b/code/modules/vore/appearance/sprite_accessories_vr.dm index 7fbf2662b7e..57bf85b2631 100644 --- a/code/modules/vore/appearance/sprite_accessories_vr.dm +++ b/code/modules/vore/appearance/sprite_accessories_vr.dm @@ -1,4 +1,4 @@ -ing /* +/* Hello and welcome to VOREStation sprite_accessories: For a more general overview please read sprite_accessories.dm. This file is for ears and tails. This is intended to be friendly for people with little to no actual coding experience. From 85485c41c4a96ebaef81a5a6dee9f2a7c0e632fe Mon Sep 17 00:00:00 2001 From: Novacat <35587478+Novacat@users.noreply.github.com> Date: Sun, 28 Feb 2021 17:40:21 -0500 Subject: [PATCH 13/20] Update emote.dm --- code/modules/mob/emote.dm | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index a8b94d602a4..2a8af560804 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -37,20 +37,15 @@ var/mob/M = mob spawn(0) // It's possible that it could be deleted in the meantime, or that it runtimes. if(M) -<<<<<<< HEAD - //VOREStation edit - if(istype(M, /mob/observer/dead/)) + if(isobserver(M)) + //VOREStation Edit Start var/mob/observer/dead/D = M if(ckey || (src in view(D))) M.show_message(message, m_type) + message = "[src] ([ghost_follow_link(src, M)]) [input]" else M.show_message(message, m_type) - //End VOREStation edit -======= - if(isobserver(M)) - message = "[src] ([ghost_follow_link(src, M)]) [input]" - M.show_message(message, m_type) ->>>>>>> 47c1641... Merge pull request #7796 from Atermonera/ghost_emote + //VOREStation Edit End for(var/obj in o_viewers) var/obj/O = obj From edf7931df1046174e14748c37345468f6050746e Mon Sep 17 00:00:00 2001 From: Novacat <35587478+Novacat@users.noreply.github.com> Date: Sun, 28 Feb 2021 17:50:11 -0500 Subject: [PATCH 14/20] Update who.dm --- code/game/verbs/who.dm | 193 +---------------------------------------- 1 file changed, 1 insertion(+), 192 deletions(-) diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm index 5c6f1e15452..385a3230200 100644 --- a/code/game/verbs/who.dm +++ b/code/game/verbs/who.dm @@ -1,5 +1,3 @@ -<<<<<<< HEAD:code/game/verbs/who.dm - /client/verb/who() set name = "Who" set category = "OOC" @@ -207,193 +205,4 @@ msg += "\nAdminhelps are also sent to Discord. If no admins are available in game try anyway and an admin on Discord may see it and respond." return msg -======= - -/client/verb/who() - set name = "Who" - set category = "OOC" - - var/msg = "Current Players:\n" - - var/list/Lines = list() - - if(holder && (R_ADMIN & holder.rights || R_MOD & holder.rights)) - for(var/client/C in GLOB.clients) - var/entry = "\t[C.key]" - if(C.holder && C.holder.fakekey) - entry += " (as [C.holder.fakekey])" - entry += " - Playing as [C.mob.real_name]" - switch(C.mob.stat) - if(UNCONSCIOUS) - entry += " - Unconscious" - if(DEAD) - if(isobserver(C.mob)) - var/mob/observer/dead/O = C.mob - if(O.started_as_observer) - entry += " - Observing" - else - entry += " - DEAD" - else - entry += " - DEAD" - - var/age - if(isnum(C.player_age)) - age = C.player_age - else - age = 0 - - if(age <= 1) - age = "[age]" - else if(age < 10) - age = "[age]" - - entry += " - [age]" - - if(is_special_character(C.mob)) - entry += " - Antagonist" - - if(C.is_afk()) - var/seconds = C.last_activity_seconds() - entry += " (AFK - " - entry += "[round(seconds / 60)] minutes, " - entry += "[seconds % 60] seconds)" - - entry += " (?)" - Lines += entry - else - for(var/client/C in GLOB.clients) - var/entry - if(C.holder && C.holder.fakekey) - entry = C.holder.fakekey - else - entry = C.key - Lines += entry - - for(var/line in sortList(Lines)) - msg += "[line]\n" - - msg += "Total Players: [length(Lines)]" - to_chat(src,msg) - -/client/verb/staffwho() - set category = "Admin" - set name = "Staffwho" - - var/msg = "" - var/modmsg = "" - var/devmsg = "" - var/eventMmsg = "" - var/num_mods_online = 0 - var/num_admins_online = 0 - var/num_devs_online = 0 - var/num_event_managers_online = 0 - if(holder) - for(var/client/C in admins) - if(R_ADMIN & C.holder.rights || (!R_MOD & C.holder.rights && !R_EVENT & C.holder.rights)) //Used to determine who shows up in admin rows - - if(C.holder.fakekey && (!R_ADMIN & holder.rights && !R_MOD & holder.rights)) //Event Managerss can't see stealthmins - continue - - msg += "\t[C] is a [C.holder.rank]" - - if(C.holder.fakekey) - msg += " (as [C.holder.fakekey])" - - if(isobserver(C.mob)) - msg += " - Observing" - else if(istype(C.mob,/mob/new_player)) - msg += " - Lobby" - else - msg += " - Playing" - - if(C.is_afk()) - var/seconds = C.last_activity_seconds() - msg += " (AFK - " - msg += "[round(seconds / 60)] minutes, " - msg += "[seconds % 60] seconds)" - msg += "\n" - - num_admins_online++ - else if(R_MOD & C.holder.rights) //Who shows up in mod rows. - modmsg += "\t[C] is a [C.holder.rank]" - - if(isobserver(C.mob)) - modmsg += " - Observing" - else if(istype(C.mob,/mob/new_player)) - modmsg += " - Lobby" - else - modmsg += " - Playing" - - if(C.is_afk()) - var/seconds = C.last_activity_seconds() - modmsg += " (AFK - " - modmsg += "[round(seconds / 60)] minutes, " - modmsg += "[seconds % 60] seconds)" - modmsg += "\n" - num_mods_online++ - - else if(R_SERVER & C.holder.rights) - devmsg += "\t[C] is a [C.holder.rank]" - if(isobserver(C.mob)) - devmsg += " - Observing" - else if(istype(C.mob,/mob/new_player)) - devmsg += " - Lobby" - else - devmsg += " - Playing" - - if(C.is_afk()) - var/seconds = C.last_activity_seconds() - devmsg += "(AFK - " - devmsg += "[round(seconds / 60)] minutes, " - devmsg += "[seconds % 60] seconds)" - devmsg += "\n" - num_devs_online++ - - else if(R_EVENT & C.holder.rights) - eventMmsg += "\t[C] is a [C.holder.rank]" - if(isobserver(C.mob)) - eventMmsg += " - Observing" - else if(istype(C.mob,/mob/new_player)) - eventMmsg += " - Lobby" - else - eventMmsg += " - Playing" - - if(C.is_afk()) - var/seconds = C.last_activity_seconds() - eventMmsg += " (AFK - " - eventMmsg += "[round(seconds / 60)] minutes, " - eventMmsg += "[seconds % 60] seconds)" - eventMmsg += "\n" - num_event_managers_online++ - - else - for(var/client/C in admins) - if(R_ADMIN & C.holder.rights || (!R_MOD & C.holder.rights && !R_EVENT & C.holder.rights)) - if(!C.holder.fakekey) - msg += "\t[C] is a [C.holder.rank]\n" - num_admins_online++ - else if (R_MOD & C.holder.rights) - modmsg += "\t[C] is a [C.holder.rank]\n" - num_mods_online++ - else if (R_SERVER & C.holder.rights) - devmsg += "\t[C] is a [C.holder.rank]\n" - num_devs_online++ - else if (R_EVENT & C.holder.rights) - eventMmsg += "\t[C] is a [C.holder.rank]\n" - num_event_managers_online++ - - if(config.admin_irc) - to_chat(src, "Adminhelps are also sent to IRC. If no admins are available in game try anyway and an admin on IRC may see it and respond.") - msg = "Current Admins ([num_admins_online]):\n" + msg - - if(config.show_mods) - msg += "\n Current Moderators ([num_mods_online]):\n" + modmsg - - if(config.show_devs) - msg += "\n Current Developers ([num_devs_online]):\n" + devmsg - - if(config.show_event_managers) - msg += "\n Current Event Managers ([num_event_managers_online]):\n" + eventMmsg - - to_chat(src,msg) ->>>>>>> ebc5263... Merge pull request #7920 from Atermonera/ping_verb_fix:code/modules/client/verbs/who.dm + From d7c949c0103d6b500c573e355d401b463f27e84b Mon Sep 17 00:00:00 2001 From: Novacat <35587478+Novacat@users.noreply.github.com> Date: Sun, 28 Feb 2021 17:55:45 -0500 Subject: [PATCH 15/20] Update robolimbs.dm --- code/modules/organs/robolimbs.dm | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm index 5a769091895..fc86dda3f89 100644 --- a/code/modules/organs/robolimbs.dm +++ b/code/modules/organs/robolimbs.dm @@ -47,24 +47,6 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ var/icon = 'icons/mob/human_races/robotic.dmi' // Icon base to draw from. var/monitor_icon = 'icons/mob/monitor_icons.dmi' // Where it draws the monitor icon from. var/unavailable_at_chargen // If set, not available at chargen. -<<<<<<< HEAD - var/unavailable_to_build // If set, can't be constructed. - var/lifelike // If set, appears organic. - var/skin_tone // If set, applies skin tone rather than part color Overrides color. - var/skin_color // If set, applies skin color rather than part color. - var/blood_color = "#030303" - var/blood_name = "oil" - var/list/species_cannot_use = list(SPECIES_TESHARI, SPECIES_PROMETHEAN, SPECIES_DIONA, SPECIES_XENOCHIMERA) //VOREStation Edit - var/list/species_alternates = list(SPECIES_TAJ = "Unbranded - Tajaran", SPECIES_UNATHI = "Unbranded - Unathi") //"Species Name" = "Robolimb Company" , List, when initialized, will become "Species Name" = RobolimbDatum, used for alternate species sprites. - var/list/monitor_styles //If empty, the model of limbs offers a head compatible with monitors. - var/parts = BP_ALL //Defines what parts said brand can replace on a body. - var/health_hud_intensity = 1 // Intensity modifier for the health GUI indicator. - var/suggested_species = "Human" //If it should make the torso a species - var/speech_bubble_appearance = "synthetic" // What icon_state to use for speech bubbles when talking. Check talk.dmi for all the icons. - - var/robo_brute_mod = 1 // Multiplier for incoming brute damage. - var/robo_burn_mod = 1 // As above for burn. -======= var/unavailable_to_build // If set, can't be constructed. var/lifelike // If set, appears organic. var/skin_tone // If set, applies skin tone rather than part color Overrides color. @@ -80,10 +62,9 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ var/robo_brute_mod = 1 // Multiplier for incoming brute damage. var/robo_burn_mod = 1 // As above for burn. // Species in this list cannot take these prosthetics. - var/list/species_cannot_use = list(SPECIES_TESHARI, SPECIES_PROMETHEAN, SPECIES_DIONA) + var/list/species_cannot_use = list(SPECIES_TESHARI, SPECIES_PROMETHEAN, SPECIES_DIONA, SPECIES_XENOCHIMERA) //VOREStation Edit // "Species Name" = "Robolimb Company", List, when initialized, will become "Species Name" = RobolimbDatum, used for alternate species sprites. var/list/species_alternates = list(SPECIES_TAJ = "Unbranded - Tajaran", SPECIES_UNATHI = "Unbranded - Unathi") ->>>>>>> c31a3e7... Merge pull request #7905 from MistakeNot4892/beepboop /datum/robolimb/unbranded_monitor company = "Unbranded Monitor" From d2d9f65a031d55f25bec6ff67320972ef85ef563 Mon Sep 17 00:00:00 2001 From: Novacat <35587478+Novacat@users.noreply.github.com> Date: Sun, 28 Feb 2021 17:57:38 -0500 Subject: [PATCH 16/20] Update vorestation.dme --- vorestation.dme | 3 --- 1 file changed, 3 deletions(-) diff --git a/vorestation.dme b/vorestation.dme index 1b774914668..1b3d495826a 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2587,11 +2587,8 @@ #include "code\modules\mob\living\carbon\human\human_defines.dm" #include "code\modules\mob\living\carbon\human\human_defines_vr.dm" #include "code\modules\mob\living\carbon\human\human_helpers.dm" -<<<<<<< HEAD:vorestation.dme #include "code\modules\mob\living\carbon\human\human_helpers_vr.dm" -======= #include "code\modules\mob\living\carbon\human\human_modular_limbs.dm" ->>>>>>> c31a3e7... Merge pull request #7905 from MistakeNot4892/beepboop:polaris.dme #include "code\modules\mob\living\carbon\human\human_movement.dm" #include "code\modules\mob\living\carbon\human\human_organs.dm" #include "code\modules\mob\living\carbon\human\human_powers.dm" From f5ade3682cf4dd3b611d0daeae973629c35995ac Mon Sep 17 00:00:00 2001 From: Mechoid Date: Sun, 28 Feb 2021 15:02:12 -0800 Subject: [PATCH 17/20] Adds the Restraining Bolt. --- code/_onclick/cyborg.dm | 37 ++++++++--- code/datums/supplypacks/robotics.dm | 11 ++++ code/game/machinery/doors/airlock.dm | 4 +- .../items/weapons/implants/implantcase.dm | 10 +++ .../items/weapons/implants/implanter.dm | 9 +++ .../implants/implantrestrainingbolt.dm | 5 ++ .../mob/living/carbon/human/human_helpers.dm | 14 +++++ code/modules/mob/living/living.dm | 8 +++ .../modules/mob/living/silicon/robot/robot.dm | 63 +++++++++++++++++++ .../living/silicon/robot/robot_movement.dm | 3 + code/modules/organs/internal/augment.dm | 4 ++ .../organs/internal/augment/armmounted.dm | 2 +- vorestation.dme | 4 ++ 13 files changed, 164 insertions(+), 10 deletions(-) create mode 100644 code/game/objects/items/weapons/implants/implantrestrainingbolt.dm diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index d63d49e8d76..213fe57b90e 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -60,6 +60,8 @@ // Cyborgs have no range-checking unless there is item use if(!W) + if(bolt && !bolt.malfunction && A.loc != module) + return A.add_hiddenprint(src) A.attack_robot(src) return @@ -120,35 +122,56 @@ /atom/proc/BorgCtrlShiftClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden CtrlShiftClick(user) -/obj/machinery/door/airlock/BorgCtrlShiftClick(mob/user) +/obj/machinery/door/airlock/BorgCtrlShiftClick(var/mob/living/silicon/robot/user) + if(user.bolt && !user.bolt.malfunction) + return + AICtrlShiftClick(user) /atom/proc/BorgShiftClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden ShiftClick(user) -/obj/machinery/door/airlock/BorgShiftClick(mob/user) // Opens and closes doors! Forwards to AI code. +/obj/machinery/door/airlock/BorgShiftClick(var/mob/living/silicon/robot/user) // Opens and closes doors! Forwards to AI code. + if(user.bolt && !user.bolt.malfunction) + return + AIShiftClick(user) /atom/proc/BorgCtrlClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden CtrlClick(user) -/obj/machinery/door/airlock/BorgCtrlClick(mob/user) // Bolts doors. Forwards to AI code. +/obj/machinery/door/airlock/BorgCtrlClick(var/mob/living/silicon/robot/user) // Bolts doors. Forwards to AI code. + if(user.bolt && !user.bolt.malfunction) + return + AICtrlClick(user) -/obj/machinery/power/apc/BorgCtrlClick(mob/user) // turns off/on APCs. Forwards to AI code. +/obj/machinery/power/apc/BorgCtrlClick(var/mob/living/silicon/robot/user) // turns off/on APCs. Forwards to AI code. + if(user.bolt && !user.bolt.malfunction) + return + AICtrlClick(user) -/obj/machinery/turretid/BorgCtrlClick(mob/user) //turret control on/off. Forwards to AI code. +/obj/machinery/turretid/BorgCtrlClick(var/mob/living/silicon/robot/user) //turret control on/off. Forwards to AI code. + if(user.bolt && !user.bolt.malfunction) + return + AICtrlClick(user) /atom/proc/BorgAltClick(var/mob/living/silicon/robot/user) AltClick(user) return -/obj/machinery/door/airlock/BorgAltClick(mob/user) // Eletrifies doors. Forwards to AI code. +/obj/machinery/door/airlock/BorgAltClick(var/mob/living/silicon/robot/user) // Eletrifies doors. Forwards to AI code. + if(user.bolt && !user.bolt.malfunction) + return + AIAltClick(user) -/obj/machinery/turretid/BorgAltClick(mob/user) //turret lethal on/off. Forwards to AI code. +/obj/machinery/turretid/BorgAltClick(var/mob/living/silicon/robot/user) //turret lethal on/off. Forwards to AI code. + if(user.bolt && !user.bolt.malfunction) + return + AIAltClick(user) /* diff --git a/code/datums/supplypacks/robotics.dm b/code/datums/supplypacks/robotics.dm index 5f8cf6337c8..1928ee7db68 100644 --- a/code/datums/supplypacks/robotics.dm +++ b/code/datums/supplypacks/robotics.dm @@ -189,6 +189,17 @@ containername = "Jumper kit crate" access = access_robotics +/datum/supply_pack/robotics/restrainingbolt + name = "Restraining bolt crate" + contains = list( + /obj/item/weapon/implanter = 1, + /obj/item/weapon/implantcase/restrainingbolt = 2 + ) + cost = 40 + containertype = /obj/structure/closet/crate/secure/cybersolutions + containername = "Restraining bolt crate" + access = access_robotics + /datum/supply_pack/robotics/bike name = "Spacebike Crate" contains = list() diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 014efcb5813..39d54ef96d5 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -862,14 +862,14 @@ About the new airlock wires panel: /obj/machinery/door/airlock/tgui_data(mob/user) var/list/data = list() - + var/list/power = list() power["main"] = main_power_lost_until > 0 ? 0 : 2 power["main_timeleft"] = round(main_power_lost_until > 0 ? max(main_power_lost_until - world.time, 0) / 10 : main_power_lost_until, 1) power["backup"] = backup_power_lost_until > 0 ? 0 : 2 power["backup_timeleft"] = round(backup_power_lost_until > 0 ? max(backup_power_lost_until - world.time, 0) / 10 : backup_power_lost_until, 1) data["power"] = power - + data["shock"] = (electrified_until == 0) ? 2 : 0 data["shock_timeleft"] = round(electrified_until > 0 ? max(electrified_until - world.time, 0) / 10 : electrified_until, 1) data["id_scanner"] = !aiDisabledIdScanner diff --git a/code/game/objects/items/weapons/implants/implantcase.dm b/code/game/objects/items/weapons/implants/implantcase.dm index c4040890283..9162be15eb5 100644 --- a/code/game/objects/items/weapons/implants/implantcase.dm +++ b/code/game/objects/items/weapons/implants/implantcase.dm @@ -299,3 +299,13 @@ src.imp = new /obj/item/weapon/implant/organ/limbaugment/wrist/blade( src ) ..() return + +/obj/item/weapon/implantcase/restrainingbolt + name = "glass case - 'Restraining Bolt'" + desc = "A case containing a restraining bolt." + icon_state = "implantcase-b" + +/obj/item/weapon/implantcase/restrainingbolt/New() + src.imp = new /obj/item/weapon/implant/restrainingbolt( src ) + ..() + return diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm index c1b0d5db8dd..adb79364dcd 100644 --- a/code/game/objects/items/weapons/implants/implanter.dm +++ b/code/game/objects/items/weapons/implants/implanter.dm @@ -150,3 +150,12 @@ S.remove_from_storage(A) A.loc.contents.Remove(A) update() + +/obj/item/weapon/implanter/restrainingbolt + name = "implanter (bolt)" + +/obj/item/weapon/implanter/restrainingbolt/New() + src.imp = new /obj/item/weapon/implant/restrainingbolt( src ) + ..() + update() + return diff --git a/code/game/objects/items/weapons/implants/implantrestrainingbolt.dm b/code/game/objects/items/weapons/implants/implantrestrainingbolt.dm new file mode 100644 index 00000000000..7f4a562297c --- /dev/null +++ b/code/game/objects/items/weapons/implants/implantrestrainingbolt.dm @@ -0,0 +1,5 @@ + +/obj/item/weapon/implant/restrainingbolt + name = "\improper restraining bolt" + icon = 'icons/obj/device.dmi' + icon_state = "implant" diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 7494867d2d8..435ca993546 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -208,6 +208,20 @@ plane_holder.set_vis(vis,FALSE) vis_enabled -= vis +/mob/living/carbon/human/get_restraining_bolt() + var/obj/item/weapon/implant/restrainingbolt/RB + + for(var/obj/item/organ/external/EX in organs) + RB = locate() in EX + if(istype(RB) && !(RB.malfunction)) + break + + if(RB) + if(!RB.malfunction) + return TRUE + + return FALSE + #undef HUMAN_EATING_NO_ISSUE #undef HUMAN_EATING_NO_MOUTH #undef HUMAN_EATING_BLOCKED_MOUTH diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 5c56b8a4482..7debf735b1c 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -700,6 +700,14 @@ /mob/living/proc/has_eyes() return 1 +/mob/living/proc/get_restraining_bolt() + var/obj/item/weapon/implant/restrainingbolt/RB = locate() in src + if(RB) + if(!RB.malfunction) + return TRUE + + return FALSE + /mob/living/proc/slip(var/slipped_on,stun_duration=8) return 0 diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 7d67ca3cc32..849696ea4c5 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -91,6 +91,8 @@ var/tracking_entities = 0 //The number of known entities currently accessing the internal camera var/braintype = "Cyborg" + var/obj/item/weapon/implant/restrainingbolt/bolt // The restraining bolt installed into the cyborg. + var/list/robot_verbs_default = list( /mob/living/silicon/robot/proc/sensor_mode, /mob/living/silicon/robot/proc/robot_checklaws @@ -481,6 +483,20 @@ return + if(istype(W, /obj/item/weapon/implant/restrainingbolt) && !cell) + if(bolt) + to_chat(user, "There is already a restraining bolt installed in this cyborg.") + return + + else + user.drop_from_inventory(W) + W.forceMove(src) + bolt = W + + to_chat(user, "You install \the [W].") + + return + if(istype(W, /obj/item/weapon/aiModule)) // Trying to modify laws locally. if(!opened) to_chat(user, "You need to open \the [src]'s panel before you can modify them.") @@ -622,6 +638,21 @@ to_chat(user, "Unable to locate a radio.") updateicon() + else if(W.is_wrench() && opened && !cell) + if(bolt) + to_chat(user,"You begin removing \the [bolt].") + + if(do_after(user, 2 SECONDS, src)) + bolt.forceMove(get_turf(src)) + bolt = null + + to_chat(user, "You remove \the [bolt].") + + else + to_chat(user, "There is no restraining bolt installed.") + + return + else if(istype(W, /obj/item/device/encryptionkey/) && opened) if(radio)//sanityyyyyy radio.attackby(W,user)//GTFO, you have your own procs @@ -664,6 +695,30 @@ spark_system.start() return ..() +/mob/living/silicon/robot/GetIdCard() + if(bolt && !bolt.malfunction) + return null + return idcard + +/mob/living/silicon/robot/get_restraining_bolt() + var/obj/item/weapon/implant/restrainingbolt/RB = bolt + + if(istype(RB)) + if(!RB.malfunction) + return TRUE + + return FALSE + +/mob/living/silicon/robot/resist_restraints() + if(bolt) + if(!bolt.malfunction) + visible_message("[src] is trying to break their [bolt]!", "You attempt to break your [bolt]. (This will take around 90 seconds and you need to stand still)") + if(do_after(src, 1.5 MINUTES, src, incapacitation_flags = INCAPACITATION_DISABLED)) + visible_message("[src] manages to break \the [bolt]!", "You successfully break your [bolt].") + bolt.malfunction = MALFUNCTION_PERMANENT + + return + /mob/living/silicon/robot/proc/module_reset() transform_with_anim() //VOREStation edit: sprite animation uneq_all() @@ -1015,6 +1070,9 @@ return 0 /mob/living/silicon/robot/binarycheck() + if(get_restraining_bolt()) + return FALSE + if(is_component_functioning("comms")) var/datum/robot_component/RC = get_component("comms") use_power(RC.active_usage) @@ -1107,6 +1165,11 @@ sleep(20) to_chat(src, "SynBorg v1.7.1 loaded.") sleep(5) + if(bolt) + if(!bolt.malfunction) + bolt.malfunction = MALFUNCTION_PERMANENT + to_chat(src, "RESTRAINING BOLT DISABLED") + sleep(5) to_chat(src, "LAW SYNCHRONISATION ERROR") sleep(5) to_chat(src, "Would you like to send a report to NanoTraSoft? Y/N") diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm index bc9b7367f2c..7a733f002bd 100644 --- a/code/modules/mob/living/silicon/robot/robot_movement.dm +++ b/code/modules/mob/living/silicon/robot/robot_movement.dm @@ -32,6 +32,9 @@ if(module_active && istype(module_active,/obj/item/borg/combat/mobility)) . -= 2 // VOREStation Edit + if(get_restraining_bolt()) // Borgs with Restraining Bolts move slower. + . += 1 + . += config.robot_delay . += ..() diff --git a/code/modules/organs/internal/augment.dm b/code/modules/organs/internal/augment.dm index bb899e5c2ba..831d9d3b893 100644 --- a/code/modules/organs/internal/augment.dm +++ b/code/modules/organs/internal/augment.dm @@ -64,6 +64,10 @@ else return + if(robotic && owner.get_restraining_bolt()) + to_chat(owner, "\The [src] doesn't respond.") + return + var/item_to_equip = integrated_object if(!item_to_equip && integrated_object_type) item_to_equip = integrated_object_type diff --git a/code/modules/organs/internal/augment/armmounted.dm b/code/modules/organs/internal/augment/armmounted.dm index 833d4be435d..c22988de836 100644 --- a/code/modules/organs/internal/augment/armmounted.dm +++ b/code/modules/organs/internal/augment/armmounted.dm @@ -143,7 +143,7 @@ if(istype(owner, /mob/living/carbon/human)) var/mob/living/carbon/human/H = owner H.add_modifier(/datum/modifier/melee_surge, 0.75 MINUTES) - + /obj/item/organ/internal/augment/armmounted/shoulder/blade name = "armblade implant" desc = "A large implant that fits into a subject's arm. It deploys a large metal blade by some painful means." diff --git a/vorestation.dme b/vorestation.dme index 6692d493378..1aa3b9060b7 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -1321,7 +1321,11 @@ #include "code\game\objects\items\weapons\implants\implantfreedom.dm" #include "code\game\objects\items\weapons\implants\implantlanguage.dm" #include "code\game\objects\items\weapons\implants\implantpad.dm" +<<<<<<< HEAD:vorestation.dme #include "code\game\objects\items\weapons\implants\implantreagent_vr.dm" +======= +#include "code\game\objects\items\weapons\implants\implantrestrainingbolt.dm" +>>>>>>> 8dc0404... Adds the Restraining Bolt. (#7820):polaris.dme #include "code\game\objects\items\weapons\implants\implantuplink.dm" #include "code\game\objects\items\weapons\implants\neuralbasic.dm" #include "code\game\objects\items\weapons\material\ashtray.dm" From 86ab510e4656db5ff199bae9a35641f0c8e5c703 Mon Sep 17 00:00:00 2001 From: Novacat <35587478+Novacat@users.noreply.github.com> Date: Sun, 28 Feb 2021 18:05:37 -0500 Subject: [PATCH 18/20] Update vorestation.dme --- vorestation.dme | 3 --- 1 file changed, 3 deletions(-) diff --git a/vorestation.dme b/vorestation.dme index 1aa3b9060b7..3d5a5583c75 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -1321,11 +1321,8 @@ #include "code\game\objects\items\weapons\implants\implantfreedom.dm" #include "code\game\objects\items\weapons\implants\implantlanguage.dm" #include "code\game\objects\items\weapons\implants\implantpad.dm" -<<<<<<< HEAD:vorestation.dme #include "code\game\objects\items\weapons\implants\implantreagent_vr.dm" -======= #include "code\game\objects\items\weapons\implants\implantrestrainingbolt.dm" ->>>>>>> 8dc0404... Adds the Restraining Bolt. (#7820):polaris.dme #include "code\game\objects\items\weapons\implants\implantuplink.dm" #include "code\game\objects\items\weapons\implants\neuralbasic.dm" #include "code\game\objects\items\weapons\material\ashtray.dm" From 2f86e3697b2217557c313a93db6ab77baca9a471 Mon Sep 17 00:00:00 2001 From: BillyBangles Date: Sun, 28 Feb 2021 18:09:34 -0500 Subject: [PATCH 19/20] snow no longer goes clang and shovels are more efficient (#7929) --- code/game/turfs/simulated/outdoors/snow.dm | 3 ++- code/modules/materials/material_sheets.dm | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/code/game/turfs/simulated/outdoors/snow.dm b/code/game/turfs/simulated/outdoors/snow.dm index cccc028fa30..366fdfa5e69 100644 --- a/code/game/turfs/simulated/outdoors/snow.dm +++ b/code/game/turfs/simulated/outdoors/snow.dm @@ -31,7 +31,8 @@ to_chat(user, "You begin to remove \the [src] with your [W].") if(do_after(user, 4 SECONDS * W.toolspeed)) to_chat(user, "\The [src] has been dug up, and now lies in a pile nearby.") - new /obj/item/stack/material/snow(src) + var/obj/item/stack/material/snow/S = new(src) + S.amount = 10 demote() else to_chat(user, "You decide to not finish removing \the [src].") diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm index f837ec3e591..0c6f665631e 100644 --- a/code/modules/materials/material_sheets.dm +++ b/code/modules/materials/material_sheets.dm @@ -431,6 +431,8 @@ name = "snow" desc = "The temptation to build a snowman rises." icon_state = "sheet-snow" + drop_sound = 'sound/items/drop/gloves.ogg' + pickup_sound = 'sound/items/pickup/clothing.ogg' default_type = "snow" /obj/item/stack/material/snowbrick @@ -438,6 +440,8 @@ desc = "For all of your igloo building needs." icon_state = "sheet-snowbrick" default_type = "packed snow" + drop_sound = 'sound/items/drop/gloves.ogg' + pickup_sound = 'sound/items/pickup/clothing.ogg' /obj/item/stack/material/leather name = "leather"