mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 01:34:01 +00:00
Death of mutant bodyparts AND external organs (#85137)
## About The Pull Request Removes mutant bodyparts and external organs from the game completely Digitgrade behaviour was mutant bodypart for no reason Cat ears now work with the bodyparts overlay system, same as all the other external organs (since all their behaviour is now just on /organ It doesn't remove all the /external types, but moves all behaviour to /organ. I'll follow up with a PR wiping all the /external organ types, but it's just conflict heaven so not this PR I've also streamlined a lot of duplicate/weird species regeneration code Melbert did the same PR as well but due to a lack of time (?) I have absorbed his PR to double nuke mutant bodyparts ## Why It's Good For The Game Frees us from the chain of unmodular code, and kills my greatest nemesis (after the shuttle meteor murder bug) ## Changelog 🆑 Time-Green and MrMelbert Refactor: External organ behaviour has been moved to /organ, ears now use the same system as the other organs Refactor: Mutant bodyparts are dead! This likely does not mean much to the average person but it's very dear to me code: Improves digitgrade handling in preference code /🆑 I have absorbed #85126, using Melberts code to improve and add some missing changes. Mainly improving the functioning of preferences and digitgrade legs. I didn't take over the hairstyle improvements. --------- Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
This commit is contained in:
@@ -152,7 +152,10 @@
|
||||
///The species is forced to have digitigrade legs in generation.
|
||||
#define DIGITIGRADE_FORCED 2
|
||||
|
||||
///Digitigrade's prefs, used in features for legs if you're meant to be a Digitigrade.
|
||||
// Preferences for leg types
|
||||
/// Legs that are normal
|
||||
#define NORMAL_LEGS "Normal Legs"
|
||||
/// Digitgrade legs that are like bended and uhhh no shoes
|
||||
#define DIGITIGRADE_LEGS "Digitigrade Legs"
|
||||
|
||||
// Health/damage defines
|
||||
|
||||
@@ -15,8 +15,6 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars, list(
|
||||
"contents",
|
||||
"cooldowns",
|
||||
"_datum_components",
|
||||
"external_organs",
|
||||
"external_organs_slot",
|
||||
"group",
|
||||
"hand_bodyparts",
|
||||
"held_items",
|
||||
|
||||
@@ -40,7 +40,6 @@ SUBSYSTEM_DEF(accessories) // just 'accessories' for brevity
|
||||
var/list/horns_list
|
||||
var/list/frills_list
|
||||
var/list/spines_list
|
||||
var/list/legs_list
|
||||
var/list/tail_spines_list
|
||||
|
||||
//Mutant Human bits
|
||||
@@ -99,7 +98,6 @@ SUBSYSTEM_DEF(accessories) // just 'accessories' for brevity
|
||||
frills_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
|
||||
spines_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/spines, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
|
||||
tail_spines_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/tail_spines, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
|
||||
legs_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/legs)[DEFAULT_SPRITE_LIST]
|
||||
caps_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/caps)[DEFAULT_SPRITE_LIST]
|
||||
moth_wings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings)[DEFAULT_SPRITE_LIST]
|
||||
moth_antennae_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_antennae)[DEFAULT_SPRITE_LIST]
|
||||
|
||||
@@ -13,6 +13,24 @@
|
||||
///Take on the dna/preference from whoever we're gonna be inserted in
|
||||
var/imprint_on_next_insertion = TRUE
|
||||
|
||||
/datum/bodypart_overlay/mutant/New(obj/item/organ/attached_organ)
|
||||
. = ..()
|
||||
|
||||
RegisterSignal(attached_organ, COMSIG_ORGAN_IMPLANTED, PROC_REF(on_mob_insert))
|
||||
|
||||
/datum/bodypart_overlay/mutant/proc/on_mob_insert(obj/item/organ/parent, mob/living/carbon/receiver)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!should_visual_organ_apply_to(parent.type, receiver))
|
||||
stack_trace("adding a [parent.type] to a [receiver.type] when it shouldn't be!")
|
||||
|
||||
if(imprint_on_next_insertion) //We only want this set *once*
|
||||
var/feature_name = receiver.dna.features[feature_key]
|
||||
if (isnull(feature_name))
|
||||
feature_name = receiver.dna.species.mutant_organs[parent.type]
|
||||
set_appearance_from_name(feature_name)
|
||||
imprint_on_next_insertion = FALSE
|
||||
|
||||
/datum/bodypart_overlay/mutant/get_overlay(layer, obj/item/bodypart/limb)
|
||||
inherit_color(limb) // If draw_color is not set yet, go ahead and do that
|
||||
return ..()
|
||||
@@ -67,7 +85,6 @@
|
||||
return appearance
|
||||
|
||||
/datum/bodypart_overlay/mutant/color_image(image/overlay, layer, obj/item/bodypart/limb)
|
||||
|
||||
overlay.color = sprite_datum.color_src ? draw_color : null
|
||||
|
||||
/datum/bodypart_overlay/mutant/added_to_limb(obj/item/bodypart/limb)
|
||||
@@ -139,3 +156,4 @@
|
||||
CRASH("External organ [type] couldn't find sprite accessory [accessory_name]!")
|
||||
else
|
||||
CRASH("External organ [type] had fetch_sprite_datum called with a null accessory name!")
|
||||
|
||||
|
||||
@@ -682,8 +682,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
|
||||
if(dna.features["pod_hair"])
|
||||
dna.features["pod_hair"] = SSaccessories.pod_hair_list[deconstruct_block(get_uni_feature_block(features, DNA_POD_HAIR_BLOCK), length(SSaccessories.pod_hair_list))]
|
||||
|
||||
for(var/obj/item/organ/external/external_organ in organs)
|
||||
external_organ.mutate_feature(features, src)
|
||||
for(var/obj/item/organ/organ in organs)
|
||||
organ.mutate_feature(features, src)
|
||||
|
||||
if(icon_update)
|
||||
update_body(is_creating = mutcolor_update)
|
||||
|
||||
@@ -127,10 +127,10 @@
|
||||
else if(isorgan(new_part))
|
||||
var/obj/item/organ/new_organ = new_part
|
||||
old_part = human_holder.get_organ_slot(new_organ.slot)
|
||||
if(new_organ.Insert(human_holder, special = TRUE))
|
||||
old_part.moveToNullspace()
|
||||
STOP_PROCESSING(SSobj, old_part)
|
||||
slot_string = new_organ.name
|
||||
new_organ.Insert(human_holder, special = TRUE)
|
||||
old_part.moveToNullspace()
|
||||
STOP_PROCESSING(SSobj, old_part)
|
||||
slot_string = new_organ.name
|
||||
|
||||
/datum/quirk/transhumanist/post_add()
|
||||
if(!slot_string)
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
* This is the source that this accessory will get its color from. Default is MUTCOLOR, but can also be HAIR, FACEHAIR, EYECOLOR and 0 if none.
|
||||
*/
|
||||
var/color_src = MUTANT_COLOR
|
||||
/// Decides if this sprite has an "inner" part, such as the fleshy parts on ears.
|
||||
var/hasinner = FALSE
|
||||
/// Is this part locked from roundstart selection? Used for parts that apply effects.
|
||||
var/locked = FALSE
|
||||
/// Should we center the sprite?
|
||||
@@ -1890,7 +1888,6 @@
|
||||
/datum/sprite_accessory/ears/cat
|
||||
name = "Cat"
|
||||
icon_state = "cat"
|
||||
hasinner = TRUE
|
||||
color_src = HAIR_COLOR
|
||||
|
||||
/datum/sprite_accessory/ears/cat/big
|
||||
@@ -1917,7 +1914,6 @@
|
||||
icon = 'icons/mob/human/fox_features.dmi'
|
||||
name = "Fox"
|
||||
icon_state = "fox"
|
||||
hasinner = TRUE
|
||||
color_src = HAIR_COLOR
|
||||
locked = TRUE
|
||||
|
||||
@@ -2124,16 +2120,6 @@
|
||||
name = "Aquatic"
|
||||
icon_state = "aqua"
|
||||
|
||||
/datum/sprite_accessory/legs //legs are a special case, they aren't actually sprite_accessories but are updated with them.
|
||||
icon = null //These datums exist for selecting legs on preference, and little else
|
||||
em_block = TRUE
|
||||
|
||||
/datum/sprite_accessory/legs/none
|
||||
name = "Normal Legs"
|
||||
|
||||
/datum/sprite_accessory/legs/digitigrade_lizard
|
||||
name = DIGITIGRADE_LEGS
|
||||
|
||||
/datum/sprite_accessory/caps
|
||||
icon = 'icons/mob/human/species/mush_cap.dmi'
|
||||
color_src = HAIR_COLOR
|
||||
|
||||
@@ -125,7 +125,6 @@
|
||||
//useless organs we throw in just to fuck with surgeons a bit more. they aren't part of a bonus, just the (absolute) state of flies
|
||||
/obj/item/organ/internal/fly
|
||||
desc = FLY_INFUSED_ORGAN_DESC
|
||||
visual = FALSE
|
||||
|
||||
/obj/item/organ/internal/fly/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
@@ -6,17 +6,4 @@
|
||||
visual = TRUE
|
||||
damage_multiplier = 2
|
||||
|
||||
/obj/item/organ/internal/ears/fox/on_mob_insert(mob/living/carbon/human/ear_owner)
|
||||
. = ..()
|
||||
if(istype(ear_owner) && ear_owner.dna)
|
||||
color = ear_owner.hair_color
|
||||
ear_owner.dna.features["ears"] = ear_owner.dna.species.mutant_bodyparts["ears"] = "Fox"
|
||||
ear_owner.dna.update_uf_block(DNA_EARS_BLOCK)
|
||||
ear_owner.update_body()
|
||||
|
||||
/obj/item/organ/internal/ears/fox/on_mob_remove(mob/living/carbon/human/ear_owner)
|
||||
. = ..()
|
||||
if(istype(ear_owner) && ear_owner.dna)
|
||||
color = ear_owner.hair_color
|
||||
ear_owner.dna.species.mutant_bodyparts -= "ears"
|
||||
ear_owner.update_body()
|
||||
sprite_accessory_override = /datum/sprite_accessory/ears/fox
|
||||
|
||||
@@ -34,7 +34,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah...
|
||||
AddElement(/datum/element/noticable_organ, "%PRONOUN_They radiate%PRONOUN_s an aura of serenity.")
|
||||
AddElement(/datum/element/update_icon_blocker)
|
||||
|
||||
/obj/item/organ/internal/heart/gondola/Insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
/obj/item/organ/internal/heart/gondola/mob_insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
. = ..()
|
||||
if(!(FACTION_HOSTILE in receiver.faction))
|
||||
factions_to_remove += FACTION_HOSTILE
|
||||
@@ -42,7 +42,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah...
|
||||
factions_to_remove += FACTION_MINING
|
||||
receiver.faction |= list(FACTION_HOSTILE, FACTION_MINING)
|
||||
|
||||
/obj/item/organ/internal/heart/gondola/Remove(mob/living/carbon/heartless, special, movement_flags)
|
||||
/obj/item/organ/internal/heart/gondola/mob_remove(mob/living/carbon/heartless, special, movement_flags)
|
||||
. = ..()
|
||||
for(var/faction in factions_to_remove)
|
||||
heartless.faction -= faction
|
||||
@@ -64,11 +64,11 @@ Fluoride Stare: After someone says 5 words, blah blah blah...
|
||||
AddElement(/datum/element/noticable_organ, "%PRONOUN_Their mouth is permanently affixed into a relaxed smile.", BODY_ZONE_PRECISE_MOUTH)
|
||||
AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/gondola)
|
||||
|
||||
/obj/item/organ/internal/tongue/gondola/Insert(mob/living/carbon/tongue_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/tongue/gondola/mob_insert(mob/living/carbon/tongue_owner, special, movement_flags)
|
||||
. = ..()
|
||||
tongue_owner.add_mood_event("gondola_zen", /datum/mood_event/gondola_serenity)
|
||||
|
||||
/obj/item/organ/internal/tongue/gondola/Remove(mob/living/carbon/tongue_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/tongue/gondola/mob_remove(mob/living/carbon/tongue_owner, special, movement_flags)
|
||||
tongue_owner.clear_mood_event("gondola_zen")
|
||||
return ..()
|
||||
|
||||
@@ -87,7 +87,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah...
|
||||
AddElement(/datum/element/noticable_organ, "%PRONOUN_Their left arm has small needles breaching the skin all over it.", BODY_ZONE_L_ARM)
|
||||
AddElement(/datum/element/noticable_organ, "%PRONOUN_Their right arm has small needles breaching the skin all over it.", BODY_ZONE_R_ARM)
|
||||
|
||||
/obj/item/organ/internal/liver/gondola/Insert(mob/living/carbon/liver_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/liver/gondola/mob_insert(mob/living/carbon/liver_owner, special, movement_flags)
|
||||
. = ..()
|
||||
var/has_left = liver_owner.has_left_hand(check_disabled = FALSE)
|
||||
var/has_right = liver_owner.has_right_hand(check_disabled = FALSE)
|
||||
@@ -102,7 +102,7 @@ Fluoride Stare: After someone says 5 words, blah blah blah...
|
||||
RegisterSignal(liver_owner, COMSIG_LIVING_TRY_PULL, PROC_REF(on_owner_try_pull))
|
||||
RegisterSignal(liver_owner, COMSIG_CARBON_HELPED, PROC_REF(on_hug))
|
||||
|
||||
/obj/item/organ/internal/liver/gondola/Remove(mob/living/carbon/liver_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/liver/gondola/mob_remove(mob/living/carbon/liver_owner, special, movement_flags)
|
||||
. = ..()
|
||||
UnregisterSignal(liver_owner, list(COMSIG_HUMAN_EQUIPPING_ITEM, COMSIG_LIVING_TRY_PULL, COMSIG_CARBON_HELPED))
|
||||
|
||||
|
||||
@@ -15,15 +15,14 @@
|
||||
if(iscarbon(loc))
|
||||
Insert(loc)
|
||||
|
||||
/obj/item/organ/internal/body_egg/Insert(mob/living/carbon/egg_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED)
|
||||
/obj/item/organ/internal/body_egg/mob_insert(mob/living/carbon/egg_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
egg_owner.add_traits(list(TRAIT_XENO_HOST, TRAIT_XENO_IMMUNE), ORGAN_TRAIT)
|
||||
egg_owner.med_hud_set_status()
|
||||
INVOKE_ASYNC(src, PROC_REF(AddInfectionImages), egg_owner)
|
||||
|
||||
/obj/item/organ/internal/body_egg/Remove(mob/living/carbon/egg_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/body_egg/mob_remove(mob/living/carbon/egg_owner, special, movement_flags)
|
||||
. = ..()
|
||||
egg_owner.remove_traits(list(TRAIT_XENO_HOST, TRAIT_XENO_IMMUNE), ORGAN_TRAIT)
|
||||
egg_owner.med_hud_set_status()
|
||||
|
||||
@@ -18,10 +18,7 @@ ADMIN_VERB(manipulate_organs, R_DEBUG, "Manipulate Organs", "Manipulate the orga
|
||||
return
|
||||
organ_to_grant = organs[organ_to_grant]
|
||||
organ_to_grant = new organ_to_grant
|
||||
if(!organ_to_grant.Insert(carbon_victim))
|
||||
to_chat(user, span_notice("[carbon_victim] is unable to carry this organ!"))
|
||||
qdel(organ_to_grant)
|
||||
return
|
||||
organ_to_grant.Insert(carbon_victim)
|
||||
log_admin("[key_name(user)] has added organ [organ_to_grant.type] to [key_name(carbon_victim)]")
|
||||
message_admins("[key_name_admin(user)] has added organ [organ_to_grant.type] to [ADMIN_LOOKUPFLW(carbon_victim)]")
|
||||
|
||||
|
||||
@@ -526,7 +526,7 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
|
||||
var/forename = names.len > 1 ? names[2] : names[1]
|
||||
var/newname = "[forename]-[pick(honorifics["[H.gender]"])]"
|
||||
H.fully_replace_character_name(H.real_name,newname)
|
||||
H.update_mutant_bodyparts()
|
||||
H.update_body_parts()
|
||||
if(animetype == "Yes")
|
||||
var/seifuku = pick(typesof(/obj/item/clothing/under/costume/schoolgirl))
|
||||
var/obj/item/clothing/under/costume/schoolgirl/I = new seifuku
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
active_mind_control = FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/internal/heart/gland/Remove(mob/living/carbon/gland_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/heart/gland/mob_remove(mob/living/carbon/gland_owner, special, movement_flags)
|
||||
. = ..()
|
||||
active = FALSE
|
||||
if(initial(uses) == 1)
|
||||
@@ -93,10 +93,8 @@
|
||||
hud.remove_atom_from_hud(gland_owner)
|
||||
clear_mind_control()
|
||||
|
||||
/obj/item/organ/internal/heart/gland/Insert(mob/living/carbon/gland_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED)
|
||||
/obj/item/organ/internal/heart/gland/mob_insert(mob/living/carbon/gland_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(special != 2 && uses) // Special 2 means abductor surgery
|
||||
Start()
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
/// When this egg last got removed from a body. If -1, the egg hasn't been removed from a body.
|
||||
var/removal_time = -1
|
||||
|
||||
/obj/item/organ/internal/body_egg/changeling_egg/Insert(mob/living/carbon/egg_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED)
|
||||
/obj/item/organ/internal/body_egg/changeling_egg/mob_insert(mob/living/carbon/egg_owner, special = FALSE, movement_flags = DELETE_IF_REPLACED)
|
||||
. = ..()
|
||||
hatch_time = world.time + (removal_time == -1 ? EGG_INCUBATION_TIME : (hatch_time - removal_time))
|
||||
|
||||
/obj/item/organ/internal/body_egg/changeling_egg/Remove(mob/living/carbon/egg_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/body_egg/changeling_egg/mob_remove(mob/living/carbon/egg_owner, special, movement_flags)
|
||||
. = ..()
|
||||
removal_time = world.time
|
||||
|
||||
|
||||
@@ -416,20 +416,13 @@
|
||||
usable_organs -= /obj/item/organ/internal/lungs/corrupt // Their lungs are already more cursed than anything I could give them
|
||||
|
||||
var/total_implant = rand(2, 4)
|
||||
var/gave_any = FALSE
|
||||
|
||||
for (var/i in 1 to total_implant)
|
||||
if (!length(usable_organs))
|
||||
break
|
||||
return
|
||||
var/organ_path = pick_n_take(usable_organs)
|
||||
var/obj/item/organ/internal/to_give = new organ_path
|
||||
if (!to_give.Insert(sac_target))
|
||||
qdel(to_give)
|
||||
else
|
||||
gave_any = TRUE
|
||||
|
||||
if (!gave_any)
|
||||
return
|
||||
to_give.Insert(sac_target)
|
||||
|
||||
new /obj/effect/gibspawner/human/bodypartless(get_turf(sac_target))
|
||||
sac_target.visible_message(span_boldwarning("Several organs force themselves out of [sac_target]!"))
|
||||
|
||||
@@ -65,9 +65,10 @@
|
||||
/obj/item/organ/internal/heart/nightmare
|
||||
name = "heart of darkness"
|
||||
desc = "An alien organ that twists and writhes when exposed to light."
|
||||
visual = TRUE
|
||||
icon_state = "demon_heart-on"
|
||||
base_icon_state = "demon_heart"
|
||||
visual = TRUE
|
||||
|
||||
color = COLOR_CRAYON_BLACK
|
||||
decay_factor = 0
|
||||
// No love is to be found in a heart so twisted.
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
if(affected_mob)
|
||||
affected_mob.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, "#1d2953")
|
||||
if(affected_mob.dna && affected_mob.dna.species)
|
||||
affected_mob.dna.species.handle_mutant_bodyparts(affected_mob)
|
||||
affected_mob.set_haircolor(null, override = TRUE)
|
||||
to_chat(affected_mob, span_notice("You feel better."))
|
||||
..()
|
||||
@@ -66,7 +65,6 @@
|
||||
affected_mob.adjustStaminaLoss(22.5 * seconds_per_tick, updating_stamina = FALSE)
|
||||
new /obj/effect/temp_visual/revenant(affected_mob.loc)
|
||||
if(affected_mob.dna && affected_mob.dna.species)
|
||||
affected_mob.dna.species.handle_mutant_bodyparts(affected_mob,"#1d2953")
|
||||
affected_mob.set_haircolor("#1d2953", override = TRUE)
|
||||
affected_mob.visible_message(span_warning("[affected_mob] looks terrifyingly gaunt..."), span_revennotice("You suddenly feel like your skin is <i>wrong</i>..."))
|
||||
affected_mob.add_atom_colour("#1d2953", TEMPORARY_COLOUR_PRIORITY)
|
||||
|
||||
@@ -111,10 +111,6 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key())
|
||||
/// DOES have random body on, will this already be randomized?
|
||||
var/randomize_by_default = TRUE
|
||||
|
||||
/// If the selected species has this in its /datum/species/mutant_bodyparts,
|
||||
/// will show the feature as selectable.
|
||||
var/relevant_mutant_bodypart = null
|
||||
|
||||
/// If the selected species has this in its /datum/species/body_markings,
|
||||
/// will show the feature as selectable.
|
||||
var/relevant_body_markings = null
|
||||
@@ -336,8 +332,7 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key())
|
||||
SHOULD_NOT_SLEEP(TRUE)
|
||||
|
||||
if ( \
|
||||
!isnull(relevant_mutant_bodypart) \
|
||||
|| !isnull(relevant_inherent_trait) \
|
||||
!isnull(relevant_inherent_trait) \
|
||||
|| !isnull(relevant_external_organ) \
|
||||
|| !isnull(relevant_head_flag) \
|
||||
|| !isnull(relevant_body_markings) \
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
savefile_identifier = PREFERENCE_CHARACTER
|
||||
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
|
||||
can_randomize = FALSE
|
||||
relevant_mutant_bodypart = "ears"
|
||||
relevant_external_organ = /obj/item/organ/internal/ears/cat
|
||||
|
||||
/datum/preference/choiced/ears/init_possible_values()
|
||||
return assoc_to_keys_features(SSaccessories.ears_list)
|
||||
|
||||
@@ -93,13 +93,51 @@
|
||||
savefile_key = "feature_lizard_legs"
|
||||
savefile_identifier = PREFERENCE_CHARACTER
|
||||
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
|
||||
relevant_mutant_bodypart = "legs"
|
||||
|
||||
/datum/preference/choiced/lizard_legs/init_possible_values()
|
||||
return assoc_to_keys_features(SSaccessories.legs_list)
|
||||
return list(NORMAL_LEGS, DIGITIGRADE_LEGS)
|
||||
|
||||
/datum/preference/choiced/lizard_legs/apply_to_human(mob/living/carbon/human/target, value)
|
||||
target.dna.features["legs"] = value
|
||||
// Hack to update the dummy in the preference menu
|
||||
// (Because digi legs are ONLY handled on species change)
|
||||
if(!isdummy(target) || target.dna.species.digitigrade_customization == DIGITIGRADE_NEVER)
|
||||
return
|
||||
|
||||
var/list/correct_legs = target.dna.species.bodypart_overrides.Copy() & list(BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
|
||||
|
||||
if(value == DIGITIGRADE_LEGS)
|
||||
correct_legs[BODY_ZONE_R_LEG] = /obj/item/bodypart/leg/right/digitigrade
|
||||
correct_legs[BODY_ZONE_L_LEG] = /obj/item/bodypart/leg/left/digitigrade
|
||||
|
||||
for(var/obj/item/bodypart/old_part as anything in target.bodyparts)
|
||||
if(old_part.change_exempt_flags & BP_BLOCK_CHANGE_SPECIES)
|
||||
continue
|
||||
|
||||
var/path = correct_legs[old_part.body_zone]
|
||||
if(!path)
|
||||
continue
|
||||
var/obj/item/bodypart/new_part = new path()
|
||||
new_part.replace_limb(target, TRUE)
|
||||
new_part.update_limb(is_creating = TRUE)
|
||||
qdel(old_part)
|
||||
|
||||
/datum/preference/choiced/lizard_legs/is_accessible(datum/preferences/preferences)
|
||||
if(!..())
|
||||
return FALSE
|
||||
var/datum/species/species_type = preferences.read_preference(/datum/preference/choiced/species)
|
||||
return initial(species_type.digitigrade_customization) == DIGITIGRADE_OPTIONAL
|
||||
|
||||
|
||||
/datum/preference/choiced/lizard_legs/is_accessible(datum/preferences/preferences)
|
||||
. = ..()
|
||||
|
||||
if(!.)
|
||||
return
|
||||
|
||||
var/datum/species/species_type = preferences.read_preference(/datum/preference/choiced/species)
|
||||
|
||||
return initial(species_type.digitigrade_customization) & DIGITIGRADE_OPTIONAL
|
||||
|
||||
/datum/preference/choiced/lizard_snout
|
||||
savefile_key = "feature_lizard_snout"
|
||||
@@ -121,7 +159,7 @@
|
||||
savefile_key = "feature_lizard_spines"
|
||||
savefile_identifier = PREFERENCE_CHARACTER
|
||||
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
|
||||
relevant_mutant_bodypart = "spines"
|
||||
relevant_external_organ = /obj/item/organ/external/spines
|
||||
|
||||
/datum/preference/choiced/lizard_spines/init_possible_values()
|
||||
return assoc_to_keys_features(SSaccessories.spines_list)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
savefile_key = "feature_mushperson_cap"
|
||||
savefile_identifier = PREFERENCE_CHARACTER
|
||||
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
|
||||
relevant_mutant_bodypart = "cap"
|
||||
relevant_external_organ = /obj/item/organ/external/mushroom_cap
|
||||
|
||||
/datum/preference/choiced/mushroom_cap/init_possible_values()
|
||||
return assoc_to_keys_features(SSaccessories.caps_list)
|
||||
|
||||
@@ -387,7 +387,7 @@
|
||||
if (organ.type == target_species.get_mutant_organ_type_for_slot(organ.slot))
|
||||
continue
|
||||
else
|
||||
if ((organ.type in target_species.mutant_organs) || (organ.type in target_species.external_organs))
|
||||
if ((organ.type in target_species.mutant_organs))
|
||||
continue
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -10,7 +10,7 @@ If the scythe isn't empowered when you sheath it, you take a heap of damage and
|
||||
desc = "This shard seems to be directly linked to some sinister entity. It might be your god! It also gives you a really horrible rash when you hold onto it for too long."
|
||||
items_to_create = list(/obj/item/vorpalscythe)
|
||||
|
||||
/obj/item/organ/internal/cyberimp/arm/shard/scythe/Insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
/obj/item/organ/internal/cyberimp/arm/shard/scythe/mob_insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
. = ..()
|
||||
if(receiver.mind)
|
||||
ADD_TRAIT(receiver.mind, TRAIT_MORBID, ORGAN_TRAIT)
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
icon = 'icons/obj/medical/organs/mining_organs.dmi'
|
||||
icon_state = "hivelord_core"
|
||||
actions_types = list(/datum/action/cooldown/monster_core_action)
|
||||
visual = FALSE
|
||||
|
||||
item_flags = NOBLUDGEON
|
||||
slot = ORGAN_SLOT_MONSTER_CORE
|
||||
organ_flags = ORGAN_ORGANIC
|
||||
@@ -66,10 +66,9 @@
|
||||
deltimer(decay_timer)
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/internal/monster_core/Insert(mob/living/carbon/target_carbon, special = FALSE, movement_flags)
|
||||
/obj/item/organ/internal/monster_core/mob_insert(mob/living/carbon/target_carbon, special = FALSE, movement_flags)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if (inert)
|
||||
to_chat(target_carbon, span_notice("[src] breaks down as you try to insert it."))
|
||||
qdel(src)
|
||||
@@ -80,7 +79,7 @@
|
||||
target_carbon.visible_message(span_notice("[src] stabilizes as it's inserted."))
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/internal/monster_core/Remove(mob/living/carbon/target_carbon, special, movement_flags)
|
||||
/obj/item/organ/internal/monster_core/mob_remove(mob/living/carbon/target_carbon, special, movement_flags)
|
||||
if (!inert && !special)
|
||||
owner.visible_message(span_notice("[src] rapidly decays as it's removed."))
|
||||
go_inert()
|
||||
|
||||
@@ -557,7 +557,6 @@
|
||||
var/obj/item/organ/external/wings/functional/wings = get_wing_choice(exposed_human, chest)
|
||||
wings = new wings()
|
||||
wings.Insert(exposed_human)
|
||||
exposed_human.dna.species.handle_mutant_bodyparts(exposed_human)
|
||||
playsound(exposed_human.loc, 'sound/items/poster_ripped.ogg', 50, TRUE, -1)
|
||||
exposed_human.apply_damage(20, def_zone = BODY_ZONE_CHEST, forced = TRUE, wound_bonus = CANT_WOUND)
|
||||
exposed_human.emote("scream")
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/obj/item/organ/internal/alien
|
||||
icon_state = "acid"
|
||||
visual = FALSE
|
||||
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/acid = 10)
|
||||
|
||||
/obj/item/organ/internal/alien/plasmavessel
|
||||
@@ -222,11 +221,11 @@
|
||||
stomach_contents -= source
|
||||
UnregisterSignal(source, list(COMSIG_MOVABLE_MOVED, COMSIG_LIVING_DEATH, COMSIG_QDELETING))
|
||||
|
||||
/obj/item/organ/internal/stomach/alien/Insert(mob/living/carbon/stomach_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/stomach/alien/mob_insert(mob/living/carbon/stomach_owner, special, movement_flags)
|
||||
RegisterSignal(stomach_owner, COMSIG_ATOM_RELAYMOVE, PROC_REF(something_moved))
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/internal/stomach/alien/Remove(mob/living/carbon/stomach_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/stomach/alien/mob_remove(mob/living/carbon/stomach_owner, special, movement_flags)
|
||||
UnregisterSignal(stomach_owner, COMSIG_ATOM_RELAYMOVE)
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -53,13 +53,8 @@
|
||||
overlays_standing[cache_index] = null
|
||||
SEND_SIGNAL(src, COMSIG_CARBON_REMOVE_OVERLAY, cache_index, I)
|
||||
|
||||
//used when putting/removing clothes that hide certain mutant body parts to just update those and not update the whole body.
|
||||
/mob/living/carbon/human/proc/update_mutant_bodyparts()
|
||||
dna?.species.handle_mutant_bodyparts(src)
|
||||
update_body_parts()
|
||||
|
||||
/mob/living/carbon/update_body(is_creating = FALSE)
|
||||
dna?.species.handle_body(src) //This calls `handle_mutant_bodyparts` which calls `update_mutant_bodyparts()`. Don't double call!
|
||||
dna?.species.handle_body(src)
|
||||
update_body_parts(is_creating)
|
||||
|
||||
/mob/living/carbon/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
|
||||
|
||||
@@ -60,16 +60,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
/// Use a [language holder datum][/datum/language_holder] typepath in this var.
|
||||
/// Should never be null.
|
||||
var/datum/language_holder/species_language_holder = /datum/language_holder/human_basic
|
||||
/**
|
||||
* Visible CURRENT bodyparts that are unique to a species.
|
||||
* DO NOT USE THIS AS A LIST OF ALL POSSIBLE BODYPARTS AS IT WILL FUCK
|
||||
* SHIT UP! Changes to this list for non-species specific bodyparts (ie
|
||||
* cat ears and tails) should be assigned at organ level if possible.
|
||||
* Assoc values are defaults for given bodyparts, also modified by aforementioned organs.
|
||||
* They also allow for faster '[]' list access versus 'in'. Other than that, they are useless right now.
|
||||
* Layer hiding is handled by [/datum/species/proc/handle_mutant_bodyparts] below.
|
||||
*/
|
||||
var/list/mutant_bodyparts = list()
|
||||
///The bodyparts this species uses. assoc of bodypart string - bodypart type. Make sure all the fucking entries are in or I'll skin you alive.
|
||||
var/list/bodypart_overrides = list(
|
||||
BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left,
|
||||
@@ -79,10 +69,8 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right,
|
||||
BODY_ZONE_CHEST = /obj/item/bodypart/chest,
|
||||
)
|
||||
///Internal organs that are unique to this race, like a tail. list(typepath of organ 1, typepath of organ 2)
|
||||
///Internal organs that are unique to this race, like a tail or other cosmetic organs. list(typepath of organ 1, typepath of organ 2 = "Round").
|
||||
var/list/mutant_organs = list()
|
||||
///List of external organs to generate like horns, frills, wings, etc. list(typepath of organ = "Round Beautiful BDSM Snout"). Still WIP
|
||||
var/list/external_organs = list()
|
||||
///Replaces default brain with a different organ
|
||||
var/obj/item/organ/internal/brain/mutantbrain = /obj/item/organ/internal/brain
|
||||
///Replaces default heart with a different organ
|
||||
@@ -283,7 +271,10 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
if(ORGAN_SLOT_STOMACH)
|
||||
return mutantstomach
|
||||
else
|
||||
CRASH("Invalid organ slot [slot]")
|
||||
// Non-standard organs we might have
|
||||
for(var/obj/item/organ/extra_organ as anything in mutant_organs)
|
||||
if(initial(extra_organ.slot) == slot)
|
||||
return extra_organ
|
||||
|
||||
/**
|
||||
* Corrects organs in a carbon, removing ones it doesn't need and adding ones it does.
|
||||
@@ -299,46 +290,33 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
* * visual_only - boolean, only load organs that change how the species looks. Do not use for normal gameplay stuff
|
||||
*/
|
||||
/datum/species/proc/regenerate_organs(mob/living/carbon/organ_holder, datum/species/old_species, replace_current = TRUE, list/excluded_zones, visual_only = FALSE)
|
||||
//what should be put in if there is no mutantorgan (brains handled separately)
|
||||
var/list/organ_slots = list(
|
||||
ORGAN_SLOT_BRAIN,
|
||||
ORGAN_SLOT_HEART,
|
||||
ORGAN_SLOT_LUNGS,
|
||||
ORGAN_SLOT_APPENDIX,
|
||||
ORGAN_SLOT_EYES,
|
||||
ORGAN_SLOT_EARS,
|
||||
ORGAN_SLOT_TONGUE,
|
||||
ORGAN_SLOT_LIVER,
|
||||
ORGAN_SLOT_STOMACH,
|
||||
)
|
||||
|
||||
for(var/slot in organ_slots)
|
||||
for(var/slot in get_all_slots())
|
||||
var/obj/item/organ/existing_organ = organ_holder.get_organ_slot(slot)
|
||||
var/obj/item/organ/new_organ = get_mutant_organ_type_for_slot(slot)
|
||||
var/old_organ_type = old_species?.get_mutant_organ_type_for_slot(slot)
|
||||
|
||||
if(isnull(new_organ)) // if they aren't suppose to have an organ here, remove it
|
||||
if(existing_organ)
|
||||
existing_organ.Remove(organ_holder, special = TRUE)
|
||||
// if we have an extra organ that before changing that the species didnt have, remove it
|
||||
if(!new_organ)
|
||||
if(existing_organ && (old_organ_type == existing_organ.type || replace_current))
|
||||
existing_organ.Remove(organ_holder)
|
||||
qdel(existing_organ)
|
||||
continue
|
||||
|
||||
// we don't want to remove organs that are not the default for this species
|
||||
if(!isnull(existing_organ))
|
||||
if(!isnull(old_species) && existing_organ.type != old_species.get_mutant_organ_type_for_slot(slot))
|
||||
continue
|
||||
else if(!replace_current && existing_organ.type != get_mutant_organ_type_for_slot(slot))
|
||||
if(existing_organ)
|
||||
// we dont want to remove organs that were not from the old species (such as from freak surgery or prosthetics)
|
||||
if(existing_organ.type != old_organ_type && !replace_current)
|
||||
continue
|
||||
|
||||
// at this point we already know new_organ is not null
|
||||
if(existing_organ?.type == new_organ)
|
||||
continue // we don't want to remove organs that are the same as the new one
|
||||
// we don't want to remove organs that are the same as the new one
|
||||
if(existing_organ.type == new_organ)
|
||||
continue
|
||||
|
||||
if(visual_only && !initial(new_organ.visual))
|
||||
if(visual_only && (!initial(new_organ.bodypart_overlay) && !initial(new_organ.visual)))
|
||||
continue
|
||||
|
||||
var/used_neworgan = FALSE
|
||||
new_organ = SSwardrobe.provide_type(new_organ)
|
||||
var/should_have = new_organ.get_availability(src, organ_holder)
|
||||
var/should_have = new_organ.get_availability(src, organ_holder) && should_visual_organ_apply_to(new_organ, organ_holder)
|
||||
|
||||
// Check for an existing organ, and if there is one check to see if we should remove it
|
||||
var/health_pct = 1
|
||||
@@ -362,46 +340,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
if(!used_neworgan)
|
||||
QDEL_NULL(new_organ)
|
||||
|
||||
if(!isnull(old_species))
|
||||
for(var/mutant_organ in old_species.mutant_organs)
|
||||
if(mutant_organ in mutant_organs)
|
||||
continue // need this mutant organ, but we already have it!
|
||||
|
||||
var/obj/item/organ/current_organ = organ_holder.get_organ_by_type(mutant_organ)
|
||||
if(current_organ)
|
||||
current_organ.Remove(organ_holder)
|
||||
QDEL_NULL(current_organ)
|
||||
|
||||
for(var/obj/item/organ/external/external_organ in organ_holder.organs)
|
||||
// External organ checking. We need to check the external organs owned by the carbon itself,
|
||||
// because we want to also remove ones not shared by its species.
|
||||
// This should be done even if species was not changed.
|
||||
if(external_organ in external_organs)
|
||||
continue // Don't remove external organs this species is supposed to have.
|
||||
|
||||
external_organ.Remove(organ_holder)
|
||||
QDEL_NULL(external_organ)
|
||||
|
||||
var/list/species_organs = mutant_organs + external_organs
|
||||
for(var/organ_path in species_organs)
|
||||
var/obj/item/organ/current_organ = organ_holder.get_organ_by_type(organ_path)
|
||||
if(ispath(organ_path, /obj/item/organ/external) && !should_external_organ_apply_to(organ_path, organ_holder))
|
||||
if(!isnull(current_organ) && replace_current)
|
||||
// if we have an organ here and we're replacing organs, remove it
|
||||
current_organ.Remove(organ_holder)
|
||||
QDEL_NULL(current_organ)
|
||||
continue
|
||||
|
||||
if(!current_organ || replace_current)
|
||||
var/obj/item/organ/replacement = SSwardrobe.provide_type(organ_path)
|
||||
// If there's an existing mutant organ, we're technically replacing it.
|
||||
// Let's abuse the snowflake proc that skillchips added. Basically retains
|
||||
// feature parity with every other organ too.
|
||||
if(current_organ)
|
||||
current_organ.before_organ_replacement(replacement)
|
||||
// organ.Insert will qdel any current organs in that slot, so we don't need to.
|
||||
replacement.Insert(organ_holder, special=TRUE, movement_flags = DELETE_IF_REPLACED)
|
||||
|
||||
/datum/species/proc/worn_items_fit_body_check(mob/living/carbon/wearer)
|
||||
for(var/obj/item/equipped_item in wearer.get_equipped_items(INCLUDE_POCKETS))
|
||||
var/equipped_item_slot = wearer.get_slot_by_item(equipped_item)
|
||||
@@ -443,7 +381,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
if(old_species.type != type)
|
||||
replace_body(human_who_gained_species, src)
|
||||
|
||||
regenerate_organs(human_who_gained_species, old_species, visual_only = human_who_gained_species.visual_only_organs)
|
||||
regenerate_organs(human_who_gained_species, old_species, replace_current = FALSE, visual_only = human_who_gained_species.visual_only_organs)
|
||||
|
||||
// Drop the items the new species can't wear
|
||||
INVOKE_ASYNC(src, PROC_REF(worn_items_fit_body_check), human_who_gained_species, TRUE)
|
||||
@@ -459,16 +397,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
//Resets blood if it is excessively high so they don't gib
|
||||
normalize_blood(human_who_gained_species)
|
||||
|
||||
if(ishuman(human_who_gained_species))
|
||||
var/mob/living/carbon/human/human = human_who_gained_species
|
||||
for(var/obj/item/organ/external/organ_path as anything in external_organs)
|
||||
if(!should_external_organ_apply_to(organ_path, human))
|
||||
continue
|
||||
|
||||
//Load a persons preferences from DNA
|
||||
var/obj/item/organ/external/new_organ = SSwardrobe.provide_type(organ_path)
|
||||
new_organ.Insert(human, special=TRUE, movement_flags = DELETE_IF_REPLACED)
|
||||
|
||||
add_body_markings(human_who_gained_species)
|
||||
|
||||
if(length(inherent_traits))
|
||||
@@ -509,10 +437,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
for(var/X in inherent_traits)
|
||||
REMOVE_TRAIT(C, X, SPECIES_TRAIT)
|
||||
|
||||
for(var/obj/item/organ/external/organ in C.organs)
|
||||
organ.Remove(C)
|
||||
qdel(organ)
|
||||
|
||||
//If their inert mutation is not the same, swap it out
|
||||
if((inert_mutation != new_species.inert_mutation) && LAZYLEN(C.dna.mutation_index) && (inert_mutation in C.dna.mutation_index))
|
||||
C.dna.remove_mutation(inert_mutation)
|
||||
@@ -546,14 +470,13 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
* Handles the body of a human
|
||||
*
|
||||
* Handles lipstick, having no eyes, eye color, undergarnments like underwear, undershirts, and socks, and body layers.
|
||||
* Calls [handle_mutant_bodyparts][/datum/species/proc/handle_mutant_bodyparts]
|
||||
* Arguments:
|
||||
* * species_human - Human, whoever we're handling the body for
|
||||
*/
|
||||
/datum/species/proc/handle_body(mob/living/carbon/human/species_human)
|
||||
species_human.remove_overlay(BODY_LAYER)
|
||||
if(HAS_TRAIT(species_human, TRAIT_INVISIBLE_MAN))
|
||||
return handle_mutant_bodyparts(species_human)
|
||||
return
|
||||
var/list/standing = list()
|
||||
|
||||
if(!HAS_TRAIT(species_human, TRAIT_HUSK))
|
||||
@@ -598,103 +521,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
species_human.overlays_standing[BODY_LAYER] = standing
|
||||
|
||||
species_human.apply_overlay(BODY_LAYER)
|
||||
handle_mutant_bodyparts(species_human)
|
||||
|
||||
/**
|
||||
* Handles the mutant bodyparts of a human
|
||||
*
|
||||
* Handles the adding and displaying of, layers, colors, and overlays of mutant bodyparts and accessories.
|
||||
* Handles digitigrade leg displaying and squishing.
|
||||
* Arguments:
|
||||
* * H - Human, whoever we're handling the body for
|
||||
* * forced_colour - The forced color of an accessory. Leave null to use mutant color.
|
||||
*/
|
||||
/datum/species/proc/handle_mutant_bodyparts(mob/living/carbon/human/source, forced_colour)
|
||||
var/list/bodyparts_to_add = mutant_bodyparts.Copy()
|
||||
var/list/relevent_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
|
||||
var/list/standing = list()
|
||||
|
||||
source.remove_overlay(BODY_BEHIND_LAYER)
|
||||
source.remove_overlay(BODY_ADJ_LAYER)
|
||||
source.remove_overlay(BODY_FRONT_LAYER)
|
||||
|
||||
if(!mutant_bodyparts || HAS_TRAIT(source, TRAIT_INVISIBLE_MAN))
|
||||
return
|
||||
|
||||
var/obj/item/bodypart/head/noggin = source.get_bodypart(BODY_ZONE_HEAD)
|
||||
|
||||
|
||||
if(mutant_bodyparts["ears"])
|
||||
if(!source.dna.features["ears"] || source.dna.features["ears"] == "None" || source.head && (source.head.flags_inv & HIDEHAIR) || (source.wear_mask && (source.wear_mask.flags_inv & HIDEHAIR)) || !noggin || IS_ROBOTIC_LIMB(noggin))
|
||||
bodyparts_to_add -= "ears"
|
||||
|
||||
if(!bodyparts_to_add)
|
||||
return
|
||||
|
||||
var/g = (source.physique == FEMALE) ? "f" : "m"
|
||||
|
||||
for(var/layer in relevent_layers)
|
||||
var/layertext = mutant_bodyparts_layertext(layer)
|
||||
|
||||
for(var/bodypart in bodyparts_to_add)
|
||||
var/datum/sprite_accessory/accessory
|
||||
switch(bodypart)
|
||||
if("ears")
|
||||
accessory = SSaccessories.ears_list[source.dna.features["ears"]]
|
||||
if("legs")
|
||||
accessory = SSaccessories.legs_list[source.dna.features["legs"]]
|
||||
|
||||
if(!accessory || accessory.icon_state == "none")
|
||||
continue
|
||||
|
||||
var/mutable_appearance/accessory_overlay = mutable_appearance(accessory.icon, layer = -layer)
|
||||
|
||||
if(accessory.gender_specific)
|
||||
accessory_overlay.icon_state = "[g]_[bodypart]_[accessory.icon_state]_[layertext]"
|
||||
else
|
||||
accessory_overlay.icon_state = "m_[bodypart]_[accessory.icon_state]_[layertext]"
|
||||
|
||||
if(accessory.em_block)
|
||||
accessory_overlay.overlays += emissive_blocker(accessory_overlay.icon, accessory_overlay.icon_state, source, accessory_overlay.alpha)
|
||||
|
||||
if(accessory.center)
|
||||
accessory_overlay = center_image(accessory_overlay, accessory.dimension_x, accessory.dimension_y)
|
||||
|
||||
if(!(HAS_TRAIT(source, TRAIT_HUSK)))
|
||||
if(!forced_colour)
|
||||
switch(accessory.color_src)
|
||||
if(MUTANT_COLOR)
|
||||
accessory_overlay.color = fixed_mut_color || source.dna.features["mcolor"]
|
||||
if(HAIR_COLOR)
|
||||
accessory_overlay.color = get_fixed_hair_color(source) || source.hair_color
|
||||
if(FACIAL_HAIR_COLOR)
|
||||
accessory_overlay.color = get_fixed_hair_color(source) || source.facial_hair_color
|
||||
if(EYE_COLOR)
|
||||
accessory_overlay.color = source.eye_color_left
|
||||
else
|
||||
accessory_overlay.color = forced_colour
|
||||
standing += accessory_overlay
|
||||
|
||||
if(accessory.hasinner)
|
||||
var/mutable_appearance/inner_accessory_overlay = mutable_appearance(accessory.icon, layer = -layer)
|
||||
if(accessory.gender_specific)
|
||||
inner_accessory_overlay.icon_state = "[g]_[bodypart]inner_[accessory.icon_state]_[layertext]"
|
||||
else
|
||||
inner_accessory_overlay.icon_state = "m_[bodypart]inner_[accessory.icon_state]_[layertext]"
|
||||
|
||||
if(accessory.center)
|
||||
inner_accessory_overlay = center_image(inner_accessory_overlay, accessory.dimension_x, accessory.dimension_y)
|
||||
|
||||
standing += inner_accessory_overlay
|
||||
|
||||
source.overlays_standing[layer] = standing.Copy()
|
||||
standing = list()
|
||||
|
||||
source.apply_overlay(BODY_BEHIND_LAYER)
|
||||
source.apply_overlay(BODY_ADJ_LAYER)
|
||||
source.apply_overlay(BODY_FRONT_LAYER)
|
||||
|
||||
update_body_markings(source)
|
||||
update_body_markings(species_human)
|
||||
|
||||
//This exists so sprite accessories can still be per-layer without having to include that layer's
|
||||
//number in their sprite name, which causes issues when those numbers change.
|
||||
@@ -737,7 +564,9 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
|
||||
var/list/new_features = list()
|
||||
var/static/list/organs_to_randomize = list()
|
||||
for(var/obj/item/organ/external/organ_path as anything in external_organs)
|
||||
for(var/obj/item/organ/organ_path as anything in mutant_organs)
|
||||
if(!organ_path.bodypart_overlay)
|
||||
continue
|
||||
var/overlay_path = initial(organ_path.bodypart_overlay)
|
||||
var/datum/bodypart_overlay/mutant/sample_overlay = organs_to_randomize[overlay_path]
|
||||
if(isnull(sample_overlay))
|
||||
@@ -1579,15 +1408,14 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
var/datum/preference/preference = GLOB.preference_entries[preference_type]
|
||||
|
||||
if ( \
|
||||
(preference.relevant_mutant_bodypart in mutant_bodyparts) \
|
||||
|| (preference.relevant_inherent_trait in inherent_traits) \
|
||||
|| (preference.relevant_external_organ in external_organs) \
|
||||
(preference.relevant_inherent_trait in inherent_traits) \
|
||||
|| (preference.relevant_external_organ in mutant_organs) \
|
||||
|| (preference.relevant_head_flag && check_head_flags(preference.relevant_head_flag)) \
|
||||
|| (preference.relevant_body_markings in body_markings) \
|
||||
)
|
||||
features += preference.savefile_key
|
||||
|
||||
for (var/obj/item/organ/external/organ_type as anything in external_organs)
|
||||
for (var/obj/item/organ/organ_type as anything in mutant_organs)
|
||||
var/preference = initial(organ_type.preference)
|
||||
if (!isnull(preference))
|
||||
features += preference
|
||||
@@ -1632,7 +1460,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
/datum/species/proc/get_types_to_preload()
|
||||
var/list/to_store = list()
|
||||
to_store += mutant_organs
|
||||
for(var/obj/item/organ/external/horny as anything in external_organs)
|
||||
for(var/obj/item/organ/horny as anything in mutant_organs)
|
||||
to_store += horny //Haha get it?
|
||||
|
||||
//Don't preload brains, cause reuse becomes a horrible headache
|
||||
@@ -2218,6 +2046,10 @@ GLOBAL_LIST_EMPTY(features_by_species)
|
||||
|
||||
/// Update the overlays if necessary
|
||||
/datum/species/proc/update_body_markings(mob/living/carbon/human/hooman)
|
||||
if(HAS_TRAIT(hooman, TRAIT_INVISIBLE_MAN))
|
||||
remove_body_markings(hooman)
|
||||
return
|
||||
|
||||
var/needs_update = FALSE
|
||||
for(var/datum/bodypart_overlay/simple/body_marking/marking as anything in body_markings)
|
||||
if(initial(marking.dna_feature_key) == body_markings[marking]) // dna is same as our species (sort of mini-cache), so no update needed
|
||||
|
||||
@@ -133,9 +133,9 @@ There are several things that need to be remembered:
|
||||
var/obj/item/bodypart/chest/my_chest = get_bodypart(BODY_ZONE_CHEST)
|
||||
my_chest?.worn_uniform_offset?.apply_offset(uniform_overlay)
|
||||
overlays_standing[UNIFORM_LAYER] = uniform_overlay
|
||||
apply_overlay(UNIFORM_LAYER)
|
||||
|
||||
update_mutant_bodyparts()
|
||||
update_body_parts()
|
||||
apply_overlay(UNIFORM_LAYER)
|
||||
|
||||
/mob/living/carbon/human/update_worn_id(update_obscured = TRUE)
|
||||
remove_overlay(ID_LAYER)
|
||||
@@ -434,12 +434,10 @@ There are several things that need to be remembered:
|
||||
var/obj/item/bodypart/chest/my_chest = get_bodypart(BODY_ZONE_CHEST)
|
||||
my_chest?.worn_suit_offset?.apply_offset(suit_overlay)
|
||||
overlays_standing[SUIT_LAYER] = suit_overlay
|
||||
|
||||
update_body_parts()
|
||||
update_mutant_bodyparts()
|
||||
|
||||
apply_overlay(SUIT_LAYER)
|
||||
|
||||
|
||||
/mob/living/carbon/human/update_pockets()
|
||||
if(client && hud_used)
|
||||
var/atom/movable/screen/inventory/inv
|
||||
@@ -489,7 +487,7 @@ There are several things that need to be remembered:
|
||||
overlays_standing[FACEMASK_LAYER] = mask_overlay
|
||||
|
||||
apply_overlay(FACEMASK_LAYER)
|
||||
update_mutant_bodyparts() //e.g. upgate needed because mask now hides lizard snout
|
||||
update_body_parts() //e.g. upgate needed because mask now hides lizard snout
|
||||
|
||||
/mob/living/carbon/human/update_worn_back(update_obscured = TRUE)
|
||||
remove_overlay(BACK_LAYER)
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
BODY_ZONE_CHEST = /obj/item/bodypart/chest,
|
||||
)
|
||||
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
|
||||
mutant_bodyparts = list("wings" = "None")
|
||||
mutantbrain = /obj/item/organ/internal/brain/dullahan
|
||||
mutanteyes = /obj/item/organ/internal/eyes/dullahan
|
||||
mutanttongue = /obj/item/organ/internal/tongue/dullahan
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
name = "Felinid"
|
||||
id = SPECIES_FELINE
|
||||
examine_limb_id = SPECIES_HUMAN
|
||||
mutant_bodyparts = list("ears" = "Cat", "wings" = "None")
|
||||
mutantbrain = /obj/item/organ/internal/brain/felinid
|
||||
mutanttongue = /obj/item/organ/internal/tongue/cat
|
||||
mutantears = /obj/item/organ/internal/ears/cat
|
||||
external_organs = list(
|
||||
mutant_organs = list(
|
||||
/obj/item/organ/external/tail/cat = "Cat",
|
||||
)
|
||||
inherent_traits = list(
|
||||
@@ -151,7 +150,7 @@
|
||||
// stored_feature_id is only set once (the first time an organ is inserted), so this should be safe.
|
||||
var/obj/item/organ/internal/ears/cat/kitty_ears = new
|
||||
kitty_ears.Insert(soon_to_be_felinid, special = TRUE, movement_flags = DELETE_IF_REPLACED)
|
||||
if(should_external_organ_apply_to(/obj/item/organ/external/tail/cat, soon_to_be_felinid)) //only give them a tail if they actually have sprites for it / are a compatible subspecies.
|
||||
if(should_visual_organ_apply_to(/obj/item/organ/external/tail/cat, soon_to_be_felinid)) //only give them a tail if they actually have sprites for it / are a compatible subspecies.
|
||||
var/obj/item/organ/external/tail/cat/kitty_tail = new
|
||||
kitty_tail.Insert(soon_to_be_felinid, special = TRUE, movement_flags = DELETE_IF_REPLACED)
|
||||
|
||||
@@ -174,8 +173,8 @@
|
||||
old_tail.Remove(purrbated_human, special = TRUE)
|
||||
qdel(old_tail)
|
||||
// Locate does not work on assoc lists, so we do it by hand
|
||||
for(var/external_organ in target_species.external_organs)
|
||||
if(!should_external_organ_apply_to(external_organ, purrbated_human))
|
||||
for(var/external_organ in target_species.mutant_organs)
|
||||
if(!should_visual_organ_apply_to(external_organ, purrbated_human))
|
||||
continue
|
||||
if(ispath(external_organ, /obj/item/organ/external/tail))
|
||||
var/obj/item/organ/external/tail/new_tail = new external_organ()
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
inherent_traits = list(
|
||||
TRAIT_USES_SKINTONES,
|
||||
)
|
||||
mutant_bodyparts = list("wings" = "None")
|
||||
skinned_type = /obj/item/stack/sheet/animalhide/human
|
||||
changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT
|
||||
payday_modifier = 1.1
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
TRAIT_MUTANT_COLORS,
|
||||
)
|
||||
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_REPTILE
|
||||
mutant_bodyparts = list("legs" = "Normal Legs")
|
||||
body_markings = list(/datum/bodypart_overlay/simple/body_marking/lizard = "None")
|
||||
external_organs = list(
|
||||
mutant_organs = list(
|
||||
/obj/item/organ/external/horns = "None",
|
||||
/obj/item/organ/external/frills = "None",
|
||||
/obj/item/organ/external/snout = "Round",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/datum/species/monkey
|
||||
name = "\improper Monkey"
|
||||
id = SPECIES_MONKEY
|
||||
external_organs = list(
|
||||
mutant_organs = list(
|
||||
/obj/item/organ/external/tail/monkey = "Monkey",
|
||||
)
|
||||
mutanttongue = /obj/item/organ/internal/tongue/monkey
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
id = SPECIES_MOTH
|
||||
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG
|
||||
body_markings = list(/datum/bodypart_overlay/simple/body_marking/moth = "None")
|
||||
external_organs = list(/obj/item/organ/external/wings/moth = "Plain", /obj/item/organ/external/antennae = "Plain")
|
||||
mutant_organs = list(/obj/item/organ/external/wings/moth = "Plain", /obj/item/organ/external/antennae = "Plain")
|
||||
meat = /obj/item/food/meat/slab/human/mutant/moth
|
||||
mutanttongue = /obj/item/organ/internal/tongue/moth
|
||||
mutanteyes = /obj/item/organ/internal/eyes/moth
|
||||
@@ -24,12 +24,6 @@
|
||||
BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/moth,
|
||||
)
|
||||
|
||||
/datum/species/moth/regenerate_organs(mob/living/carbon/C, datum/species/old_species, replace_current= TRUE, list/excluded_zones, visual_only)
|
||||
. = ..()
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
handle_mutant_bodyparts(H)
|
||||
|
||||
/datum/species/moth/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load)
|
||||
. = ..()
|
||||
RegisterSignal(human_who_gained_species, COMSIG_MOB_APPLY_DAMAGE_MODIFIERS, PROC_REF(damage_weakness))
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
fixed_mut_color = "#DBBF92"
|
||||
|
||||
external_organs = list(/obj/item/organ/external/mushroom_cap = "Round")
|
||||
mutant_organs = list(/obj/item/organ/external/mushroom_cap = "Round")
|
||||
|
||||
inherent_traits = list(
|
||||
TRAIT_MUTANT_COLORS,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
TRAIT_MUTANT_COLORS,
|
||||
TRAIT_PLANT_SAFE,
|
||||
)
|
||||
external_organs = list(
|
||||
mutant_organs = list(
|
||||
/obj/item/organ/external/pod_hair = "None",
|
||||
)
|
||||
inherent_biotypes = MOB_ORGANIC | MOB_HUMANOID | MOB_PLANT
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
TRAIT_NO_MIRROR_REFLECTION,
|
||||
)
|
||||
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
|
||||
mutant_bodyparts = list("wings" = "None")
|
||||
changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN
|
||||
exotic_bloodtype = "U"
|
||||
blood_deficiency_drain_rate = BLOOD_DEFICIENCY_MODIFIER // vampires already passively lose blood, so this just makes them lose it slightly more quickly when they have blood deficiency.
|
||||
|
||||
@@ -225,8 +225,7 @@
|
||||
organ_evacced.Remove(target, special = TRUE)
|
||||
organ_evacced.forceMove(get_turf(target))
|
||||
|
||||
if (!organ.Insert(target))
|
||||
organ.forceMove(drop_location())
|
||||
organ.Insert(target)
|
||||
organ = null
|
||||
|
||||
///Patrient Transport - Generates hardlight bags you can put people in.
|
||||
|
||||
@@ -953,7 +953,7 @@
|
||||
if(should_draw_greyscale) //Should the limb be colored?
|
||||
draw_color ||= species_color || (skin_tone ? skintone2hex(skin_tone) : null)
|
||||
|
||||
recolor_external_organs()
|
||||
recolor_bodypart_overlays()
|
||||
return TRUE
|
||||
|
||||
//to update the bodypart's icon when not attached to a mob
|
||||
@@ -1274,7 +1274,7 @@
|
||||
QDEL_NULL(current_gauze)
|
||||
|
||||
///Loops through all of the bodypart's external organs and update's their color.
|
||||
/obj/item/bodypart/proc/recolor_external_organs()
|
||||
/obj/item/bodypart/proc/recolor_bodypart_overlays()
|
||||
for(var/datum/bodypart_overlay/mutant/overlay in bodypart_overlays)
|
||||
overlay.inherit_color(src, force = TRUE)
|
||||
|
||||
|
||||
@@ -404,12 +404,12 @@
|
||||
qdel(phantom_loss)
|
||||
|
||||
//Copied from /datum/species/proc/on_species_gain()
|
||||
for(var/obj/item/organ/external/organ_path as anything in dna.species.external_organs)
|
||||
for(var/obj/item/organ/organ_path as anything in dna.species.mutant_organs)
|
||||
//Load a persons preferences from DNA
|
||||
var/zone = initial(organ_path.zone)
|
||||
if(zone != limb_zone)
|
||||
continue
|
||||
var/obj/item/organ/external/new_organ = SSwardrobe.provide_type(organ_path)
|
||||
var/obj/item/organ/new_organ = SSwardrobe.provide_type(organ_path)
|
||||
new_organ.Insert(src)
|
||||
|
||||
update_body_parts()
|
||||
|
||||
@@ -182,8 +182,8 @@
|
||||
/mob/living/carbon/proc/synchronize_bodytypes()
|
||||
var/all_limb_flags = NONE
|
||||
for(var/obj/item/bodypart/limb as anything in bodyparts)
|
||||
for(var/obj/item/organ/external/ext_organ in limb)
|
||||
all_limb_flags |= ext_organ.external_bodytypes
|
||||
for(var/obj/item/organ/organ in limb)
|
||||
all_limb_flags |= organ.external_bodytypes
|
||||
all_limb_flags |= limb.bodytype
|
||||
|
||||
bodytype = all_limb_flags
|
||||
@@ -192,8 +192,8 @@
|
||||
/mob/living/carbon/proc/synchronize_bodyshapes()
|
||||
var/all_limb_flags = NONE
|
||||
for(var/obj/item/bodypart/limb as anything in bodyparts)
|
||||
for(var/obj/item/organ/external/ext_organ in limb)
|
||||
all_limb_flags |= ext_organ.external_bodyshapes
|
||||
for(var/obj/item/organ/organ in limb)
|
||||
all_limb_flags |= organ.external_bodyshapes
|
||||
all_limb_flags |= limb.bodyshape
|
||||
|
||||
bodyshape = all_limb_flags
|
||||
|
||||
@@ -239,22 +239,20 @@
|
||||
tool = tool.contents[1]
|
||||
target_organ = tool
|
||||
user.temporarilyRemoveItemFromInventory(target_organ, TRUE)
|
||||
if(target_organ.Insert(target))
|
||||
if(apparatus)
|
||||
apparatus.icon_state = initial(apparatus.icon_state)
|
||||
apparatus.desc = initial(apparatus.desc)
|
||||
apparatus.cut_overlays()
|
||||
display_results(
|
||||
user,
|
||||
target,
|
||||
span_notice("You insert [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]."),
|
||||
span_notice("[user] inserts [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
|
||||
span_notice("[user] inserts something into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
|
||||
)
|
||||
display_pain(target, "Your [target.parse_zone_with_bodypart(target_zone)] throbs with pain as your new [tool.name] comes to life!")
|
||||
target_organ.on_surgical_insertion(user, target, target_zone, tool)
|
||||
else
|
||||
target_organ.forceMove(target.loc)
|
||||
target_organ.Insert(target)
|
||||
if(apparatus)
|
||||
apparatus.icon_state = initial(apparatus.icon_state)
|
||||
apparatus.desc = initial(apparatus.desc)
|
||||
apparatus.cut_overlays()
|
||||
display_results(
|
||||
user,
|
||||
target,
|
||||
span_notice("You insert [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]."),
|
||||
span_notice("[user] inserts [tool] into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
|
||||
span_notice("[user] inserts something into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
|
||||
)
|
||||
display_pain(target, "Your [target.parse_zone_with_bodypart(target_zone)] throbs with pain as your new [tool.name] comes to life!")
|
||||
target_organ.on_surgical_insertion(user, target, target_zone, tool)
|
||||
|
||||
else if(current_type == "extract")
|
||||
if(target_organ && target_organ.owner == target)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/obj/item/organ
|
||||
name = "organ"
|
||||
icon = 'icons/obj/medical/organs/organs.dmi'
|
||||
@@ -79,6 +78,9 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
|
||||
volume = reagent_vol,\
|
||||
after_eat = CALLBACK(src, PROC_REF(OnEatFrom)))
|
||||
|
||||
if(bodypart_overlay)
|
||||
setup_bodypart_overlay()
|
||||
|
||||
/obj/item/organ/Destroy()
|
||||
if(bodypart_owner && !owner && !QDELETED(bodypart_owner))
|
||||
bodypart_remove(bodypart_owner)
|
||||
@@ -140,7 +142,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
|
||||
return
|
||||
|
||||
/obj/item/organ/proc/on_life(seconds_per_tick, times_fired)
|
||||
CRASH("Oh god oh fuck something is calling parent organ life")
|
||||
return
|
||||
|
||||
/obj/item/organ/examine(mob/user)
|
||||
. = ..()
|
||||
@@ -342,3 +344,16 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
|
||||
/// Tries to replace the existing organ on the passed mob with this one, with special handling for replacing a brain without ghosting target
|
||||
/obj/item/organ/proc/replace_into(mob/living/carbon/new_owner)
|
||||
return Insert(new_owner, special = TRUE, movement_flags = DELETE_IF_REPLACED)
|
||||
|
||||
|
||||
/// Get all possible organ slots by checking every organ, and then store it and give it whenever needed
|
||||
/proc/get_all_slots()
|
||||
var/static/list/all_organ_slots = list()
|
||||
|
||||
if(!all_organ_slots.len)
|
||||
for(var/obj/item/organ/an_organ as anything in subtypesof(/obj/item/organ))
|
||||
if(!initial(an_organ.slot))
|
||||
continue
|
||||
all_organ_slots |= initial(an_organ.slot)
|
||||
|
||||
return all_organ_slots
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
/**
|
||||
* System for drawing organs with overlays. These overlays are drawn directly on the bodypart, attached to a person or not
|
||||
* Works in tandem with the /datum/sprite_accessory datum to generate sprites
|
||||
* Unlike normal organs, we're actually inside a persons limbs at all times
|
||||
/*
|
||||
System for drawing organs with overlays. These overlays are drawn directly on the bodypart, attached to a person or not
|
||||
Works in tandem with the /datum/sprite_accessory datum to generate sprites
|
||||
Unlike normal organs, we're actually inside a persons limbs at all times
|
||||
*/
|
||||
/obj/item/organ/external
|
||||
name = "external organ"
|
||||
desc = "An external organ that is too external."
|
||||
|
||||
organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE
|
||||
visual = TRUE
|
||||
|
||||
/obj/item/organ
|
||||
///The overlay datum that actually draws stuff on the limb
|
||||
var/datum/bodypart_overlay/mutant/bodypart_overlay
|
||||
///If not null, overrides the appearance with this sprite accessory datum
|
||||
var/sprite_accessory_override
|
||||
|
||||
/// The savefile_key of the preference this relates to. Used for the preferences UI.
|
||||
var/preference
|
||||
@@ -23,21 +15,24 @@
|
||||
///Set to EXTERNAL_BEHIND, EXTERNAL_FRONT or EXTERNAL_ADJACENT if you want to draw one of those layers as the object sprite. FALSE to use your own
|
||||
///This will not work if it doesn't have a limb to generate its icon with
|
||||
var/use_mob_sprite_as_obj_sprite = FALSE
|
||||
|
||||
///Does this organ have any bodytypes to pass to its bodypart_owner?
|
||||
var/external_bodytypes = NONE
|
||||
///Does this organ have any bodyshapes to pass to its bodypart_owner?
|
||||
var/external_bodyshapes = NONE
|
||||
|
||||
///Which flags does a 'modification tool' need to have to restyle us, if it all possible (located in code/_DEFINES/mobs)
|
||||
var/restyle_flags = NONE
|
||||
|
||||
/**mob_sprite is optional if you havent set sprite_datums for the object, and is used mostly to generate sprite_datums from a persons DNA
|
||||
///If not null, overrides the appearance with this sprite accessory datum
|
||||
var/sprite_accessory_override
|
||||
|
||||
/**accessory_type is optional if you havent set sprite_datums for the object, and is used mostly to generate sprite_datums from a persons DNA
|
||||
* For _mob_sprite we make a distinction between "Round Snout" and "round". Round Snout is the name of the sprite datum, while "round" would be part of the sprite
|
||||
* I'm sorry
|
||||
*/
|
||||
/obj/item/organ/external/Initialize(mapload, accessory_type)
|
||||
. = ..()
|
||||
|
||||
bodypart_overlay = new bodypart_overlay()
|
||||
/obj/item/organ/proc/setup_bodypart_overlay(accessory_type)
|
||||
bodypart_overlay = new bodypart_overlay(src)
|
||||
|
||||
accessory_type = accessory_type ? accessory_type : sprite_accessory_override
|
||||
var/update_overlays = TRUE
|
||||
@@ -55,61 +50,13 @@
|
||||
if(restyle_flags)
|
||||
RegisterSignal(src, COMSIG_ATOM_RESTYLE, PROC_REF(on_attempt_feature_restyle))
|
||||
|
||||
/obj/item/organ/external/Insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
. = ..()
|
||||
receiver.update_body_parts()
|
||||
/// Some sanity checks, but mostly to check if the person has their preference/dna set to load
|
||||
/proc/should_visual_organ_apply_to(obj/item/organ/organpath, mob/living/carbon/target)
|
||||
if(!initial(organpath.bodypart_overlay))
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/external/Remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
. = ..()
|
||||
if(!special)
|
||||
organ_owner.update_body_parts()
|
||||
|
||||
/obj/item/organ/external/mob_insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
if(!should_external_organ_apply_to(type, receiver))
|
||||
stack_trace("adding a [type] to a [receiver.type] when it shouldn't be!")
|
||||
|
||||
. = ..()
|
||||
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(bodypart_overlay.imprint_on_next_insertion) //We only want this set *once*
|
||||
var/feature_name = receiver.dna.features[bodypart_overlay.feature_key]
|
||||
if (isnull(feature_name))
|
||||
feature_name = receiver.dna.species.external_organs[type]
|
||||
bodypart_overlay.set_appearance_from_name(feature_name)
|
||||
bodypart_overlay.imprint_on_next_insertion = FALSE
|
||||
|
||||
if(external_bodytypes)
|
||||
receiver.synchronize_bodytypes()
|
||||
if(external_bodyshapes)
|
||||
receiver.synchronize_bodyshapes()
|
||||
|
||||
receiver.update_body_parts()
|
||||
|
||||
/obj/item/organ/external/mob_remove(mob/living/carbon/organ_owner, special, moving)
|
||||
if(!special)
|
||||
organ_owner.synchronize_bodytypes()
|
||||
organ_owner.synchronize_bodyshapes()
|
||||
organ_owner.update_body_parts()
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/external/on_bodypart_insert(obj/item/bodypart/bodypart)
|
||||
bodypart.add_bodypart_overlay(bodypart_overlay)
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/external/on_bodypart_remove(obj/item/bodypart/bodypart)
|
||||
bodypart.remove_bodypart_overlay(bodypart_overlay)
|
||||
|
||||
if(use_mob_sprite_as_obj_sprite)
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
|
||||
color = bodypart_overlay.draw_color // so a pink felinid doesn't drop a gray tail
|
||||
return ..()
|
||||
|
||||
/proc/should_external_organ_apply_to(obj/item/organ/external/organpath, mob/living/carbon/target)
|
||||
if(isnull(organpath) || isnull(target))
|
||||
stack_trace("passed a null path or mob to 'should_external_organ_apply_to'")
|
||||
stack_trace("passed a null path or mob to 'should_visual_organ_apply_to'")
|
||||
return FALSE
|
||||
|
||||
var/datum/bodypart_overlay/mutant/bodypart_overlay = initial(organpath.bodypart_overlay)
|
||||
@@ -122,7 +69,7 @@
|
||||
return FALSE
|
||||
|
||||
///Update our features after something changed our appearance
|
||||
/obj/item/organ/external/proc/mutate_feature(features, mob/living/carbon/human/human)
|
||||
/obj/item/organ/proc/mutate_feature(features, mob/living/carbon/human/human)
|
||||
if(!dna_block)
|
||||
return
|
||||
|
||||
@@ -131,7 +78,7 @@
|
||||
bodypart_overlay.set_appearance_from_name(feature_list[deconstruct_block(get_uni_feature_block(features, dna_block), feature_list.len)])
|
||||
|
||||
///If you need to change an external_organ for simple one-offs, use this. Pass the accessory type : /datum/accessory/something
|
||||
/obj/item/organ/external/proc/simple_change_sprite(accessory_type)
|
||||
/obj/item/organ/proc/simple_change_sprite(accessory_type)
|
||||
var/datum/sprite_accessory/typed_accessory = accessory_type //we only take types for maintainability
|
||||
|
||||
bodypart_overlay.set_appearance(typed_accessory)
|
||||
@@ -142,10 +89,7 @@
|
||||
bodypart_owner.update_icon_dropped()
|
||||
//else if(use_mob_sprite_as_obj_sprite) //are we out in the world, unprotected by flesh?
|
||||
|
||||
/obj/item/organ/external/on_life(seconds_per_tick, times_fired)
|
||||
return
|
||||
|
||||
/obj/item/organ/external/update_overlays()
|
||||
/obj/item/organ/update_overlays()
|
||||
. = ..()
|
||||
|
||||
if(!use_mob_sprite_as_obj_sprite)
|
||||
@@ -260,17 +204,16 @@
|
||||
///Store our old datum here for if our antennae are healed
|
||||
var/original_sprite_datum
|
||||
|
||||
/obj/item/organ/external/antennae/Insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
/obj/item/organ/external/antennae/mob_insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
RegisterSignal(receiver, COMSIG_HUMAN_BURNING, PROC_REF(try_burn_antennae))
|
||||
RegisterSignal(receiver, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(heal_antennae))
|
||||
|
||||
/obj/item/organ/external/antennae/Remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
/obj/item/organ/external/antennae/mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
. = ..()
|
||||
if(organ_owner)
|
||||
UnregisterSignal(organ_owner, list(COMSIG_HUMAN_BURNING, COMSIG_LIVING_POST_FULLY_HEAL))
|
||||
|
||||
UnregisterSignal(organ_owner, list(COMSIG_HUMAN_BURNING, COMSIG_LIVING_POST_FULLY_HEAL))
|
||||
|
||||
///check if our antennae can burn off ;_;
|
||||
/obj/item/organ/external/antennae/proc/try_burn_antennae(mob/living/carbon/human/human)
|
||||
@@ -1,7 +1,7 @@
|
||||
//Contains a bunch of procs for different types, but in the end it just lets you restyle external_organs so thats why its here
|
||||
//Contains a bunch of procs for different types, but in the end it just lets you restyle the bodypart overlay so thats why its here
|
||||
|
||||
///Helper proc to fetch a list of styles a player might want to restyle their features into during the round : returns list("Cabbage" = /datum/sprite_accessory/cabbage)
|
||||
/obj/item/organ/external/proc/get_valid_restyles()
|
||||
/obj/item/organ/proc/get_valid_restyles()
|
||||
var/list/valid_restyles
|
||||
|
||||
valid_restyles = list()
|
||||
@@ -31,18 +31,18 @@
|
||||
///Asks the external organs inside the limb if they can restyle
|
||||
/obj/item/bodypart/proc/attempt_feature_restyle(atom/source, mob/living/trimmer, atom/movable/original_target, body_zone, restyle_type, style_speed)
|
||||
var/list/valid_features = list()
|
||||
for(var/obj/item/organ/external/feature in contents)
|
||||
for(var/obj/item/organ/feature in contents)
|
||||
if(feature.restyle_flags & restyle_type)
|
||||
valid_features.Add(feature)
|
||||
|
||||
var/obj/item/organ/external/target_organ
|
||||
var/obj/item/organ/target_organ
|
||||
switch(LAZYLEN(valid_features))
|
||||
if(1)
|
||||
target_organ = valid_features[1]
|
||||
if(2 to INFINITY)
|
||||
var/choose_options = list()
|
||||
var/name_to_organ = list() //literally so I dont have to loop again after someones made their choice
|
||||
for(var/obj/item/organ/external/organ_choice as anything in valid_features)
|
||||
for(var/obj/item/organ/organ_choice as anything in valid_features)
|
||||
choose_options[organ_choice.name] = image(organ_choice)
|
||||
name_to_organ[organ_choice.name] = organ_choice
|
||||
var/picked_option = show_radial_menu(trimmer, original_target, choose_options, radius = 38, require_near = TRUE)
|
||||
@@ -57,7 +57,7 @@
|
||||
target_organ.attempt_feature_restyle(source, trimmer, original_target, body_zone, restyle_type, style_speed)
|
||||
|
||||
///Invoke async so we dont break signals
|
||||
/obj/item/organ/external/proc/on_attempt_feature_restyle(atom/source, mob/living/trimmer, atom/movable/original_target, body_zone, restyle_type, style_speed)
|
||||
/obj/item/organ/proc/on_attempt_feature_restyle(atom/source, mob/living/trimmer, atom/movable/original_target, body_zone, restyle_type, style_speed)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(restyle_flags & restyle_type)
|
||||
@@ -66,7 +66,7 @@
|
||||
to_chat(trimmer, span_warning("This tool is incompatible with the [src.name]!"))
|
||||
|
||||
///Restyles the external organ from a list of valid options
|
||||
/obj/item/organ/external/proc/attempt_feature_restyle(atom/source, mob/living/trimmer, atom/movable/original_target, body_zone, restyle_type, style_speed)
|
||||
/obj/item/organ/proc/attempt_feature_restyle(atom/source, mob/living/trimmer, atom/movable/original_target, body_zone, restyle_type, style_speed)
|
||||
var/list/restyles = get_valid_restyles()
|
||||
var/new_style = tgui_input_list(trimmer, "Select a new style", "Grooming", restyles)
|
||||
|
||||
@@ -80,5 +80,4 @@
|
||||
span_notice("You successfully change [original_target == trimmer ? "your" : original_target.name + "'s"] [name].")
|
||||
)
|
||||
|
||||
|
||||
simple_change_sprite(restyles[new_style]) //turn name to type and pass it on
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
|
||||
bodypart_overlay = /datum/bodypart_overlay/mutant/spines
|
||||
|
||||
/obj/item/organ/external/spines/Insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
/obj/item/organ/external/spines/mob_insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
// If we have a tail, attempt to add a tail spines overlay
|
||||
var/obj/item/organ/external/tail/our_tail = receiver.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL)
|
||||
our_tail?.try_insert_tail_spines(our_tail.bodypart_owner)
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/external/spines/Remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
/obj/item/organ/external/spines/mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
// If we have a tail, remove any tail spines overlay
|
||||
var/obj/item/organ/external/tail/our_tail = organ_owner.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL)
|
||||
our_tail?.remove_tail_spines(our_tail.bodypart_owner)
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
///The overlay for tail spines, if any
|
||||
var/datum/bodypart_overlay/mutant/tail_spines/tail_spines_overlay
|
||||
|
||||
/obj/item/organ/external/tail/Insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
/obj/item/organ/external/tail/mob_insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
receiver.clear_mood_event("tail_lost")
|
||||
@@ -34,7 +34,7 @@
|
||||
// If it's not your tail AND of different species, we are horrified
|
||||
if(IS_WEAKREF_OF(receiver, original_owner))
|
||||
receiver.add_mood_event("tail_regained", /datum/mood_event/tail_regained_right)
|
||||
else if(type in receiver.dna.species.external_organs)
|
||||
else if(type in receiver.dna.species.mutant_organs)
|
||||
receiver.add_mood_event("tail_regained", /datum/mood_event/tail_regained_species)
|
||||
else
|
||||
receiver.add_mood_event("tail_regained", /datum/mood_event/tail_regained_wrong)
|
||||
@@ -83,7 +83,7 @@
|
||||
|
||||
organ_owner.clear_mood_event("tail_regained")
|
||||
|
||||
if(type in organ_owner.dna.species.external_organs)
|
||||
if(type in organ_owner.dna.species.mutant_organs)
|
||||
organ_owner.add_mood_event("tail_lost", /datum/mood_event/tail_lost)
|
||||
organ_owner.add_mood_event("tail_balance_lost", /datum/mood_event/tail_balance_lost)
|
||||
|
||||
|
||||
@@ -35,15 +35,14 @@
|
||||
QDEL_NULL(fly)
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/external/wings/functional/Insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
/obj/item/organ/external/wings/functional/mob_insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(QDELETED(fly))
|
||||
fly = new
|
||||
fly.Grant(receiver)
|
||||
|
||||
/obj/item/organ/external/wings/functional/Remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
/obj/item/organ/external/wings/functional/mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
. = ..()
|
||||
fly?.Remove(organ_owner)
|
||||
if(wings_open)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
name = "appendix"
|
||||
icon_state = "appendix"
|
||||
base_icon_state = "appendix"
|
||||
visual = FALSE
|
||||
|
||||
zone = BODY_ZONE_PRECISE_GROIN
|
||||
slot = ORGAN_SLOT_APPENDIX
|
||||
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/bad_food = 5)
|
||||
|
||||
@@ -27,14 +27,13 @@
|
||||
eye_owner.remove_traits(HUD_traits, ORGAN_TRAIT)
|
||||
balloon_alert(eye_owner, "hud enabled")
|
||||
|
||||
/obj/item/organ/internal/cyberimp/eyes/hud/Insert(mob/living/carbon/eye_owner, special = FALSE, movement_flags)
|
||||
/obj/item/organ/internal/cyberimp/eyes/hud/mob_insert(mob/living/carbon/eye_owner, special = FALSE, movement_flags)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
eye_owner.add_traits(HUD_traits, ORGAN_TRAIT)
|
||||
toggled_on = TRUE
|
||||
|
||||
/obj/item/organ/internal/cyberimp/eyes/hud/Remove(mob/living/carbon/eye_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/cyberimp/eyes/hud/mob_remove(mob/living/carbon/eye_owner, special, movement_flags)
|
||||
. = ..()
|
||||
eye_owner.remove_traits(HUD_traits, ORGAN_TRAIT)
|
||||
toggled_on = FALSE
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/obj/item/organ/internal/cyberimp
|
||||
name = "cybernetic implant"
|
||||
desc = "A state-of-the-art implant that improves a baseline's functionality."
|
||||
visual = FALSE
|
||||
|
||||
organ_flags = ORGAN_ROBOTIC
|
||||
failing_desc = "seems to be broken."
|
||||
var/implant_color = COLOR_WHITE
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
desc = "There are three parts to the ear. Inner, middle and outer. Only one of these parts should be normally visible."
|
||||
zone = BODY_ZONE_HEAD
|
||||
slot = ORGAN_SLOT_EARS
|
||||
visual = FALSE
|
||||
gender = PLURAL
|
||||
|
||||
healing_factor = STANDARD_ORGAN_HEALING
|
||||
@@ -136,28 +135,34 @@
|
||||
icon_state = "kitty"
|
||||
visual = TRUE
|
||||
damage_multiplier = 2
|
||||
// Keeps track of which cat ears sprite is associated with this.
|
||||
var/variant = "Cat"
|
||||
|
||||
/obj/item/organ/internal/ears/cat/Initialize(mapload, variant_pref)
|
||||
. = ..()
|
||||
if(variant_pref)
|
||||
variant = variant_pref
|
||||
preference = "feature_human_ears"
|
||||
|
||||
/obj/item/organ/internal/ears/cat/on_mob_insert(mob/living/carbon/human/ear_owner)
|
||||
. = ..()
|
||||
if(istype(ear_owner) && ear_owner.dna)
|
||||
color = ear_owner.hair_color
|
||||
ear_owner.dna.features["ears"] = ear_owner.dna.species.mutant_bodyparts["ears"] = variant
|
||||
ear_owner.dna.update_uf_block(DNA_EARS_BLOCK)
|
||||
ear_owner.update_body()
|
||||
dna_block = DNA_EARS_BLOCK
|
||||
|
||||
/obj/item/organ/internal/ears/cat/on_mob_remove(mob/living/carbon/human/ear_owner)
|
||||
. = ..()
|
||||
if(istype(ear_owner) && ear_owner.dna)
|
||||
color = ear_owner.hair_color
|
||||
ear_owner.dna.species.mutant_bodyparts -= "ears"
|
||||
ear_owner.update_body()
|
||||
bodypart_overlay = /datum/bodypart_overlay/mutant/cat_ears
|
||||
|
||||
/// Bodypart overlay for the horrible cat ears
|
||||
/datum/bodypart_overlay/mutant/cat_ears
|
||||
layers = EXTERNAL_FRONT | EXTERNAL_ADJACENT
|
||||
color_source = ORGAN_COLOR_HAIR
|
||||
feature_key = "ears"
|
||||
|
||||
/// We dont color the inner part, which is the front layer
|
||||
var/colorless_layer = EXTERNAL_FRONT
|
||||
|
||||
/datum/bodypart_overlay/mutant/cat_ears/get_global_feature_list()
|
||||
return SSaccessories.ears_list
|
||||
|
||||
/datum/bodypart_overlay/mutant/cat_ears/can_draw_on_bodypart(mob/living/carbon/human/human)
|
||||
if((human.head?.flags_inv & HIDEHAIR) || (human.wear_mask?.flags_inv & HIDEHAIR))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/bodypart_overlay/mutant/cat_ears/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
|
||||
if(draw_layer != bitflag_to_layer(colorless_layer))
|
||||
return ..()
|
||||
return overlay
|
||||
|
||||
/obj/item/organ/internal/ears/penguin
|
||||
name = "penguin ears"
|
||||
|
||||
@@ -52,21 +52,18 @@
|
||||
/// Native FOV that will be applied if a config is enabled
|
||||
var/native_fov = FOV_90_DEGREES
|
||||
|
||||
/obj/item/organ/internal/eyes/Insert(mob/living/carbon/eye_recipient, special = FALSE, movement_flags = DELETE_IF_REPLACED)
|
||||
/obj/item/organ/internal/eyes/mob_insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
// If we don't do this before everything else, heterochromia will be reset leading to eye_color_right no longer being accurate
|
||||
if(ishuman(eye_recipient))
|
||||
var/mob/living/carbon/human/human_recipient = eye_recipient
|
||||
if(ishuman(receiver))
|
||||
var/mob/living/carbon/human/human_recipient = receiver
|
||||
old_eye_color_left = human_recipient.eye_color_left
|
||||
old_eye_color_right = human_recipient.eye_color_right
|
||||
|
||||
. = ..()
|
||||
|
||||
if(!.)
|
||||
return
|
||||
|
||||
eye_recipient.cure_blind(NO_EYES)
|
||||
receiver.cure_blind(NO_EYES)
|
||||
apply_damaged_eye_effects()
|
||||
refresh(eye_recipient, call_update = TRUE)
|
||||
refresh(receiver, call_update = TRUE)
|
||||
|
||||
/// Refreshes the visuals of the eyes
|
||||
/// If call_update is TRUE, we also will call update_body
|
||||
@@ -94,31 +91,32 @@
|
||||
if(call_update)
|
||||
affected_human.update_body()
|
||||
|
||||
/obj/item/organ/internal/eyes/Remove(mob/living/carbon/eye_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/eyes/mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
. = ..()
|
||||
if(ishuman(eye_owner))
|
||||
var/mob/living/carbon/human/human_owner = eye_owner
|
||||
|
||||
if(ishuman(organ_owner))
|
||||
var/mob/living/carbon/human/human_owner = organ_owner
|
||||
if(initial(eye_color_left))
|
||||
human_owner.eye_color_left = old_eye_color_left
|
||||
if(initial(eye_color_right))
|
||||
human_owner.eye_color_right = old_eye_color_right
|
||||
if(native_fov)
|
||||
eye_owner.remove_fov_trait(type)
|
||||
organ_owner.remove_fov_trait(type)
|
||||
if(!special)
|
||||
human_owner.update_body()
|
||||
|
||||
// Cure blindness from eye damage
|
||||
eye_owner.cure_blind(EYE_DAMAGE)
|
||||
eye_owner.cure_nearsighted(EYE_DAMAGE)
|
||||
organ_owner.cure_blind(EYE_DAMAGE)
|
||||
organ_owner.cure_nearsighted(EYE_DAMAGE)
|
||||
// Eye blind and temp blind go to, even if this is a bit of cheesy way to clear blindness
|
||||
eye_owner.remove_status_effect(/datum/status_effect/eye_blur)
|
||||
eye_owner.remove_status_effect(/datum/status_effect/temporary_blindness)
|
||||
organ_owner.remove_status_effect(/datum/status_effect/eye_blur)
|
||||
organ_owner.remove_status_effect(/datum/status_effect/temporary_blindness)
|
||||
// Then become blind anyways (if not special)
|
||||
if(!special)
|
||||
eye_owner.become_blind(NO_EYES)
|
||||
organ_owner.become_blind(NO_EYES)
|
||||
|
||||
eye_owner.update_tint()
|
||||
eye_owner.update_sight()
|
||||
organ_owner.update_tint()
|
||||
organ_owner.update_sight()
|
||||
|
||||
#define OFFSET_X 1
|
||||
#define OFFSET_Y 2
|
||||
@@ -428,7 +426,7 @@
|
||||
deactivate(close_ui = TRUE)
|
||||
|
||||
/// Set the initial color of the eyes on insert to be the mob's previous eye color.
|
||||
/obj/item/organ/internal/eyes/robotic/glow/Insert(mob/living/carbon/eye_recipient, special = FALSE, movement_flags = DELETE_IF_REPLACED)
|
||||
/obj/item/organ/internal/eyes/robotic/glow/mob_insert(mob/living/carbon/eye_recipient, special = FALSE, movement_flags = DELETE_IF_REPLACED)
|
||||
. = ..()
|
||||
left_eye_color_string = old_eye_color_left
|
||||
right_eye_color_string = old_eye_color_right
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
desc = "I feel bad for the heartless bastard who lost this."
|
||||
icon_state = "heart-on"
|
||||
base_icon_state = "heart"
|
||||
visual = FALSE
|
||||
|
||||
zone = BODY_ZONE_CHEST
|
||||
slot = ORGAN_SLOT_HEART
|
||||
item_flags = NO_BLOOD_ON_ITEM
|
||||
|
||||
@@ -21,15 +21,14 @@
|
||||
add_atom_colour(ethereal_color, FIXED_COLOUR_PRIORITY)
|
||||
update_appearance()
|
||||
|
||||
/obj/item/organ/internal/heart/ethereal/Insert(mob/living/carbon/heart_owner, special = FALSE, movement_flags)
|
||||
/obj/item/organ/internal/heart/ethereal/mob_insert(mob/living/carbon/heart_owner, special = FALSE, movement_flags)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
RegisterSignal(heart_owner, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_change))
|
||||
RegisterSignal(heart_owner, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(on_owner_fully_heal))
|
||||
RegisterSignal(heart_owner, COMSIG_QDELETING, PROC_REF(owner_deleted))
|
||||
|
||||
/obj/item/organ/internal/heart/ethereal/Remove(mob/living/carbon/heart_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/heart/ethereal/mob_remove(mob/living/carbon/heart_owner, special, movement_flags)
|
||||
UnregisterSignal(heart_owner, list(COMSIG_MOB_STATCHANGE, COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_QDELETING))
|
||||
REMOVE_TRAIT(heart_owner, TRAIT_CORPSELOCKED, SPECIES_TRAIT)
|
||||
stop_crystalization_process(heart_owner)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
name = "liver"
|
||||
desc = "Pairing suggestion: chianti and fava beans."
|
||||
icon_state = "liver"
|
||||
visual = FALSE
|
||||
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
zone = BODY_ZONE_CHEST
|
||||
slot = ORGAN_SLOT_LIVER
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/obj/item/organ/internal/lungs
|
||||
name = "lungs"
|
||||
icon_state = "lungs"
|
||||
visual = FALSE
|
||||
|
||||
zone = BODY_ZONE_CHEST
|
||||
slot = ORGAN_SLOT_LUNGS
|
||||
gender = PLURAL
|
||||
@@ -154,17 +154,16 @@
|
||||
add_gas_reaction(/datum/gas/zauker, while_present = PROC_REF(too_much_zauker))
|
||||
|
||||
///Simply exists so that you don't keep any alerts from your previous lack of lungs.
|
||||
/obj/item/organ/internal/lungs/Insert(mob/living/carbon/receiver, special = FALSE, movement_flags)
|
||||
/obj/item/organ/internal/lungs/mob_insert(mob/living/carbon/receiver, special = FALSE, movement_flags)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return .
|
||||
|
||||
receiver.clear_alert(ALERT_NOT_ENOUGH_OXYGEN)
|
||||
receiver.clear_alert(ALERT_NOT_ENOUGH_CO2)
|
||||
receiver.clear_alert(ALERT_NOT_ENOUGH_NITRO)
|
||||
receiver.clear_alert(ALERT_NOT_ENOUGH_PLASMA)
|
||||
receiver.clear_alert(ALERT_NOT_ENOUGH_N2O)
|
||||
|
||||
/obj/item/organ/internal/lungs/Remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/lungs/mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
. = ..()
|
||||
// This is very "manual" I realize, but it's useful to ensure cleanup for gases we're removing happens
|
||||
// Avoids stuck alerts and such
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
name = "stomach"
|
||||
desc = "Onaka ga suite imasu."
|
||||
icon_state = "stomach"
|
||||
visual = FALSE
|
||||
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
zone = BODY_ZONE_CHEST
|
||||
slot = ORGAN_SLOT_STOMACH
|
||||
@@ -246,11 +246,11 @@
|
||||
disgusted.throw_alert(ALERT_DISGUST, /atom/movable/screen/alert/disgusted)
|
||||
disgusted.add_mood_event("disgust", /datum/mood_event/disgusted)
|
||||
|
||||
/obj/item/organ/internal/stomach/Insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
/obj/item/organ/internal/stomach/mob_insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
. = ..()
|
||||
receiver.hud_used?.hunger?.update_appearance()
|
||||
|
||||
/obj/item/organ/internal/stomach/Remove(mob/living/carbon/stomach_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/stomach/mob_remove(mob/living/carbon/stomach_owner, special, movement_flags)
|
||||
if(ishuman(stomach_owner))
|
||||
var/mob/living/carbon/human/human_owner = owner
|
||||
human_owner.clear_alert(ALERT_DISGUST)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "tongue"
|
||||
desc = "A fleshy muscle mostly used for lying."
|
||||
icon_state = "tongue"
|
||||
visual = FALSE
|
||||
|
||||
zone = BODY_ZONE_PRECISE_MOUTH
|
||||
slot = ORGAN_SLOT_TONGUE
|
||||
attack_verb_continuous = list("licks", "slobbers", "slaps", "frenches", "tongues")
|
||||
@@ -124,30 +124,30 @@
|
||||
food_taste_reaction = FOOD_LIKED
|
||||
return food_taste_reaction
|
||||
|
||||
/obj/item/organ/internal/tongue/Insert(mob/living/carbon/tongue_owner, special = FALSE, movement_flags)
|
||||
/obj/item/organ/internal/tongue/mob_insert(mob/living/carbon/receiver, special, movement_flags)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(modifies_speech)
|
||||
RegisterSignal(tongue_owner, COMSIG_MOB_SAY, PROC_REF(handle_speech))
|
||||
tongue_owner.voice_filter = voice_filter
|
||||
RegisterSignal(receiver, COMSIG_MOB_SAY, PROC_REF(handle_speech))
|
||||
receiver.voice_filter = voice_filter
|
||||
/* This could be slightly simpler, by making the removal of the
|
||||
* NO_TONGUE_TRAIT conditional on the tongue's `sense_of_taste`, but
|
||||
* then you can distinguish between ageusia from no tongue, and
|
||||
* ageusia from having a non-tasting tongue.
|
||||
*/
|
||||
REMOVE_TRAIT(tongue_owner, TRAIT_AGEUSIA, NO_TONGUE_TRAIT)
|
||||
REMOVE_TRAIT(receiver, TRAIT_AGEUSIA, NO_TONGUE_TRAIT)
|
||||
apply_tongue_effects()
|
||||
|
||||
/obj/item/organ/internal/tongue/Remove(mob/living/carbon/tongue_owner, special, movement_flags)
|
||||
/obj/item/organ/internal/tongue/mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
. = ..()
|
||||
|
||||
temp_say_mod = ""
|
||||
UnregisterSignal(tongue_owner, COMSIG_MOB_SAY)
|
||||
REMOVE_TRAIT(tongue_owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE)
|
||||
REMOVE_TRAIT(tongue_owner, TRAIT_AGEUSIA, ORGAN_TRAIT)
|
||||
UnregisterSignal(organ_owner, COMSIG_MOB_SAY)
|
||||
REMOVE_TRAIT(organ_owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE)
|
||||
REMOVE_TRAIT(organ_owner, TRAIT_AGEUSIA, ORGAN_TRAIT)
|
||||
// Carbons by default start with NO_TONGUE_TRAIT caused TRAIT_AGEUSIA
|
||||
ADD_TRAIT(tongue_owner, TRAIT_AGEUSIA, NO_TONGUE_TRAIT)
|
||||
tongue_owner.voice_filter = initial(tongue_owner.voice_filter)
|
||||
ADD_TRAIT(organ_owner, TRAIT_AGEUSIA, NO_TONGUE_TRAIT)
|
||||
organ_owner.voice_filter = initial(organ_owner.voice_filter)
|
||||
|
||||
/obj/item/organ/internal/tongue/apply_organ_damage(damage_amount, maximum = maxHealth, required_organ_flag)
|
||||
. = ..()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/obj/item/organ/internal/vocal_cords //organs that are activated through speech with the :x/MODE_KEY_VOCALCORDS channel
|
||||
name = "vocal cords"
|
||||
icon_state = "appendix"
|
||||
visual = FALSE
|
||||
zone = BODY_ZONE_PRECISE_MOUTH
|
||||
slot = ORGAN_SLOT_VOICE
|
||||
gender = PLURAL
|
||||
@@ -87,7 +86,6 @@
|
||||
next_command = world.time + (cooldown * cooldown_mod)
|
||||
|
||||
/obj/item/organ/internal/adamantine_resonator
|
||||
visual = FALSE
|
||||
name = "adamantine resonator"
|
||||
desc = "Fragments of adamantine exist in all golems, stemming from their origins as purely magical constructs. These are used to \"hear\" messages from their leaders."
|
||||
zone = BODY_ZONE_HEAD
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
mob_insert(receiver, special, movement_flags)
|
||||
bodypart_insert(limb_owner = receiver, movement_flags = movement_flags)
|
||||
|
||||
return TRUE
|
||||
if(!special)
|
||||
receiver.update_body_parts()
|
||||
|
||||
/*
|
||||
* Remove the organ from the select mob.
|
||||
@@ -32,6 +33,9 @@
|
||||
mob_remove(organ_owner, special, movement_flags)
|
||||
bodypart_remove(limb_owner = organ_owner, movement_flags = movement_flags)
|
||||
|
||||
if(!special)
|
||||
organ_owner.update_body_parts()
|
||||
|
||||
/*
|
||||
* Insert the organ into the select mob.
|
||||
*
|
||||
@@ -65,6 +69,11 @@
|
||||
wash(CLEAN_TYPE_BLOOD)
|
||||
organ_flags &= ~ORGAN_VIRGIN
|
||||
|
||||
if(external_bodytypes)
|
||||
receiver.synchronize_bodytypes()
|
||||
if(external_bodyshapes)
|
||||
receiver.synchronize_bodyshapes()
|
||||
|
||||
receiver.organs |= src
|
||||
receiver.organs_slot[slot] = src
|
||||
owner = receiver
|
||||
@@ -120,6 +129,9 @@
|
||||
ADD_TRAIT(src, TRAIT_NODROP, ORGAN_INSIDE_BODY_TRAIT)
|
||||
interaction_flags_item &= ~INTERACT_ITEM_ATTACK_HAND_PICKUP
|
||||
|
||||
if(bodypart_overlay)
|
||||
limb.add_bodypart_overlay(bodypart_overlay)
|
||||
|
||||
/*
|
||||
* Remove the organ from the select mob.
|
||||
*
|
||||
@@ -163,6 +175,9 @@
|
||||
SEND_SIGNAL(organ_owner, COMSIG_CARBON_LOSE_ORGAN, src, special)
|
||||
ADD_TRAIT(src, TRAIT_USED_ORGAN, ORGAN_TRAIT)
|
||||
|
||||
organ_owner.synchronize_bodytypes()
|
||||
organ_owner.synchronize_bodyshapes()
|
||||
|
||||
var/list/diseases = organ_owner.get_static_viruses()
|
||||
if(!LAZYLEN(diseases))
|
||||
return
|
||||
@@ -211,6 +226,16 @@
|
||||
REMOVE_TRAIT(src, TRAIT_NODROP, ORGAN_INSIDE_BODY_TRAIT)
|
||||
interaction_flags_item |= INTERACT_ITEM_ATTACK_HAND_PICKUP
|
||||
|
||||
if(!bodypart_overlay)
|
||||
return
|
||||
|
||||
limb.remove_bodypart_overlay(bodypart_overlay)
|
||||
|
||||
if(use_mob_sprite_as_obj_sprite)
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
|
||||
color = bodypart_overlay.draw_color // so a pink felinid doesn't drop a gray tail
|
||||
|
||||
/// In space station videogame, nothing is sacred. If somehow an organ is removed unexpectedly, handle it properly
|
||||
/obj/item/organ/proc/forced_removal()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/datum/unit_test/organ_bodypart_shuffle
|
||||
|
||||
/datum/unit_test/organ_bodypart_shuffle/Run()
|
||||
var/mob/living/carbon/human/hollow_boy = allocate(/mob/living/carbon/human/consistent)
|
||||
var/mob/living/carbon/human/hollow_boy = allocate(/mob/living/carbon/human/consistent) //freshly filled with wet insides
|
||||
|
||||
// Test if organs are all properly updating when forcefully removed
|
||||
var/list/removed_organs = list()
|
||||
@@ -30,5 +30,3 @@
|
||||
continue
|
||||
TEST_ASSERT(organ in hollow_boy.organs, "Organ '[organ.name] was put in an empty bodypart that replaced a humans, but the organ did not come with.")
|
||||
|
||||
// Test if bodyparts are all properly updating when forcefully removed
|
||||
hollow_boy = allocate(/mob/living/carbon/human/consistent) //freshly filled with wet insides
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
// Attempt to insert entire list of mutant organs for the given infusion_entry.
|
||||
for(var/obj/item/organ/organ as anything in output_organs)
|
||||
organ = new organ()
|
||||
TEST_ASSERT(organ.Insert(lab_rat, special = TRUE, movement_flags = DELETE_IF_REPLACED), "The organ `[organ.type]` for `[infuser_entry.type]` was not inserted in the mob when expected, Insert() returned falsy when TRUE was expected.")
|
||||
organ.Insert(lab_rat, special = TRUE, movement_flags = DELETE_IF_REPLACED)
|
||||
inserted_organs += organ
|
||||
|
||||
// Search for added Status Effect.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
desc = "An implant that can be placed in a user's head to control circuits using their brain."
|
||||
icon = 'icons/obj/science/circuits.dmi'
|
||||
icon_state = "bci"
|
||||
visual = FALSE
|
||||
zone = BODY_ZONE_HEAD
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -6028,7 +6028,7 @@
|
||||
#include "code\modules\surgery\organs\autosurgeon.dm"
|
||||
#include "code\modules\surgery\organs\helpers.dm"
|
||||
#include "code\modules\surgery\organs\organ_movement.dm"
|
||||
#include "code\modules\surgery\organs\external\_external_organ.dm"
|
||||
#include "code\modules\surgery\organs\external\_visual_organs.dm"
|
||||
#include "code\modules\surgery\organs\external\restyling.dm"
|
||||
#include "code\modules\surgery\organs\external\spines.dm"
|
||||
#include "code\modules\surgery\organs\external\tails.dm"
|
||||
|
||||
Reference in New Issue
Block a user