diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index 1048aaa5c861..e44755574eea 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -35,6 +35,7 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/squid_face, GLOB.squid_face_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/ipc_screens, GLOB.ipc_screens_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/ipc_antennas, GLOB.ipc_antennas_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/ipc_tail, GLOB.ipc_tail_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/ipc_chassis, GLOB.ipc_chassis_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_markings, GLOB.moth_markings_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/spider_legs, GLOB.spider_legs_list)
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 8838ba324530..fdeadc13b61a 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -72,6 +72,8 @@
init_sprite_accessory_subtypes(/datum/sprite_accessory/ipc_screens, GLOB.ipc_screens_list)
if(!GLOB.ipc_antennas_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/ipc_antennas, GLOB.ipc_antennas_list)
+ if(!GLOB.ipc_tail_list.len)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/ipc_antennas, GLOB.ipc_tail_list)
if(!GLOB.ipc_chassis_list.len)
init_sprite_accessory_subtypes(/datum/sprite_accessory/ipc_chassis, GLOB.ipc_chassis_list)
if(!GLOB.spider_legs_list.len)
diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm
index aca090086487..479e43e34543 100644
--- a/code/_globalvars/lists/flavor_misc.dm
+++ b/code/_globalvars/lists/flavor_misc.dm
@@ -39,6 +39,7 @@ GLOBAL_LIST_EMPTY(moth_markings_list)
GLOBAL_LIST_EMPTY(squid_face_list)
GLOBAL_LIST_EMPTY(ipc_screens_list)
GLOBAL_LIST_EMPTY(ipc_antennas_list)
+GLOBAL_LIST_EMPTY(ipc_tail_list)
GLOBAL_LIST_EMPTY(ipc_chassis_list)
GLOBAL_LIST_INIT(ipc_brain_list, list("Posibrain", "Man-Machine Interface"))
GLOBAL_LIST_EMPTY(spider_legs_list)
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index e73a186087f3..3fa8bfc5266b 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -112,6 +112,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"squid_face" = "Squidward",
"ipc_screen" = "Blue",
"ipc_antenna" = "None",
+ "ipc_tail" = "None",
"ipc_chassis" = "Morpheus Cyberkinetics (Custom)",
"ipc_brain" = "Posibrain",
"kepori_feathers" = "Plain",
@@ -675,6 +676,19 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += ""
mutant_category = 0
+ if("ipc_tail" in pref_species.default_features)
+ if(!mutant_category)
+ dat += APPEARANCE_CATEGORY_COLUMN
+
+ dat += "
Tail Style
"
+
+ dat += "[features["ipc_tail"]]
"
+
+ mutant_category++
+ if(mutant_category >= MAX_MUTANT_ROWS)
+ dat += ""
+ mutant_category = 0
+
if("ipc_chassis" in pref_species.default_features)
if(!mutant_category)
dat += APPEARANCE_CATEGORY_COLUMN
@@ -1913,6 +1927,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(new_ipc_antenna)
features["ipc_antenna"] = new_ipc_antenna
+ if("ipc_tail")
+ var/new_ipc_tail
+
+ new_ipc_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.ipc_tail_list
+
+ if(new_ipc_tail)
+ features["ipc_tail"] = new_ipc_tail
+
if("ipc_chassis")
var/new_ipc_chassis
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 7800a7b57f33..0b95e291b794 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -431,6 +431,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
READ_FILE(S["feature_squid_face"], features["squid_face"])
READ_FILE(S["feature_ipc_screen"], features["ipc_screen"])
READ_FILE(S["feature_ipc_antenna"], features["ipc_antenna"])
+ READ_FILE(S["feature_ipc_tail"], features["ipc_tail"])
READ_FILE(S["feature_ipc_chassis"], features["ipc_chassis"])
READ_FILE(S["feature_ipc_brain"], features["ipc_brain"])
READ_FILE(S["feature_kepori_feathers"], features["kepori_feathers"])
@@ -541,6 +542,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
features["squid_face"] = sanitize_inlist(features["squid_face"], GLOB.squid_face_list, "Squidward")
features["ipc_screen"] = sanitize_inlist(features["ipc_screen"], GLOB.ipc_screens_list)
features["ipc_antenna"] = sanitize_inlist(features["ipc_antenna"], GLOB.ipc_antennas_list)
+ features["ipc_tail"] = sanitize_inlist(features["ipc_tail"], GLOB.ipc_tail_list)
features["ipc_chassis"] = sanitize_inlist(features["ipc_chassis"], GLOB.ipc_chassis_list)
features["ipc_brain"] = sanitize_inlist(features["ipc_brain"], GLOB.ipc_brain_list)
features["kepori_feathers"] = sanitize_inlist(features["kepori_feathers"], GLOB.kepori_feathers_list, "Plain")
@@ -618,6 +620,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["feature_squid_face"] , features["squid_face"])
WRITE_FILE(S["feature_ipc_screen"] , features["ipc_screen"])
WRITE_FILE(S["feature_ipc_antenna"] , features["ipc_antenna"])
+ WRITE_FILE(S["feature_ipc_tail"] , features["ipc_tail"])
WRITE_FILE(S["feature_ipc_chassis"] , features["ipc_chassis"])
WRITE_FILE(S["feature_ipc_brain"] , features["ipc_brain"])
WRITE_FILE(S["feature_kepori_feathers"] , features["kepori_feathers"])
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/ipc.dm b/code/modules/mob/dead/new_player/sprite_accessories/ipc.dm
index 20f2fe732d31..b13b8f96a51e 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/ipc.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/ipc.dm
@@ -236,12 +236,71 @@
name = "Right Angle"
icon_state = "rangle"
+/datum/sprite_accessory/ipc_antennas/sprinter
+ name = "Sprinter Tail"
+ icon_state = "sprinter"
+
+/datum/sprite_accessory/ipc_antennas/simple
+ name = "Synth Simple"
+ icon_state = "simple_synth"
+
+/datum/sprite_accessory/ipc_antennas/short
+ name = "Synth Short"
+ icon_state = "short_synth"
+
+/datum/sprite_accessory/ipc_antennas/curled
+ name = "Synth Curled"
+ icon_state = "curled_synth"
+
+/datum/sprite_accessory/ipc_antennas/ram //remade
+ name = "Synth Ram"
+ icon_state = "ram_synth"
+
+// Start tails
+
+/datum/sprite_accessory/ipc_tail
+ icon = 'icons/mob/ipc_accessories.dmi'
+ color_src = MUTCOLORS
+
+/datum/sprite_accessory/ipc_tail/none
+ name = "None"
+ icon_state = "none"
+
+/datum/sprite_accessory/ipc_tail/lizard
+ name = "Synthetic Sarathi"
+ icon_state = "synth"
+
+/datum/sprite_accessory/ipc_tail/lizard_big
+ name = "Synthetic Sarathi Large"
+ icon_state = "large"
+
+/datum/sprite_accessory/ipc_tail/plug
+ name = "Power Plug"
+ icon_state = "plug"
+ secondary_color = TRUE
+
+/datum/sprite_accessory/ipc_tail/cat
+ name = "Pawsitrons Cat"
+ icon_state = "cat"
+
+/datum/sprite_accessory/ipc_tail/fox
+ name = "Pawsitrons Fox"
+ icon_state = "fox"
+
+/datum/sprite_accessory/ipc_tail/fox_alt
+ name = "Pawsitrons Fox 2"
+ icon_state = "fox2"
+
// Start chassis - the worst thing ever please rework this
/datum/sprite_accessory/ipc_chassis // Used for changing limb icons, doesn't need to hold the actual icon. That's handled in ipc.dm
icon = null
icon_state = "who cares fuck you" // In order to pull the chassis correctly, we need AN icon_state(see line 36-39). It doesn't have to be useful, because it isn't used.
color_src = 0
+ var/use_eyes = FALSE //do we use normal robotic eyes? used when we dont want a screen but still want visible eyes
+ var/has_screen = TRUE //do we have a screen to toggle
+ var/has_overlay = FALSE //does this chasis have a overlay icon?
+ var/is_digi = FALSE //does this chasis use digitigrade
/datum/sprite_accessory/ipc_chassis/mcgreyscale
name = "Morpheus Cyberkinetics (Custom)"
@@ -287,3 +346,25 @@
/datum/sprite_accessory/ipc_chassis/zenghupharmaceuticals
name = "Zeng-Hu Pharmaceuticals"
limbs_id = "zhpipc"
+
+/datum/sprite_accessory/ipc_chassis/pgfmechanicsplantigrade
+ name = "PGF MECHANICS TYPE-P"
+ limbs_id = "pgfipc-p"
+ has_screen = FALSE
+ color_src = MUTCOLORS
+ has_overlay = TRUE
+ use_eyes = TRUE
+
+/datum/sprite_accessory/ipc_chassis/pgfmechanicsdigigrade
+ name = "PGF MECHANICS TYPE-D"
+ limbs_id = "pgfipc-p" //the digigrade var makes it so we use digi leg variant instead
+ has_screen = FALSE
+ color_src = MUTCOLORS
+ has_overlay = TRUE
+ use_eyes = TRUE
+ is_digi = TRUE
+
+/datum/sprite_accessory/ipc_chassis/inteqsprinter
+ name = "Inteq Mothership 'Sprinter'"
+ limbs_id = "inteqsprinter"
+ has_screen = FALSE
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index fee2b6f0957d..8a8677523fc1 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -971,6 +971,8 @@ GLOBAL_LIST_EMPTY(roundstart_races)
S = GLOB.ipc_screens_list[H.dna.features["ipc_screen"]]
if("ipc_antenna")
S = GLOB.ipc_antennas_list[H.dna.features["ipc_antenna"]]
+ if("ipc_tail")
+ S = GLOB.ipc_tail_list[H.dna.features["ipc_tail"]]
if("ipc_chassis")
S = GLOB.ipc_chassis_list[H.dna.features["ipc_chassis"]]
if("ipc_brain")
diff --git a/code/modules/mob/living/carbon/human/species_types/IPC.dm b/code/modules/mob/living/carbon/human/species_types/IPC.dm
index dfa12f329054..381708757fd1 100644
--- a/code/modules/mob/living/carbon/human/species_types/IPC.dm
+++ b/code/modules/mob/living/carbon/human/species_types/IPC.dm
@@ -17,8 +17,8 @@
mutantlungs = null //no more collecting change for you
mutantappendix = null
mutant_organs = list(/obj/item/organ/cyberimp/arm/power_cord)
- mutant_bodyparts = list("ipc_screen", "ipc_antenna", "ipc_chassis", "ipc_brain")
- default_features = list("mcolor" = "#7D7D7D", "ipc_screen" = "Static", "ipc_antenna" = "None", "ipc_chassis" = "Morpheus Cyberkinetics (Custom)", "ipc_brain" = "Posibrain", "body_size" = "Normal")
+ mutant_bodyparts = list("ipc_screen", "ipc_antenna", "ipc_chassis", "ipc_tail", "ipc_brain")
+ default_features = list("mcolor" = "#7D7D7D", "ipc_screen" = "Static", "ipc_antenna" = "None", "ipc_chassis" = "Morpheus Cyberkinetics (Custom)", "ipc_tail" = "None", "ipc_brain" = "Posibrain", "body_size" = "Normal")
meat = /obj/item/stack/sheet/plasteel{amount = 5}
skinned_type = /obj/item/stack/sheet/metal{amount = 10}
exotic_bloodtype = "Coolant"
@@ -49,13 +49,14 @@
/// The last screen used when the IPC died.
var/saved_screen
var/datum/action/innate/change_screen/change_screen
+ var/has_screen = TRUE //do we have a screen. Used to determine if we mess with the screen or not
/datum/species/ipc/random_name(unique)
var/ipc_name = "[pick(GLOB.posibrain_names)]-[rand(100, 999)]"
return ipc_name
/datum/species/ipc/New()
- . = ..()
+
// This is in new because "[HEAD_LAYER]" etc. is NOT a constant compile-time value. For some reason.
// Why not just use HEAD_LAYER? Well, because HEAD_LAYER is a number, and if you try to use numbers as indexes,
// BYOND will try to make it an ordered list. So, we have to use a string. This is annoying, but it's the only way to do it smoothly.
@@ -64,17 +65,19 @@
)
/datum/species/ipc/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) // Let's make that IPC actually robotic.
+ . = ..()
if(ishuman(C))
var/mob/living/carbon/human/H = C
if(!change_screen)
- change_screen = new
- change_screen.Grant(H)
+ var/datum/species/ipc/species_datum = H.dna.species
+ if(species_datum?.has_screen)
+ change_screen = new
+ change_screen.Grant(H)
if(H.dna.features["ipc_brain"] == "Man-Machine Interface")
mutantbrain = /obj/item/organ/brain/mmi_holder
else
mutantbrain = /obj/item/organ/brain/mmi_holder/posibrain
C.RegisterSignal(C, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, TYPE_PROC_REF(/mob/living/carbon, charge))
- return ..()
/datum/species/ipc/on_species_loss(mob/living/carbon/C)
. = ..()
@@ -83,6 +86,8 @@
C.UnregisterSignal(C, COMSIG_PROCESS_BORGCHARGER_OCCUPANT)
/datum/species/ipc/spec_death(gibbed, mob/living/carbon/C)
+ if(!has_screen)
+ return
saved_screen = C.dna.features["ipc_screen"]
C.dna.features["ipc_screen"] = "BSOD"
C.update_body()
@@ -91,6 +96,8 @@
/datum/species/ipc/proc/post_death(mob/living/carbon/C)
if(C.stat < DEAD)
return
+ if(!has_screen)
+ return
C.dna.features["ipc_screen"] = null // Turns off their monitor on death.
C.update_body()
@@ -110,6 +117,11 @@
if(!ishuman(owner))
return
var/mob/living/carbon/human/H = owner
+ var/datum/species/ipc/species_datum = H.dna.species
+ if(!species_datum)
+ return
+ if(!species_datum.has_screen)
+ return
H.dna.features["ipc_screen"] = screen_choice
H.eye_color = sanitize_hexcolor(color_choice)
H.update_body()
@@ -215,14 +227,17 @@
/datum/species/ipc/spec_revival(mob/living/carbon/human/H)
- H.dna.features["ipc_screen"] = "BSOD"
- H.update_body()
+ if(has_screen)
+ H.dna.features["ipc_screen"] = "BSOD"
+ H.update_body()
H.say("Reactivating [pick("core systems", "central subroutines", "key functions")]...")
addtimer(CALLBACK(src, PROC_REF(post_revival), H), 6 SECONDS)
/datum/species/ipc/proc/post_revival(mob/living/carbon/human/H)
if(H.stat == DEAD)
return
+ if(!has_screen)
+ return
H.dna.features["ipc_screen"] = saved_screen
H.update_body()
@@ -231,12 +246,39 @@
var/datum/sprite_accessory/ipc_chassis/chassis_of_choice = GLOB.ipc_chassis_list[C.dna.features["ipc_chassis"]]
+ if(chassis_of_choice.use_eyes)
+ LAZYREMOVE(species_traits, NOEYESPRITES)
+ LAZYADD(species_traits, EYECOLOR)
+ C.update_body()
+
+ if(!chassis_of_choice.has_screen)
+ has_screen = FALSE
+ C.dna.features["ipc_screen"] = null
+ C.update_body()
+
+ if(chassis_of_choice.is_digi)
+ digitigrade_customization = DIGITIGRADE_FORCED
+ bodytype = BODYTYPE_DIGITIGRADE
+
for(var/obj/item/bodypart/BP as anything in C.bodyparts) //Override bodypart data as necessary
if(BP.limb_id=="synth")
BP.uses_mutcolor = chassis_of_choice.color_src ? TRUE : FALSE
+
+ if(chassis_of_choice.icon)
+ BP.static_icon = chassis_of_choice.icon
+ BP.icon = chassis_of_choice.icon
+
+ if(chassis_of_choice.has_overlay)
+ BP.overlay_icon_state = TRUE
+
+ if(chassis_of_choice.is_digi)
+ if(istype(BP,/obj/item/bodypart/leg))
+ BP.bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC | BODYTYPE_DIGITIGRADE //i hate this so much
+
if(BP.uses_mutcolor)
BP.should_draw_greyscale = TRUE
BP.species_color = C.dna?.features["mcolor"]
+ BP.species_secondary_color = C.dna?.features["mcolor2"]
BP.limb_id = chassis_of_choice.limbs_id
BP.name = "\improper[chassis_of_choice.name] [parse_zone(BP.body_zone)]"
diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm
index de0ebac6eddb..0c200df9f6b1 100644
--- a/code/modules/surgery/organs/eyes.dm
+++ b/code/modules/surgery/organs/eyes.dm
@@ -141,6 +141,7 @@
/obj/item/organ/eyes/robotic
name = "robotic eyes"
icon_state = "robotic_eyes"
+ eye_icon_state = "eyes_synth" // i feel like this should be here
desc = "A very basic set of optical sensors with no extra vision modes or functions."
status = ORGAN_ROBOTIC
organ_flags = ORGAN_SYNTHETIC
diff --git a/icons/mob/ipc_accessories.dmi b/icons/mob/ipc_accessories.dmi
index 86311ca3172e..e9fb262aa319 100644
Binary files a/icons/mob/ipc_accessories.dmi and b/icons/mob/ipc_accessories.dmi differ
diff --git a/icons/mob/species/ipc/bodyparts.dmi b/icons/mob/species/ipc/bodyparts.dmi
index f5c348617b56..1b4b568dcc78 100644
Binary files a/icons/mob/species/ipc/bodyparts.dmi and b/icons/mob/species/ipc/bodyparts.dmi differ