From da592558c244016785ece095125e91c8ae300a82 Mon Sep 17 00:00:00 2001
From: FlamingLily <80451102+FlamingLily@users.noreply.github.com>
Date: Thu, 8 May 2025 04:36:16 +1000
Subject: [PATCH] Hidden Shell Records, take TWO!!! (#20713)
!!! Please merge AFTER #20723 for migrate version (this PR is set up to
seamlessly be merged after that PR) !!!
Adds a new option to character preferences determining whether a shell
is a hidden shell or not. Right now this is a Yes/No toggle that solely
makes records display as "Human" instead of "Shell Frame".
The previous iteration of this was icky.

I hope this is better.
My rationale for this is twofold:
Right now, you can only play a hidden shell "correctly" if you're
untagged. Firstly, this isn't explained anywhere, so people might miss
this by playing a tagged shell that's playing human. Someone might do
this because a tag can be a potent story tool, especially for specific
brands or lines of shells. Imagine tag scanning a runaway you've found
and getting presented with `HLTD-S07U24`, suddenly you get a huge amount
of storytelling there that wouldn't be present without the tag. any
similarities to persons living or dead is purely coincidental.
Secondly, it also means you can't play a shell who doesn't try and hide
it, but also has no tag, because that'll automatically show as human,
which is problematic in many ways.
Also, I moved the "species" field in records to the top with the rest of
the public info, and took it out of employement records, because
security and medical would definitely also get that info, logically
speaking.
In the future (with lore team approval) i would like to enable certain
human citizenships for shells with this preference enabled (likely just
Sol, but i mean if lore team wants we can get wacky with Dominia too),
but that's out of scope for this PR.
---
SQL/migrate-2023/V013__hidden_shells.sql | 5 ++
code/datums/records.dm | 4 +-
.../preference_setup/general/01_basic.dm | 20 ++++++-
code/modules/client/preferences.dm | 1 +
.../species/station/ipc/ipc_subspecies.dm | 3 +-
.../flaminglily-hidden-shell-records.yml | 59 +++++++++++++++++++
tgui/packages/tgui/interfaces/Records.tsx | 56 +++++++++---------
7 files changed, 115 insertions(+), 33 deletions(-)
create mode 100644 SQL/migrate-2023/V013__hidden_shells.sql
create mode 100644 html/changelogs/flaminglily-hidden-shell-records.yml
diff --git a/SQL/migrate-2023/V013__hidden_shells.sql b/SQL/migrate-2023/V013__hidden_shells.sql
new file mode 100644
index 00000000000..22a51e8d41f
--- /dev/null
+++ b/SQL/migrate-2023/V013__hidden_shells.sql
@@ -0,0 +1,5 @@
+--
+-- Adds hidden shell status
+--
+
+ALTER TABLE `ss13_characters_ipc_tags` ADD COLUMN `hidden_status` TINYINT(1) NOT NULL DEFAULT 0 AFTER `ownership_status`
diff --git a/code/datums/records.dm b/code/datums/records.dm
index 83a3fda439a..a09f0bba928 100644
--- a/code/datums/records.dm
+++ b/code/datums/records.dm
@@ -125,10 +125,10 @@
var/rank = "Unassigned"
var/age = 0
var/sex = "Unknown"
+ var/species = "Unknown"
var/fingerprint = "Unknown"
var/physical_status = "Active"
var/mental_status = "Stable"
- var/species = "Unknown"
var/citizenship = "Unknown"
var/employer = "Unknown"
var/religion = "Unknown"
@@ -138,7 +138,7 @@
var/icon/photo_side
var/datum/record/medical/medical
var/datum/record/security/security
- var/list/advanced_fields = list("species", "citizenship", "employer", "religion", "ccia_record", "ccia_actions")
+ var/list/advanced_fields = list("citizenship", "employer", "religion", "ccia_record", "ccia_actions")
cmp_field = "name"
excluded_fields = list("photo_front", "photo_side", "advanced_fields", "real_rank")
excluded_print_fields = list("ccia_actions")
diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm
index 42837582013..2218f0f9289 100644
--- a/code/modules/client/preference_setup/general/01_basic.dm
+++ b/code/modules/client/preference_setup/general/01_basic.dm
@@ -17,6 +17,8 @@
S["ipc_tag_status"] >> pref.machine_tag_status
S["ipc_serial_number"] >> pref.machine_serial_number
S["ipc_ownership_status"] >> pref.machine_ownership_status
+ if(istype(GLOB.all_species[pref.species], /datum/species/machine/shell))
+ S["hidden_shell_status"] >> pref.hidden_shell_status
/datum/category_item/player_setup_item/general/basic/save_character(var/savefile/S)
S["real_name"] << pref.real_name
@@ -33,6 +35,8 @@
S["ipc_tag_status"] << pref.machine_tag_status
S["ipc_serial_number"] << pref.machine_serial_number
S["ipc_ownership_status"] << pref.machine_ownership_status
+ if(istype(GLOB.all_species[pref.species], /datum/species/machine/shell))
+ S["hidden_shell_status"] << pref.hidden_shell_status
// if table_name and pref.var_name is different, then do it like
// "table_name" = "pref.var_name", as below
@@ -57,7 +61,8 @@
"vars" = list(
"tag_status" = "machine_tag_status",
"serial_number" = "machine_serial_number",
- "ownership_status" = "machine_ownership_status"
+ "ownership_status" = "machine_ownership_status",
+ "hidden_status" = "hidden_shell_status"
),
"args" = list("char_id")
)
@@ -91,6 +96,7 @@
"tag_status",
"serial_number",
"ownership_status",
+ "hidden_status",
"char_id" = 1 // = 1 signifies argument
)
)
@@ -108,6 +114,7 @@
"tag_status" = pref.machine_tag_status,
"serial_number" = pref.machine_serial_number,
"ownership_status" = pref.machine_ownership_status,
+ "hidden_status" = pref.hidden_shell_status,
"id" = pref.current_character,
"char_id" = pref.current_character,
"floating_chat_color" = pref.floating_chat_color,
@@ -197,6 +204,8 @@
else
dat += "Serial Number: [pref.machine_serial_number] (?) "
dat += "Ownership Status: [pref.machine_ownership_status] (?) "
+ if(istype(S, /datum/species/machine/shell))
+ dat += "Is Hidden Shell:[pref.hidden_shell_status ? "Hidden" : "Not Hidden"] "
if(GLOB.config.allow_Metadata)
dat += "OOC Notes: Edit " \
+ "Clear" + " "
@@ -357,6 +366,15 @@
pref.machine_ownership_status = new_ownership_status
return TOPIC_REFRESH
+ else if(href_list["hidden_status"])
+ var/choice = alert(user, "Do you want to be a hidden Shell? This will label your Shell as a Human in their records.\n\n WARNING: This would involve forging of records or some other form of fraud, and is highly illegal in the Republic of Biesel", "Hidden Shell Status", "Yes", "No")
+ if(CanUseTopic(user))
+ if(choice == "Yes")
+ pref.hidden_shell_status = TRUE
+ else
+ pref.hidden_shell_status = FALSE
+ return TOPIC_REFRESH
+
else if (href_list["clear_metadata"])
if (CanUseTopic(user))
var/user_choice = alert(
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index e29923f7164..086ae994a3c 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -92,6 +92,7 @@ GLOBAL_LIST_EMPTY_TYPED(preferences_datums, /datum/preferences)
var/machine_tag_status = TRUE
var/machine_serial_number
var/machine_ownership_status = IPC_OWNERSHIP_COMPANY
+ var/hidden_shell_status = FALSE
//Some faction information.
var/home_system = "Unset" //System of birth.
diff --git a/code/modules/mob/living/carbon/human/species/station/ipc/ipc_subspecies.dm b/code/modules/mob/living/carbon/human/species/station/ipc/ipc_subspecies.dm
index 79ea59ed188..3bd59767881 100644
--- a/code/modules/mob/living/carbon/human/species/station/ipc/ipc_subspecies.dm
+++ b/code/modules/mob/living/carbon/human/species/station/ipc/ipc_subspecies.dm
@@ -83,8 +83,7 @@
/datum/species/machine/shell/get_species(var/reference, var/mob/living/carbon/human/H, var/records)
if(reference)
return src
- // it's illegal for shells in Tau Ceti space to not have tags, so their records would have to be falsified
- if(records && !H.internal_organs_by_name[BP_IPCTAG])
+ if(records && H.client.prefs.hidden_shell_status)
return "Human"
return name
diff --git a/html/changelogs/flaminglily-hidden-shell-records.yml b/html/changelogs/flaminglily-hidden-shell-records.yml
new file mode 100644
index 00000000000..d52b6be5deb
--- /dev/null
+++ b/html/changelogs/flaminglily-hidden-shell-records.yml
@@ -0,0 +1,59 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# - (fixes bugs)
+# wip
+# - (work in progress)
+# qol
+# - (quality of life)
+# soundadd
+# - (adds a sound)
+# sounddel
+# - (removes a sound)
+# rscadd
+# - (adds a feature)
+# rscdel
+# - (removes a feature)
+# imageadd
+# - (adds an image or sprite)
+# imagedel
+# - (removes an image or sprite)
+# spellcheck
+# - (fixes spelling or grammar)
+# experiment
+# - (experimental change)
+# balance
+# - (balance changes)
+# code_imp
+# - (misc internal code change)
+# refactor
+# - (refactors code)
+# config
+# - (makes a change to the config files)
+# admin
+# - (makes changes to administrator tools)
+# server
+# - (miscellaneous changes to server)
+#################################
+
+# Your name.
+author: FlamingLily
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
+# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - rscadd: "Added an option to character setup to allow shells to play human. This alters what species is listed in records, and is no longer tied to the shell's tag status."
+ - qol: "Moved the 'Species' entry in records out of employment records and to the global records. It really didn't make sense that medical and security couldn't see what species a person is."
diff --git a/tgui/packages/tgui/interfaces/Records.tsx b/tgui/packages/tgui/interfaces/Records.tsx
index 60b02e1c6e5..649ce41c613 100644
--- a/tgui/packages/tgui/interfaces/Records.tsx
+++ b/tgui/packages/tgui/interfaces/Records.tsx
@@ -325,6 +325,34 @@ export const ListActive = (props, context) => {
{capitalize(data.active.sex)}
+
+ {data.editable & 1 ? (
+
+ {editingSpecies ? (
+
+ act('editrecord', {
+ key: 'species',
+ value: v,
+ })
+ }
+ />
+ ) : (
+
+ {data.active.species}
+
+ )}
+
+ ) : (
+ data.active.species
+ )}
+ {data.active.rank}
{data.editable & 1 || data.editable & 2 ? (
@@ -570,34 +598,6 @@ export const ListActive = (props, context) => {
)}
{data.available_types & 1 && recordTab === 'General' ? (
<>
-
- {data.editable & 1 ? (
-
- {editingSpecies ? (
-
- act('editrecord', {
- key: 'species',
- value: v,
- })
- }
- />
- ) : (
-
- {data.active.species}
-
- )}
-
- ) : (
- data.active.species
- )}
-
{data.editable & 1 ? (