Skip to content

Commit

Permalink
ID rework - trait information on IDs, confidential information toggle…
Browse files Browse the repository at this point in the history
…, and more (#6595)

## About The Pull Request
This PR reworks how IDs are displayed, allows for traits to be displayed
within IDs, fixes a few things, and generally makes 'em look nicer. This
was primarily motivated by
https://discord.com/channels/161574200581029888/1262064135110398032


![dreamseeker_2pBMwy3E2y](https://github.com/user-attachments/assets/ab736d98-3efd-456c-9c48-733dbbc37c07)

The screenshot above is how the new IDs look ingame, featuring a few
snippets of what a few traits display as within. IDs now properly
display the photo (and the generation for said photo has been fixed!),
IDs will now show your pronouns, and IDs now have a confidential
information section (of which visibility can be toggled by alt-clicking
the ID).

Additionally, the new feature where traits are displayed on your ID card
is something that can be controlled in character generation, under the
new "ID-visible traits" section. This section lists all traits you have
that feature text for your ID. Clicking a trait will toggle whether or
not it's hidden from your ID. This allows traits like vetalism to be
omitted from IDs if desired.

![image](https://github.com/user-attachments/assets/e20cc939-ce9f-4048-92ad-ed348aa5f0e3)



## Why It's Good For The Game
The primary benefit to this is allowing medical to view potentially
important information regarding a patient, such as if they have alcohol
intolerance, require blood for their survival, are naturally deaf or
blind, and more! All while making sure that information is hidden by
default, with the ID needing to be physically held in order to toggle
the visibility of that extra information. There's also the additional
layer of players being allowed to omit traits from their ID.

Additionally, it simply looks quite a bit nicer overall, as IDs now
display a preview of the character.

## Changelog

:cl: Bhijn and Myr
add: The way IDs display information via examine has had an overhaul.
They will now display a photo of the employee tied to them, and are now
capable of displaying information related to traits. Additionally,
confidential information (such as your blood type and trait information)
is hidden by default, and their visibility can be toggled by
alt-clicking the ID.
add: Additionally, character generation has a new section that allows
omitting information from IDs outright.
/:cl:
  • Loading branch information
deathride58 authored Jul 17, 2024
1 parent 98436ee commit 62e2088
Show file tree
Hide file tree
Showing 15 changed files with 196 additions and 100 deletions.
2 changes: 1 addition & 1 deletion code/datums/outfits/outfit.dm
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
post_equip(H)

if(W) // We set ID info last to ensure the ID photo is as correct as possible.
H.set_id_info(W)
H.set_id_info(W, H.client)
return 1

/datum/outfit/proc/equip_base(mob/living/carbon/human/H)
Expand Down
4 changes: 1 addition & 3 deletions code/datums/uplink/announcements.dm
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
general.fields["rank"] = I.assignment
general.fields["real_rank"] = I.assignment
general.fields["name"] = I.registered_name
general.fields["sex"] = I.sex
general.fields["sex"] = capitalize(user.gender)
else
var/mob/living/carbon/human/H
if(istype(user,/mob/living/carbon/human))
Expand Down Expand Up @@ -89,8 +89,6 @@
medical.fields["b_dna"] = random_medical_record.fields["b_type"]

if(I)
general.fields["fingerprint"] = I.fingerprint_hash
medical.fields["b_type"] = I.blood_type
medical.fields["b_dna"] = I.dna_hash

AnnounceArrivalSimple(general.fields["name"], general.fields["rank"])
Expand Down
6 changes: 3 additions & 3 deletions code/game/objects/items/id_cards/contractor_ids.dm
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
icon_state = "chit"

/obj/item/card/id/contractor/dat()
. += "<b>Employing Company:</b> [employing_coperation]"
. += "<b>External Job Title:</b> [extern_title]"
// . += "<b>Expiration Date:</b> [expiry_date]"
. = ..()
. += "Employing Company: [employing_coperation]"
. += "External Job Title: [extern_title]"
// . += "Expiration Date: [expiry_date]"

/obj/item/card/id/contractor/update_icon()
return 0
Expand Down
19 changes: 9 additions & 10 deletions code/game/objects/items/id_cards/guest.dm
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,18 @@
else
. += "<span class='warning'>It expired at [worldtime2stationtime(expire_time)].</span>"

/obj/item/card/id/guest/read()
if(!Adjacent(usr))
return //Too far to read
/obj/item/card/id/guest/get_description_info()
. = ..()
if (expired)
to_chat(usr, "<span class='notice'>This pass expired at [worldtime2stationtime(expire_time)].</span>")
. += SPAN_NOTICE("This pass expired at [worldtime2stationtime(expire_time)].")
else
to_chat(usr, "<span class='notice'>This pass expires at [worldtime2stationtime(expire_time)].</span>")
to_chat(usr, "<span class='notice'>It grants access to following areas:</span>")
. += SPAN_NOTICE("This pass expires at [worldtime2stationtime(expire_time)].")
. += SPAN_NOTICE("It grants access to following areas:")
for (var/A in access)
to_chat(usr, "<span class='notice'>[get_access_desc(A)].</span>")
to_chat(usr, "<span class='notice'>Issuing reason: [given_reason].</span>")
to_chat(usr, SPAN_NOTICE("Issuer name: [giver_name]"))
to_chat(usr, SPAN_NOTICE("Issuer rank: [giver_rank]"))
. += SPAN_NOTICE("[get_access_desc(A)].")
. += SPAN_NOTICE("Issuing reason: [given_reason].")
. += SPAN_NOTICE("Issuer name: [giver_name]")
. += SPAN_NOTICE("Issuer rank: [giver_rank]")

/obj/item/card/id/guest/attack_self(mob/user)
. = ..()
Expand Down
120 changes: 78 additions & 42 deletions code/game/objects/items/id_cards/station_ids.dm
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@
slot_flags = SLOT_ID | SLOT_EARS

var/age = "\[UNSET\]"
var/blood_type = "\[UNSET\]"
var/dna_hash = "\[UNSET\]"
var/fingerprint_hash = "\[UNSET\]"
var/sex = "\[UNSET\]"
var/pronouns = "\[UNSET\]"
var/species = "\[UNSET\]"
var/icon/front
var/icon/side
var/photoupdatequeued

/// Keyed list containing confidential information, such as blood type, vetalism, and more
var/list/extra_info = list()
var/extra_info_visible

var/last_job_switch
var/lost_access = list()
Expand Down Expand Up @@ -52,15 +55,28 @@
job_access_type = getting_from

/obj/item/card/id/examine(mob/user, dist)
var/list/result = dat()
result.Insert(1, ..())
return result
//show(user)

/obj/item/card/id/examine_more(mob/user)
. = ..()
. += SPAN_NOTICE("<i>You examine [src] closer, and note the following...</i>")

. += "<div"
if(front || side)
. += " style='background: "
if(side)
. += "url([icon2html(side, world, sourceonly = TRUE)])"
if(front && side)
. += ", "
if(front)
. += "url([icon2html(front, world, sourceonly = TRUE)])"
. += "; background-repeat: no-repeat; background-size: 64px; background-position: right 0px top 0px, right 64px top 0px; -ms-interpolation-mode: nearest-neighbor; image-rendering: pixelated'"
. += ">"
. += dat()
. += "</div>"
if(Adjacent(user))
. += SPAN_NOTICE("<b>Alt-click</b> to [extra_info_visible ? "close" : "open"] the confidential information flap.")
return .

/obj/item/card/id/get_description_info()
. = ..()
if(.)
. += "<br>"
if(mining_points)
. += "There's [mining_points] mining equipment redemption point\s loaded onto this card."

Expand Down Expand Up @@ -102,26 +118,46 @@
return

/obj/item/card/id/proc/set_id_photo(var/mob/M)
var/icon/charicon = cached_character_icon(M)
front = icon(charicon,dir = SOUTH)
side = icon(charicon,dir = WEST)
if(!photoupdatequeued)
addtimer(CALLBACK(src, PROC_REF(_set_id_photo)), 1)
photoupdatequeued = M


/mob/proc/set_id_info(var/obj/item/card/id/id_card)
/obj/item/card/id/proc/_set_id_photo()
var/mob/M = photoupdatequeued
if(istype(M))
UNTIL(!(M.atom_flags & ATOM_OVERLAY_QUEUED)) // this is necessary specifically because roundstart characters simply do not render their clothes, as they are waiting for overlays to compile. we are in hell we think
front = get_flat_icon(M, SOUTH, TRUE)
side = get_flat_icon(M, WEST, TRUE)
photoupdatequeued = null

/mob/proc/set_id_info(obj/item/card/id/id_card, client/C)
id_card.extra_info = list()
id_card.age = 0
id_card.registered_name = real_name
id_card.sex = capitalize(gender)
id_card.set_id_photo(src)
id_card.extra_info["sex"] = "<b>Biological Sex:</b> [capitalize(gender)]" //most people just use sex for the handful of pixels worth of difference in body model but eh why the hell not
var/datum/gender/G = GLOB.gender_datums[get_gender()]
if(istype(G))
id_card.pronouns = G.pronoun_preview
else
id_card.pronouns = "Unknown"

if(dna)
id_card.blood_type = dna.b_type
id_card.extra_info["bloodtype"] = "<b>Blood Type:</b> [dna.b_type]"
id_card.extra_info["dnahash"] = "<b>DNA Hash:</b> [dna.unique_enzymes]"
id_card.extra_info["fingerprint"] = "<b>Fingerprint:</b> [md5(dna.uni_identity)]"
id_card.dna_hash = dna.unique_enzymes
id_card.fingerprint_hash= md5(dna.uni_identity)
if(C && C.prefs)
id_card.extra_info += C.prefs.get_trait_id_info()
id_card.update_name()
id_card.set_id_photo(src)

/mob/living/carbon/human/set_id_info(var/obj/item/card/id/id_card)
/mob/living/carbon/human/set_id_info(obj/item/card/id/id_card, client/C)
..()
id_card.age = age
id_card.species = src.species.name
id_card.species = custom_species ? custom_species : species.get_examine_name()

id_card.extra_info["biospecies"] = "<b>Biological Species:</b> [species.get_examine_name()]"

if(istype(id_card,/obj/item/card/id/contractor))
var/obj/item/card/id/contractor/c_id = id_card
Expand All @@ -131,17 +167,20 @@

/obj/item/card/id/proc/dat()
var/dat = list()
dat += "Name: [registered_name]"
dat += "Sex: [sex]"
dat += "Age: [age]"
dat += "Rank: [assignment]"
dat += "Species: [species]"
// dat += "Fingerprint: [fingerprint_hash]</A><BR>\n"
dat += "Blood Type: [blood_type]"
// dat += "DNA Hash: [dna_hash]<BR><BR>\n"
/*if(front && side)
dat +="<td align = center valign = top>Photo</td>"*/
//dat += "</tr></table>"
dat += "<b>Name:</b> [registered_name]"
dat += "<b>Pronouns:</b> [pronouns]"
dat += "<b>Age:</b> [age]"
dat += "<b>Rank:</b> [assignment]"
dat += "<b>Species:</b> [species]"
if(extra_info_visible)
dat += SPAN_NOTICE("<br>CONFIDENTIAL:")
if(length(extra_info))
for(var/key in extra_info) // doing a simple dat += extra_info just results in the ID displaying all the keys instead of the actual text tied to 'em
dat += extra_info[key]
else
dat += SPAN_NOTICE("The confidential information section is blank.")
else
dat += "The confidential information flap is closed."
return dat

/obj/item/card/id/attack_self(mob/user)
Expand All @@ -154,22 +193,19 @@
src.add_fingerprint(user)
return

/obj/item/card/id/AltClick(mob/user)
if(Adjacent(user))
extra_info_visible = !extra_info_visible
user.visible_message("[user] flips [src]'s confidential information flap [extra_info_visible ? "open" : "closed"].",\
"You flip [src]'s confidential information flap [extra_info_visible ? "open" : "closed"].")


/obj/item/card/id/GetAccess()
return access.Copy()

/obj/item/card/id/GetID()
return src

/obj/item/card/id/verb/read()
set name = "Read ID Card"
set category = VERB_CATEGORY_OBJECT
set src in usr

to_chat(usr, "[icon2html(thing = src, target = usr)] [src.name]: The current assignment on the card is [src.assignment].")
to_chat(usr, "The blood type on the card is [blood_type].")
to_chat(usr, "The DNA hash on the card is [dna_hash].")
to_chat(usr, "The fingerprint hash on the card is [fingerprint_hash].")

/obj/item/card/id/vv_get_dropdown()
. = ..()
VV_DROPDOWN_OPTION(null, "-----")
Expand Down
42 changes: 9 additions & 33 deletions code/game/objects/items/id_cards/syndicate_ids.dm
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,10 @@
entries[++entries.len] = list("name" = "Age", "value" = age)
entries[++entries.len] = list("name" = "Appearance", "value" = "Set")
entries[++entries.len] = list("name" = "Assignment", "value" = assignment)
entries[++entries.len] = list("name" = "Blood Type", "value" = blood_type)
entries[++entries.len] = list("name" = "DNA Hash", "value" = dna_hash)
entries[++entries.len] = list("name" = "Fingerprint Hash", "value" = fingerprint_hash)
entries[++entries.len] = list("name" = "Name", "value" = registered_name)
entries[++entries.len] = list("name" = "Photo", "value" = "Update")
entries[++entries.len] = list("name" = "Sex", "value" = sex)
entries[++entries.len] = list("name" = "Pronouns", "value" = pronouns)
entries[++entries.len] = list("name" = "Factory Reset", "value" = "Use With Care")
data["electronic_warfare"] = electronic_warfare
data["entries"] = entries
Expand Down Expand Up @@ -122,17 +120,6 @@
to_chat(user, "<span class='notice'>Occupation changed to '[new_job]'.</span>")
update_name()
. = 1
if("Blood Type")
var/default = blood_type
if(default == initial(blood_type) && ishuman(user))
var/mob/living/carbon/human/H = user
if(H.dna)
default = H.dna.b_type
var/new_blood_type = sanitize(input(user,"What blood type would you like to be written on this card?","Agent Card Blood Type",default) as null|text)
if(!isnull(new_blood_type) && CanUseTopic(user, state))
src.blood_type = new_blood_type
to_chat(user, "<span class='notice'>Blood type changed to '[new_blood_type]'.</span>")
. = 1
if("DNA Hash")
var/default = dna_hash
if(default == initial(dna_hash) && ishuman(user))
Expand All @@ -144,17 +131,6 @@
src.dna_hash = new_dna_hash
to_chat(user, "<span class='notice'>DNA hash changed to '[new_dna_hash]'.</span>")
. = 1
if("Fingerprint Hash")
var/default = fingerprint_hash
if(default == initial(fingerprint_hash) && ishuman(user))
var/mob/living/carbon/human/H = user
if(H.dna)
default = md5(H.dna.uni_identity)
var/new_fingerprint_hash = sanitize(input(user,"What fingerprint hash would you like to be written on this card?","Agent Card Fingerprint Hash",default) as null|text)
if(!isnull(new_fingerprint_hash) && CanUseTopic(user, state))
src.fingerprint_hash = new_fingerprint_hash
to_chat(user, "<span class='notice'>Fingerprint hash changed to '[new_fingerprint_hash]'.</span>")
. = 1
if("Name")
var/new_name = sanitizeName(input(user,"What name would you like to put on this card?","Agent Card Name", registered_name) as null|text)
if(!isnull(new_name) && CanUseTopic(user, state))
Expand All @@ -166,28 +142,28 @@
set_id_photo(user)
to_chat(user, "<span class='notice'>Photo changed.</span>")
. = 1
if("Sex")
var/new_sex = sanitize(input(user,"What sex would you like to put on this card?","Agent Card Sex", sex) as null|text)
if(!isnull(new_sex) && CanUseTopic(user, state))
src.sex = new_sex
to_chat(user, "<span class='notice'>Sex changed to '[new_sex]'.</span>")
if("Pronouns")
var/new_pronouns = sanitize(input(user,"What pronouns would you like to put on this card?","Agent Card Sex", pronouns) as null|text)
if(!isnull(new_pronouns) && CanUseTopic(user, state))
src.pronouns = new_pronouns
to_chat(user, "<span class='notice'>Sex changed to '[new_pronouns]'.</span>")
. = 1
if("Factory Reset")
if(alert("This will factory reset the card, including access and owner. Continue?", "Factory Reset", "No", "Yes") == "Yes" && CanUseTopic(user, state))
age = initial(age)
access = syndicate_access.Copy()
assignment = initial(assignment)
blood_type = initial(blood_type)
//blood_type = initial(blood_type)
dna_hash = initial(dna_hash)
electronic_warfare = initial(electronic_warfare)
fingerprint_hash = initial(fingerprint_hash)
//fingerprint_hash = initial(fingerprint_hash)
icon_state = initial(icon_state)
sprite_stack = list("")
update_icon()
name = initial(name)
registered_name = initial(registered_name)
unset_registered_user()
sex = initial(sex)
pronouns = initial(pronouns)
to_chat(user, "<span class='notice'>All information has been deleted from \the [src].</span>")
. = 1

Expand Down
5 changes: 5 additions & 0 deletions code/modules/mob/living/carbon/human/traits/_trait.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
var/name
var/desc = "Contact a developer if you see this trait."

/// Extra IC information about this trait that gets placed within the confidential flap of ID cards
var/extra_id_info
/// Whether or not this trait can have extra info opted out of
var/extra_id_info_optional = TRUE

/// 0 is neutral, negative cost means negative, positive cost means positive.
var/cost = 0
/// A list to apply to the custom species vars.
Expand Down
Loading

0 comments on commit 62e2088

Please sign in to comment.