diff --git a/__DEFINES/colors.dm b/__DEFINES/colors.dm
index ad5404c0813..201b2a1cbbe 100644
--- a/__DEFINES/colors.dm
+++ b/__DEFINES/colors.dm
@@ -16,3 +16,8 @@
#define COLOR_GLUE "#FFFFCC"
#define COLOR_BEESWAX "#FFB700"
#define COLOR_DEFAULT_CANDLE "#BE0000"
+#define COLOR_RED "#FF0000"
+#define COLOR_GREEN "#00FF00"
+#define COLOR_BLUE "#0000FF"
+
+#define COLOR_MATRIX_ADD(color) list(COLOR_RED, COLOR_GREEN, COLOR_BLUE, color)
diff --git a/__DEFINES/limb_defines.dm b/__DEFINES/limb_defines.dm
index 3179ab63844..266e7f382d2 100644
--- a/__DEFINES/limb_defines.dm
+++ b/__DEFINES/limb_defines.dm
@@ -15,3 +15,5 @@
#define UNCUFF_LEGS -1
#define UNCUFF_BOTH 0
#define UNCUFF_HANDS 1
+
+#define COSMETIC_ORGAN_TAIL "tail"
diff --git a/__DEFINES/setup.dm b/__DEFINES/setup.dm
index 559089e54b5..6c6dfeb7b01 100644
--- a/__DEFINES/setup.dm
+++ b/__DEFINES/setup.dm
@@ -326,6 +326,7 @@ var/MAX_EXPLOSION_RANGE = 32
#define ARM_RIGHT 256
#define HAND_LEFT 512
#define HAND_RIGHT 1024
+#define TAIL 524288
// bitflags for clothing parts
@@ -352,6 +353,7 @@ var/MAX_EXPLOSION_RANGE = 32
#define HIDEEARS EARS
#define HIDEEYES EYES
#define HIDEFACE FACE
+#define HIDETAIL TAIL
#define HIDEHEADHAIR 65536
#define MASKHEADHAIR 131072
#define HIDEBEARDHAIR BEARD
@@ -1006,6 +1008,7 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse
#define ACID4WATER 4096 //Acid now acts like water, and vice versa.
#define NO_BALD 8192 //cannot lose hair through being shaved/radiation/etc
#define RGBSKINTONE 16384
+#define HAS_ICON_SKIN_TONE 32768
var/default_colour_matrix = list(1,0,0,0,\
0,1,0,0,\
@@ -1252,29 +1255,31 @@ var/default_colour_matrix = list(1,0,0,0,\
//Human Overlays Indexes/////////THIS DEFINES WHAT LAYERS APPEARS ON TOP OF OTHERS
#define FIRE_LAYER 1 //If you're on fire (/tg/ shit)
#define MUTANTRACE_LAYER 2 //TODO: make part of body?
-#define MUTATIONS_LAYER 3
-#define DAMAGE_LAYER 4
-#define UNIFORM_LAYER 5
-#define SHOES_LAYER 6
-#define GLOVES_LAYER 7
-#define EARS_LAYER 8
-#define SUIT_LAYER 9
-#define GLASSES_LAYER 10
-#define BELT_LAYER 11 //Possible make this an overlay of somethign required to wear a belt?
-#define SUIT_STORE_LAYER 12
-#define HAIR_LAYER 13 //TODO: make part of head layer?
-#define GLASSES_OVER_HAIR_LAYER 14
-#define FACEMASK_LAYER 15
-#define HEAD_LAYER 16
-#define BACK_LAYER 17 //Back should be above head so that headgear doesn't hides backpack when facing north
-#define ID_LAYER 18 //IDs should be visible above suits and backpacks
-#define HANDCUFF_LAYER 19
-#define MUTUALCUFF_LAYER 20
-#define LEGCUFF_LAYER 21
-#define HAND_LAYER 22
-#define TAIL_LAYER 23 //bs12 specific. this hack is probably gonna come back to haunt me
-#define TARGETED_LAYER 24 //BS12: Layer for the target overlay from weapon targeting system
-#define TOTAL_LAYERS 24
+#define TAIL_UNDERLIMBS_LAYER 3
+#define LIMBS_LAYER 4
+#define MUTATIONS_LAYER 5
+#define DAMAGE_LAYER 6
+#define UNIFORM_LAYER 7
+#define SHOES_LAYER 8
+#define GLOVES_LAYER 9
+#define EARS_LAYER 10
+#define SUIT_LAYER 11
+#define GLASSES_LAYER 12
+#define BELT_LAYER 13 //Possible make this an overlay of somethign required to wear a belt?
+#define SUIT_STORE_LAYER 14
+#define HAIR_LAYER 15 //TODO: make part of head layer?
+#define GLASSES_OVER_HAIR_LAYER 16
+#define TAIL_LAYER 17
+#define FACEMASK_LAYER 18
+#define HEAD_LAYER 19
+#define BACK_LAYER 20 //Back should be above head so that headgear doesn't hides backpack when facing north
+#define ID_LAYER 21 //IDs should be visible above suits and backpacks
+#define HANDCUFF_LAYER 22
+#define MUTUALCUFF_LAYER 23
+#define LEGCUFF_LAYER 24
+#define HAND_LAYER 25
+#define TARGETED_LAYER 26 //BS12: Layer for the target overlay from weapon targeting system
+#define TOTAL_LAYERS 26
//////////////////////////////////
//Snake stuff so leaderboard can see it too
diff --git a/__DEFINES/span.dm b/__DEFINES/span.dm
new file mode 100644
index 00000000000..bf07f4e4fe3
--- /dev/null
+++ b/__DEFINES/span.dm
@@ -0,0 +1,2 @@
+// Sorted alphabetically
+#define span_warning(str) ("" + str + "")
diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm
index 920e192fbe0..9fd72b04937 100644
--- a/code/datums/emotes.dm
+++ b/code/datums/emotes.dm
@@ -1,5 +1,6 @@
-#define EMOTE_VISIBLE 1
-#define EMOTE_AUDIBLE 2
+#define EMOTE_VISIBLE (1<<0)
+#define EMOTE_AUDIBLE (1<<1)
+#define EMOTE_NO_RUNECHAT (1<<2)
/* Emote datums, ported from TG station. */
@@ -66,17 +67,19 @@
if (user.client && M?.client?.prefs.mob_chat_on_map && get_dist(M, user) < M?.client.view)
M.create_chat_message(user, null, msg_runechat, "", list("italics"))
- if (emote_type == EMOTE_VISIBLE)
+ if(emote_type & EMOTE_VISIBLE)
user.visible_message(msg)
- for(var/z0 in GetOpenConnectedZlevels(user))
- for (var/mob/O in viewers(world.view, locate(user.x,user.y,z0)))
- if (user.client && O?.client?.prefs.mob_chat_on_map && O.stat != UNCONSCIOUS && !(isinvisible(user)))
- O.create_chat_message(user, null, msg_runechat, "", list("italics"))
- else
+ if(!(emote_type & EMOTE_NO_RUNECHAT))
+ for(var/z0 in GetOpenConnectedZlevels(user))
+ for (var/mob/O in viewers(world.view, locate(user.x,user.y,z0)))
+ if (user.client && O?.client?.prefs.mob_chat_on_map && O.stat != UNCONSCIOUS && !(isinvisible(user)))
+ O.create_chat_message(user, null, msg_runechat, "", list("italics"))
+ else if(emote_type & EMOTE_AUDIBLE)
for(var/mob/O in get_hearers_in_view(world.view, user))
O.show_message(msg)
- if (user.client && O?.client?.prefs.mob_chat_on_map && O.stat != UNCONSCIOUS && !O.is_deaf())
- O.create_chat_message(user, null, msg_runechat, "", list("italics"))
+ if(!(emote_type & EMOTE_NO_RUNECHAT))
+ if(user.client && O?.client?.prefs.mob_chat_on_map && O.stat != UNCONSCIOUS && !O.is_deaf())
+ O.create_chat_message(user, null, msg_runechat, "", list("italics"))
var/turf/T = get_turf(user)
var/location = T ? "[T.x],[T.y],[T.z]" : "nullspace"
diff --git a/code/datums/gamemode/dynamic/dynamic_rulesets_midround.dm b/code/datums/gamemode/dynamic/dynamic_rulesets_midround.dm
index 4be4c08f75c..7edaddd1e4a 100644
--- a/code/datums/gamemode/dynamic/dynamic_rulesets_midround.dm
+++ b/code/datums/gamemode/dynamic/dynamic_rulesets_midround.dm
@@ -564,7 +564,7 @@
return ..()
/datum/dynamic_ruleset/midround/from_ghosts/rambler/generate_ruleset_body(mob/applicant)
- var/mob/living/carbon/human/frankenstein/new_frank = new(pick(latejoin))
+ var/mob/living/carbon/human/frankenstein/new_frank = new(pick(latejoin), no_tail = TRUE)
var/gender = pick(MALE, FEMALE)
new_frank.randomise_appearance_for(gender)
new_frank.key = applicant.key
diff --git a/code/datums/mutable_appearance.dm b/code/datums/mutable_appearance.dm
new file mode 100644
index 00000000000..42b72a2f72f
--- /dev/null
+++ b/code/datums/mutable_appearance.dm
@@ -0,0 +1,31 @@
+// Mutable appearances are an inbuilt byond datastructure. Read the documentation on them by hitting F1 in DM.
+// Basically use them instead of images for overlays/underlays and when changing an object's appearance if you're doing so with any regularity.
+// Unless you need the overlay/underlay to have a different direction than the base object. Then you have to use an image due to a bug.
+
+// Mutable appearances are children of images, just so you know.
+
+// Mutable appearances erase template vars on new, because they accept an appearance to copy as an arg
+// If we have nothin to copy, we set the float plane
+/mutable_appearance/New(mutable_appearance/to_copy)
+ ..()
+ if(!to_copy)
+ plane = FLOAT_PLANE
+
+/** Helper similar to image()
+ *
+ * icon - Our appearance's icon
+ * icon_state - Our appearance's icon state
+ * layer - Our appearance's layer
+ * plane - The plane to use for the appearance.
+ * alpha - Our appearance's alpha
+ * appearance_flags - Our appearance's appearance_flags
+**/
+/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER, plane = FLOAT_PLANE, alpha = 255, appearance_flags = NONE)
+ var/mutable_appearance/appearance = new()
+ appearance.icon = icon
+ appearance.icon_state = icon_state
+ appearance.layer = layer
+ appearance.plane = plane
+ appearance.alpha = alpha
+ appearance.appearance_flags |= appearance_flags
+ return appearance
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index d60e0e72c1b..afc5660913a 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -12,6 +12,9 @@
var/brute_dam = 0
var/burn_dam = 0
+/obj/item/robot_parts/proc/on_attach(datum/organ/external/attached_site)
+ return
+
/obj/item/robot_parts/l_arm
name = "robot left arm"
desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case."
@@ -36,6 +39,40 @@
icon_state = LIMB_RIGHT_LEG
part = list(LIMB_RIGHT_LEG,LIMB_RIGHT_FOOT)
+/obj/item/robot_parts/tail
+ name = "robot tail"
+ desc = "A skeletal appendage wrapped in pseudomuscles, with a low-conductivity case."
+ icon_state = null
+ part = list(COSMETIC_ORGAN_TAIL)
+ var/tail_icon_file = 'icons/mob/tails.dmi'
+ var/tail_type = "vox"
+ var/static/list/tail_icons = list()
+
+/obj/item/robot_parts/tail/New(loc, type_of_tail)
+ if(type_of_tail)
+ tail_type = type_of_tail
+ update_icon()
+ return ..()
+
+/obj/item/robot_parts/tail/on_attach(datum/organ/external/tail/attached_site)
+ attached_site.tail_type = tail_type
+
+/obj/item/robot_parts/tail/attackby(obj/item/W, mob/user)
+ if(!ismultitool(W))
+ return ..()
+ var/type_of_tail = input(user, "Configure tail type", "Robotic tail design", "vox") as null|anything in list("vox", "tajaran", "unathi")
+ tail_type = type_of_tail
+ update_icon()
+
+/obj/item/robot_parts/tail/update_icon()
+ var/returned_tail_icon = tail_icons[tail_type]
+ if(!returned_tail_icon)
+ var/icon/new_tail_icon = icon(tail_icon_file, "[tail_type]_robotic_BEHIND", EAST)
+ new_tail_icon.Shift(EAST, 6)
+ new_tail_icon.Shift(NORTH, 3)
+ returned_tail_icon = tail_icons[tail_type] = new_tail_icon
+ icon = returned_tail_icon
+
/obj/item/robot_parts/chest
name = "robot torso"
desc = "A heavily reinforced case containing cyborg logic boards, with space for a standard power cell."
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index e1d100fab90..f0a3937c35c 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -1027,7 +1027,7 @@ var/global/maxStackDepth = 10
permeability_coefficient = 0.02
flags = FPRINT
pressure_resistance = 5 * ONE_ATMOSPHERE
- body_parts_covered = ARMS|LEGS|FULL_TORSO|FEET|HANDS
+ body_parts_covered = ARMS|LEGS|FULL_TORSO|FEET|HANDS|TAIL
allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/)
slowdown = HARDSUIT_SLOWDOWN_BULKY
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 50)
diff --git a/code/modules/clothing/spacesuits/captain.dm b/code/modules/clothing/spacesuits/captain.dm
index 65ace76c0b2..58fa127e733 100644
--- a/code/modules/clothing/spacesuits/captain.dm
+++ b/code/modules/clothing/spacesuits/captain.dm
@@ -54,7 +54,7 @@
permeability_coefficient = 0.02
clothing_flags = ONESIZEFITSALL
pressure_resistance = 200 * ONE_ATMOSPHERE
- body_parts_covered = ARMS|LEGS|FULL_TORSO|FEET
+ body_parts_covered = ARMS|LEGS|FULL_TORSO|FEET|TAIL
allowed = list(/obj/item/weapon/tank, /obj/item/weapon/tank/emergency_oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy, /obj/item/weapon/gun/projectile, /obj/item/ammo_storage, /obj/item/ammo_casing, /obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/tank/emergency_nitrogen)
slowdown = HARDSUIT_SLOWDOWN_HIGH
armor = list(melee = 65, bullet = 50, laser = 50, energy = 25, bomb = 50, bio = 100, rad = 50)
diff --git a/code/modules/clothing/suits/bio.dm b/code/modules/clothing/suits/bio.dm
index ce7618f0091..91d7a9ef09f 100644
--- a/code/modules/clothing/suits/bio.dm
+++ b/code/modules/clothing/suits/bio.dm
@@ -25,7 +25,7 @@
permeability_coefficient = 0.01
flags = FPRINT
clothing_flags = PLASMAGUARD
- body_parts_covered = ARMS|LEGS|FULL_TORSO|FEET|HANDS
+ body_parts_covered = ARMS|LEGS|FULL_TORSO|FEET|HANDS|TAIL
slowdown = HARDSUIT_SLOWDOWN_LOW
allowed = list(/obj/item/weapon/tank/emergency_oxygen,/obj/item/weapon/tank/emergency_nitrogen,/obj/item/weapon/pen,/obj/item/device/flashlight/pen)
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 20)
diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm
index 9425bf14638..6bb13285842 100644
--- a/code/modules/clothing/suits/miscellaneous.dm
+++ b/code/modules/clothing/suits/miscellaneous.dm
@@ -487,7 +487,7 @@ var/list/tag_suits_list = list()
icon_state = "strait_jacket"
item_state = "strait_jacket"
origin_tech = Tc_BIOTECH + "=2"
- body_parts_covered = ARMS|LEGS|FULL_TORSO|FEET|HANDS
+ body_parts_covered = ARMS|LEGS|FULL_TORSO|FEET|HANDS|TAIL
species_fit = list(INSECT_SHAPED)
/obj/item/clothing/suit/ianshirt
diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm
index 0a08c5f5413..95079c14c0e 100644
--- a/code/modules/clothing/suits/utility.dm
+++ b/code/modules/clothing/suits/utility.dm
@@ -18,7 +18,7 @@
w_class = W_CLASS_LARGE//bulky item
gas_transfer_coefficient = 0.90
permeability_coefficient = 0.50
- body_parts_covered = ARMS|LEGS|FULL_TORSO|FEET|HANDS
+ body_parts_covered = ARMS|LEGS|FULL_TORSO|FEET|HANDS|TAIL
allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/emergency_oxygen,/obj/item/weapon/tank/emergency_nitrogen,/obj/item/weapon/extinguisher,/obj/item/tool/irons,/obj/item/tool/crowbar/halligan)
slowdown = HARDSUIT_SLOWDOWN_LOW
clothing_flags = ONESIZEFITSALL
@@ -85,6 +85,7 @@
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01
flags = FPRINT
+ body_parts_covered = ARMS|LEGS|FULL_TORSO|TAIL
slowdown = HARDSUIT_SLOWDOWN_HIGH
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 100, bio = 0, rad = 0)
max_heat_protection_temperature = ARMOR_MAX_HEAT_PROTECTION_TEMPERATURE
@@ -157,7 +158,7 @@
w_class = W_CLASS_LARGE//bulky item
gas_transfer_coefficient = 0.90
permeability_coefficient = 0.50
- body_parts_covered = FULL_BODY
+ body_parts_covered = FULL_BODY|TAIL
allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/emergency_oxygen,/obj/item/weapon/tank/emergency_nitrogen)
slowdown = 1.5
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100)
diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm
index 70a1793e5f8..24c8bc44589 100644
--- a/code/modules/mob/emote.dm
+++ b/code/modules/mob/emote.dm
@@ -75,16 +75,18 @@
if(isobserver(M) && M.client.prefs && (M.client.prefs.toggles & CHAT_GHOSTSIGHT) && !(M in viewers(user)))
M.show_message("(Follow) " + msg)
- if (emote_type == EMOTE_VISIBLE)
+ if(emote_type & EMOTE_VISIBLE)
user.visible_message(msg)
- for(var/mob/O in viewers(world.view, user))
- if (O.client && O?.client?.prefs.mob_chat_on_map && get_dist(O, user) < O?.client.view)
- O.create_chat_message(user, null, message, "", list("italics"))
- else
+ if(!(emote_type & EMOTE_NO_RUNECHAT))
+ for(var/mob/O in viewers(world.view, user))
+ if(O.client && O?.client?.prefs.mob_chat_on_map && get_dist(O, user) < O?.client.view)
+ O.create_chat_message(user, null, message, "", list("italics"))
+ else if(emote_type & EMOTE_AUDIBLE)
for(var/mob/O in get_hearers_in_view(world.view, user))
O.show_message(msg)
- if (O.client && O?.client?.prefs.mob_chat_on_map && get_dist(O, user) < O?.client.view)
- O.create_chat_message(user, null, message, "", list("italics"))
+ if(!(emote_type & EMOTE_NO_RUNECHAT))
+ if(O.client && O?.client?.prefs.mob_chat_on_map && get_dist(O, user) < O?.client.view)
+ O.create_chat_message(user, null, message, "", list("italics"))
var/location = T ? "[T.x],[T.y],[T.z]" : "nullspace"
log_emote("[user.name]/[user.key] (@[location]): [message]")
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index fcff75175f3..68013d85a65 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -14,6 +14,8 @@
if(prob(100 - E.get_damage()))
//Override the current limb status and don't cause an explosion
E.droplimb(1, 1)
+ for(var/datum/organ/external/cosmetic_organ in cosmetic_organs)
+ cosmetic_organ.droplimb(TRUE, TRUE)
var/gib_radius = 0
if(reagents.has_reagent(LUBE))
gib_radius = 6 //Your insides are all lubed, so gibs travel much further
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index ad557589825..d23693d0ee5 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -97,7 +97,7 @@
..(new_loc)
initialize_basic_NPC_components()
-/mob/living/carbon/human/frankenstein/New(var/new_loc, delay_ready_dna = 0) //Just fuck my shit up: the mob
+/mob/living/carbon/human/frankenstein/New(var/new_loc, delay_ready_dna = 0, no_tail = FALSE) //Just fuck my shit up: the mob
var/list/valid_species = (all_species - list("Krampus", "Horror", "Manifested"))
var/datum/species/new_species = all_species[pick(valid_species)]
@@ -109,7 +109,20 @@
for(var/datum/organ/external/E in organs)
E.species = all_species[pick(valid_species)]
-
+ var/datum/organ/external/tail/tail_datum = get_cosmetic_organ(COSMETIC_ORGAN_TAIL)
+ if(no_tail)
+ tail_datum.droplimb(TRUE, spawn_limb = FALSE)
+ else
+ var/list/tailed_species = list()
+ for(var/species_name in all_species)
+ var/datum/species/picked_species = all_species[species_name]
+ if(picked_species.anatomy_flags & HAS_TAIL)
+ tailed_species += picked_species
+ var/datum/species/species_with_tail = pick(tailed_species)
+ tail_datum.fleshify()
+ tail_datum.create_tail_info(species_with_tail)
+ tail_datum.species = species_with_tail
+ tail_datum.update_tail(src, random = TRUE)
update_body()
/mob/living/carbon/human/mushroom/New(var/new_loc, delay_ready_dna = 0)
@@ -167,6 +180,8 @@
obj_overlays[FIRE_LAYER] = new /obj/abstract/Overlays/fire_layer
obj_overlays[MUTANTRACE_LAYER] = new /obj/abstract/Overlays/mutantrace_layer
+ obj_overlays[TAIL_UNDERLIMBS_LAYER] = new /obj/abstract/Overlays/tail_underlimbs_layer
+ obj_overlays[LIMBS_LAYER] = new /obj/abstract/Overlays/limbs_layer
obj_overlays[MUTATIONS_LAYER] = new /obj/abstract/Overlays/mutations_layer
obj_overlays[DAMAGE_LAYER] = new /obj/abstract/Overlays/damage_layer
obj_overlays[UNIFORM_LAYER] = new /obj/abstract/Overlays/uniform_layer
@@ -181,13 +196,13 @@
obj_overlays[BACK_LAYER] = new /obj/abstract/Overlays/back_layer
obj_overlays[HAIR_LAYER] = new /obj/abstract/Overlays/hair_layer
obj_overlays[GLASSES_OVER_HAIR_LAYER] = new /obj/abstract/Overlays/glasses_over_hair_layer
+ obj_overlays[TAIL_LAYER] = new /obj/abstract/Overlays/tail_layer
obj_overlays[FACEMASK_LAYER] = new /obj/abstract/Overlays/facemask_layer
obj_overlays[HEAD_LAYER] = new /obj/abstract/Overlays/head_layer
obj_overlays[HANDCUFF_LAYER] = new /obj/abstract/Overlays/handcuff_layer
obj_overlays[MUTUALCUFF_LAYER] = new /obj/abstract/Overlays/mutualcuff_layer
obj_overlays[LEGCUFF_LAYER] = new /obj/abstract/Overlays/legcuff_layer
//obj_overlays[HAND_LAYER] = new /obj/abstract/Overlays/hand_layer
- obj_overlays[TAIL_LAYER] = new /obj/abstract/Overlays/tail_layer
obj_overlays[TARGETED_LAYER] = new /obj/abstract/Overlays/targeted_layer
..()
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index bee1f1fc0ef..d4fd6c8eade 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -307,14 +307,20 @@ This function restores all organs.
return
-/mob/living/carbon/human/get_organ(var/zone)
+/mob/living/carbon/human/get_organ(var/zone, cosmetic = FALSE)
RETURN_TYPE(/datum/organ/external)
if(!zone)
zone = LIMB_CHEST
if (zone in list( "eyes", "mouth" ))
zone = LIMB_HEAD
- return organs_by_name[zone]
+ var/list/organ_list = organs_by_name.Copy()
+ if(cosmetic)
+ organ_list |= cosmetic_organs_by_name
+ return organ_list[zone]
+/mob/living/carbon/human/proc/get_cosmetic_organ(zone)
+ RETURN_TYPE(/datum/organ/external)
+ return cosmetic_organs_by_name[zone]
//Picks a random usable organ from the organs passed to the arguments
//You can feed organ references, or organ strings into this obj
diff --git a/code/modules/mob/living/carbon/human/plasmaman/species.dm b/code/modules/mob/living/carbon/human/species/plasmaman.dm
similarity index 100%
rename from code/modules/mob/living/carbon/human/plasmaman/species.dm
rename to code/modules/mob/living/carbon/human/species/plasmaman.dm
diff --git a/code/modules/mob/living/carbon/human/species/vox.dm b/code/modules/mob/living/carbon/human/species/vox.dm
new file mode 100644
index 00000000000..64c3142692a
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species/vox.dm
@@ -0,0 +1,160 @@
+/datum/species/vox
+ name = "Vox"
+ icobase = 'icons/mob/human_races/vox/r_vox.dmi'
+ deform = 'icons/mob/human_races/vox/r_def_vox.dmi'
+ known_languages = list(LANGUAGE_VOX)
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/rawchicken/vox
+ tacklePower = 40
+ anatomy_flags = HAS_SWEAT_GLANDS | HAS_ICON_SKIN_TONE | HAS_TAIL
+
+ survival_gear = /obj/item/weapon/storage/box/survival/vox
+
+ primitive = /mob/living/carbon/monkey/vox
+
+ cold_level_1 = 80
+ cold_level_2 = 50
+ cold_level_3 = 0
+
+ eyes = "vox_eyes_s"
+ breath_type = GAS_NITROGEN
+
+ default_mutations = list(M_BEAK, M_TALONS)
+ flags = PLAYABLE | WHITELISTED
+ blood_color = VOX_BLOOD
+ flesh_color = "#808D11"
+ max_skin_tone = 6
+ tail = "green"
+ tail_icon = 'icons/mob/human_races/vox/tails.dmi'
+ tail_type = "vox"
+ footprint_type = /obj/effect/decal/cleanable/blood/tracks/footprints/vox //Bird claws
+
+ uniform_icons = 'icons/mob/species/vox/uniform.dmi'
+// fat_uniform_icons = 'icons/mob/uniform_fat.dmi'
+ gloves_icons = 'icons/mob/species/vox/gloves.dmi'
+ glasses_icons = 'icons/mob/species/vox/eyes.dmi'
+// ears_icons = 'icons/mob/ears.dmi'
+ shoes_icons = 'icons/mob/species/vox/shoes.dmi'
+ head_icons = 'icons/mob/species/vox/head.dmi'
+// belt_icons = 'icons/mob/belt.dmi'
+ wear_suit_icons = 'icons/mob/species/vox/suit.dmi'
+ wear_mask_icons = 'icons/mob/species/vox/masks.dmi'
+ back_icons = 'icons/mob/species/vox/back.dmi'
+
+ has_mutant_race = 0
+ has_organ = list(
+ "heart" = /datum/organ/internal/heart/vox,
+ "lungs" = /datum/organ/internal/lungs/vox,
+ "liver" = /datum/organ/internal/liver,
+ "kidneys" = /datum/organ/internal/kidney,
+ "brain" = /datum/organ/internal/brain,
+ "appendix" = /datum/organ/internal/appendix,
+ "eyes" = /datum/organ/internal/eyes/vox
+ )
+
+ species_intro = "You are a Vox.
\
+ You are somewhat more adept at handling the lower pressures of space and colder temperatures.
\
+ You have talons with which you can slice others in a fist fight, and a beak which can be used to butcher corpses without the need for finer tools.
\
+ However, Oxygen is incredibly toxic to you, in breathing it or consuming it. You can only breathe nitrogen."
+
+// -- Outfit datums --
+/datum/species/vox/final_equip(var/mob/living/carbon/human/H)
+ var/tank_slot = slot_s_store
+ var/tank_slot_name = "suit storage"
+ if(tank_slot)
+ H.equip_or_collect(new/obj/item/weapon/tank/nitrogen(H), tank_slot)
+ else
+ H.put_in_hands(new/obj/item/weapon/tank/nitrogen(H))
+ to_chat(H, "You are now running on nitrogen internals from the [H.s_store] in your [tank_slot_name].")
+ var/obj/item/weapon/tank/nitrogen/N = H.get_item_by_slot(tank_slot)
+ if(!N)
+ N = H.get_item_by_slot(slot_back)
+ H.internal = N
+ if (H.internals)
+ H.internals.icon_state = "internal1"
+
+/datum/species/vox/makeName(var/gender,var/mob/living/carbon/human/H=null)
+ var/sounds = rand(3,8)
+ var/newname = ""
+
+ for(var/i = 1 to sounds)
+ newname += pick(vox_name_syllables)
+ return capitalize(newname)
+
+/datum/species/vox/handle_post_spawn(var/mob/living/carbon/human/H)
+ if(myhuman != H)
+ return
+ updatespeciescolor(H)
+ H.update_icon()
+
+/datum/species/vox/updatespeciescolor(mob/living/carbon/human/vox)
+ var/datum/organ/external/tail/vox_tail = vox.get_cosmetic_organ(COSMETIC_ORGAN_TAIL)
+ switch(vox.my_appearance.s_tone)
+ if(VOXEMERALD)
+ icobase = 'icons/mob/human_races/vox/r_voxemrl.dmi'
+ deform = 'icons/mob/human_races/vox/r_def_voxemrl.dmi'
+ if(VOXAZURE)
+ icobase = 'icons/mob/human_races/vox/r_voxazu.dmi'
+ deform = 'icons/mob/human_races/vox/r_def_voxazu.dmi'
+ if(VOXLGREEN)
+ icobase = 'icons/mob/human_races/vox/r_voxlgrn.dmi'
+ deform = 'icons/mob/human_races/vox/r_def_voxlgrn.dmi'
+ if(VOXGRAY)
+ icobase = 'icons/mob/human_races/vox/r_voxgry.dmi'
+ deform = 'icons/mob/human_races/vox/r_def_voxgry.dmi'
+ if(VOXBROWN)
+ icobase = 'icons/mob/human_races/vox/r_voxbrn.dmi'
+ deform = 'icons/mob/human_races/vox/r_def_voxbrn.dmi'
+ else
+ icobase = 'icons/mob/human_races/vox/r_vox.dmi'
+ deform = 'icons/mob/human_races/vox/r_def_vox.dmi'
+ if(vox_tail && (vox_tail.status & ORGAN_DESTROYED))
+ return
+ vox_tail.update_tail(vox)
+
+/datum/species/skellington/skelevox // Science never goes too far, it's the public that's too conservative
+ name = "Skeletal Vox"
+ icobase = 'icons/mob/human_races/vox/r_voxboney.dmi'
+ deform = 'icons/mob/human_races/vox/r_voxboney.dmi' //Do bones deform noticeably?
+ known_languages = list(LANGUAGE_VOX, LANGUAGE_CLATTER)
+
+ survival_gear = /obj/item/weapon/storage/box/survival/vox
+
+ primitive = /mob/living/carbon/monkey/vox/skeletal
+
+ warning_low_pressure = 50
+ hazard_low_pressure = 0
+
+ cold_level_1 = 80
+ cold_level_2 = 50
+ cold_level_3 = 0
+
+ eyes = "vox_eyes_s"
+
+ default_mutations = list(M_BEAK, M_TALONS)
+
+ footprint_type = /obj/effect/decal/cleanable/blood/tracks/footprints/vox
+
+ uniform_icons = 'icons/mob/species/vox/uniform.dmi'
+// fat_uniform_icons = 'icons/mob/uniform_fat.dmi'
+ gloves_icons = 'icons/mob/species/vox/gloves.dmi'
+ glasses_icons = 'icons/mob/species/vox/eyes.dmi'
+// ears_icons = 'icons/mob/ears.dmi'
+ shoes_icons = 'icons/mob/species/vox/shoes.dmi'
+ head_icons = 'icons/mob/species/vox/head.dmi'
+// belt_icons = 'icons/mob/belt.dmi'
+ wear_suit_icons = 'icons/mob/species/vox/suit.dmi'
+ wear_mask_icons = 'icons/mob/species/vox/masks.dmi'
+// back_icons = 'icons/mob/back.dmi'
+
+ has_organ = list(
+ "brain" = /datum/organ/internal/brain,
+ "eyes" = /datum/organ/internal/eyes/vox
+ )
+
+/datum/species/skellington/skelevox/makeName(var/gender,var/mob/living/carbon/human/H=null)
+ var/sounds = rand(3,8)
+ var/newname = ""
+
+ for(var/i = 1 to sounds)
+ newname += pick(vox_name_syllables)
+ return capitalize(newname)
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index c35bc3acf69..00fc82d0af5 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -194,7 +194,8 @@ var/global/list/damage_icon_parts = list()
var/g = "m"
if(gender == FEMALE)
g = "f"
-
+ if(species && species.anatomy_flags & HAS_ICON_SKIN_TONE)
+ species.updatespeciescolor(src)
var/datum/organ/external/chest = get_organ(LIMB_CHEST)
stand_icon = chest.get_icon(g,fat)
if(!skeleton)
@@ -269,7 +270,15 @@ var/global/list/damage_icon_parts = list()
mask.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0)
husk_over.Blend(mask, ICON_ADD)
stand_icon.Blend(husk_over, ICON_OVERLAY)
-
+ var/datum/organ/external/tail/tail = get_cosmetic_organ(COSMETIC_ORGAN_TAIL)
+ if(tail && (!(tail.status & ORGAN_DESTROYED) && tail.overlap_overlays))
+ var/obj/abstract/Overlays/limbs_overlay = obj_overlays[LIMBS_LAYER]
+ var/mutable_appearance/stand_icon_image = mutable_appearance(stand_icon)
+ limbs_overlay.icon = stand_icon_image.icon
+ limbs_overlay.icon_state = stand_icon_image.icon_state
+ obj_to_plane_overlay(limbs_overlay, LIMBS_LAYER)
+ else
+ overlays -= obj_overlays[LIMBS_LAYER]
if(has_head)
//Eyes
if(!skeleton)
@@ -307,7 +316,7 @@ var/global/list/damage_icon_parts = list()
stand_icon -= rgb(0,0,0,lowest_alpha)
//tail
- update_tail_showing(0)
+ update_tail_layer(FALSE)
//HAIR OVERLAY
@@ -523,6 +532,7 @@ var/global/list/damage_icon_parts = list()
update_inv_mutual_handcuffed(0)
update_inv_legcuffed(0)
update_inv_pockets(0)
+ update_tail_layer()
QueueUpdateDamageIcon(1)
update_icons()
//Hud Stuff
@@ -1298,10 +1308,7 @@ var/global/list/damage_icon_parts = list()
O.pixel_y = species.inventory_offsets["[slot_wear_suit]"]["pixel_y"] * PIXEL_MULTIPLIER
obj_to_plane_overlay(O,SUIT_LAYER)
//overlays_standing[SUIT_LAYER] = standing
- update_tail_showing(0)
- else
- //overlays_standing[SUIT_LAYER] = null
- update_tail_showing(0)
+ update_tail_layer()
if(update_icons)
update_icons()
@@ -1547,22 +1554,34 @@ var/global/list/damage_icon_parts = list()
/mob/living/carbon/human/update_inv_l_hand(var/update_icons=1)
return update_inv_hand(GRASP_LEFT_HAND, update_icons)
-/mob/living/carbon/human/proc/update_tail_showing(var/update_icons=1)
- //overlays_standing[TAIL_LAYER] = null
+/mob/living/carbon/human/proc/update_tail_layer(update_icons = TRUE)
+ overlays -= obj_overlays[TAIL_UNDERLIMBS_LAYER]
overlays -= obj_overlays[TAIL_LAYER]
- if(species && species.tail && species.anatomy_flags & HAS_TAIL)
- if(!wear_suit || !is_slot_hidden(wear_suit.body_parts_covered, HIDEJUMPSUIT, 0, wear_suit.body_parts_visible_override))
- var/obj/abstract/Overlays/O = obj_overlays[TAIL_LAYER]
- O.icon = 'icons/effects/species.dmi'
- O.icon_state = "[species.tail]_s"
- obj_to_plane_overlay(O,TAIL_LAYER)
- //if(!old_tail_state) //only update if we didnt show our tail already
-
- //overlays_standing[TAIL_LAYER] = image("icon" = 'icons/effects/species.dmi', "icon_state" = "[species.tail]_s")
-// to_chat(src, "update: tail is different")
- //else
- //overlays_standing[TAIL_LAYER] = null
-
+ var/datum/organ/external/tail/tail_organ = get_cosmetic_organ(COSMETIC_ORGAN_TAIL)
+ if(!tail_organ || (tail_organ.status & ORGAN_DESTROYED))
+ return
+ if(wear_suit || check_hidden_body_flags(HIDETAIL))
+ return
+ var/tail_file = tail_organ.tail_icon_file
+ var/tail_icon_state = tail_organ.icon_name
+ if(!tail_file || !tail_icon_state)
+ return
+ var/mutable_appearance/tail_image = mutable_appearance(tail_file, tail_icon_state, layer = -TAIL_LAYER)
+ if(species.anatomy_flags & MULTICOLOR)
+ tail_image.color = COLOR_MATRIX_ADD(rgb(multicolor_skin_r, multicolor_skin_g, multicolor_skin_b))
+ if(tail_organ.overlap_overlays) // Tail is overlapped by limbs, so we need special tail icon generation
+ // Gives the underlimbs layer SEW directions since it's overlayed by limbs and just about everything else anyway.
+ var/mutable_appearance/tail_underlimbs = mutable_appearance(tail_file, "[tail_icon_state]_BEHIND", -TAIL_UNDERLIMBS_LAYER)
+ var/obj/abstract/Overlays/underlimbs_overlay = obj_overlays[TAIL_UNDERLIMBS_LAYER]
+ underlimbs_overlay.icon = tail_underlimbs.icon
+ underlimbs_overlay.icon_state = tail_underlimbs.icon_state
+ obj_to_plane_overlay(underlimbs_overlay, TAIL_UNDERLIMBS_LAYER)
+ // North direction sprite before passing that to the tail layer that overlays uniforms and such.
+ tail_image.icon_state = "[tail_icon_state]_FRONT"
+ var/obj/abstract/Overlays/tail_overlay = obj_overlays[TAIL_LAYER]
+ tail_overlay.icon = tail_image.icon
+ tail_overlay.icon_state = tail_image.icon_state
+ obj_to_plane_overlay(tail_overlay, TAIL_LAYER)
if(update_icons)
update_icons()
diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm
index fac52aed432..4bafdb1aa19 100644
--- a/code/modules/mob/living/carbon/species.dm
+++ b/code/modules/mob/living/carbon/species.dm
@@ -42,7 +42,10 @@ var/global/list/playable_species = list("Human")
var/eyes = "eyes_s" // Icon for eyes.
var/primitive // Lesser form, if any (ie. monkey for humans)
- var/tail // Name of tail image in species effects icon file.
+ var/tail // Name of tail icon state
+ var/tail_icon = 'icons/mob/tails.dmi'
+ var/tail_type
+ var/tail_overlapping = TRUE
var/list/known_languages = list(LANGUAGE_GALACTIC_COMMON) // Languages that this species innately knows.
var/default_language = LANGUAGE_GALACTIC_COMMON // Default language is used when 'say' is used without modifiers.
var/attack_verb = "punches" // Empty hand hurt intent verb.
@@ -204,9 +207,15 @@ var/global/list/playable_species = list("Human")
for(var/datum/organ/I in H.internal_organs)
qdel(I)
H.internal_organs.len=0
+ if(H.cosmetic_organs)
+ for(var/organ in H.cosmetic_organs)
+ qdel(organ)
+ H.cosmetic_organs.len=0
//The rest SHOULD only refer to organs that were already deleted by the above loops, so we can just clear the lists.
if(H.organs_by_name)
H.organs_by_name.len=0
+ if(H.cosmetic_organs_by_name)
+ H.cosmetic_organs_by_name.len = 0
if(H.internal_organs_by_name)
H.internal_organs_by_name.len=0
if(H.grasp_organs)
@@ -219,6 +228,7 @@ var/global/list/playable_species = list("Human")
//This is a basic humanoid limb setup.
H.organs = list()
+ H.cosmetic_organs = list()
H.organs_by_name[LIMB_CHEST] = new/datum/organ/external/chest()
H.organs_by_name[LIMB_GROIN] = new/datum/organ/external/groin(H.organs_by_name[LIMB_CHEST])
H.organs_by_name[LIMB_HEAD] = new/datum/organ/external/head(H.organs_by_name[LIMB_CHEST])
@@ -231,6 +241,8 @@ var/global/list/playable_species = list("Human")
H.organs_by_name[LIMB_LEFT_FOOT] = new/datum/organ/external/l_foot(H.organs_by_name[LIMB_LEFT_LEG])
H.organs_by_name[LIMB_RIGHT_FOOT] = new/datum/organ/external/r_foot(H.organs_by_name[LIMB_RIGHT_LEG])
+ H.cosmetic_organs_by_name[COSMETIC_ORGAN_TAIL] = new/datum/organ/external/tail(H.organs_by_name[LIMB_GROIN], src)
+
H.internal_organs = list()
for(var/organ in has_organ)
var/organ_type = has_organ[organ]
@@ -245,9 +257,13 @@ var/global/list/playable_species = list("Human")
H.organs += OE
if(OE.grasp_id)
H.grasp_organs += OE
-
- for(var/datum/organ/external/O in H.organs)
- O.owner = H
+ for(var/organ in H.cosmetic_organs_by_name)
+ var/datum/organ/external/cosmetic_organ = H.cosmetic_organs_by_name[organ]
+ H.cosmetic_organs += cosmetic_organ
+ for(var/datum/organ/external/external_organ in H.organs)
+ external_organ.owner = H
+ for(var/datum/organ/external/cosmetic_organ as anything in H.cosmetic_organs)
+ cosmetic_organ.owner = H
/datum/species/proc/handle_post_spawn(var/mob/living/carbon/human/H) //Handles anything not already covered by basic species assignment.
return
@@ -385,7 +401,8 @@ var/global/list/playable_species = list("Human")
icobase = 'icons/mob/human_races/r_lizard.dmi'
deform = 'icons/mob/human_races/r_def_lizard.dmi'
known_languages = list(LANGUAGE_UNATHI)
- tail = "sogtail"
+ tail = "unathi"
+ tail_type = "unathi"
attack_verb = "scratches"
punch_damage = 2
primitive = /mob/living/carbon/monkey/unathi
@@ -467,61 +484,13 @@ var/global/list/playable_species = list("Human")
H.drop_all()
qdel(src)
-
-/datum/species/skellington/skelevox // Science never goes too far, it's the public that's too conservative
- name = "Skeletal Vox"
- icobase = 'icons/mob/human_races/vox/r_voxboney.dmi'
- deform = 'icons/mob/human_races/vox/r_voxboney.dmi' //Do bones deform noticeably?
- known_languages = list(LANGUAGE_VOX, LANGUAGE_CLATTER)
-
- survival_gear = /obj/item/weapon/storage/box/survival/vox
-
- primitive = /mob/living/carbon/monkey/vox/skeletal
-
- warning_low_pressure = 50
- hazard_low_pressure = 0
-
- cold_level_1 = 80
- cold_level_2 = 50
- cold_level_3 = 0
-
- eyes = "vox_eyes_s"
-
- default_mutations = list(M_BEAK, M_TALONS)
-
- footprint_type = /obj/effect/decal/cleanable/blood/tracks/footprints/vox
-
- uniform_icons = 'icons/mob/species/vox/uniform.dmi'
-// fat_uniform_icons = 'icons/mob/uniform_fat.dmi'
- gloves_icons = 'icons/mob/species/vox/gloves.dmi'
- glasses_icons = 'icons/mob/species/vox/eyes.dmi'
-// ears_icons = 'icons/mob/ears.dmi'
- shoes_icons = 'icons/mob/species/vox/shoes.dmi'
- head_icons = 'icons/mob/species/vox/head.dmi'
-// belt_icons = 'icons/mob/belt.dmi'
- wear_suit_icons = 'icons/mob/species/vox/suit.dmi'
- wear_mask_icons = 'icons/mob/species/vox/masks.dmi'
-// back_icons = 'icons/mob/back.dmi'
-
- has_organ = list(
- "brain" = /datum/organ/internal/brain,
- "eyes" = /datum/organ/internal/eyes/vox
- )
-
-/datum/species/skellington/skelevox/makeName(var/gender,var/mob/living/carbon/human/H=null)
- var/sounds = rand(3,8)
- var/newname = ""
-
- for(var/i = 1 to sounds)
- newname += pick(vox_name_syllables)
- return capitalize(newname)
-
/datum/species/tajaran
name = "Tajaran"
icobase = 'icons/mob/human_races/r_tajaran.dmi'
deform = 'icons/mob/human_races/r_def_tajaran.dmi'
known_languages = list(LANGUAGE_CATBEAST, LANGUAGE_MOUSE)
- tail = "tajtail"
+ tail = "tajaran_brown"
+ tail_type = "tajaran"
attack_verb = "scratches"
punch_damage = 2 //Claws add 3 damage without gloves, so the total is 5
@@ -536,7 +505,7 @@ var/global/list/playable_species = list("Human")
primitive = /mob/living/carbon/monkey/tajara
flags = WHITELISTED
- anatomy_flags = HAS_LIPS | HAS_UNDERWEAR | HAS_TAIL | HAS_SWEAT_GLANDS
+ anatomy_flags = HAS_LIPS | HAS_UNDERWEAR | HAS_TAIL | HAS_SWEAT_GLANDS | HAS_ICON_SKIN_TONE
default_mutations=list(M_CLAWS)
@@ -568,18 +537,20 @@ var/global/list/playable_species = list("Human")
updatespeciescolor(H)
H.update_icon()
-/datum/species/tajaran/updatespeciescolor(var/mob/living/carbon/human/H)
- switch(H.my_appearance.s_tone)
+/datum/species/tajaran/updatespeciescolor(mob/living/carbon/human/tajaran)
+ var/datum/organ/external/tail/tajaran_tail = tajaran.get_cosmetic_organ(COSMETIC_ORGAN_TAIL)
+ switch(tajaran.my_appearance.s_tone)
if(CATBEASTBLACK)
icobase = 'icons/mob/human_races/r_tajaranblack.dmi'
deform = 'icons/mob/human_races/r_def_tajaranblack.dmi'
- tail = "tajtailb"
- H.my_appearance.h_style = "Black Tajaran Ears"
+ tajaran.my_appearance.h_style = "Black Tajaran Ears"
else
icobase = 'icons/mob/human_races/r_tajaran.dmi'
deform = 'icons/mob/human_races/r_def_tajaran.dmi'
- tail = "tajtail"
- H.my_appearance.h_style = "Tajaran Ears"
+ tajaran.my_appearance.h_style = "Tajaran Ears"
+ if(tajaran_tail && (tajaran_tail.status & ORGAN_DESTROYED))
+ return
+ tajaran_tail.update_tail(tajaran)
/datum/species/tajaran/handle_speech(var/datum/speech/speech, mob/living/carbon/human/H)
if (prob(15))
@@ -610,7 +581,7 @@ var/global/list/playable_species = list("Human")
primitive = /mob/living/carbon/monkey/grey
flags = PLAYABLE | WHITELISTED
- anatomy_flags = HAS_LIPS | HAS_SWEAT_GLANDS | ACID4WATER
+ anatomy_flags = HAS_LIPS | HAS_SWEAT_GLANDS | ACID4WATER | HAS_ICON_SKIN_TONE
spells = list(/spell/targeted/telepathy)
@@ -736,114 +707,6 @@ var/global/list/playable_species = list("Human")
head_icons = 'icons/mob/species/skrell/head.dmi'
wear_suit_icons = 'icons/mob/species/skrell/suit.dmi'
-/datum/species/vox
- name = "Vox"
- icobase = 'icons/mob/human_races/vox/r_vox.dmi'
- deform = 'icons/mob/human_races/vox/r_def_vox.dmi'
- known_languages = list(LANGUAGE_VOX)
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/rawchicken/vox
- tacklePower = 40
- anatomy_flags = HAS_SWEAT_GLANDS
-
- survival_gear = /obj/item/weapon/storage/box/survival/vox
-
- primitive = /mob/living/carbon/monkey/vox
-
- cold_level_1 = 80
- cold_level_2 = 50
- cold_level_3 = 0
-
- eyes = "vox_eyes_s"
- breath_type = GAS_NITROGEN
-
- default_mutations = list(M_BEAK, M_TALONS)
- flags = PLAYABLE | WHITELISTED
-
- blood_color = VOX_BLOOD
- flesh_color = "#808D11"
- max_skin_tone = 6
-
- footprint_type = /obj/effect/decal/cleanable/blood/tracks/footprints/vox //Bird claws
-
- uniform_icons = 'icons/mob/species/vox/uniform.dmi'
-// fat_uniform_icons = 'icons/mob/uniform_fat.dmi'
- gloves_icons = 'icons/mob/species/vox/gloves.dmi'
- glasses_icons = 'icons/mob/species/vox/eyes.dmi'
-// ears_icons = 'icons/mob/ears.dmi'
- shoes_icons = 'icons/mob/species/vox/shoes.dmi'
- head_icons = 'icons/mob/species/vox/head.dmi'
-// belt_icons = 'icons/mob/belt.dmi'
- wear_suit_icons = 'icons/mob/species/vox/suit.dmi'
- wear_mask_icons = 'icons/mob/species/vox/masks.dmi'
- back_icons = 'icons/mob/species/vox/back.dmi'
-
- has_mutant_race = 0
- has_organ = list(
- "heart" = /datum/organ/internal/heart/vox,
- "lungs" = /datum/organ/internal/lungs/vox,
- "liver" = /datum/organ/internal/liver,
- "kidneys" = /datum/organ/internal/kidney,
- "brain" = /datum/organ/internal/brain,
- "appendix" = /datum/organ/internal/appendix,
- "eyes" = /datum/organ/internal/eyes/vox
- )
-
- species_intro = "You are a Vox.
\
- You are somewhat more adept at handling the lower pressures of space and colder temperatures.
\
- You have talons with which you can slice others in a fist fight, and a beak which can be used to butcher corpses without the need for finer tools.
\
- However, Oxygen is incredibly toxic to you, in breathing it or consuming it. You can only breathe nitrogen."
-
-// -- Outfit datums --
-/datum/species/vox/final_equip(var/mob/living/carbon/human/H)
- var/tank_slot = slot_s_store
- var/tank_slot_name = "suit storage"
- if(tank_slot)
- H.equip_or_collect(new/obj/item/weapon/tank/nitrogen(H), tank_slot)
- else
- H.put_in_hands(new/obj/item/weapon/tank/nitrogen(H))
- to_chat(H, "You are now running on nitrogen internals from the [H.s_store] in your [tank_slot_name].")
- var/obj/item/weapon/tank/nitrogen/N = H.get_item_by_slot(tank_slot)
- if(!N)
- N = H.get_item_by_slot(slot_back)
- H.internal = N
- if (H.internals)
- H.internals.icon_state = "internal1"
-
-/datum/species/vox/makeName(var/gender,var/mob/living/carbon/human/H=null)
- var/sounds = rand(3,8)
- var/newname = ""
-
- for(var/i = 1 to sounds)
- newname += pick(vox_name_syllables)
- return capitalize(newname)
-
-/datum/species/vox/handle_post_spawn(var/mob/living/carbon/human/H)
- if(myhuman != H)
- return
- updatespeciescolor(H)
- H.update_icon()
-
-/datum/species/vox/updatespeciescolor(var/mob/living/carbon/human/H)
- switch(H.my_appearance.s_tone)
- if(6)
- icobase = 'icons/mob/human_races/vox/r_voxemrl.dmi'
- deform = 'icons/mob/human_races/vox/r_def_voxemrl.dmi'
- if(5)
- icobase = 'icons/mob/human_races/vox/r_voxazu.dmi'
- deform = 'icons/mob/human_races/vox/r_def_voxazu.dmi'
- if(4)
- icobase = 'icons/mob/human_races/vox/r_voxlgrn.dmi'
- deform = 'icons/mob/human_races/vox/r_def_voxlgrn.dmi'
- if(3)
- icobase = 'icons/mob/human_races/vox/r_voxgry.dmi'
- deform = 'icons/mob/human_races/vox/r_def_voxgry.dmi'
- if(2)
- icobase = 'icons/mob/human_races/vox/r_voxbrn.dmi'
- deform = 'icons/mob/human_races/vox/r_def_voxbrn.dmi'
- else
- icobase = 'icons/mob/human_races/vox/r_vox.dmi'
- deform = 'icons/mob/human_races/vox/r_def_vox.dmi'
-
/datum/species/diona
name = "Diona"
icobase = 'icons/mob/human_races/r_plant.dmi'
@@ -1421,4 +1284,4 @@ var/list/has_died_as_golem = list()
head_organ.droplimb(1,1)
H.drop_all()
- qdel(src)
\ No newline at end of file
+ qdel(src)
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index 0d378974686..37a9c9cd9f5 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -352,6 +352,9 @@ var/list/animals_with_wings = list(
else
alert("Unable to use this emote, must be either hearable or visible.")
return
+ var/display_runechat = input("Display Runechat?") as null|anything in list("Yes", "No")
+ if(display_runechat == "No")
+ emote_type |= EMOTE_NO_RUNECHAT
message = custom_emote
else
message = params
diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm
index c672b2c41f0..c584fd8102d 100644
--- a/code/modules/mob/new_player/preferences_setup.dm
+++ b/code/modules/mob/new_player/preferences_setup.dm
@@ -174,25 +174,25 @@
if(current_species)
if(current_species.name == "Vox")
switch(s_tone)
- if(6)
+ if(VOXEMERALD)
icobase = 'icons/mob/human_races/vox/r_voxemrl.dmi'
- if(5)
+ if(VOXAZURE)
icobase = 'icons/mob/human_races/vox/r_voxazu.dmi'
- if(4)
+ if(VOXLGREEN)
icobase = 'icons/mob/human_races/vox/r_voxlgrn.dmi'
- if(3)
+ if(VOXGRAY)
icobase = 'icons/mob/human_races/vox/r_voxgry.dmi'
- if(2)
+ if(VOXBROWN)
icobase = 'icons/mob/human_races/vox/r_voxbrn.dmi'
else
icobase = 'icons/mob/human_races/vox/r_vox.dmi'
else if(current_species.name == "Grey")
switch(s_tone)
- if(4)
+ if(GREYBLUE)
icobase = 'icons/mob/human_races/grey/r_greyblue.dmi'
- if(3)
+ if(GREYGREEN)
icobase = 'icons/mob/human_races/grey/r_greygreen.dmi'
- if(2)
+ if(GREYLIGHT)
icobase = 'icons/mob/human_races/grey/r_greylight.dmi'
else
icobase = 'icons/mob/human_races/grey/r_grey.dmi'
@@ -230,7 +230,31 @@
var/icon/temp = new /icon(o_icobase, "[name]")
preview_icon.Blend(temp, ICON_OVERLAY)
-
+ //Tail
+ if(current_species && (current_species.anatomy_flags & HAS_TAIL))
+ var/tail_icon_state = current_species.tail
+ if(current_species.name == "Vox")
+ switch(s_tone)
+ if(VOXEMERALD)
+ tail_icon_state = "emerald"
+ if(VOXAZURE)
+ tail_icon_state = "azure"
+ if(VOXLGREEN)
+ tail_icon_state = "lightgreen"
+ if(VOXGRAY)
+ tail_icon_state = "grey"
+ if(VOXBROWN)
+ tail_icon_state = "brown"
+ else
+ tail_icon_state = "green"
+ if(current_species.name == "Tajaran")
+ switch(s_tone)
+ if(CATBEASTBLACK)
+ tail_icon_state = "tajaran_black"
+ else
+ tail_icon_state = "tajaran_brown"
+ var/icon/temp_tail_icon = icon(current_species.tail_icon, "[tail_icon_state]_BEHIND")
+ preview_icon.Blend(temp_tail_icon, ICON_UNDERLAY)
// Skin tone
if(current_species && (current_species.anatomy_flags & HAS_SKIN_TONE))
if (s_tone >= 0)
diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm
index e16afd28040..e64081c17eb 100644
--- a/code/modules/organs/organ.dm
+++ b/code/modules/organs/organ.dm
@@ -78,7 +78,9 @@
W.time_inflicted = world.time
/mob/living/carbon/human/var/list/organs = list()
+/mob/living/carbon/human/var/list/cosmetic_organs = list()
/mob/living/carbon/human/var/list/datum/organ/external/organs_by_name = list() //Map organ names to organs
+/mob/living/carbon/human/var/list/datum/organ/external/cosmetic_organs_by_name = list()
/mob/living/carbon/human/var/list/datum/organ/internal/internal_organs_by_name = list() //So internal organs have less ickiness too
/mob/living/carbon/human/var/list/grasp_organs = list()
diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm
index 7ff4b2fc0db..055e3df562b 100644
--- a/code/modules/organs/organ_external.dm
+++ b/code/modules/organs/organ_external.dm
@@ -50,7 +50,7 @@
var/wound_update_accuracy = 1
var/has_fat = 0 //Has a _fat variant
-
+ var/cosmetic_only = FALSE
var/grasp_id = 0 //Does this organ affect other grasping organs?
var/can_grasp = 0 //Can this organ actually grasp something?
@@ -154,6 +154,8 @@
droplimb(1, spawn_limb = 0, display_message = FALSE)
/datum/organ/external/proc/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list())
+ if(cosmetic_only)
+ return
if(owner?.status_flags & GODMODE)
return 0 //godmode
if((brute <= 0) && (burn <= 0))
@@ -277,6 +279,8 @@
return result
/datum/organ/external/proc/heal_damage(brute, burn, internal = 0, robo_repair = 0)
+ if(cosmetic_only)
+ return
if(is_robotic() && !robo_repair) //This item can't fix robotic limbs
return
@@ -330,6 +334,8 @@
owner.updatehealth()
/datum/organ/external/proc/createwound(var/type = CUT, var/damage)
+ if(cosmetic_only)
+ return
if(!damage || damage < 0) //We weren't passed a damage value, or it's negative for some reason
return
@@ -409,7 +415,6 @@
return 0
/datum/organ/external/process()
-
//Process wounds, doing healing etc. Only do this every few ticks to save processing power
if(owner.life_tick % wound_update_accuracy == 0)
update_wounds()
@@ -448,7 +453,6 @@
//Cancer growth for external organs is simple, it grows, hurts, damages, and suddenly grows out of control
//Limb cancer is relatively benign until it grows large, then it cripples you and metastases
/datum/organ/external/handle_cancer()
-
if(..())
return 1
@@ -500,6 +504,8 @@ Note that amputating the affected organ does in fact remove the infection from t
*/
/datum/organ/external/proc/update_germs()
+ if(cosmetic_only)
+ return
if(!is_existing() || !is_organic()) //Needs to be organic and existing
germ_level = 0
return
@@ -590,7 +596,8 @@ Note that amputating the affected organ does in fact remove the infection from t
//Updating wounds. Handles wound natural healing, internal bleedings and infections
/datum/organ/external/proc/update_wounds()
-
+ if(cosmetic_only)
+ return
if(!is_organic()) //Non-organic limbs don't heal or get worse
return
@@ -748,7 +755,7 @@ Note that amputating the affected organ does in fact remove the infection from t
if(body_part == (UPPER_TORSO || LOWER_TORSO)) //We can't lose either, those cannot be amputated and will cause extremely serious problems
return
- var/datum/species/species = src.species || owner.species
+ var/datum/species/species = src.species || owner?.species
var/obj/item/organ/external/organ //Dropped limb object
if(override)
@@ -837,7 +844,8 @@ Note that amputating the affected organ does in fact remove the infection from t
//Throw organs around
var/randomdir = pick(cardinal)
step(organ, randomdir)
-
+ if(!owner)
+ return organ
owner.update_body(1)
owner.handle_organs(1)
@@ -873,7 +881,7 @@ Note that amputating the affected organ does in fact remove the infection from t
O.removed(owner,owner)
O.loc = headloc
QDEL_NULL(organ)
-
+ organ?.update_icon()
return organ
/datum/organ/external/proc/get_organ_item()
@@ -941,6 +949,8 @@ Note that amputating the affected organ does in fact remove the infection from t
return rval
/datum/organ/external/proc/clamp_wounds() //Inconsistent with the other names but clamp is a reserved word now
+ if(cosmetic_only)
+ return
var/rval = 0
src.status &= ~ORGAN_BLEEDING
for(var/datum/wound/W in wounds)
@@ -958,6 +968,8 @@ Note that amputating the affected organ does in fact remove the infection from t
return rval
/datum/organ/external/proc/fracture()
+ if(cosmetic_only)
+ return
if(owner?.status_flags & GODMODE)
return 0 //godmode
var/datum/species/species = src.species || owner.species
@@ -1053,7 +1065,7 @@ Note that amputating the affected organ does in fact remove the infection from t
src.status = organ.status
src.brute_dam = organ.brute_dam
src.burn_dam = organ.burn_dam
-
+ on_attach(organ)
owner.butchering_drops += organ.butchering_drops
//Transfer any internal_organs from the organ item to the body
@@ -1086,7 +1098,7 @@ Note that amputating the affected organ does in fact remove the infection from t
else if(istype(I, /obj/item/robot_parts)) //Robotic limb
var/obj/item/robot_parts/R = I
-
+ R.on_attach(src)
src.robotize()
src.sabotaged = R.sabotaged
@@ -1103,6 +1115,9 @@ Note that amputating the affected organ does in fact remove the infection from t
owner.updatehealth()
owner.UpdateDamageIcon()
+/datum/organ/external/proc/on_attach()
+ return
+
/datum/organ/external/proc/mutate()
src.status |= ORGAN_MUTATED
owner.update_body()
@@ -1247,6 +1262,85 @@ Note that amputating the affected organ does in fact remove the infection from t
body_part = LOWER_TORSO
vital = 1
+/datum/organ/external/tail
+ name = COSMETIC_ORGAN_TAIL
+ display_name = "tail"
+ icon_name = "tail"
+ max_damage = 75
+ min_broken_damage = 30
+ body_part = TAIL
+ cosmetic_only = TRUE
+ var/tail_icon_file = 'icons/mob/tails.dmi'
+ var/tail_type
+ var/overlap_overlays = TRUE
+
+/datum/organ/external/tail/New(datum/organ/external/parent, datum/species/passed_species)
+ if(passed_species && (!(passed_species.anatomy_flags & HAS_TAIL)))
+ droplimb(TRUE, spawn_limb = FALSE)
+ return
+ create_tail_info(passed_species)
+ return ..()
+
+/datum/organ/external/tail/proc/create_tail_info(datum/species/passed_species, obj/item/organ/external/tail/tail_item)
+ icon_name = passed_species?.tail || tail_item?.tail_state_name
+ tail_icon_file = passed_species?.tail_icon || tail_item?.tail_icon_file
+ tail_type = passed_species?.tail_type || tail_item?.tail_type
+ overlap_overlays = passed_species?.tail_overlapping || tail_item?.tail_overlapping
+
+/datum/organ/external/tail/generate_dropped_organ(current_organ)
+ if(!current_organ)
+ if(is_robotic())
+ current_organ = new /obj/item/robot_parts/tail(owner.loc, tail_type)
+ else
+ current_organ = new /obj/item/organ/external/tail(owner.loc, owner, src)
+ return current_organ
+
+/datum/organ/external/tail/on_attach(obj/item/organ/external/tail/tail_item)
+ create_tail_info(tail_item = tail_item)
+
+/datum/organ/external/tail/proc/update_tail(mob/living/carbon/human/tail_owner, skin_tone, random = FALSE)
+ if(!skin_tone)
+ skin_tone = tail_owner?.my_appearance.s_tone || owner?.my_appearance.s_tone
+ if(is_robotic(src))
+ icon_name = "[tail_type]_robotic"
+ else
+ switch(tail_type)
+ if("vox")
+ if(random)
+ skin_tone = rand(1, 6)
+ switch(skin_tone)
+ if(VOXEMERALD)
+ icon_name = "emerald"
+ if(VOXAZURE)
+ icon_name = "azure"
+ if(VOXLGREEN)
+ icon_name = "lightgreen"
+ if(VOXGRAY)
+ icon_name = "grey"
+ if(VOXBROWN)
+ icon_name = "brown"
+ else
+ icon_name = "green"
+ if("tajaran")
+ if(random)
+ skin_tone = rand(1, 2)
+ switch(skin_tone)
+ if(CATBEASTBLACK)
+ icon_name = "tajaran_black"
+ else
+ icon_name = "tajaran_brown"
+ var/mob/living/carbon/human/tail_haver = tail_owner || owner
+ tail_haver?.update_tail_layer()
+
+/datum/organ/external/tail/robotize()
+ tail_icon_file = initial(tail_icon_file)
+ ..()
+ if(owner)
+ update_tail(owner)
+
+/datum/organ/external/tail/peggify()
+ return
+
//=====Legs======
/datum/organ/external/l_leg
@@ -1607,6 +1701,7 @@ Note that amputating the affected organ does in fact remove the infection from t
..(loc)
if(!istype(H))
return
+ post_creation(source)
if(H.dna)
owner_dna = H.dna.Clone()
if(!blood_DNA)
@@ -1641,6 +1736,9 @@ Note that amputating the affected organ does in fact remove the infection from t
//The reason why B isn't just transferred from H.butchering_drops to src.butchering_drops is:
//on examine(), each butchering drop's "desc_modifier()" is added to the description. This adds stuff like "he HAS NO TEETH AT ALL!!!" to the resulting description.
+/obj/item/organ/external/proc/post_creation(datum/organ/external/organ_datum)
+ return
+
/obj/item/organ/external/examine(mob/user)
..()
@@ -1675,8 +1773,6 @@ Note that amputating the affected organ does in fact remove the infection from t
to_chat(user, "[butchery]")
/obj/item/organ/external/update_icon(mob/living/carbon/human/H)
- ..()
-
if(!H && !species)
return
@@ -1804,6 +1900,34 @@ Note that amputating the affected organ does in fact remove the infection from t
if(B)
B.infest_limb(src)
+/obj/item/organ/external/tail
+ name = "tail"
+ part = COSMETIC_ORGAN_TAIL
+ w_class = W_CLASS_SMALL
+ var/tail_icon_file
+ var/tail_type
+ var/tail_icon_key
+ var/tail_state_name
+ var/tail_overlapping = TRUE
+ var/static/list/tail_organ_icons = list()
+
+/obj/item/organ/external/tail/post_creation(datum/organ/external/tail/organ_datum)
+ tail_icon_file = organ_datum.tail_icon_file
+ tail_state_name = organ_datum.icon_name
+ tail_type = organ_datum.tail_type
+ tail_overlapping = organ_datum.overlap_overlays
+ update_icon()
+
+/obj/item/organ/external/tail/update_icon()
+ tail_icon_key = "[tail_state_name]_[tail_type]"
+ var/returned_tail_icon = tail_organ_icons[tail_icon_key]
+ if(!returned_tail_icon)
+ var/icon/new_tail_icon = icon(tail_icon_file, "[tail_state_name]_BEHIND", EAST)
+ new_tail_icon.Shift(EAST, 6)
+ new_tail_icon.Shift(NORTH, 3)
+ returned_tail_icon = tail_organ_icons[tail_icon_key] = new_tail_icon
+ icon = returned_tail_icon
+
/obj/item/organ/external/head
dir = NORTH
name = LIMB_HEAD
@@ -2030,6 +2154,8 @@ Note that amputating the affected organ does in fact remove the infection from t
return FALSE
/datum/organ/external/send_to_past(var/duration)
+ if(cosmetic_only)
+ return
..()
var/static/list/resettable_vars = list(
"damage_state",
diff --git a/code/modules/overlays/mobs.dm b/code/modules/overlays/mobs.dm
index 700dd55adeb..02db8a62942 100644
--- a/code/modules/overlays/mobs.dm
+++ b/code/modules/overlays/mobs.dm
@@ -9,6 +9,12 @@
/obj/abstract/Overlays/mutantrace_layer
layer = FLOAT_LAYER - (TOTAL_LAYERS - MUTANTRACE_LAYER)
+/obj/abstract/Overlays/tail_underlimbs_layer
+ layer = FLOAT_LAYER - (TOTAL_LAYERS - TAIL_UNDERLIMBS_LAYER)
+
+/obj/abstract/Overlays/limbs_layer
+ layer = FLOAT_LAYER - (TOTAL_LAYERS - LIMBS_LAYER)
+
/obj/abstract/Overlays/mutations_layer
layer = FLOAT_LAYER - (TOTAL_LAYERS - MUTATIONS_LAYER)
@@ -45,6 +51,9 @@
/obj/abstract/Overlays/glasses_over_hair_layer
layer = FLOAT_LAYER - (TOTAL_LAYERS - GLASSES_OVER_HAIR_LAYER)
+/obj/abstract/Overlays/tail_layer
+ layer = FLOAT_LAYER - (TOTAL_LAYERS - TAIL_LAYER)
+
/obj/abstract/Overlays/facemask_layer
layer = FLOAT_LAYER - (TOTAL_LAYERS - FACEMASK_LAYER)
@@ -69,9 +78,6 @@
/obj/abstract/Overlays/hand_layer
layer = FLOAT_LAYER - (TOTAL_LAYERS - HAND_LAYER)
-/obj/abstract/Overlays/tail_layer
- layer = FLOAT_LAYER - (TOTAL_LAYERS - TAIL_LAYER)
-
/obj/abstract/Overlays/targeted_layer
layer = FLOAT_LAYER - (TOTAL_LAYERS - TARGETED_LAYER)
@@ -84,6 +90,8 @@
/*
var/obj/abstract/Overlays/fire_layer/fire_layer = new
var/obj/abstract/Overlays/mutantrace_layer/mutantrace_layer = new
+ var/obj/abstract/Overlays/tail_underlimbs_layer/tail_underlimbs_layer = new
+ var/obj/abstract/Overlays/limbs_layer/limbs_layer = new
var/obj/abstract/Overlays/mutations_layer/mutations_layer = new
var/obj/abstract/Overlays/damage_layer/damage_layer = new
var/obj/abstract/Overlays/uniform_layer/uniform_layer = new
@@ -98,12 +106,12 @@
var/obj/abstract/Overlays/back_layer/back_layer = new
var/obj/abstract/Overlays/hair_layer/hair_layer = new
var/obj/abstract/Overlays/glasses_over_hair_layer/glasses_over_hair_layer = new
+ var/obj/abstract/Overlays/tail_layer/tail_layer = new
var/obj/abstract/Overlays/facemask_layer/facemask_layer = new
var/obj/abstract/Overlays/head_layer/head_layer = new
var/obj/abstract/Overlays/handcuff_layer/handcuff_layer = new
var/obj/abstract/Overlays/legcuff_layer/legcuff_layer = new
var/obj/abstract/Overlays/l_hand_layer/l_hand_layer = new
var/obj/abstract/Overlays/r_hand_layer/r_hand_layer = new
- var/obj/abstract/Overlays/tail_layer/tail_layer = new
var/obj/abstract/Overlays/targeted_layer/targeted_layer = new
*/
diff --git a/code/modules/research/designs/robot.dm b/code/modules/research/designs/robot.dm
index 03b7616d649..3228574da5f 100644
--- a/code/modules/research/designs/robot.dm
+++ b/code/modules/research/designs/robot.dm
@@ -58,6 +58,16 @@
category = "Robot"
materials = list(MAT_IRON=15000)
+/datum/design/robot/tail
+ name = "Cyborg Component (Robot tail)"
+ desc = "Used to build a Robot tail."
+ id = "robot_tail"
+ req_tech = list(Tc_ENGINEERING = 1)
+ build_type = MECHFAB
+ build_path = /obj/item/robot_parts/tail
+ category = "Robot"
+ materials = list(MAT_IRON=15000)
+
/datum/design/robot/head
name = "Cyborg Component (Robot head)"
desc = "Used to build a Robot head."
@@ -198,4 +208,4 @@
build_type = MECHFAB
build_path = /obj/item/robot_parts/robot_component/armour/reinforced
category = "Robot_Part"
- materials = list(MAT_IRON=5000, MAT_DIAMOND=5000)
\ No newline at end of file
+ materials = list(MAT_IRON=5000, MAT_DIAMOND=5000)
diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm
index fab84860e83..2daff4596d3 100644
--- a/code/modules/surgery/generic.dm
+++ b/code/modules/surgery/generic.dm
@@ -5,6 +5,7 @@
/datum/surgery_step/generic/
can_infect = 1
+ supports_cosmetic_organs = TRUE
var/painful=1
/datum/surgery_step/generic/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
@@ -14,7 +15,7 @@
return 0
if (!hasorgans(target))
return 0
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
if (affected == null)
return 0
if (affected.status & ORGAN_DESTROYED)
@@ -40,7 +41,6 @@
)
priority = 0.1 //so the tool checks for this step before /generic/cut_open
-
duration = 4 SECONDS
/datum/surgery_step/generic/cut_with_laser/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
@@ -48,29 +48,30 @@
if(target.species && (target.species.anatomy_flags & NO_SKIN))
to_chat(user, "[target] has no skin!")
return 0
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
return affected.open == 0 && target_zone != "mouth"
/datum/surgery_step/generic/cut_with_laser/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] starts the bloodless incision on [target]'s [affected.display_name] with \the [tool].", \
"You start the bloodless incision on [target]'s [affected.display_name] with \the [tool].")
target.custom_pain("You feel a horrible, searing pain in your [affected.display_name]!",1, scream=TRUE)
..()
/datum/surgery_step/generic/cut_with_laser/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] has made a bloodless incision on [target]'s [affected.display_name] with \the [tool].", \
"You have made a bloodless incision on [target]'s [affected.display_name] with \the [tool].",)
//Could be cleaner ...
affected.open = 1
- affected.status |= ORGAN_BLEEDING
+ if(!affected.cosmetic_only)
+ affected.status |= ORGAN_BLEEDING
affected.createwound(CUT, 1)
affected.clamp_wounds()
//spread_germs_to_organ(affected, user) //a laser scalpel shouldn't spread germs.
/datum/surgery_step/generic/cut_with_laser/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user]'s hand slips as the blade sputters, searing a long gash in [target]'s [affected.display_name] with \the [tool]!", \
"Your hand slips as the blade sputters, searing a long gash in [target]'s [affected.display_name] with \the [tool]!")
affected.createwound(CUT, 7.5)
@@ -88,7 +89,6 @@
)
priority = 0.1 //so the tool checks for this step before /generic/cut_open
-
duration = 8 SECONDS
/datum/surgery_step/generic/incision_manager/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
@@ -97,11 +97,11 @@
to_chat(user, "[target] has no skin!")
return 0
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
return affected.open == 0 && target_zone != "mouth"
/datum/surgery_step/generic/incision_manager/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] starts to construct a prepared incision on and within [target]'s [affected.display_name] with \the [tool].", \
"You start to construct a prepared incision on and within [target]'s [affected.display_name] with \the [tool].")
target.custom_pain("You feel a horrible, searing pain in your [affected.display_name] as it is pushed apart!",1, scream=TRUE)
@@ -111,18 +111,19 @@
..()
/datum/surgery_step/generic/incision_manager/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] has constructed a prepared incision on and within [target]'s [affected.display_name] with \the [tool].", \
"You have constructed a prepared incision on and within [target]'s [affected.display_name] with \the [tool].",)
affected.open = 1
- affected.status |= ORGAN_BLEEDING
+ if(!affected.cosmetic_only)
+ affected.status |= ORGAN_BLEEDING
affected.createwound(CUT, 1)
affected.clamp_wounds()
affected.open = 2
tool.icon_state = "[initial(tool.icon_state)]_off"
/datum/surgery_step/generic/incision_manager/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user]'s hand jolts as the system sparks, ripping a gruesome hole in [target]'s [affected.display_name] with \the [tool]!", \
"Your hand jolts as the system sparks, ripping a gruesome hole in [target]'s [affected.display_name] with \the [tool]!")
affected.createwound(CUT, 20)
@@ -148,7 +149,6 @@
)
priority = 0
-
duration = 4 SECONDS
/datum/surgery_step/generic/cut_open/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
@@ -157,28 +157,29 @@
to_chat(user, "[target] has no skin!")
return 0
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
if(. && !affected.open && target_zone != "mouth")
return .
return 0
/datum/surgery_step/generic/cut_open/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] starts the incision on [target]'s [affected.display_name] with \the [tool].", \
"You start the incision on [target]'s [affected.display_name] with \the [tool].")
target.custom_pain("You feel a horrible pain as if from a sharp knife in your [affected.display_name]!",1, scream=TRUE)
..()
/datum/surgery_step/generic/cut_open/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] has made an incision on [target]'s [affected.display_name] with \the [tool].", \
"You have made an incision on [target]'s [affected.display_name] with \the [tool].",)
affected.open = 1
- affected.status |= ORGAN_BLEEDING
+ if(!affected.cosmetic_only)
+ affected.status |= ORGAN_BLEEDING
affected.createwound(CUT, 1)
/datum/surgery_step/generic/cut_open/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user]'s hand slips, slicing open [target]'s [affected.display_name] in the wrong place with \the [tool]!", \
"Your hand slips, slicing open [target]'s [affected.display_name] in the wrong place with \the [tool]!")
affected.createwound(CUT, 10)
@@ -193,7 +194,7 @@
/obj/item/weapon/talisman = 70,
/obj/item/device/assembly/mousetrap = 20,
)
-
+ supports_cosmetic_organs = FALSE
duration = 3 SECONDS
/datum/surgery_step/generic/clamp_bleeders/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
@@ -234,7 +235,6 @@
/obj/item/tool/crowbar = 75,
/obj/item/weapon/kitchen/utensil/fork = 50
)
-
duration = 3 SECONDS
/datum/surgery_step/generic/retract_skin/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
@@ -243,11 +243,11 @@
to_chat(user, "[target] has no skin!")
return 0
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
return affected.open == 1 //&& !(affected.status & ORGAN_BLEEDING)
/datum/surgery_step/generic/retract_skin/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
var/msg = "[user] starts to pry open the incision on [target]'s [affected.display_name] with \the [tool]."
var/self_msg = "You start to pry open the incision on [target]'s [affected.display_name] with \the [tool]."
if (target_zone == LIMB_CHEST)
@@ -261,7 +261,7 @@
..()
/datum/surgery_step/generic/retract_skin/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
var/msg = "[user] keeps the incision open on [target]'s [affected.display_name] with \the [tool]."
var/self_msg = "You keep the incision open on [target]'s [affected.display_name] with \the [tool]."
if (target_zone == LIMB_CHEST)
@@ -274,7 +274,7 @@
affected.open = 2
/datum/surgery_step/generic/retract_skin/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
var/msg = "[user]'s hand slips, tearing the edges of the incision on [target]'s [affected.display_name] with \the [tool]!"
var/self_msg = "Your hand slips, tearing the edges of the incision on [target]'s [affected.display_name] with \the [tool]!"
if (target_zone == LIMB_CHEST)
@@ -303,7 +303,6 @@
/obj/item/weapon/lighter = 50,
/obj/item/tool/weldingtool = 25,
)
-
duration = 3 SECONDS
/datum/surgery_step/generic/cauterize/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
@@ -312,18 +311,18 @@
to_chat(user, "[target] has no skin!")
return 0
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
return affected.open && target_zone != "mouth"
/datum/surgery_step/generic/cauterize/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] is beginning to cauterize the incision on [target]'s [affected.display_name] with \the [tool]." , \
"You are beginning to cauterize the incision on [target]'s [affected.display_name] with \the [tool].")
target.custom_pain("Your [affected.display_name] is being burned!",1, scream=TRUE)
..()
/datum/surgery_step/generic/cauterize/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] cauterizes the incision on [target]'s [affected.display_name] with \the [tool].", \
"You cauterize the incision on [target]'s [affected.display_name] with \the [tool].")
affected.open = 0
@@ -331,7 +330,7 @@
affected.status &= ~ORGAN_BLEEDING
/datum/surgery_step/generic/cauterize/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user]'s hand slips, leaving a small burn on [target]'s [affected.display_name] with \the [tool]!", \
"Your hand slips, leaving a small burn on [target]'s [affected.display_name] with \the [tool]!")
target.apply_damage(3, BURN, affected)
@@ -345,7 +344,6 @@
/obj/item/weapon/kitchen/utensil/knife/large/butch = 75,
/obj/item/weapon/hatchet = 75,
)
-
duration = 11 SECONDS
/datum/surgery_step/generic/cut_limb/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
@@ -353,7 +351,7 @@
return 0
if (!hasorgans(target))
return 0
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
if (affected == null)
return 0
if (affected.status & ORGAN_DESTROYED)
@@ -363,14 +361,14 @@
return target_zone != LIMB_CHEST && target_zone != LIMB_GROIN && target_zone != LIMB_HEAD
/datum/surgery_step/generic/cut_limb/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] is beginning to cut off [target]'s [affected.display_name] with \the [tool]." , \
"You are beginning to cut off [target]'s [affected.display_name] with \the [tool].")
target.custom_pain("Your [affected.display_name] is being ripped apart!",1, scream=TRUE)
..()
/datum/surgery_step/generic/cut_limb/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] cuts off [target]'s [affected.display_name] with \the [tool].", \
"You cut off [target]'s [affected.display_name] with \the [tool].")
affected.open = 0 //Resets surgery status on limb, should prevent conflicting/phantom surgery
@@ -397,7 +395,7 @@
)
priority = 0.1 //Tries to inject biofoam before other steps
-
+ supports_cosmetic_organs = FALSE
duration = 1 SECONDS
/datum/surgery_step/generic/injectfoam/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
diff --git a/code/modules/surgery/robolimbs.dm b/code/modules/surgery/robolimbs.dm
index a900f2b11bd..86d9c9dd68f 100644
--- a/code/modules/surgery/robolimbs.dm
+++ b/code/modules/surgery/robolimbs.dm
@@ -5,10 +5,12 @@
/datum/surgery_step/limb
can_infect = 1
+ supports_cosmetic_organs = TRUE
+
/datum/surgery_step/limb/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if (!hasorgans(target))
return 0
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
if (!affected || affected.name == LIMB_HEAD)
return 0
if (!(affected.status & ORGAN_DESTROYED))
@@ -38,19 +40,19 @@
duration = 8 SECONDS
/datum/surgery_step/limb/cut/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] starts cutting away flesh where [target]'s [affected.display_name] used to be with \the [tool].", \
"You start cutting away flesh where [target]'s [affected.display_name] used to be with \the [tool].")
..()
/datum/surgery_step/limb/cut/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] cuts away flesh where [target]'s [affected.display_name] used to be with \the [tool].", \
"You cut away flesh where [target]'s [affected.display_name] used to be with \the [tool].")
affected.status |= ORGAN_CUT_AWAY
/datum/surgery_step/limb/cut/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
if (affected.parent)
affected = affected.parent
user.visible_message("[user]'s hand slips, cutting [target]'s [affected.display_name] open!", \
@@ -70,23 +72,23 @@
duration = 8 SECONDS
/datum/surgery_step/limb/mend/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
return ..() && affected.status & ORGAN_CUT_AWAY
/datum/surgery_step/limb/mend/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] is beginning to reposition flesh and nerve endings where [target]'s [affected.display_name] used to be with [tool].", \
"You start repositioning flesh and nerve endings where [target]'s [affected.display_name] used to be with [tool].")
..()
/datum/surgery_step/limb/mend/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] has finished repositioning flesh and nerve endings where [target]'s [affected.display_name] used to be with [tool].", \
"You have finished repositioning flesh and nerve endings where [target]'s [affected.display_name] used to be with [tool].")
affected.open = 3
/datum/surgery_step/limb/mend/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
if (affected.parent)
affected = affected.parent
user.visible_message("[user]'s hand slips, tearing flesh on [target]'s [affected.display_name]!", \
@@ -114,17 +116,17 @@
duration = 6 SECONDS
/datum/surgery_step/limb/prepare/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
return ..() && affected.open == 3
/datum/surgery_step/limb/prepare/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] starts adjusting area around [target]'s [affected.display_name] with \the [tool].", \
"You start adjusting area around [target]'s [affected.display_name] with \the [tool].")
..()
/datum/surgery_step/limb/prepare/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] has finished adjusting the area around [target]'s [affected.display_name] with \the [tool].", \
"You have finished adjusting the area around [target]'s [affected.display_name] with \the [tool].")
affected.status |= ORGAN_ATTACHABLE
@@ -133,7 +135,7 @@
affected.open = 0
/datum/surgery_step/limb/prepare/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
if (affected.parent)
affected = affected.parent
user.visible_message("[user]'s hand slips, searing [target]'s [affected.display_name]!", \
@@ -147,15 +149,13 @@
allowed_tools = list(
/obj/item/robot_parts = 100,
)
-
can_infect = 0
-
duration = 8 SECONDS
/datum/surgery_step/limb/attach/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/robot_parts/p = tool
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
if(!(affected.status & ORGAN_ATTACHABLE) || !istype(p))
return 0 //not even ready for this and we're assuming they're using a fucking robot part!
if (p.part)
@@ -167,19 +167,19 @@
return ..()
/datum/surgery_step/limb/attach/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] starts attaching [tool] where [target]'s [affected.display_name] used to be.", \
"You start attaching [tool] where [target]'s [affected.display_name] used to be.")
/datum/surgery_step/limb/attach/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] has attached [tool] where [target]'s [affected.display_name] used to be.", \
"You have attached [tool] where [target]'s [affected.display_name] used to be.")
affected.attach(tool)
/datum/surgery_step/limb/attach/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user]'s hand slips, damaging connectors on [target]'s [affected.display_name]!", \
"Your hand slips, damaging connectors on [target]'s [affected.display_name]!")
target.apply_damage(10, BRUTE, affected)
@@ -193,7 +193,7 @@
)
can_infect = 0
-
+ supports_cosmetic_organs = FALSE
duration = 8 SECONDS
/datum/surgery_step/limb/attach_plank/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
@@ -236,7 +236,7 @@
/datum/surgery_step/limb/attach_flesh/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/o = tool
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
if(!(affected.status & ORGAN_ATTACHABLE) || !istype(o))
return 0
if (o.part)
@@ -249,19 +249,19 @@
return ..()
/datum/surgery_step/limb/attach_flesh/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] starts attaching [tool] where [target]'s [affected.display_name] used to be.", \
"You start attaching [tool] where [target]'s [affected.display_name] used to be.")
/datum/surgery_step/limb/attach_flesh/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user] has attached [tool] where [target]'s [affected.display_name] used to be.", \
"You have attached [tool] where [target]'s [affected.display_name] used to be.")
affected.attach(tool)
/datum/surgery_step/limb/attach_flesh/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/datum/organ/external/affected = target.get_organ(target_zone)
+ var/datum/organ/external/affected = target.get_organ(target_zone, cosmetic = TRUE)
user.visible_message("[user]'s hand slips, damaging connectors on [target]'s [affected.display_name]!", \
"Your hand slips, damaging connectors on [target]'s [affected.display_name]!")
target.apply_damage(10, BRUTE, affected)
diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm
index c3c6d92bd8f..a162bd5790a 100644
--- a/code/modules/surgery/surgery.dm
+++ b/code/modules/surgery/surgery.dm
@@ -10,7 +10,7 @@
var/list/disallowed_species = null
var/duration = 0
-
+ var/supports_cosmetic_organs = FALSE
var/list/mob/doing_surgery = list() //who's doing this RIGHT NOW
// evil infection stuff that will make everyone hate me
@@ -65,7 +65,7 @@
if (can_infect && affected)
spread_germs_to_organ(affected, user)
- if(!(affected.status & (ORGAN_ROBOT|ORGAN_PEG)))//robot organs and pegs can't spread diseases or splatter blood
+ if((!(affected.status & (ORGAN_ROBOT|ORGAN_PEG))) && !affected.cosmetic_only)//robot organs and pegs can't spread diseases or splatter blood
var/block = user.check_contact_sterility(HANDS)
var/bleeding = user.check_bodypart_bleeding(HANDS)
target.oneway_contact_diseases(user,block,bleeding)//potentially spreads diseases from us to them, wear latex gloves!
@@ -108,7 +108,7 @@
return null
/proc/spread_germs_to_organ(datum/organ/external/E, mob/living/carbon/human/user)
- if(!istype(user) || !istype(E))
+ if(!istype(user) || !istype(E) || E.cosmetic_only)
return
var/germ_level = user.germ_level
@@ -131,8 +131,19 @@
clumsy = 1
var/target_area = user.zone_sel ? user.zone_sel.selecting : get_random_zone_sel()
+ if(target_area == LIMB_GROIN)
+ var/groin_or_tail = input(user, "Groin or tail?", "Choose Target Zone", "Groin") as null|anything in list("Groin", "Tail")
+ switch(groin_or_tail)
+ if("Groin")
+ target_area = LIMB_GROIN
+ if("Tail")
+ target_area = COSMETIC_ORGAN_TAIL
for(var/datum/surgery_step/S in surgery_steps)
+ if(ishuman(M))
+ var/mob/living/carbon/human/human_target = M
+ if((target_area in human_target.cosmetic_organs_by_name) && !S.supports_cosmetic_organs)
+ continue
//check if tool is right or close enough and if this step is possible
sleep_fail = 0
if(S.tool_quality(tool))
diff --git a/icons/effects/species.dmi b/icons/effects/species.dmi
index dea7af2b0ef..f7ca464f73e 100644
Binary files a/icons/effects/species.dmi and b/icons/effects/species.dmi differ
diff --git a/icons/mob/human_races/vox/r_def_vox.dmi b/icons/mob/human_races/vox/r_def_vox.dmi
index 6f2497be47d..cacf1d90fd1 100644
Binary files a/icons/mob/human_races/vox/r_def_vox.dmi and b/icons/mob/human_races/vox/r_def_vox.dmi differ
diff --git a/icons/mob/human_races/vox/r_def_voxazu.dmi b/icons/mob/human_races/vox/r_def_voxazu.dmi
index 886a726fb30..c0394361dc5 100644
Binary files a/icons/mob/human_races/vox/r_def_voxazu.dmi and b/icons/mob/human_races/vox/r_def_voxazu.dmi differ
diff --git a/icons/mob/human_races/vox/r_def_voxbrn.dmi b/icons/mob/human_races/vox/r_def_voxbrn.dmi
index e2b48f1959a..af7be19bd18 100644
Binary files a/icons/mob/human_races/vox/r_def_voxbrn.dmi and b/icons/mob/human_races/vox/r_def_voxbrn.dmi differ
diff --git a/icons/mob/human_races/vox/r_def_voxemrl.dmi b/icons/mob/human_races/vox/r_def_voxemrl.dmi
index 339bd6f2f0e..c9e622a1d6a 100644
Binary files a/icons/mob/human_races/vox/r_def_voxemrl.dmi and b/icons/mob/human_races/vox/r_def_voxemrl.dmi differ
diff --git a/icons/mob/human_races/vox/r_def_voxgry.dmi b/icons/mob/human_races/vox/r_def_voxgry.dmi
index ecf93b8adda..d3b4f5e2824 100644
Binary files a/icons/mob/human_races/vox/r_def_voxgry.dmi and b/icons/mob/human_races/vox/r_def_voxgry.dmi differ
diff --git a/icons/mob/human_races/vox/r_def_voxlgrn.dmi b/icons/mob/human_races/vox/r_def_voxlgrn.dmi
index a3c5076f62a..cdcdc187263 100644
Binary files a/icons/mob/human_races/vox/r_def_voxlgrn.dmi and b/icons/mob/human_races/vox/r_def_voxlgrn.dmi differ
diff --git a/icons/mob/human_races/vox/r_vox.dmi b/icons/mob/human_races/vox/r_vox.dmi
index 994aa4d3684..92bfe552a84 100644
Binary files a/icons/mob/human_races/vox/r_vox.dmi and b/icons/mob/human_races/vox/r_vox.dmi differ
diff --git a/icons/mob/human_races/vox/r_voxazu.dmi b/icons/mob/human_races/vox/r_voxazu.dmi
index e8283333af6..8ad3b14c35b 100644
Binary files a/icons/mob/human_races/vox/r_voxazu.dmi and b/icons/mob/human_races/vox/r_voxazu.dmi differ
diff --git a/icons/mob/human_races/vox/r_voxbrn.dmi b/icons/mob/human_races/vox/r_voxbrn.dmi
index 22a1291294d..b9c791e57c9 100644
Binary files a/icons/mob/human_races/vox/r_voxbrn.dmi and b/icons/mob/human_races/vox/r_voxbrn.dmi differ
diff --git a/icons/mob/human_races/vox/r_voxemrl.dmi b/icons/mob/human_races/vox/r_voxemrl.dmi
index 7651192eea6..7f754b65c70 100644
Binary files a/icons/mob/human_races/vox/r_voxemrl.dmi and b/icons/mob/human_races/vox/r_voxemrl.dmi differ
diff --git a/icons/mob/human_races/vox/r_voxgry.dmi b/icons/mob/human_races/vox/r_voxgry.dmi
index c552bfd7ea8..e347a1aa794 100644
Binary files a/icons/mob/human_races/vox/r_voxgry.dmi and b/icons/mob/human_races/vox/r_voxgry.dmi differ
diff --git a/icons/mob/human_races/vox/r_voxlgrn.dmi b/icons/mob/human_races/vox/r_voxlgrn.dmi
index 3a11997d4da..21997d08b0d 100644
Binary files a/icons/mob/human_races/vox/r_voxlgrn.dmi and b/icons/mob/human_races/vox/r_voxlgrn.dmi differ
diff --git a/icons/mob/human_races/vox/tails.dmi b/icons/mob/human_races/vox/tails.dmi
new file mode 100644
index 00000000000..9cd42af7f60
Binary files /dev/null and b/icons/mob/human_races/vox/tails.dmi differ
diff --git a/icons/mob/tails.dmi b/icons/mob/tails.dmi
new file mode 100644
index 00000000000..91984884058
Binary files /dev/null and b/icons/mob/tails.dmi differ
diff --git a/vgstation13.dme b/vgstation13.dme
index b749fcc0b24..7009e6cb34a 100644
--- a/vgstation13.dme
+++ b/vgstation13.dme
@@ -71,6 +71,7 @@
#include "__DEFINES\simple_animal_defines.dm"
#include "__DEFINES\snow.dm"
#include "__DEFINES\sort.dm"
+#include "__DEFINES\span.dm"
#include "__DEFINES\spell_defines.dm"
#include "__DEFINES\striketeam_defines.dm"
#include "__DEFINES\stylesheet.dm"
@@ -296,6 +297,7 @@
#include "code\datums\mind.dm"
#include "code\datums\mixed.dm"
#include "code\datums\modules.dm"
+#include "code\datums\mutable_appearance.dm"
#include "code\datums\next_map.dm"
#include "code\datums\periodic_news.dm"
#include "code\datums\profiling.dm"
@@ -1986,7 +1988,8 @@
#include "code\modules\mob\living\carbon\human\life\handle_statis_bag.dm"
#include "code\modules\mob\living\carbon\human\life\handle_stomach.dm"
#include "code\modules\mob\living\carbon\human\life\life_helpers.dm"
-#include "code\modules\mob\living\carbon\human\plasmaman\species.dm"
+#include "code\modules\mob\living\carbon\human\species\plasmaman.dm"
+#include "code\modules\mob\living\carbon\human\species\vox.dm"
#include "code\modules\mob\living\carbon\monkey\combat.dm"
#include "code\modules\mob\living\carbon\monkey\death.dm"
#include "code\modules\mob\living\carbon\monkey\diona.dm"