"
else
@@ -751,7 +751,7 @@ What a mess.*/
if("Change Rank")
if(active1)
active1.fields["rank"] = strip_html(href_list["rank"])
- if(href_list["rank"] in get_all_jobs())
+ if(href_list["rank"] in SSjob.station_jobs)
active1.fields["real_rank"] = href_list["real_rank"]
if("Change Criminal Status")
diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm
index 30c669ee7b0..cce851049ed 100644
--- a/code/game/machinery/doors/airlock_electronics.dm
+++ b/code/game/machinery/doors/airlock_electronics.dm
@@ -25,21 +25,11 @@
/obj/item/electronics/airlock/ui_static_data(mob/user)
var/list/data = list()
- var/list/regions = list()
- for(var/i in 1 to 7)
- var/list/accesses = list()
- for(var/access in get_region_accesses(i))
- if (get_access_desc(access))
- accesses += list(list(
- "desc" = replacetext(get_access_desc(access), " ", " "),
- "ref" = access,
- ))
- regions += list(list(
- "name" = get_region_accesses_name(i),
- "regid" = i,
- "accesses" = accesses
- ))
+ var/list/regions = list()
+ var/list/tgui_region_data = SSid_access.all_region_access_tgui
+ for(var/region in SSid_access.station_regions)
+ regions += tgui_region_data[region]
data["regions"] = regions
return data
@@ -62,7 +52,7 @@
one_access = 0
. = TRUE
if("grant_all")
- accesses = get_all_accesses()
+ accesses = SSid_access.get_region_access_list(list(REGION_ALL_STATION))
. = TRUE
if("one_access")
one_access = !one_access
@@ -79,16 +69,16 @@
unres_sides ^= unres_direction //XOR, toggles only the bit that was clicked
. = TRUE
if("grant_region")
- var/region = text2num(params["region"])
+ var/region = params["region"]
if(isnull(region))
return
- accesses |= get_region_accesses(region)
+ accesses |= SSid_access.get_region_access_list(list(region))
. = TRUE
if("deny_region")
- var/region = text2num(params["region"])
+ var/region = params["region"]
if(isnull(region))
return
- accesses -= get_region_accesses(region)
+ accesses -= SSid_access.get_region_access_list(list(region))
. = TRUE
/obj/item/electronics/airlock/ui_host()
diff --git a/code/game/machinery/gulag_item_reclaimer.dm b/code/game/machinery/gulag_item_reclaimer.dm
index 74bfb358a07..4274e82cb10 100644
--- a/code/game/machinery/gulag_item_reclaimer.dm
+++ b/code/game/machinery/gulag_item_reclaimer.dm
@@ -43,8 +43,8 @@
if(isliving(user))
var/mob/living/L = user
I = L.get_idcard(TRUE)
- if(istype(I, /obj/item/card/id/prisoner))
- var/obj/item/card/id/prisoner/P = I
+ if(istype(I, /obj/item/card/id/advanced/prisoner))
+ var/obj/item/card/id/advanced/prisoner/P = I
if(P.points >= P.goal)
can_reclaim = TRUE
diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm
index 72b1d94ce29..b23a147d90a 100644
--- a/code/game/machinery/porta_turret/portable_turret.dm
+++ b/code/game/machinery/porta_turret/portable_turret.dm
@@ -546,7 +546,7 @@ DEFINE_BITFIELD(turret_flags, list(
return 10
if(turret_flags & TURRET_FLAG_AUTH_WEAPONS) //check for weapon authorization
- if(isnull(perp.wear_id) || istype(perp.wear_id.GetID(), /obj/item/card/id/syndicate))
+ if(isnull(perp.wear_id) || istype(perp.wear_id.GetID(), /obj/item/card/id/advanced/chameleon))
if(allowed(perp)) //if the perp has security access, return 0
return 0
diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm
index 2d3aca0c067..e6a14193d5c 100644
--- a/code/game/machinery/recycler.dm
+++ b/code/game/machinery/recycler.dm
@@ -33,8 +33,8 @@
)
AddComponent(/datum/component/material_container, allowed_materials, INFINITY, MATCONTAINER_NO_INSERT|BREAKDOWN_FLAGS_RECYCLER)
. = ..()
- update_appearance()
- req_one_access = get_all_accesses() + get_all_centcom_access()
+ update_appearance(UPDATE_ICON)
+ req_one_access = SSid_access.get_region_access_list(list(REGION_ALL_STATION, REGION_CENTCOM))
/obj/machinery/recycler/RefreshParts()
var/amt_made = 0
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index 044c3faab17..cd5e804089a 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -61,38 +61,52 @@
* ID CARDS
*/
+/// "Retro" ID card that renders itself as the icon state with no overlays.
/obj/item/card/id
- name = "identification card"
+ name = "retro identification card"
desc = "A card used to provide ID and determine access across the station."
- icon_state = "id"
+ icon_state = "card_grey"
+ worn_icon_state = "card_retro"
inhand_icon_state = "card-id"
lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
slot_flags = ITEM_SLOT_ID
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100)
resistance_flags = FIRE_PROOF | ACID_PROOF
- var/id_type_name = "identification card"
- var/mining_points = 0 //For redeeming at mining equipment vendors
- ///The stuff that makes you open doors and shit
- var/list/access = list()
- ///Access that cannot be removed by the ID console. Do not add access levels that are actually visible in the console here if a HoP knowing what kind of ID he's modifying is a concern.
- var/list/sticky_access
+
+ /// How many magical mining Disney Dollars this card has for spending at the mining equipment vendors.
+ var/mining_points = 0
/// The name registered on the card (for example: Dr Bryan See)
var/registered_name = null
- ///The job name registered on the card (for example: Assistant)
- var/assignment = null
- /// mapping aid
- var/access_txt
+ /// Linked bank account.
var/datum/bank_account/registered_account
+ /// Linked paystand.
var/obj/machinery/paystand/my_store
- var/uses_overlays = TRUE
- var/icon/cached_flat_icon
- var/registered_age = 13 // default age for ss13 players
+ /// Registered owner's age.
+ var/registered_age = 13
+
+ /// The job name registered on the card (for example: Assistant).
+ var/assignment
+
+ /// Trim datum associated with the card. Controls which job icon is displayed on the card and which accesses do not require wildcards.
+ var/datum/id_trim/trim
+
+ /// Access levels held by this card.
+ var/list/access = list()
+
+ /// List of wildcard slot names as keys with lists of wildcard data as values.
+ var/list/wildcard_slots = list()
/obj/item/card/id/Initialize(mapload)
. = ..()
- if(mapload && access_txt)
- access = text2access(access_txt)
+
+ // Applying the trim updates the label and icon, so don't do this twice.
+ if(ispath(trim))
+ SSid_access.apply_trim_to_card(src, trim)
+ else
+ update_label()
+ update_icon()
+
RegisterSignal(src, COMSIG_ATOM_UPDATED_ICON, .proc/update_in_wallet)
/obj/item/card/id/Destroy()
@@ -102,6 +116,264 @@
my_store.my_card = null
return ..()
+/obj/item/card/id/get_id_examine_strings(mob/user)
+ . = ..()
+ . += list("[icon2html(get_icon_source(), user, extra_classes = "bigicon")]")
+
+/// Simple helper proc. Returns the source of the icon for this card. Advanced cards can override this to return their icon that has been cached due to using overlays.
+/obj/item/card/id/proc/get_icon_source()
+ return src
+
+/**
+ * Helper proc, checks whether the ID card can hold any given set of wildcards.
+ *
+ * Returns TRUE if the card can hold the wildcards, FALSE otherwise.
+ * Arguments:
+ * * wildcard_list - List of accesses to check.
+ * * try_wildcard - If not null, will attempt to add wildcards for this wildcard specifically and will return FALSE if the card cannot hold all wildcards in this slot.
+ */
+/obj/item/card/id/proc/can_add_wildcards(list/wildcard_list, try_wildcard = null)
+ if(!length(wildcard_list))
+ return TRUE
+
+ var/list/new_wildcard_limits = list()
+
+ for(var/flag_name in wildcard_slots)
+ if(try_wildcard && !(flag_name == try_wildcard))
+ continue
+ var/list/wildcard_info = wildcard_slots[flag_name]
+ new_wildcard_limits[flag_name] = wildcard_info["limit"] - length(wildcard_info["usage"])
+
+ if(!length(new_wildcard_limits))
+ return FALSE
+
+ var/wildcard_allocated
+ for(var/wildcard in wildcard_list)
+ var/wildcard_flag = SSid_access.get_access_flag(wildcard)
+ wildcard_allocated = FALSE
+ for(var/flag_name in new_wildcard_limits)
+ var/limit_flags = SSid_access.wildcard_flags_by_wildcard[flag_name]
+ if(!(wildcard_flag & limit_flags))
+ continue
+ // Negative limits mean infinite slots. Positive limits mean limited slots still available. 0 slots means no slots.
+ if(new_wildcard_limits[flag_name] == 0)
+ continue
+ new_wildcard_limits[flag_name]--
+ wildcard_allocated = TRUE
+ break
+ if(!wildcard_allocated)
+ return FALSE
+
+ return TRUE
+
+/**
+ * Attempts to add the given wildcards to the ID card.
+ *
+ * Arguments:
+ * * wildcard_list - List of accesses to add.
+ * * try_wildcard - If not null, will attempt to add all wildcards to this wildcard slot only.
+ * * mode - The method to use when adding wildcards. See define for ERROR_ON_FAIL
+ */
+/obj/item/card/id/proc/add_wildcards(list/wildcard_list, try_wildcard = null, mode = ERROR_ON_FAIL)
+ var/wildcard_allocated
+ // Iterate through each wildcard in our list. Get its access flag. Then iterate over wildcard slots and try to fit it in.
+ for(var/wildcard in wildcard_list)
+ var/wildcard_flag = SSid_access.get_access_flag(wildcard)
+ wildcard_allocated = FALSE
+ for(var/flag_name in wildcard_slots)
+ if(flag_name == WILDCARD_NAME_FORCED)
+ continue
+
+ if(try_wildcard && !(flag_name == try_wildcard))
+ continue
+
+ var/limit_flags = SSid_access.wildcard_flags_by_wildcard[flag_name]
+
+ if(!(wildcard_flag & limit_flags))
+ continue
+
+ var/list/wildcard_info = wildcard_slots[flag_name]
+ var/wildcard_limit = wildcard_info["limit"]
+ var/list/wildcard_usage = wildcard_info["usage"]
+
+ var/wildcard_count = wildcard_limit - length(wildcard_usage)
+
+ // Negative limits mean infinite slots. Positive limits mean limited slots still available. 0 slots means no slots.
+ if(wildcard_count == 0)
+ continue
+
+ wildcard_usage |= wildcard
+ access |= wildcard
+ wildcard_allocated = TRUE
+ break
+ // Fallback for if we couldn't allocate the wildcard for some reason.
+ if(!wildcard_allocated)
+ if(mode == ERROR_ON_FAIL)
+ CRASH("Wildcard ([wildcard]) could not be added to [src].")
+
+ if(mode == TRY_ADD_ALL)
+ continue
+
+ // If the card has no info for historic forced wildcards, create the list.
+ if(!wildcard_slots[WILDCARD_NAME_FORCED])
+ wildcard_slots[WILDCARD_NAME_FORCED] = list(limit = 0, usage = list())
+
+ var/list/wildcard_info = wildcard_slots[WILDCARD_NAME_FORCED]
+ var/list/wildcard_usage = wildcard_info["usage"]
+ wildcard_usage |= wildcard
+ access |= wildcard
+ wildcard_info["limit"] = length(wildcard_usage)
+
+/**
+ * Removes wildcards from the ID card.
+ *
+ * Arguments:
+ * * wildcard_list - List of accesses to remove.
+ */
+/obj/item/card/id/proc/remove_wildcards(list/wildcard_list)
+ var/wildcard_removed
+ // Iterate through each wildcard in our list. Get its access flag. Then iterate over wildcard slots and try to remove it.
+ for(var/wildcard in wildcard_list)
+ wildcard_removed = FALSE
+ for(var/flag_name in wildcard_slots)
+ if(flag_name == WILDCARD_NAME_FORCED)
+ continue
+
+ var/list/wildcard_info = wildcard_slots[flag_name]
+ var/wildcard_usage = wildcard_info["usage"]
+
+ if(!(wildcard in wildcard_usage))
+ continue
+
+ wildcard_usage -= wildcard
+ access -= wildcard
+ wildcard_removed = TRUE
+ break
+ // Fallback to see if this was a force-added wildcard.
+ if(!wildcard_removed)
+ // If the card has no info for historic forced wildcards, that's an error state.
+ if(!wildcard_slots[WILDCARD_NAME_FORCED])
+ stack_trace("Wildcard ([wildcard]) could not be removed from [src]. This card has no forced wildcard data and the wildcard is not in this card's wildcard lists.")
+
+ var/list/wildcard_info = wildcard_slots[WILDCARD_NAME_FORCED]
+ var/wildcard_usage = wildcard_info["usage"]
+
+ if(!(wildcard in wildcard_usage))
+ stack_trace("Wildcard ([wildcard]) could not be removed from [src]. This access is not a wildcard on this card.")
+
+ wildcard_usage -= wildcard
+ access -= wildcard
+ wildcard_info["limit"] = length(wildcard_usage)
+
+ if(!wildcard_info["limit"])
+ wildcard_slots -= WILDCARD_NAME_FORCED
+
+/**
+ * Attempts to add the given accesses to the ID card as non-wildcards.
+ *
+ * Depending on the mode, may add accesses as wildcards or error if it can't add them as non-wildcards.
+ * Arguments:
+ * * add_accesses - List of accesses to check.
+ * * try_wildcard - If not null, will attempt to add all accesses that require wildcard slots to this wildcard slot only.
+ * * mode - The method to use when adding accesses. See define for ERROR_ON_FAIL
+ */
+/obj/item/card/id/proc/add_access(list/add_accesses, try_wildcard = null, mode = ERROR_ON_FAIL)
+ var/list/wildcard_access = list()
+ var/list/normal_access = list()
+
+ build_access_lists(add_accesses, normal_access, wildcard_access)
+
+ // Check if we can add the wildcards.
+ if(mode == ERROR_ON_FAIL)
+ if(!can_add_wildcards(wildcard_access, try_wildcard))
+ CRASH("Cannot add wildcards from \[[add_accesses.Join(",")]\] to [src]")
+
+ // All clear to add the accesses.
+ access |= normal_access
+ if(mode != TRY_ADD_ALL_NO_WILDCARD)
+ add_wildcards(wildcard_access, try_wildcard, mode = mode)
+
+ return TRUE
+
+/**
+ * Removes the given accesses from the ID Card.
+ *
+ * Will remove the wildcards if the accesses given are on the card as wildcard accesses.
+ * Arguments:
+ * * rem_accesses - List of accesses to remove.
+ */
+/obj/item/card/id/proc/remove_access(list/rem_accesses)
+ var/list/wildcard_access = list()
+ var/list/normal_access = list()
+
+ build_access_lists(rem_accesses, normal_access, wildcard_access)
+
+ access -= normal_access
+ remove_wildcards(wildcard_access)
+
+/**
+ * Attempts to set the card's accesses to the given accesses, clearing all accesses not in the given list.
+ *
+ * Depending on the mode, may add accesses as wildcards or error if it can't add them as non-wildcards.
+ * Arguments:
+ * * new_access_list - List of all accesses that this card should hold exclusively.
+ * * mode - The method to use when setting accesses. See define for ERROR_ON_FAIL
+ */
+/obj/item/card/id/proc/set_access(list/new_access_list, mode = ERROR_ON_FAIL)
+ var/list/wildcard_access = list()
+ var/list/normal_access = list()
+
+ build_access_lists(new_access_list, normal_access, wildcard_access)
+
+ // Check if we can add the wildcards.
+ if(mode == ERROR_ON_FAIL)
+ if(!can_add_wildcards(wildcard_access))
+ CRASH("Cannot add wildcards from \[[new_access_list.Join(",")]\] to [src]")
+
+ clear_access()
+
+ access = normal_access.Copy()
+
+ if(mode != TRY_ADD_ALL_NO_WILDCARD)
+ add_wildcards(wildcard_access, mode = mode)
+
+ return TRUE
+
+/// Clears all accesses from the ID card - both wildcard and normal.
+/obj/item/card/id/proc/clear_access()
+ // Go through the wildcards and reset them.
+ for(var/flag_name in wildcard_slots)
+ var/list/wildcard_info = wildcard_slots[flag_name]
+ var/list/wildcard_usage = wildcard_info["usage"]
+ wildcard_usage.Cut()
+
+ // Hard reset access
+ access.Cut()
+
+/**
+ * Helper proc. Creates access lists for the access procs.
+ *
+ * Takes the accesses list and compares it with the trim. Any basic accesses that match the trim are
+ * added to basic_access_list and the rest are added to wildcard_access_list.
+
+ * This proc directly modifies the lists passed in as args. It expects these lists to be instantiated.
+ * There is no return value.
+ * Arguments:
+ */
+/obj/item/card/id/proc/build_access_lists(list/accesses, list/basic_access_list, list/wildcard_access_list)
+ if(!length(accesses) || isnull(basic_access_list) || isnull(wildcard_access_list))
+ CRASH("Invalid parameters passed to build_access_lists")
+
+ var/list/trim_accesses = trim?.access
+
+ // Populate the lists.
+ for(var/new_access in accesses)
+ if(new_access in trim_accesses)
+ basic_access_list |= new_access
+ continue
+
+ wildcard_access_list |= new_access
+
/obj/item/card/id/attack_self(mob/user)
if(Adjacent(user))
var/minor
@@ -114,8 +386,12 @@
. = ..()
if(.)
switch(var_name)
- if(NAMEOF(src, assignment),NAMEOF(src, registered_name),NAMEOF(src, registered_age))
+ if(NAMEOF(src, assignment), NAMEOF(src, registered_name), NAMEOF(src, registered_age))
update_label()
+ update_icon()
+ if(NAMEOF(src, trim))
+ if(ispath(trim))
+ SSid_access.apply_trim_to_card(src, trim)
/obj/item/card/id/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/holochip))
@@ -139,25 +415,40 @@
else
return ..()
-/obj/item/card/id/proc/insert_money(obj/item/I, mob/user, physical_currency)
+/**
+ * Insert credits or coins into the ID card and add their value to the associated bank account.
+ *
+ * Arguments:
+ * money - The item to attempt to convert to credits and insert into the card.
+ * user - The user inserting the item.
+ * physical_currency - Boolean, whether this is a physical currency such as a coin and not a holochip.
+ */
+/obj/item/card/id/proc/insert_money(obj/item/money, mob/user, physical_currency)
if(!registered_account)
- to_chat(user, "[src] doesn't have a linked account to deposit [I] into!")
+ to_chat(user, "[src] doesn't have a linked account to deposit [money] into!")
return
- var/cash_money = I.get_item_credit_value()
+ var/cash_money = money.get_item_credit_value()
if(!cash_money)
- to_chat(user, "[I] doesn't seem to be worth anything!")
+ to_chat(user, "[money] doesn't seem to be worth anything!")
return
registered_account.adjust_money(cash_money)
SSblackbox.record_feedback("amount", "credits_inserted", cash_money)
log_econ("[cash_money] credits were inserted into [src] owned by [src.registered_name]")
if(physical_currency)
- to_chat(user, "You stuff [I] into [src]. It disappears in a small puff of bluespace smoke, adding [cash_money] credits to the linked account.")
+ to_chat(user, "You stuff [money] into [src]. It disappears in a small puff of bluespace smoke, adding [cash_money] credits to the linked account.")
else
- to_chat(user, "You insert [I] into [src], adding [cash_money] credits to the linked account.")
+ to_chat(user, "You insert [money] into [src], adding [cash_money] credits to the linked account.")
to_chat(user, "The linked account now reports a balance of [registered_account.account_balance] cr.")
- qdel(I)
+ qdel(money)
+/**
+ * Insert multiple money or money-equivalent items at once.
+ *
+ * Arguments:
+ * money - List of items to attempt to convert to credits and insert into the card.
+ * user - The user inserting the items.
+ */
/obj/item/card/id/proc/mass_insert_money(list/money, mob/user)
if(!registered_account)
to_chat(user, "[src] doesn't have a linked account to deposit into!")
@@ -179,6 +470,7 @@
return total
+/// Helper proc. Can the user alt-click the ID?
/obj/item/card/id/proc/alt_click_can_use_id(mob/living/user)
if(!isliving(user))
return
@@ -187,7 +479,7 @@
return TRUE
-// Returns true if new account was set.
+/// Attempts to set a new bank account on the ID card.
/obj/item/card/id/proc/set_new_account(mob/living/user)
. = FALSE
var/datum/bank_account/old_account = registered_account
@@ -291,17 +583,7 @@
/obj/item/card/id/RemoveID()
return src
-/obj/item/card/id/update_overlays()
- . = ..()
- if(!uses_overlays)
- return
- cached_flat_icon = null
- var/job = assignment ? ckey(GetJobName()) : null
- if(registered_name && registered_name != "Captain")
- . += mutable_appearance(icon, "assigned")
- if(job)
- . += mutable_appearance(icon, "id[job]")
-
+/// Called on COMSIG_ATOM_UPDATED_ICON. Updates the visuals of the wallet this card is in.
/obj/item/card/id/proc/update_in_wallet()
SIGNAL_HANDLER
@@ -311,384 +593,26 @@
powergaming.update_label()
powergaming.update_appearance()
-/obj/item/card/id/proc/get_cached_flat_icon()
- if(!cached_flat_icon)
- cached_flat_icon = getFlatIcon(src)
- return cached_flat_icon
-
-
-/obj/item/card/id/get_examine_string(mob/user, thats = FALSE)
- if(uses_overlays)
- return "[icon2html(get_cached_flat_icon(), user)] [thats? "That's ":""][get_examine_name(user)]" //displays all overlays in chat
- return ..()
-
-/*
-Usage:
-update_label()
- Sets the id name to whatever registered_name and assignment is
-*/
-
+/// Updates the name based on the card's vars and state.
/obj/item/card/id/proc/update_label()
var/blank = !registered_name
- name = "[blank ? id_type_name : "[registered_name]'s ID Card"][(!assignment) ? "" : " ([assignment])"]"
- update_appearance()
-
-/obj/item/card/id/silver
- name = "silver identification card"
- id_type_name = "silver identification card"
- desc = "A silver card which shows honour and dedication."
- icon_state = "silver"
- inhand_icon_state = "silver_id"
- lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
-
-/obj/item/card/id/silver/reaper
- name = "Thirteen's ID Card (Reaper)"
- access = list(ACCESS_MAINT_TUNNELS)
- assignment = "Reaper"
- registered_name = "Thirteen"
-
-/obj/item/card/id/gold
- name = "gold identification card"
- id_type_name = "gold identification card"
- desc = "A golden card which shows power and might."
- icon_state = "gold"
- inhand_icon_state = "gold_id"
- lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
-
-/obj/item/card/id/syndicate
- name = "agent card"
- access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE)
- sticky_access = list(ACCESS_SYNDICATE)
- ///Can anyone forge the ID or just syndicate?
- var/anyone = FALSE
- ///have we set a custom name and job assignment, or will we use what we're given when we chameleon change?
- var/forged = FALSE
-
-/obj/item/card/id/syndicate/Initialize()
- . = ..()
- var/datum/action/item_action/chameleon/change/id/chameleon_action = new(src)
- chameleon_action.chameleon_type = /obj/item/card/id
- chameleon_action.chameleon_name = "ID Card"
- chameleon_action.initialize_disguises()
-
-/obj/item/card/id/syndicate/afterattack(obj/item/O, mob/user, proximity)
- if(!proximity)
- return
- if(istype(O, /obj/item/card/id))
- var/obj/item/card/id/I = O
- src.access |= I.access
- if(isliving(user) && user.mind)
- if(user.mind.special_role || anyone)
- to_chat(usr, "The card's microscanners activate as you pass it over the ID, copying its access.")
-
-/obj/item/card/id/syndicate/attack_self(mob/user)
- if(isliving(user) && user.mind)
- var/first_use = registered_name ? FALSE : TRUE
- if(!(user.mind.special_role || anyone)) //Unless anyone is allowed, only syndies can use the card, to stop metagaming.
- if(first_use) //If a non-syndie is the first to forge an unassigned agent ID, then anyone can forge it.
- anyone = TRUE
- else
- return ..()
-
- var/popup_input = alert(user, "Choose Action", "Agent ID", "Show", "Forge/Reset", "Change Account ID")
- if(user.incapacitated())
- return
- if(popup_input == "Forge/Reset" && !forged)
- var/input_name = stripped_input(user, "What name would you like to put on this card? Leave blank to randomise.", "Agent card name", registered_name ? registered_name : (ishuman(user) ? user.real_name : user.name), MAX_NAME_LEN)
- input_name = sanitize_name(input_name)
- if(!input_name)
- // Invalid/blank names give a randomly generated one.
- if(user.gender == MALE)
- input_name = "[pick(GLOB.first_names_male)] [pick(GLOB.last_names)]"
- else if(user.gender == FEMALE)
- input_name = "[pick(GLOB.first_names_female)] [pick(GLOB.last_names)]"
- else
- input_name = "[pick(GLOB.first_names)] [pick(GLOB.last_names)]"
-
- var/target_occupation = stripped_input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than Maintenance.", "Agent card job assignment", assignment ? assignment : "Assistant", MAX_MESSAGE_LEN)
- if(!target_occupation)
- return
-
- var/newAge = input(user, "Choose the ID's age:\n([AGE_MIN]-[AGE_MAX])", "Agent card age") as num|null
- if(newAge)
- registered_age = max(round(text2num(newAge)), 0)
-
- registered_name = input_name
- assignment = target_occupation
- update_label()
- forged = TRUE
- to_chat(user, "You successfully forge the ID card.")
- log_game("[key_name(user)] has forged \the [initial(name)] with name \"[registered_name]\" and occupation \"[assignment]\".")
-
- // First time use automatically sets the account id to the user.
- if (first_use && !registered_account)
- if(ishuman(user))
- var/mob/living/carbon/human/accountowner = user
-
- var/datum/bank_account/account = SSeconomy.bank_accounts_by_id["[accountowner.account_id]"]
- if(account)
- account.bank_cards += src
- registered_account = account
- to_chat(user, "Your account number has been automatically assigned.")
- return
- else if (popup_input == "Forge/Reset" && forged)
- registered_name = initial(registered_name)
- assignment = initial(assignment)
- log_game("[key_name(user)] has reset \the [initial(name)] named \"[src]\" to default.")
- update_label()
- forged = FALSE
- to_chat(user, "You successfully reset the ID card.")
- return
- else if (popup_input == "Change Account ID")
- set_new_account(user)
- return
- return ..()
-
-/obj/item/card/id/syndicate/anyone
- anyone = TRUE
-
-/obj/item/card/id/syndicate/nuke_leader
- name = "lead agent card"
- access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER)
- sticky_access = list(ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER)
-
-/obj/item/card/id/syndicate_command
- name = "syndicate ID card"
- id_type_name = "syndicate ID card"
- desc = "An ID straight from the Syndicate."
- registered_name = "Syndicate"
- assignment = "Syndicate Overlord"
- icon_state = "syndie"
- access = list(ACCESS_SYNDICATE)
- sticky_access = list(ACCESS_SYNDICATE)
- uses_overlays = FALSE
- registered_age = null
-
-/obj/item/card/id/syndicate_command/crew_id
- name = "syndicate ID card"
- id_type_name = "syndicate ID card"
- desc = "An ID straight from the Syndicate."
- registered_name = "Syndicate"
- assignment = "Syndicate Operative"
- icon_state = "syndie"
- access = list(ACCESS_SYNDICATE, ACCESS_ROBOTICS)
- sticky_access = list(ACCESS_SYNDICATE)
- uses_overlays = FALSE
-
-/obj/item/card/id/syndicate_command/captain_id
- name = "syndicate captain ID card"
- id_type_name = "syndicate captain ID card"
- desc = "An ID straight from the Syndicate."
- registered_name = "Syndicate"
- assignment = "Syndicate Ship Captain"
- icon_state = "syndie"
- access = list(ACCESS_SYNDICATE, ACCESS_ROBOTICS)
- sticky_access = list(ACCESS_SYNDICATE)
- uses_overlays = FALSE
-
-/obj/item/card/id/captains_spare
- name = "captain's spare ID"
- id_type_name = "captain's spare ID"
- desc = "The spare ID of the High Lord himself."
- icon_state = "gold"
- inhand_icon_state = "gold_id"
- lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
- registered_name = "Captain"
- assignment = "Captain"
- registered_age = null
-
-/obj/item/card/id/captains_spare/Initialize()
- var/datum/job/captain/J = new/datum/job/captain
- access = J.get_access()
- . = ..()
- update_label()
-
-/obj/item/card/id/captains_spare/update_label() //so it doesn't change to Captain's ID card (Captain) on a sneeze
- if(registered_name == "Captain")
- name = "[id_type_name][(!assignment || assignment == "Captain") ? "" : " ([assignment])"]"
- update_appearance()
- else
- ..()
-
-/obj/item/card/id/centcom
- name = "\improper CentCom ID"
- id_type_name = "\improper CentCom ID"
- desc = "An ID straight from Central Command."
- icon_state = "centcom"
- registered_name = "Central Command"
- assignment = "Central Command"
- uses_overlays = FALSE
- registered_age = null
-
-/obj/item/card/id/centcom/Initialize()
- access = get_all_centcom_access()
- . = ..()
-
-/obj/item/card/id/ert
- name = "\improper CentCom ID"
- id_type_name = "\improper CentCom ID"
- desc = "An ERT ID card."
- icon_state = "ert_commander"
- registered_name = "Emergency Response Team Commander"
- assignment = "Emergency Response Team Commander"
- uses_overlays = FALSE
- registered_age = null
-
-/obj/item/card/id/ert/Initialize()
- access = get_all_accesses()+get_ert_access("commander")-ACCESS_CHANGE_IDS
- . = ..()
-
-/obj/item/card/id/ert/security
- registered_name = "Security Response Officer"
- assignment = "Security Response Officer"
- icon_state = "ert_security"
-
-/obj/item/card/id/ert/security/Initialize()
- access = get_all_accesses()+get_ert_access("sec")-ACCESS_CHANGE_IDS
- . = ..()
-
-/obj/item/card/id/ert/engineer
- registered_name = "Engineering Response Officer"
- assignment = "Engineering Response Officer"
- icon_state = "ert_engineer"
-
-/obj/item/card/id/ert/engineer/Initialize()
- access = get_all_accesses()+get_ert_access("eng")-ACCESS_CHANGE_IDS
- . = ..()
-
-/obj/item/card/id/ert/medical
- registered_name = "Medical Response Officer"
- assignment = "Medical Response Officer"
- icon_state = "ert_medic"
-
-/obj/item/card/id/ert/medical/Initialize()
- access = get_all_accesses()+get_ert_access("med")-ACCESS_CHANGE_IDS
- . = ..()
-
-/obj/item/card/id/ert/chaplain
- registered_name = "Religious Response Officer"
- assignment = "Religious Response Officer"
- icon_state = "ert_chaplain"
-
-/obj/item/card/id/ert/chaplain/Initialize()
- access = get_all_accesses()+get_ert_access("sec")-ACCESS_CHANGE_IDS
- . = ..()
-
-/obj/item/card/id/ert/janitor
- registered_name = "Janitorial Response Officer"
- assignment = "Janitorial Response Officer"
- icon_state = "ert_janitor"
-
-/obj/item/card/id/ert/janitor/Initialize()
- access = get_all_accesses()
- . = ..()
-
-/obj/item/card/id/ert/clown
- registered_name = "Entertainment Response Officer"
- assignment = "Entertainment Response Officer"
- icon_state = "ert_clown"
-
-/obj/item/card/id/ert/clown/Initialize()
- access = get_all_accesses()
- . = ..()
-
-/obj/item/card/id/ert/deathsquad
- name = "\improper Death Squad ID"
- id_type_name = "\improper Death Squad ID"
- desc = "A Death Squad ID card."
- icon_state = "deathsquad" //NO NO SIR DEATH SQUADS ARENT A PART OF NANOTRASEN AT ALL
- registered_name = "Death Commando"
- assignment = "Death Commando"
- uses_overlays = FALSE
-
-/obj/item/card/id/debug
- name = "\improper Debug ID"
- desc = "A debug ID card. Has ALL the all access, you really shouldn't have this."
- icon_state = "ert_janitor"
- assignment = "Jannie"
- uses_overlays = FALSE
-
-/obj/item/card/id/debug/Initialize()
- access = get_all_accesses()+get_all_centcom_access()+get_all_syndicate_access()
- registered_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
- . = ..()
-
-/obj/item/card/id/prisoner
- name = "prisoner ID card"
- id_type_name = "prisoner ID card"
- desc = "You are a number, you are not a free man."
- icon_state = "orange"
- inhand_icon_state = "orange-id"
- lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
- assignment = "Prisoner"
- registered_name = "Scum"
- uses_overlays = FALSE
- var/goal = 0 //How far from freedom?
- var/points = 0
- registered_age = null
-
-/obj/item/card/id/prisoner/attack_self(mob/user)
- to_chat(usr, "You have accumulated [points] out of the [goal] points you need for freedom.")
-
-/obj/item/card/id/prisoner/one
- name = "Prisoner #13-001"
- registered_name = "Prisoner #13-001"
- icon_state = "prisoner_001"
-
-/obj/item/card/id/prisoner/two
- name = "Prisoner #13-002"
- registered_name = "Prisoner #13-002"
- icon_state = "prisoner_002"
-
-/obj/item/card/id/prisoner/three
- name = "Prisoner #13-003"
- registered_name = "Prisoner #13-003"
- icon_state = "prisoner_003"
-
-/obj/item/card/id/prisoner/four
- name = "Prisoner #13-004"
- registered_name = "Prisoner #13-004"
- icon_state = "prisoner_004"
-
-/obj/item/card/id/prisoner/five
- name = "Prisoner #13-005"
- registered_name = "Prisoner #13-005"
- icon_state = "prisoner_005"
-
-/obj/item/card/id/prisoner/six
- name = "Prisoner #13-006"
- registered_name = "Prisoner #13-006"
- icon_state = "prisoner_006"
-
-/obj/item/card/id/prisoner/seven
- name = "Prisoner #13-007"
- registered_name = "Prisoner #13-007"
- icon_state = "prisoner_007"
-
-/obj/item/card/id/mining
- name = "mining ID"
- access = list(ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MECH_MINING, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM)
+ name = "[blank ? initial(name) : "[registered_name]'s ID Card"][(!assignment) ? "" : " ([assignment])"]"
/obj/item/card/id/away
name = "\proper a perfectly generic identification card"
desc = "A perfectly generic identification card. Looks like it could use some flavor."
- access = list(ACCESS_AWAY_GENERAL)
+ trim = /datum/id_trim/away
icon_state = "retro"
- uses_overlays = FALSE
registered_age = null
/obj/item/card/id/away/hotel
name = "Staff ID"
desc = "A staff ID used to access the hotel's doors."
- access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_MAINT)
+ trim = /datum/id_trim/away/hotel
/obj/item/card/id/away/hotel/securty
name = "Officer ID"
- access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_MAINT, ACCESS_AWAY_SEC)
+ trim = /datum/id_trim/away/hotel/security
/obj/item/card/id/away/old
name = "\proper a perfectly generic identification card"
@@ -697,34 +621,30 @@ update_label()
/obj/item/card/id/away/old/sec
name = "Charlie Station Security Officer's ID card"
desc = "A faded Charlie Station ID card. You can make out the rank \"Security Officer\"."
- assignment = "Charlie Station Security Officer"
- access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_SEC)
+ trim = /datum/id_trim/away/old/sec
/obj/item/card/id/away/old/sci
name = "Charlie Station Scientist's ID card"
desc = "A faded Charlie Station ID card. You can make out the rank \"Scientist\"."
- assignment = "Charlie Station Scientist"
- access = list(ACCESS_AWAY_GENERAL)
+ trim = /datum/id_trim/away/old/sci
/obj/item/card/id/away/old/eng
name = "Charlie Station Engineer's ID card"
desc = "A faded Charlie Station ID card. You can make out the rank \"Station Engineer\"."
- assignment = "Charlie Station Engineer"
- access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_ENGINE)
+ trim = /datum/id_trim/away/old/eng
/obj/item/card/id/away/old/apc
name = "APC Access ID"
desc = "A special ID card that allows access to APC terminals."
- access = list(ACCESS_ENGINE_EQUIP)
+ trim = /datum/id_trim/away/old/apc
/obj/item/card/id/away/deep_storage //deepstorage.dmm space ruin
name = "bunker access ID"
/obj/item/card/id/departmental_budget
- name = "departmental card (FUCK)"
+ name = "departmental card (ERROR)"
desc = "Provides access to the departmental budget."
icon_state = "budgetcard"
- uses_overlays = FALSE
var/department_ID = ACCOUNT_CIV
var/department_name = ACCOUNT_CIV_NAME
registered_age = null
@@ -754,3 +674,469 @@ update_label()
/obj/item/card/id/departmental_budget/AltClick(mob/living/user)
registered_account.bank_card_talk("Withdrawing is not compatible with this card design.", TRUE) //prevents the vault bank machine being useless and putting money from the budget to your card to go over personal crates
+
+/obj/item/card/id/advanced
+ name = "identification card"
+ desc = "A card used to provide ID and determine access across the station. Has an integrated digital display and advanced microchips."
+ icon_state = "card_grey"
+ worn_icon_state = "card_grey"
+
+ wildcard_slots = WILDCARD_LIMIT_GREY
+
+ /// An overlay icon state for when the card is assigned to a name. Usually manifests itself as a little scribble to the right of the job icon.
+ var/assigned_icon_state = "assigned"
+ /// Cached icon that has been built for this card.
+ var/icon/cached_flat_icon
+
+ /// If this is set, will manually override the icon file for the trim. Intended for admins to VV edit and chameleon ID cards.
+ var/trim_icon_override
+ /// If this is set, will manually override the icon state for the trim. Intended for admins to VV edit and chameleon ID cards.
+ var/trim_state_override
+
+/obj/item/card/id/advanced/get_icon_source()
+ return get_cached_flat_icon()
+
+/// If no cached_flat_icon exists, this proc creates it. This proc then returns the cached_flat_icon.
+/obj/item/card/id/advanced/proc/get_cached_flat_icon()
+ if(!cached_flat_icon)
+ cached_flat_icon = getFlatIcon(src)
+ return cached_flat_icon
+
+/obj/item/card/id/advanced/get_examine_string(mob/user, thats = FALSE)
+ return "[icon2html(get_cached_flat_icon(), user)] [thats? "That's ":""][get_examine_name(user)]" //displays all overlays in chat
+
+/obj/item/card/id/advanced/update_overlays()
+ . = ..()
+
+ cached_flat_icon = null
+
+ if(registered_name && registered_name != "Captain")
+ . += mutable_appearance(icon, assigned_icon_state)
+
+ var/trim_icon_file = trim_icon_override ? trim_icon_override : trim?.trim_icon
+ var/trim_icon_state = trim_state_override ? trim_state_override : trim?.trim_state
+
+ if(!trim_icon_file || !trim_icon_state)
+ return
+
+ . += mutable_appearance(trim_icon_file, trim_icon_state)
+
+/obj/item/card/id/advanced/silver
+ name = "silver identification card"
+ desc = "A silver card which shows honour and dedication."
+ icon_state = "card_silver"
+ worn_icon_state = "card_silver"
+ inhand_icon_state = "silver_id"
+ wildcard_slots = WILDCARD_LIMIT_SILVER
+
+/datum/id_trim/maint_reaper
+ access = list(ACCESS_MAINT_TUNNELS)
+ trim_state = "trim_janitor"
+ assignment = "Reaper"
+
+/obj/item/card/id/advanced/silver/reaper
+ name = "Thirteen's ID Card (Reaper)"
+ trim = /datum/id_trim/maint_reaper
+ registered_name = "Thirteen"
+
+/obj/item/card/id/advanced/gold
+ name = "gold identification card"
+ desc = "A golden card which shows power and might."
+ icon_state = "card_gold"
+ worn_icon_state = "card_gold"
+ inhand_icon_state = "gold_id"
+ wildcard_slots = WILDCARD_LIMIT_GOLD
+
+/obj/item/card/id/advanced/gold/captains_spare
+ name = "captain's spare ID"
+ desc = "The spare ID of the High Lord himself."
+ registered_name = "Captain"
+ trim = /datum/id_trim/job/captain
+ registered_age = null
+
+/obj/item/card/id/advanced/gold/captains_spare/update_label() //so it doesn't change to Captain's ID card (Captain) on a sneeze
+ if(registered_name == "Captain")
+ name = "[initial(name)][(!assignment || assignment == "Captain") ? "" : " ([assignment])"]"
+ update_appearance(UPDATE_ICON)
+ else
+ ..()
+
+/obj/item/card/id/advanced/centcom
+ name = "\improper CentCom ID"
+ desc = "An ID straight from Central Command."
+ icon_state = "card_centcom"
+ worn_icon_state = "card_centcom"
+ assigned_icon_state = "assigned_centcom"
+ registered_name = "Central Command"
+ registered_age = null
+ trim = /datum/id_trim/centcom
+ wildcard_slots = WILDCARD_LIMIT_CENTCOM
+
+/obj/item/card/id/advanced/centcom/ert
+ name = "\improper CentCom ID"
+ desc = "An ERT ID card."
+ registered_age = null
+ registered_name = "Emergency Response Intern"
+ trim = /datum/id_trim/centcom/ert
+
+/obj/item/card/id/advanced/centcom/ert
+ registered_name = "Emergency Response Team Commander"
+ trim = /datum/id_trim/centcom/ert/commander
+
+/obj/item/card/id/advanced/centcom/ert/security
+ registered_name = "Security Response Officer"
+ trim = /datum/id_trim/centcom/ert/security
+
+/obj/item/card/id/advanced/centcom/ert/engineer
+ registered_name = "Engineering Response Officer"
+ trim = /datum/id_trim/centcom/ert/engineer
+
+/obj/item/card/id/advanced/centcom/ert/medical
+ registered_name = "Medical Response Officer"
+ trim = /datum/id_trim/centcom/ert/medical
+
+/obj/item/card/id/advanced/centcom/ert/chaplain
+ registered_name = "Religious Response Officer"
+ trim = /datum/id_trim/centcom/ert/chaplain
+
+/obj/item/card/id/advanced/centcom/ert/janitor
+ registered_name = "Janitorial Response Officer"
+ trim = /datum/id_trim/centcom/ert/janitor
+
+/obj/item/card/id/advanced/centcom/ert/clown
+ registered_name = "Entertainment Response Officer"
+ trim = /datum/id_trim/centcom/ert/clown
+
+/obj/item/card/id/advanced/black
+ name = "black identification card"
+ desc = "This card is telling you one thing and one thing alone. The person holding this card is an utter badass."
+ icon_state = "card_black"
+ worn_icon_state = "card_black"
+ assigned_icon_state = "assigned_syndicate"
+ wildcard_slots = WILDCARD_LIMIT_GOLD
+
+/obj/item/card/id/advanced/black/deathsquad
+ name = "\improper Death Squad ID"
+ desc = "A Death Squad ID card."
+ registered_name = "Death Commando"
+ trim = /datum/id_trim/centcom/deathsquad
+ wildcard_slots = WILDCARD_LIMIT_DEATHSQUAD
+
+/obj/item/card/id/advanced/black/syndicate_command
+ name = "syndicate ID card"
+ desc = "An ID straight from the Syndicate."
+ registered_name = "Syndicate"
+ registered_age = null
+ trim = /datum/id_trim/syndicom
+ wildcard_slots = WILDCARD_LIMIT_SYNDICATE
+
+/obj/item/card/id/advanced/black/syndicate_command/crew_id
+ name = "syndicate ID card"
+ desc = "An ID straight from the Syndicate."
+ registered_name = "Syndicate"
+ trim = /datum/id_trim/syndicom/crew
+
+/obj/item/card/id/advanced/black/syndicate_command/captain_id
+ name = "syndicate captain ID card"
+ desc = "An ID straight from the Syndicate."
+ registered_name = "Syndicate"
+ trim = /datum/id_trim/syndicom/captain
+
+/obj/item/card/id/advanced/debug
+ name = "\improper Debug ID"
+ desc = "A debug ID card. Has ALL the all access, you really shouldn't have this."
+ icon_state = "card_centcom"
+ worn_icon_state = "card_centcom"
+ assigned_icon_state = "assigned_centcom"
+ trim = /datum/id_trim/admin
+ wildcard_slots = WILDCARD_LIMIT_ADMIN
+
+/obj/item/card/id/advanced/debug/Initialize()
+ . = ..()
+ registered_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
+
+/obj/item/card/id/advanced/prisoner
+ name = "prisoner ID card"
+ desc = "You are a number, you are not a free man."
+ icon_state = "card_prisoner"
+ worn_icon_state = "card_prisoner"
+ inhand_icon_state = "orange-id"
+ lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
+ registered_name = "Scum"
+ registered_age = null
+ trim = /datum/id_trim/job/prisoner
+
+ wildcard_slots = WILDCARD_LIMIT_PRISONER
+
+ /// Number of gulag points required to earn freedom.
+ var/goal = 0
+ /// Number of gulag points earned.
+ var/points = 0
+
+/obj/item/card/id/advanced/prisoner/attack_self(mob/user)
+ to_chat(usr, "You have accumulated [points] out of the [goal] points you need for freedom.")
+
+/obj/item/card/id/advanced/prisoner/one
+ name = "Prisoner #13-001"
+ registered_name = "Prisoner #13-001"
+ trim = /datum/id_trim/job/prisoner/one
+
+/obj/item/card/id/advanced/prisoner/two
+ name = "Prisoner #13-002"
+ registered_name = "Prisoner #13-002"
+ trim = /datum/id_trim/job/prisoner/two
+
+/obj/item/card/id/advanced/prisoner/three
+ name = "Prisoner #13-003"
+ registered_name = "Prisoner #13-003"
+ trim = /datum/id_trim/job/prisoner/three
+
+/obj/item/card/id/advanced/prisoner/four
+ name = "Prisoner #13-004"
+ registered_name = "Prisoner #13-004"
+ trim = /datum/id_trim/job/prisoner/four
+
+/obj/item/card/id/advanced/prisoner/five
+ name = "Prisoner #13-005"
+ registered_name = "Prisoner #13-005"
+ trim = /datum/id_trim/job/prisoner/five
+
+/obj/item/card/id/advanced/prisoner/six
+ name = "Prisoner #13-006"
+ registered_name = "Prisoner #13-006"
+ trim = /datum/id_trim/job/prisoner/six
+
+/obj/item/card/id/advanced/prisoner/seven
+ name = "Prisoner #13-007"
+ registered_name = "Prisoner #13-007"
+ trim = /datum/id_trim/job/prisoner/seven
+
+/obj/item/card/id/advanced/mining
+ name = "mining ID"
+ trim = /datum/id_trim/job/shaft_miner/spare
+
+/obj/item/card/id/advanced/highlander
+ name = "highlander ID"
+ registered_name = "Highlander"
+ desc = "There can be only one!"
+ icon_state = "card_black"
+ worn_icon_state = "card_black"
+ assigned_icon_state = "assigned_syndicate"
+ trim = /datum/id_trim/highlander
+ wildcard_slots = WILDCARD_LIMIT_ADMIN
+
+/obj/item/card/id/advanced/chameleon
+ name = "agent card"
+ desc = "A highly advanced chameleon ID card. Touch this card on another ID card to choose which accesses to copy."
+ wildcard_slots = WILDCARD_LIMIT_CHAMELEON
+
+ /// Have we set a custom name and job assignment, or will we use what we're given when we chameleon change?
+ var/forged = FALSE
+ /// Anti-metagaming protections. If TRUE, anyone can change the ID card's details. If FALSE, only syndicate agents can.
+ var/anyone = FALSE
+ /// Weak ref to the ID card we're currently attempting to steal access from.
+ var/datum/weakref/theft_target
+
+/obj/item/card/id/advanced/chameleon/Initialize()
+ . = ..()
+ var/datum/action/item_action/chameleon/change/id/chameleon_card_action = new(src)
+ chameleon_card_action.chameleon_type = /obj/item/card/id/advanced
+ chameleon_card_action.chameleon_name = "ID Card"
+ chameleon_card_action.initialize_disguises()
+
+/obj/item/card/id/advanced/chameleon/Destroy()
+ theft_target = null
+ . = ..()
+
+/obj/item/card/id/advanced/chameleon/afterattack(obj/item/O, mob/user, proximity)
+ if(!proximity)
+ return
+ if(istype(O, /obj/item/card/id))
+ theft_target = WEAKREF(O)
+ ui_interact(user)
+ return
+
+ return ..()
+
+/obj/item/card/id/advanced/chameleon/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "ChameleonCard", name)
+ ui.open()
+
+/obj/item/card/id/advanced/chameleon/ui_static_data(mob/user)
+ var/list/data = list()
+ data["wildcardFlags"] = SSid_access.wildcard_flags_by_wildcard
+ data["accessFlagNames"] = SSid_access.access_flag_string_by_flag
+ data["accessFlags"] = SSid_access.flags_by_access
+ return data
+
+/obj/item/card/id/advanced/chameleon/ui_data(mob/user)
+ var/list/data = list()
+
+ data["showBasic"] = FALSE
+
+ var/list/regions = list()
+
+ var/obj/item/card/id/target_card = theft_target.resolve()
+ if(target_card)
+ var/list/tgui_region_data = SSid_access.all_region_access_tgui
+ for(var/region in SSid_access.station_regions)
+ regions += tgui_region_data[region]
+
+ data["accesses"] = regions
+ data["ourAccess"] = access
+ data["ourTrimAccess"] = trim ? trim.access : list()
+ data["theftAccess"] = target_card.access.Copy()
+ data["wildcardSlots"] = wildcard_slots
+ data["selectedList"] = access
+ data["trimAccess"] = list()
+
+ return data
+
+/obj/item/card/id/advanced/chameleon/ui_act(action, list/params)
+ . = ..()
+ if(.)
+ return
+
+ var/obj/item/card/id/target_card = theft_target?.resolve()
+ if(QDELETED(target_card))
+ to_chat(usr, "The ID card you were attempting to scan is no longer in range.")
+ target_card = null
+ return TRUE
+
+ // Wireless ID theft!
+ var/turf/our_turf = get_turf(src)
+ var/turf/target_turf = get_turf(target_card)
+ if(!our_turf.Adjacent(target_turf))
+ to_chat(usr, "The ID card you were attempting to scan is no longer in range.")
+ target_card = null
+ return TRUE
+
+ switch(action)
+ if("mod_access")
+ var/access_type = params["access_target"]
+ var/try_wildcard = params["access_wildcard"]
+ if(access_type in access)
+ remove_access(list(access_type))
+ LOG_ID_ACCESS_CHANGE(usr, src, "removed [SSid_access.get_access_desc(access_type)]")
+ return TRUE
+
+ if(!(access_type in target_card.access))
+ to_chat(usr, "ID error: ID card rejected your attempted access modification.")
+ LOG_ID_ACCESS_CHANGE(usr, src, "failed to add [SSid_access.get_access_desc(access_type)][try_wildcard ? " with wildcard [try_wildcard]" : ""]")
+ return TRUE
+
+ if(!can_add_wildcards(list(access_type), try_wildcard))
+ to_chat(usr, "ID error: ID card rejected your attempted access modification.")
+ LOG_ID_ACCESS_CHANGE(usr, src, "failed to add [SSid_access.get_access_desc(access_type)][try_wildcard ? " with wildcard [try_wildcard]" : ""]")
+ return TRUE
+
+ if(!add_access(list(access_type), try_wildcard))
+ to_chat(usr, "ID error: ID card rejected your attempted access modification.")
+ LOG_ID_ACCESS_CHANGE(usr, src, "failed to add [SSid_access.get_access_desc(access_type)][try_wildcard ? " with wildcard [try_wildcard]" : ""]")
+ return TRUE
+
+ if(access_type in ACCESS_ALERT_ADMINS)
+ message_admins("[ADMIN_LOOKUPFLW(usr)] just added [SSid_access.get_access_desc(access_type)] to an ID card [ADMIN_VV(src)] [(registered_name) ? "belonging to [registered_name]." : "with no registered name."]")
+ LOG_ID_ACCESS_CHANGE(usr, src, "added [SSid_access.get_access_desc(access_type)]")
+ return TRUE
+
+/obj/item/card/id/advanced/chameleon/attack_self(mob/user)
+ if(isliving(user) && user.mind)
+ var/popup_input = alert(user, "Choose Action", "Agent ID", "Show", "Forge/Reset", "Change Account ID")
+ if(user.incapacitated())
+ return
+ if(!user.is_holding(src))
+ return
+ if(popup_input == "Forge/Reset")
+ if(!forged)
+ var/input_name = stripped_input(user, "What name would you like to put on this card? Leave blank to randomise.", "Agent card name", registered_name ? registered_name : (ishuman(user) ? user.real_name : user.name), MAX_NAME_LEN)
+ input_name = sanitize_name(input_name)
+ if(!input_name)
+ // Invalid/blank names give a randomly generated one.
+ if(user.gender == MALE)
+ input_name = "[pick(GLOB.first_names_male)] [pick(GLOB.last_names)]"
+ else if(user.gender == FEMALE)
+ input_name = "[pick(GLOB.first_names_female)] [pick(GLOB.last_names)]"
+ else
+ input_name = "[pick(GLOB.first_names)] [pick(GLOB.last_names)]"
+
+ registered_name = input_name
+
+ var/change_trim = alert(user, "Adjust the appearance of your card's trim?", "Modify Trim", "Yes", "No")
+ if(change_trim == "Yes")
+ var/list/blacklist = typecacheof(type) + typecacheof(/obj/item/card/id/advanced/simple_bot)
+ var/list/trim_list = list()
+ for(var/trim_path in typesof(/datum/id_trim))
+ if(blacklist[trim_path])
+ continue
+
+ var/datum/id_trim/trim = SSid_access.trim_singletons_by_path[trim_path]
+
+ if(trim && trim.trim_state && trim.assignment)
+ var/fake_trim_name = "[trim.assignment] ([trim.trim_state])"
+ trim_list[fake_trim_name] = trim_path
+
+ var/selected_trim_path
+ selected_trim_path = input("Select trim to apply to your card.\nNote: This will not grant any trim accesses.", "Forge Trim", selected_trim_path) as null|anything in sortList(trim_list, /proc/cmp_typepaths_asc)
+ if(selected_trim_path)
+ SSid_access.apply_trim_to_chameleon_card(src, trim_list[selected_trim_path])
+
+ var/target_occupation = stripped_input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels.", "Agent card job assignment", assignment ? assignment : "Assistant", MAX_MESSAGE_LEN)
+ if(target_occupation)
+ assignment = target_occupation
+
+ var/new_age = input(user, "Choose the ID's age:\n([AGE_MIN]-[AGE_MAX])", "Agent card age") as num|null
+ if(new_age)
+ registered_age = max(round(text2num(new_age)), 0)
+
+ update_label()
+ update_icon()
+ forged = TRUE
+ to_chat(user, "You successfully forge the ID card.")
+ log_game("[key_name(user)] has forged \the [initial(name)] with name \"[registered_name]\", occupation \"[assignment]\" and trim \"[trim?.assignment]\".")
+
+ if(!registered_account)
+ if(ishuman(user))
+ var/mob/living/carbon/human/accountowner = user
+
+ var/datum/bank_account/account = SSeconomy.bank_accounts_by_id["[accountowner.account_id]"]
+ if(account)
+ account.bank_cards += src
+ registered_account = account
+ to_chat(user, "Your account number has been automatically assigned.")
+ return
+ if(forged)
+ registered_name = initial(registered_name)
+ assignment = initial(assignment)
+ SSid_access.remove_trim_from_card(src)
+ log_game("[key_name(user)] has reset \the [initial(name)] named \"[src]\" to default.")
+ update_label()
+ update_icon()
+ forged = FALSE
+ to_chat(user, "You successfully reset the ID card.")
+ return
+ if (popup_input == "Change Account ID")
+ set_new_account(user)
+ return
+ return ..()
+
+/// A special variant of the classic chameleon ID card which accepts all access.
+/obj/item/card/id/advanced/chameleon/black
+ icon_state = "card_black"
+ worn_icon_state = "card_black"
+ assigned_icon_state = "assigned_syndicate"
+ wildcard_slots = WILDCARD_LIMIT_GOLD
+
+/obj/item/card/id/advanced/engioutpost
+ registered_name = "George 'Plastic' Miller"
+ desc = "A card used to provide ID and determine access across the station. There's blood dripping from the corner. Ew."
+ trim = /datum/id_trim/engioutpost
+ registered_age = 47
+
+/obj/item/card/id/advanced/simple_bot
+ name = "simple bot ID card"
+ desc = "An internal ID card used by the station's non-sentient bots. You should report this to a coder if you're holding it."
+ wildcard_slots = WILDCARD_LIMIT_ADMIN
diff --git a/code/game/objects/items/control_wand.dm b/code/game/objects/items/control_wand.dm
index 88e7f40ef78..17b1f7f2b94 100644
--- a/code/game/objects/items/control_wand.dm
+++ b/code/game/objects/items/control_wand.dm
@@ -12,13 +12,13 @@
desc = "Remotely controls airlocks."
w_class = WEIGHT_CLASS_TINY
var/mode = WAND_OPEN
- var/region_access = 1 //See access.dm
+ var/region_access = REGION_GENERAL
var/list/access_list
network_id = NETWORK_DOOR_REMOTES
/obj/item/door_remote/Initialize()
. = ..()
- access_list = get_region_accesses(region_access)
+ access_list = SSid_access.get_region_access_list(list(region_access))
RegisterSignal(src, COMSIG_COMPONENT_NTNET_NAK, .proc/bad_signal)
RegisterSignal(src, COMSIG_COMPONENT_NTNET_ACK, .proc/good_signal)
@@ -65,48 +65,47 @@
ntnet_send(data)
-
/obj/item/door_remote/omni
name = "omni door remote"
desc = "This control wand can access any door on the station."
icon_state = "gangtool-yellow"
- region_access = 0
+ region_access = REGION_ALL_STATION
/obj/item/door_remote/captain
name = "command door remote"
icon_state = "gangtool-yellow"
- region_access = 7
+ region_access = REGION_COMMAND
/obj/item/door_remote/chief_engineer
name = "engineering door remote"
icon_state = "gangtool-orange"
- region_access = 5
+ region_access = REGION_ENGINEERING
/obj/item/door_remote/research_director
name = "research door remote"
icon_state = "gangtool-purple"
- region_access = 4
+ region_access = REGION_RESEARCH
/obj/item/door_remote/head_of_security
name = "security door remote"
icon_state = "gangtool-red"
- region_access = 2
+ region_access = REGION_SECURITY
/obj/item/door_remote/quartermaster
name = "supply door remote"
desc = "Remotely controls airlocks. This remote has additional Vault access."
icon_state = "gangtool-green"
- region_access = 6
+ region_access = REGION_SUPPLY
/obj/item/door_remote/chief_medical_officer
name = "medical door remote"
icon_state = "gangtool-blue"
- region_access = 3
+ region_access = REGION_MEDBAY
/obj/item/door_remote/civilian
name = "civilian door remote"
icon_state = "gangtool-white"
- region_access = 1
+ region_access = REGION_GENERAL
#undef WAND_OPEN
#undef WAND_BOLT
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 31f1641aed1..98815fcb56b 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -12,12 +12,12 @@ GLOBAL_LIST_EMPTY(PDAs)
#define PDA_SPAM_DELAY 2 MINUTES
/obj/item/pda
- name = "\improper PDA"
+ name = "\improper standard PDA"
desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by a preprogrammed ROM cartridge."
icon = 'icons/obj/pda.dmi'
icon_state = "pda"
inhand_icon_state = "electronic"
- worn_icon_state = "electronic"
+ worn_icon_state = "pda"
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
item_flags = NOBLUDGEON
@@ -151,6 +151,12 @@ GLOBAL_LIST_EMPTY(PDAs)
else
return ..()
+/obj/item/pda/get_id_examine_strings(mob/user)
+ . = ..()
+ if(id)
+ . += "\The [src] is displaying [id]."
+ . += id.get_id_examine_strings(user)
+
/obj/item/pda/GetID()
return id
@@ -488,8 +494,6 @@ GLOBAL_LIST_EMPTY(PDAs)
id_check(U)
if("UpdateInfo")
ownjob = id.assignment
- if(istype(id, /obj/item/card/id/syndicate))
- owner = id.registered_name
update_label()
if(!silent)
playsound(src, 'sound/machines/terminal_processing.ogg', 15, TRUE)
@@ -709,6 +713,8 @@ GLOBAL_LIST_EMPTY(PDAs)
if(H.wear_id == src)
H.sec_hud_set_ID()
+ update_slot_icon()
+
/obj/item/pda/proc/msg_input(mob/living/U = usr)
var/t = stripped_input(U, "Please enter message", name)
@@ -960,6 +966,8 @@ GLOBAL_LIST_EMPTY(PDAs)
else
old_id.forceMove(get_turf(src))
+ update_slot_icon()
+
/obj/item/pda/pre_attack(obj/target, mob/living/user, params)
if(!ismachinery(target))
diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm
index c106e634d3a..23c9eb391db 100644
--- a/code/game/objects/items/storage/boxes.dm
+++ b/code/game/objects/items/storage/boxes.dm
@@ -538,7 +538,7 @@
/obj/item/storage/box/ids/PopulateContents()
for(var/i in 1 to 7)
- new /obj/item/card/id(src)
+ new /obj/item/card/id/advanced(src)
//Some spare PDAs in a box
/obj/item/storage/box/pdas
@@ -565,7 +565,7 @@
/obj/item/storage/box/silver_ids/PopulateContents()
for(var/i in 1 to 7)
- new /obj/item/card/id/silver(src)
+ new /obj/item/card/id/advanced/silver(src)
/obj/item/storage/box/prisoner
name = "box of prisoner IDs"
@@ -575,13 +575,13 @@
/obj/item/storage/box/prisoner/PopulateContents()
..()
- new /obj/item/card/id/prisoner/one(src)
- new /obj/item/card/id/prisoner/two(src)
- new /obj/item/card/id/prisoner/three(src)
- new /obj/item/card/id/prisoner/four(src)
- new /obj/item/card/id/prisoner/five(src)
- new /obj/item/card/id/prisoner/six(src)
- new /obj/item/card/id/prisoner/seven(src)
+ new /obj/item/card/id/advanced/prisoner/one(src)
+ new /obj/item/card/id/advanced/prisoner/two(src)
+ new /obj/item/card/id/advanced/prisoner/three(src)
+ new /obj/item/card/id/advanced/prisoner/four(src)
+ new /obj/item/card/id/advanced/prisoner/five(src)
+ new /obj/item/card/id/advanced/prisoner/six(src)
+ new /obj/item/card/id/advanced/prisoner/seven(src)
/obj/item/storage/box/seccarts
name = "box of PDA security cartridges"
diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm
index 13e08514ef5..6e817bf28f4 100644
--- a/code/game/objects/items/storage/secure.dm
+++ b/code/game/objects/items/storage/secure.dm
@@ -21,6 +21,7 @@
var/l_setshort = FALSE
var/l_hacking = FALSE
var/open = FALSE
+ var/can_hack_open = TRUE
w_class = WEIGHT_CLASS_NORMAL
desc = "This shouldn't exist. If it does, create an issue report."
@@ -35,30 +36,31 @@
. += "The service panel is currently [open ? "unscrewed" : "screwed shut"]."
/obj/item/storage/secure/attackby(obj/item/W, mob/user, params)
- if(SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
+ if(can_hack_open && SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
if (W.tool_behaviour == TOOL_SCREWDRIVER)
if (W.use_tool(src, user, 20))
- open =! open
+ open = !open
to_chat(user, "You [open ? "open" : "close"] the service panel.")
return
if (W.tool_behaviour == TOOL_WIRECUTTER)
to_chat(user, "[src] is protected from this sort of tampering, yet it appears the internal memory wires can still be pulsed.")
- if ((W.tool_behaviour == TOOL_MULTITOOL) && (!l_hacking))
+ return
+ if (W.tool_behaviour == TOOL_MULTITOOL)
+ if(l_hacking)
+ to_chat(user, "This safe is already being hacked.")
+ return
if(open == TRUE)
to_chat(user, "Now attempting to reset internal memory, please hold.")
l_hacking = TRUE
if (W.use_tool(src, user, 400))
to_chat(user, "Internal memory reset - lock has been disengaged.")
l_set = FALSE
- l_hacking = FALSE
- else
- l_hacking = FALSE
- else
- to_chat(user, "You must unscrew the service panel before you can pulse the wiring!")
+
+ l_hacking = FALSE
+ return
+
+ to_chat(user, "You must unscrew the service panel before you can pulse the wiring!")
return
- //At this point you have exhausted all the special things to do when locked
- // ... but it's still locked.
- return
// -> storage/attackby() what with handle insertion, etc
return ..()
@@ -187,3 +189,35 @@
/obj/item/storage/secure/safe/hos
name = "head of security's safe"
+
+/**
+ * This safe is meant to be damn robust. To break in, you're supposed to get creative, or use acid or an explosion.
+ *
+ * This makes the safe still possible to break in for someone who is prepared and capable enough, either through
+ * chemistry, botany or whatever else.
+ *
+ * The safe is also weak to explosions, so spending some early TC could allow an antag to blow it upen if they can
+ * get access to it.
+ */
+/obj/item/storage/secure/safe/caps_spare
+ name = "captain's spare ID safe"
+ desc = "In case of emergency, do not break glass. All Captains and Acting Captains are provided with codes to access this safe. \
+It is made out of the same material as the station's Black Box and is designed to resist all conventional weaponry. \
+There appears to be a small amount of surface corrosion. It doesn't look like it could withstand much of an explosion."
+ can_hack_open = FALSE
+ armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 70, BIO = 100, RAD = 100, FIRE = 80, ACID = 70)
+ max_integrity = 300
+ color = "#ffdd33"
+
+/obj/item/storage/secure/safe/caps_spare/Initialize()
+ . = ..()
+
+ l_code = SSid_access.spare_id_safe_code
+ l_set = TRUE
+ SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, TRUE)
+
+/obj/item/storage/secure/safe/caps_spare/PopulateContents()
+ new /obj/item/card/id/advanced/gold/captains_spare(src)
+
+/obj/item/storage/secure/safe/caps_spare/rust_heretic_act()
+ take_damage(damage_amount = 100, damage_type = BRUTE, damage_flag = MELEE, armour_penetration = 100)
diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm
index 003b3360aab..e097add0dcb 100644
--- a/code/game/objects/items/storage/uplink_kits.dm
+++ b/code/game/objects/items/storage/uplink_kits.dm
@@ -16,7 +16,6 @@
if("bloodyspai")
new /obj/item/clothing/under/chameleon(src) // 2 tc since it's not the full set
new /obj/item/clothing/mask/chameleon(src) // Goes with above
- new /obj/item/card/id/syndicate(src) // 2 tc
new /obj/item/clothing/shoes/chameleon/noslip(src) // 2 tc
new /obj/item/camera_bug(src) // 1 tc
new /obj/item/multitool/ai_detect(src) // 1 tc
@@ -79,7 +78,6 @@
new /obj/item/storage/toolbox/syndicate(src)
new /obj/item/camera_bug(src)
new /obj/item/clothing/glasses/thermal/syndi(src)
- new /obj/item/card/id/syndicate(src)
if("lordsingulo")
new /obj/item/sbeacondrop(src)
@@ -87,7 +85,7 @@
new /obj/item/clothing/head/helmet/space/syndicate/black/red(src)
new /obj/item/card/emag(src)
new /obj/item/storage/toolbox/syndicate(src)
- new /obj/item/card/mining_access_card(src)
+ new /obj/item/card/id/advanced/mining(src)
new /obj/item/stack/spacecash/c10000(src)
new /obj/item/toy/spinningtoy(src) //lol
@@ -127,7 +125,6 @@
new /obj/item/ammo_box/magazine/m9mm(src)
new /obj/item/ammo_box/magazine/m9mm(src)
new /obj/item/clothing/under/chameleon(src)
- new /obj/item/card/id/syndicate(src)
new /obj/item/reagent_containers/hypospray/medipen/stimulants(src)
new /obj/item/reagent_containers/glass/rag(src)
@@ -137,14 +134,12 @@
for(var/i in 1 to 6)
new /obj/item/throwing_star(src) // ~5 tc for all 6
new /obj/item/storage/belt/chameleon(src) // Unique but worth at least 2 tc
- new /obj/item/card/id/syndicate(src) // 2 tc
new /obj/item/chameleon(src) // 7 tc
if("darklord")
new /obj/item/dualsaber(src)
new /obj/item/dnainjector/telemut/darkbundle(src)
new /obj/item/clothing/suit/hooded/chaplain_hoodie(src)
- new /obj/item/card/id/syndicate(src)
new /obj/item/clothing/shoes/chameleon/noslip(src) //because slipping while being a dark lord sucks
new /obj/item/book/granter/spell/summonitem(src)
@@ -259,7 +254,6 @@
new /obj/item/clothing/suit/space/syndicate/contract(src)
new /obj/item/clothing/under/chameleon(src)
new /obj/item/clothing/mask/chameleon(src)
- new /obj/item/card/id/syndicate(src)
new /obj/item/storage/fancy/cigarettes/cigpack_syndicate(src)
new /obj/item/lighter(src)
diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm
index e48c79cf596..94f9c04c665 100644
--- a/code/game/objects/items/storage/wallets.dm
+++ b/code/game/objects/items/storage/wallets.dm
@@ -42,27 +42,52 @@
/obj/item/storage/wallet/Exited(atom/movable/AM)
. = ..()
- refreshID()
+ refreshID(removed = TRUE)
-/obj/item/storage/wallet/proc/refreshID()
+/**
+ * Calculates the new front ID.
+ *
+ * Picks the ID card that has the most combined command or higher tier accesses.
+ * Arguments:
+ * * removed - If this proc was called because a card was removed. There's a chance we don't need to calculate the new front ID if a card was removed.
+ */
+/obj/item/storage/wallet/proc/refreshID(removed = FALSE)
LAZYCLEARLIST(combined_access)
- if(!(front_id in src))
- front_id = null
- for(var/obj/item/card/id/I in contents)
- if(!front_id)
- front_id = I
+
+ // If the front_id is still in our wallet an we removed a card, we can return early.
+ if((front_id in src) && removed)
+ return
+
+ front_id = null
+ var/winning_tally = 0
+ for(var/card in contents)
+ var/obj/item/card/id/id_card = card
+ if(!istype(id_card))
+ continue
+ var/card_tally = SSid_access.tally_access(id_card, ACCESS_FLAG_COMMAND)
+ if(card_tally > winning_tally)
+ winning_tally = card_tally
+ front_id = id_card
LAZYINITLIST(combined_access)
- combined_access |= I.access
+ combined_access |= id_card.access
+
+ // If we didn't pick a front ID - Maybe none of our cards have any command accesses? Just grab the first card (if we even have one).
+ // We could also have no ID card in the wallet at all, which will mean we end up with a null front_id and that's fine too.
+ if(!front_id)
+ front_id = (locate(/obj/item/card/id) in contents)
+
if(ishuman(loc))
- var/mob/living/carbon/human/H = loc
- if(H.wear_id == src)
- H.sec_hud_set_ID()
- update_appearance()
+ var/mob/living/carbon/human/wearing_human = loc
+ if(wearing_human.wear_id == src)
+ wearing_human.sec_hud_set_ID()
+
update_label()
+ update_appearance(UPDATE_ICON)
+ update_slot_icon()
/obj/item/storage/wallet/Entered(atom/movable/AM)
. = ..()
- refreshID()
+ refreshID(removed = FALSE)
/obj/item/storage/wallet/update_overlays()
. = ..()
@@ -94,6 +119,12 @@
if(front_id)
. += "Alt-click to remove the id."
+/obj/item/storage/wallet/get_id_examine_strings(mob/user)
+ . = ..()
+ if(front_id)
+ . += "\The [src] is displaying [front_id]."
+ . += front_id.get_id_examine_strings(user)
+
/obj/item/storage/wallet/GetID()
return front_id
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index bb03dda5599..32b01f20e49 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -499,7 +499,7 @@
open()
else
req_access = list()
- req_access += pick(get_all_accesses())
+ req_access += pick(SSid_access.get_region_access_list(list(REGION_ALL_STATION)))
/obj/structure/closet/contents_explosion(severity, target)
for(var/thing in contents)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index e562173bf36..93c513abee2 100755
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -31,7 +31,6 @@
new /obj/item/storage/belt/sabre(src)
new /obj/item/gun/energy/e_gun(src)
new /obj/item/door_remote/captain(src)
- new /obj/item/card/id/captains_spare(src)
new /obj/item/storage/photo_album/captain(src)
/obj/structure/closet/secure_closet/hop
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index 4e1e8763945..7f8c0d64ee7 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -434,7 +434,8 @@
ears = /obj/item/radio/headset/syndicate/alt
back = /obj/item/storage/backpack
implants = list(/obj/item/implant/weapons_auth)
- id = /obj/item/card/id/syndicate
+ id = /obj/item/card/id/advanced/chameleon
+ id_trim = /datum/id_trim/chameleon/operative
/datum/outfit/syndicate_empty/post_equip(mob/living/carbon/human/H)
H.faction |= ROLE_SYNDICATE
@@ -476,7 +477,6 @@
flavour_text = "Your job is to oversee your crew, defend the ship, and destroy Space Station 13. The ship has an armory, multiple ships, beam cannons, and multiple crewmembers to accomplish this goal."
important_info = "As the captain, this whole operation falls on your shoulders. You do not need to nuke the station, causing sufficient damage and preventing your ship from being destroyed will be enough."
outfit = /datum/outfit/syndicate_empty/battlecruiser/assault/captain
- id_access_list = list(150,151)
/datum/outfit/syndicate_empty/battlecruiser/assault/captain
name = "Syndicate Battlecruiser Captain"
@@ -488,6 +488,7 @@
head = /obj/item/clothing/head/hos/syndicate
mask = /obj/item/clothing/mask/cigarette/cigar/havana
glasses = /obj/item/clothing/glasses/thermal/eyepatch
+ id_trim = /datum/id_trim/battlecruiser/captain
//Ancient cryogenic sleepers. Players become NT crewmen from a hundred year old space station, now on the verge of collapse.
/obj/effect/mob_spawn/human/oldsec
@@ -712,7 +713,7 @@
l_pocket = /obj/item/gun/ballistic/automatic/pistol
r_pocket = /obj/item/kitchen/knife/combat/survival
belt = /obj/item/storage/belt/military/assault
- id = /obj/item/card/id/syndicate_command/crew_id
+ id = /obj/item/card/id/advanced/black/syndicate_command/crew_id
implants = list(/obj/item/implant/weapons_auth)
/datum/outfit/syndicatespace/syndicaptain
@@ -726,7 +727,7 @@
back = /obj/item/storage/backpack
r_pocket = /obj/item/kitchen/knife/combat/survival
belt = /obj/item/storage/belt/military/assault
- id = /obj/item/card/id/syndicate_command/captain_id
+ id = /obj/item/card/id/advanced/black/syndicate_command/captain_id
implants = list(/obj/item/implant/weapons_auth)
backpack_contents = list(/obj/item/documents/syndicate/red, /obj/item/paper/fluff/ruins/forgottenship/password, /obj/item/gun/ballistic/automatic/pistol/aps)
@@ -747,7 +748,7 @@
flavour_text = "It's up to you to make sure nobody drowns or gets eaten by sharks and stuff."
mob_gender = "female"
name = "lifeguard sleeper"
- id_job = "Lifeguard"
+ outfit = /datum/outfit/beachbum/lifeguard
uniform = /obj/item/clothing/under/shorts/red
/datum/outfit/beachbum
@@ -756,7 +757,7 @@
r_pocket = /obj/item/storage/wallet/random
l_pocket = /obj/item/food/pizzaslice/dank
uniform = /obj/item/clothing/under/pants/youngfolksjeans
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
/datum/outfit/beachbum/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
. = ..()
@@ -764,6 +765,9 @@
return
H.dna.add_mutation(STONER)
+/datum/outfit/beachbum/lifeguard
+ id_trim = /datum/id_trim/lifeguard
+
/obj/effect/mob_spawn/human/bartender/alive
death = FALSE
roundstart = FALSE
@@ -774,7 +778,6 @@
short_desc = "You are a space bartender!"
flavour_text = "Time to mix drinks and change lives. Smoking space drugs makes it easier to understand your patrons' odd dialect."
assignedrole = "Space Bartender"
- id_job = "Bartender"
/datum/outfit/spacebartender
name = "Space Bartender"
@@ -783,7 +786,8 @@
shoes = /obj/item/clothing/shoes/sneakers/black
suit = /obj/item/clothing/suit/armor/vest
glasses = /obj/item/clothing/glasses/sunglasses/reagent
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
+ id_trim = /datum/id_trim/space_bartender
/datum/outfit/spacebartender/post_equip(mob/living/carbon/human/H, visualsOnly)
. = ..()
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index f13c6ddf477..0495449c409 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -195,30 +195,32 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
var/mob/living/carbon/human/H = M
var/obj/item/worn = H.wear_id
var/obj/item/card/id/id = null
+
if(worn)
id = worn.GetID()
if(id)
- id.icon_state = "gold"
- id.access = get_all_accesses()+get_all_centcom_access()+get_all_syndicate_access()
- else
- id = new /obj/item/card/id/gold(H.loc)
- id.access = get_all_accesses()+get_all_centcom_access()+get_all_syndicate_access()
- id.registered_name = H.real_name
- id.assignment = "Captain"
- id.update_label()
+ if(id == worn)
+ worn = null
+ qdel(id)
- if(worn)
- if(istype(worn, /obj/item/pda))
- var/obj/item/pda/PDA = worn
- PDA.id = id
- id.forceMove(PDA)
- else if(istype(worn, /obj/item/storage/wallet))
- var/obj/item/storage/wallet/W = worn
- W.front_id = id
- id.forceMove(W)
- W.update_appearance()
- else
- H.equip_to_slot(id,ITEM_SLOT_ID)
+ id = new /obj/item/card/id/advanced/debug()
+
+ id.registered_name = H.real_name
+ id.update_label()
+ id.update_icon()
+
+ if(worn)
+ if(istype(worn, /obj/item/pda))
+ var/obj/item/pda/PDA = worn
+ PDA.id = id
+ id.forceMove(PDA)
+ else if(istype(worn, /obj/item/storage/wallet))
+ var/obj/item/storage/wallet/W = worn
+ W.front_id = id
+ id.forceMove(W)
+ W.update_icon()
+ else
+ H.equip_to_slot(id,ITEM_SLOT_ID)
else
alert("Invalid mob")
diff --git a/code/modules/antagonists/fugitive/fugitive_outfits.dm b/code/modules/antagonists/fugitive/fugitive_outfits.dm
index 0882e7109db..abd63eae07f 100644
--- a/code/modules/antagonists/fugitive/fugitive_outfits.dm
+++ b/code/modules/antagonists/fugitive/fugitive_outfits.dm
@@ -74,7 +74,7 @@
ears = /obj/item/radio/headset
l_pocket = /obj/item/ammo_box/magazine/m45
r_pocket = /obj/item/restraints/handcuffs
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
/datum/outfit/spacepol/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
if(visualsOnly)
@@ -83,6 +83,7 @@
W.assignment = "Police Officer"
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
/datum/outfit/russiancorpse/hunter
ears = /obj/item/radio/headset
@@ -104,7 +105,7 @@
glasses = /obj/item/clothing/glasses/sunglasses/garb
ears = /obj/item/radio/headset
r_pocket = /obj/item/restraints/handcuffs/cable
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
l_hand = /obj/item/tank/internals/plasma/full
r_hand = /obj/item/flamethrower/full/tank
@@ -115,6 +116,7 @@
W.assignment = "Bounty Hunter"
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
/datum/outfit/bountyhook
name = "Bounty Hunter - Hook"
@@ -126,7 +128,7 @@
shoes = /obj/item/clothing/shoes/jackboots
mask = /obj/item/clothing/mask/scarecrow
r_pocket = /obj/item/restraints/handcuffs/cable
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
r_hand = /obj/item/gun/ballistic/shotgun/doublebarrel/hook
backpack_contents = list(
@@ -140,6 +142,7 @@
W.assignment = "Bounty Hunter"
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
/datum/outfit/bountysynth
name = "Bounty Hunter - Synth"
@@ -150,7 +153,7 @@
glasses = /obj/item/clothing/glasses/eyepatch
r_pocket = /obj/item/restraints/handcuffs/cable
ears = /obj/item/radio/headset
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
r_hand = /obj/item/storage/firstaid/regular
l_hand = /obj/item/pinpointer/shuttle
@@ -169,3 +172,4 @@
W.assignment = "Bounty Hunter"
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
diff --git a/code/modules/antagonists/gang/outfits.dm b/code/modules/antagonists/gang/outfits.dm
index 9b9fb67807d..82babe31609 100644
--- a/code/modules/antagonists/gang/outfits.dm
+++ b/code/modules/antagonists/gang/outfits.dm
@@ -3,10 +3,9 @@
return
var/obj/item/card/id/W = H.wear_id
- W.access = get_all_accesses() // I have a warrant.
- W.assignment = "Space Police"
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
..()
/datum/outfit/families_police/beatcop
@@ -24,7 +23,7 @@
belt = /obj/item/gun/ballistic/automatic/pistol/m1911
r_pocket = /obj/item/lighter
l_pocket = /obj/item/restraints/handcuffs
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced/black
r_hand = /obj/item/gun/energy/disabler
backpack_contents = list(/obj/item/storage/box/handcuffs = 1,
/obj/item/storage/box/teargas = 1,
@@ -34,6 +33,8 @@
/obj/item/ammo_box/c45 = 2,
/obj/item/storage/box/survival/security)
+ id_trim = /datum/id_trim/space_police
+
/datum/outfit/families_police/beatcop/armored
name = "Families: Armored Beat Cop"
suit = /obj/item/clothing/suit/armor/vest/blueshirt
diff --git a/code/modules/antagonists/highlander/highlander.dm b/code/modules/antagonists/highlander/highlander.dm
index 9e1dce422d6..c1e636e51e3 100644
--- a/code/modules/antagonists/highlander/highlander.dm
+++ b/code/modules/antagonists/highlander/highlander.dm
@@ -62,13 +62,11 @@
H.equip_to_slot_or_del(new /obj/item/pinpointer/nuke(H), ITEM_SLOT_LPOCKET)
for(var/obj/item/pinpointer/nuke/P in H)
P.attack_self(H)
- var/obj/item/card/id/centcom/W = new(H)
- W.access = get_all_accesses()
- W.access += get_all_centcom_access()
- W.assignment = "Highlander"
+ var/obj/item/card/id/advanced/highlander/W = new(H)
W.registered_name = H.real_name
ADD_TRAIT(W, TRAIT_NODROP, HIGHLANDER)
W.update_label()
+ W.update_icon()
H.equip_to_slot_or_del(W, ITEM_SLOT_ID)
sword = new(H)
diff --git a/code/modules/antagonists/traitor/equipment/contractor.dm b/code/modules/antagonists/traitor/equipment/contractor.dm
index 9553bd04a10..d462ae5c257 100644
--- a/code/modules/antagonists/traitor/equipment/contractor.dm
+++ b/code/modules/antagonists/traitor/equipment/contractor.dm
@@ -188,8 +188,9 @@
mask = /obj/item/clothing/mask/cigarette/syndicate
shoes = /obj/item/clothing/shoes/chameleon/noslip
ears = /obj/item/radio/headset/chameleon
- id = /obj/item/card/id/syndicate
+ id = /obj/item/card/id/advanced/chameleon
r_hand = /obj/item/storage/toolbox/syndicate
+ id_trim = /datum/id_trim/chameleon/operative
backpack_contents = list(/obj/item/storage/box/survival, /obj/item/implanter/uplink, /obj/item/clothing/mask/chameleon,
/obj/item/storage/fancy/cigarettes/cigpack_syndicate, /obj/item/lighter)
diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm
index 94fffc90c71..ab2c9555561 100644
--- a/code/modules/awaymissions/capture_the_flag.dm
+++ b/code/modules/awaymissions/capture_the_flag.dm
@@ -567,6 +567,7 @@
no_drops += W
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
no_drops += H.get_item_by_slot(ITEM_SLOT_OCLOTHING)
no_drops += H.get_item_by_slot(ITEM_SLOT_GLOVES)
@@ -586,7 +587,7 @@
r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/red
l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/red
r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/red
- id = /obj/item/card/id/syndicate_command //it's red
+ id = /obj/item/card/id/advanced/black/syndicate_command //it's red
/datum/outfit/ctf/red/instagib
r_hand = /obj/item/gun/energy/laser/instakill/red
@@ -597,7 +598,7 @@
r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/blue
l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/blue
r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/blue
- id = /obj/item/card/id/centcom //it's blue
+ id = /obj/item/card/id/advanced/centcom //it's blue
/datum/outfit/ctf/blue/instagib
r_hand = /obj/item/gun/energy/laser/instakill/blue
diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm
index 40547868f9e..8656d29758f 100644
--- a/code/modules/awaymissions/corpse.dm
+++ b/code/modules/awaymissions/corpse.dm
@@ -147,10 +147,6 @@
var/datum/outfit/outfit = /datum/outfit //If this is a path, it will be instanced in Initialize()
var/disable_pda = TRUE
var/disable_sensors = TRUE
- //All of these only affect the ID that the outfit has placed in the ID slot
- var/id_job = null //Such as "Clown" or "Chef." This just determines what the ID reads as, not their access
- var/id_access = null //This is for access. See access.dm for which jobs give what access. Use "Captain" if you want it to be all access.
- var/id_access_list = null //Allows you to manually add access to an ID card.
assignedrole = "Ghost Role"
var/husk = null
@@ -243,20 +239,9 @@
if(W)
if(H.age)
W.registered_age = H.age
- if(id_access)
- for(var/jobtype in typesof(/datum/job))
- var/datum/job/J = new jobtype
- if(J.title == id_access)
- W.access = J.get_access()
- break
- if(id_access_list)
- if(!islist(W.access))
- W.access = list()
- W.access |= id_access_list
- if(id_job)
- W.assignment = id_job
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
//Instant version - use when spawning corpses during runtime
/obj/effect/mob_spawn/human/corpse
@@ -340,6 +325,11 @@
outfit = /datum/outfit/job/doctor
icon_state = "corpsedoctor"
+/obj/effect/mob_spawn/human/geneticist
+ name = "Geneticist"
+ outfit = /datum/outfit/job/geneticist
+ icon_state = "corpsescientist"
+
/obj/effect/mob_spawn/human/engineer
name = "Engineer"
outfit = /datum/outfit/job/engineer/gloved
@@ -348,6 +338,9 @@
/obj/effect/mob_spawn/human/engineer/rig
outfit = /datum/outfit/job/engineer/gloved/rig
+/obj/effect/mob_spawn/human/engineer/rig/gunner
+ outfit = /datum/outfit/job/engineer/gloved/rig/gunner
+
/obj/effect/mob_spawn/human/clown
name = "Clown"
outfit = /datum/outfit/job/clown
@@ -375,8 +368,6 @@
/obj/effect/mob_spawn/human/bartender
name = "Space Bartender"
- id_job = "Bartender"
- id_access_list = list(ACCESS_BAR)
outfit = /datum/outfit/spacebartender
/obj/effect/mob_spawn/human/beach
@@ -386,8 +377,6 @@
/obj/effect/mob_spawn/human/bridgeofficer
name = "Bridge Officer"
- id_job = "Bridge Officer"
- id_access_list = list(ACCESS_CENT_CAPTAIN)
outfit = /datum/outfit/nanotrasenbridgeofficercorpse
/datum/outfit/nanotrasenbridgeofficercorpse
@@ -397,12 +386,11 @@
suit = /obj/item/clothing/suit/armor/bulletproof
shoes = /obj/item/clothing/shoes/sneakers/black
glasses = /obj/item/clothing/glasses/sunglasses
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced/centcom
+ id_trim = /datum/id_trim/centcom/corpse/bridge_officer
/obj/effect/mob_spawn/human/commander
name = "Commander"
- id_job = "Commander"
- id_access_list = list(ACCESS_CENT_CAPTAIN, ACCESS_CENT_GENERAL, ACCESS_CENT_SPECOPS, ACCESS_CENT_MEDICAL, ACCESS_CENT_STORAGE)
outfit = /datum/outfit/nanotrasencommandercorpse
/datum/outfit/nanotrasencommandercorpse
@@ -416,12 +404,11 @@
gloves = /obj/item/clothing/gloves/tackler/combat
shoes = /obj/item/clothing/shoes/combat/swat
r_pocket = /obj/item/lighter
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced/centcom
+ id_trim = /datum/id_trim/centcom/corpse/commander
/obj/effect/mob_spawn/human/nanotrasensoldier
name = "\improper Nanotrasen Private Security Officer"
- id_job = "Private Security Force"
- id_access_list = list(ACCESS_CENT_CAPTAIN, ACCESS_CENT_GENERAL, ACCESS_CENT_SPECOPS, ACCESS_CENT_MEDICAL, ACCESS_CENT_STORAGE, ACCESS_SECURITY, ACCESS_MECH_SECURITY)
outfit = /datum/outfit/nanotrasensoldiercorpse
/datum/outfit/nanotrasensoldiercorpse
@@ -433,7 +420,8 @@
mask = /obj/item/clothing/mask/gas/sechailer/swat
head = /obj/item/clothing/head/helmet/swat/nanotrasen
back = /obj/item/storage/backpack/security
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
+ id_trim = /datum/id_trim/centcom/corpse/private_security
/////////////////Spooky Undead//////////////////////
//there are living variants of many of these, they're now in ghost_role_spawners.dm
diff --git a/code/modules/awaymissions/mission_code/Academy.dm b/code/modules/awaymissions/mission_code/Academy.dm
index efdb4dfa8c0..65f4c06aad6 100644
--- a/code/modules/awaymissions/mission_code/Academy.dm
+++ b/code/modules/awaymissions/mission_code/Academy.dm
@@ -343,7 +343,7 @@
if(18)
//Captain ID
T.visible_message("A golden identification card appears!")
- new /obj/item/card/id/captains_spare(drop_location())
+ new /obj/item/card/id/advanced/gold/captains_spare(drop_location())
do_smoke(0, drop_location())
if(19)
//Instrinct Resistance
diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm
index 45c506162a7..25f68606f04 100644
--- a/code/modules/awaymissions/mission_code/snowdin.dm
+++ b/code/modules/awaymissions/mission_code/snowdin.dm
@@ -595,9 +595,9 @@
shoes = /obj/item/clothing/shoes/combat/coldres
ears = /obj/item/radio/headset/syndicate/alt
r_pocket = /obj/item/gun/ballistic/automatic/pistol
- id = /obj/item/card/id/syndicate
+ id = /obj/item/card/id/advanced/chameleon
implants = list(/obj/item/implant/exile)
-
+ id_trim = /datum/id_trim/chameleon/operative
/obj/effect/mob_spawn/human/syndicatesoldier/coldres/alive/female
mob_gender = FEMALE
diff --git a/code/modules/cargo/order.dm b/code/modules/cargo/order.dm
index fc63973efd4..e44801c0b38 100644
--- a/code/modules/cargo/order.dm
+++ b/code/modules/cargo/order.dm
@@ -51,7 +51,7 @@
P.info += "Order #[id] "
P.info += "Time of Order: [station_time_timestamp()] "
P.info += "Item: [pack.name] "
- P.info += "Access Restrictions: [get_access_desc(pack.access)] "
+ P.info += "Access Restrictions: [SSid_access.get_access_desc(pack.access)] "
P.info += "Requested by: [orderer] "
if(paying_account)
P.info += "Paid by: [paying_account.account_holder] "
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index c35b4534ffb..e00ff166f52 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -329,8 +329,6 @@
/obj/item/gun/energy/laser)
crate_name = "laser crate"
-
-
/datum/supply_pack/security/securitybarriers
name = "Security Barrier Grenades"
desc = "Stem the tide with four Security Barrier grenades. Requires Security access to open."
@@ -1615,6 +1613,22 @@
/obj/item/reagent_containers/food/drinks/bottle/champagne)
crate_name = "wedding crate"
+/// Box of 7 grey IDs.
+/datum/supply_pack/service/greyidbox
+ name = "Grey ID Card Multipack Cate"
+ desc = "A convenient crate containing a box of cheap ID cards in a handy wallet-sized form factor. Cards come in every colour you can imagne, as long as it's grey."
+ cost = CARGO_CRATE_VALUE * 3
+ contains = list(/obj/item/storage/box/ids)
+ crate_name = "basic id card crate"
+
+/// Single silver ID.
+/datum/supply_pack/service/silverid
+ name = "Silver ID Card Crate"
+ desc = "Did we forget to hire any Heads of Staff? Recruit your own with this high value ID card capable of holding advanced levels of access in a handy wallet-sized form factor"
+ cost = CARGO_CRATE_VALUE * 7
+ contains = list(/obj/item/card/id/advanced/silver)
+ crate_name = "silver id card crate"
+
/datum/supply_pack/service/emptycrate
name = "Empty Crate"
desc = "It's an empty crate, for all your storage needs."
diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm
index f2479ac26d3..6dd0cb5bfaf 100644
--- a/code/modules/clothing/chameleon.dm
+++ b/code/modules/clothing/chameleon.dm
@@ -257,24 +257,89 @@
/datum/action/item_action/chameleon/change/id/update_item(obj/item/picked_item)
..()
- var/obj/item/card/id/syndicate/agent_card = target
+ var/obj/item/card/id/advanced/chameleon/agent_card = target
if(istype(agent_card))
var/obj/item/card/id/copied_card = picked_item
- agent_card.uses_overlays = initial(copied_card.uses_overlays)
- agent_card.id_type_name = initial(copied_card.id_type_name)
+
+ // If the outfit comes with a special trim override, we'll steal some stuff from that.
+ var/new_trim = initial(copied_card.trim)
+
+ if(new_trim)
+ SSid_access.apply_trim_to_chameleon_card(agent_card, new_trim, TRUE)
+
+ // If the ID card hasn't been forged, we'll check if there has been an assignment set already by any new trim.
+ // If there has not, we set the assignment to the copied card's default as well as copying over the the
+ // default registered name from the copied card.
if(!agent_card.forged)
+ if(!agent_card.assignment)
+ agent_card.assignment = initial(copied_card.assignment)
+
agent_card.registered_name = initial(copied_card.registered_name)
- agent_card.assignment = initial(copied_card.assignment)
+
+ agent_card.icon_state = initial(copied_card.icon_state)
+ if(ispath(copied_card, /obj/item/card/id/advanced))
+ var/obj/item/card/id/advanced/copied_advanced_card = copied_card
+ agent_card.assigned_icon_state = initial(copied_advanced_card.assigned_icon_state)
+
agent_card.update_label()
- if(!agent_card.forged)
- agent_card.name = initial(copied_card.name) //e.g. captain's spare ID, not Captain's ID Card (Captain)
+ agent_card.update_icon()
/datum/action/item_action/chameleon/change/id/apply_job_data(datum/job/job_datum)
..()
- var/obj/item/card/id/syndicate/agent_card = target
+ var/obj/item/card/id/advanced/chameleon/agent_card = target
if(istype(agent_card) && istype(job_datum))
agent_card.forged = TRUE
- agent_card.assignment = job_datum.title
+
+ // job_outfit is going to be a path.
+ var/datum/outfit/job/job_outfit = job_datum.outfit
+ if(!job_outfit)
+ return
+
+ // copied_card is also going to be a path.
+ var/obj/item/card/id/copied_card = initial(job_outfit.id)
+ if(!copied_card)
+ return
+
+ // If the outfit comes with a special trim override, we'll use that. Otherwise, use the card's default trim. Failing that, no trim at all.
+ var/new_trim = initial(job_outfit.id_trim) ? initial(job_outfit.id_trim) : initial(copied_card.trim)
+
+ if(new_trim)
+ SSid_access.apply_trim_to_chameleon_card(agent_card, new_trim, FALSE)
+ else
+ agent_card.assignment = job_datum.title
+
+ agent_card.icon_state = initial(copied_card.icon_state)
+ if(ispath(copied_card, /obj/item/card/id/advanced))
+ var/obj/item/card/id/advanced/copied_advanced_card = copied_card
+ agent_card.assigned_icon_state = initial(copied_advanced_card.assigned_icon_state)
+
+ agent_card.update_label()
+ agent_card.update_icon()
+
+/datum/action/item_action/chameleon/change/id_trim/initialize_disguises()
+ if(button)
+ button.name = "Change [chameleon_name] Appearance"
+
+ chameleon_blacklist |= typecacheof(target.type)
+ for(var/trim_path in typesof(chameleon_type))
+ if(ispath(trim_path) && ispath(trim_path, /datum/id_trim))
+ if(chameleon_blacklist[trim_path])
+ continue
+
+ var/datum/id_trim/trim = SSid_access.trim_singletons_by_path[trim_path]
+
+ if(trim && trim.trim_state && trim.assignment)
+ var/chameleon_item_name = "[trim.assignment] ([trim.trim_state])"
+ chameleon_list[chameleon_item_name] = trim_path
+
+/datum/action/item_action/chameleon/change/id_trim/update_item(picked_trim_path)
+ var/obj/item/card/id/advanced/chameleon/agent_card = target
+
+ if(istype(agent_card))
+ SSid_access.apply_trim_to_chameleon_card(agent_card, picked_trim_path, TRUE)
+
+ agent_card.update_label()
+ agent_card.update_icon()
/datum/action/item_action/chameleon/change/pda/update_item(obj/item/picked_item)
..()
diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm
index fad9363db0a..9de70e4d1cd 100644
--- a/code/modules/clothing/outfits/ert.dm
+++ b/code/modules/clothing/outfits/ert.dm
@@ -19,12 +19,13 @@
if(W)
W.registered_name = H.real_name
W.update_label()
- ..()
+ W.update_icon()
+ return ..()
/datum/outfit/centcom/ert/commander
name = "ERT Commander"
- id = /obj/item/card/id/ert
+ id = /obj/item/card/id/advanced/centcom/ert
suit = /obj/item/clothing/suit/space/hardsuit/ert
suit_store = /obj/item/gun/energy/e_gun
glasses = /obj/item/clothing/glasses/hud/security/sunglasses
@@ -56,7 +57,7 @@
/datum/outfit/centcom/ert/security
name = "ERT Security"
- id = /obj/item/card/id/ert/security
+ id = /obj/item/card/id/advanced/centcom/ert/security
suit = /obj/item/clothing/suit/space/hardsuit/ert/sec
suit_store = /obj/item/gun/energy/e_gun/stun
glasses = /obj/item/clothing/glasses/hud/security/sunglasses
@@ -91,7 +92,7 @@
/datum/outfit/centcom/ert/medic
name = "ERT Medic"
- id = /obj/item/card/id/ert/medical
+ id = /obj/item/card/id/advanced/centcom/ert/medical
suit = /obj/item/clothing/suit/space/hardsuit/ert/med
suit_store = /obj/item/gun/energy/e_gun
glasses = /obj/item/clothing/glasses/hud/health
@@ -126,7 +127,7 @@
/datum/outfit/centcom/ert/engineer
name = "ERT Engineer"
- id = /obj/item/card/id/ert/engineer
+ id = /obj/item/card/id/advanced/centcom/ert/engineer
suit = /obj/item/clothing/suit/space/hardsuit/ert/engi
suit_store = /obj/item/gun/energy/e_gun
glasses = /obj/item/clothing/glasses/meson/engine
@@ -174,8 +175,9 @@
back = /obj/item/storage/backpack/satchel
r_pocket = /obj/item/pda/heads
l_hand = /obj/item/clipboard
- id = /obj/item/card/id/centcom
+ id = /obj/item/card/id/advanced/centcom
backpack_contents = list(/obj/item/stamp/centcom=1)
+ id_trim = /datum/id_trim/centcom/official
/datum/outfit/centcom/centcom_official/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
if(visualsOnly)
@@ -187,12 +189,10 @@
pda.update_label()
var/obj/item/card/id/W = H.wear_id
- W.access = get_centcom_access("CentCom Official")
- W.access += ACCESS_WEAPONS
- W.assignment = "CentCom Official"
W.registered_name = H.real_name
W.update_label()
- ..()
+ W.update_icon()
+ return ..()
/datum/outfit/centcom/ert/commander/inquisitor
name = "Inquisition Commander"
@@ -227,7 +227,7 @@
suit = /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor // Chap role always gets this suit
suit_store = /obj/item/gun/energy/e_gun
- id = /obj/item/card/id/ert/chaplain
+ id = /obj/item/card/id/advanced/centcom/ert/chaplain
glasses = /obj/item/clothing/glasses/hud/health
back = /obj/item/storage/backpack/cultpack
belt = /obj/item/storage/belt/soulstone
@@ -255,7 +255,7 @@
/datum/outfit/centcom/ert/janitor
name = "ERT Janitor"
- id = /obj/item/card/id/ert/janitor
+ id = /obj/item/card/id/advanced/centcom/ert/janitor
suit = /obj/item/clothing/suit/space/hardsuit/ert/jani
glasses = /obj/item/clothing/glasses/night
back = /obj/item/storage/backpack/ert/janitor
@@ -295,7 +295,7 @@
suit = /obj/item/clothing/suit/space/hardsuit/ert/clown
mask = /obj/item/clothing/mask/gas/clown_hat
- id = /obj/item/card/id/ert/clown
+ id = /obj/item/card/id/advanced/centcom/ert/clown
glasses = /obj/item/clothing/glasses/godeye
back = /obj/item/storage/backpack/ert/clown
belt = /obj/item/storage/belt/champion
@@ -332,19 +332,19 @@
back = /obj/item/storage/backpack/satchel
l_pocket = /obj/item/ammo_box/a762
r_pocket = /obj/item/ammo_box/a762
- id = /obj/item/card/id/centcom
+ id = /obj/item/card/id/advanced/centcom
backpack_contents = list(/obj/item/storage/box/survival = 1)
+ id_trim = /datum/id_trim/centcom/intern
/datum/outfit/centcom/centcom_intern/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
if(visualsOnly)
return
var/obj/item/card/id/W = H.wear_id
- W.access = get_centcom_access(name)
- W.access += ACCESS_WEAPONS
- W.assignment = name
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
+ return ..()
/datum/outfit/centcom/centcom_intern/unarmed
name = "CentCom Intern (Unarmed)"
diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm
index fbc4fe8ac5c..189d1635417 100644
--- a/code/modules/clothing/outfits/standard.dm
+++ b/code/modules/clothing/outfits/standard.dm
@@ -19,18 +19,17 @@
belt = /obj/item/gun/energy/pulse/pistol/m1911
r_pocket = /obj/item/lighter
back = /obj/item/storage/backpack/satchel/leather
- id = /obj/item/card/id/centcom
+ id = /obj/item/card/id/advanced/centcom
+ id_trim = /datum/id_trim/centcom/specops_officer
/datum/outfit/centcom/spec_ops/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
if(visualsOnly)
return
var/obj/item/card/id/W = H.wear_id
- W.access = get_all_accesses()
- W.access += get_centcom_access("Special Ops Officer")
- W.assignment = "Special Ops Officer"
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
var/obj/item/radio/headset/R = H.ears
R.set_frequency(FREQ_CENTCOM)
@@ -138,6 +137,7 @@
if(outfit_id)
outfit_id.registered_name = equipped.real_name
outfit_id.update_label()
+ outfit_id.update_icon()
/datum/outfit/pirate/captain
name = "Space Pirate Captain"
@@ -150,7 +150,7 @@
head = /obj/item/clothing/head/helmet/space/pirate/bandana
mask = /obj/item/clothing/mask/breath
suit_store = /obj/item/tank/internals/oxygen
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
/datum/outfit/pirate/space/captain
name = "Space Pirate Captain (EVA)"
@@ -166,25 +166,14 @@
shoes = /obj/item/clothing/shoes/laceup
suit = /obj/item/clothing/suit/armor/vest/alt
gloves = /obj/item/clothing/gloves/color/black
-
- id = /obj/item/card/id/silver
-
- ///special fluff for the ID's job
- var/scale_assignment = "Silver Scale Member"
-
-/datum/outfit/pirate/silverscale/post_equip(mob/living/carbon/human/equipped)
- ..()
- var/obj/item/card/id/outfit_id = equipped.wear_id
- if(outfit_id)
- outfit_id.assignment = scale_assignment
- outfit_id.update_label()
+ id_trim = /datum/id_trim/pirate/silverscale
+ id = /obj/item/card/id/advanced/silver
/datum/outfit/pirate/silverscale/captain
mask = /obj/item/clothing/mask/cigarette/cigar/havana
l_pocket = /obj/item/lighter
head = /obj/item/clothing/head/crown
-
- scale_assignment = "Silver Scale VIP"
+ id_trim = /datum/id_trim/pirate/silverscale/captain
/datum/outfit/tunnel_clown
name = "Tunnel Clown"
@@ -198,18 +187,18 @@
suit = /obj/item/clothing/suit/hooded/chaplain_hoodie
l_pocket = /obj/item/food/grown/banana
r_pocket = /obj/item/bikehorn
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced/gold
l_hand = /obj/item/fireaxe
+ id_trim = /datum/id_trim/tunnel_clown
/datum/outfit/tunnel_clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
if(visualsOnly)
return
var/obj/item/card/id/W = H.wear_id
- W.access = get_all_accesses()
- W.assignment = "Tunnel Clown!"
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
/datum/outfit/psycho
name = "Masked Killer"
@@ -243,8 +232,9 @@
glasses = /obj/item/clothing/glasses/sunglasses
l_pocket = /obj/item/melee/transforming/energy/sword/saber
l_hand = /obj/item/storage/secure/briefcase
- id = /obj/item/card/id/syndicate
+ id = /obj/item/card/id/advanced/chameleon/black
belt = /obj/item/pda/heads
+ id_trim = /datum/id_trim/reaper_assassin
/datum/outfit/assassin/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
var/obj/item/clothing/under/U = H.w_uniform
@@ -269,11 +259,10 @@
pda.ownjob = "Reaper"
pda.update_label()
- var/obj/item/card/id/syndicate/W = H.wear_id
- W.access = get_all_accesses()
- W.assignment = "Reaper"
+ var/obj/item/card/id/W = H.wear_id
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
/datum/outfit/centcom/commander
name = "CentCom Commander"
@@ -290,18 +279,17 @@
r_pocket = /obj/item/lighter
l_pocket = /obj/item/ammo_box/a357
back = /obj/item/storage/backpack/satchel/leather
- id = /obj/item/card/id/centcom
+ id = /obj/item/card/id/advanced/centcom
+ id_trim = /datum/id_trim/centcom/commander
/datum/outfit/centcom/commander/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
if(visualsOnly)
return
var/obj/item/card/id/W = H.wear_id
- W.access = get_all_accesses()
- W.access += get_centcom_access("CentCom Commander")
- W.assignment = "CentCom Commander"
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
..()
/datum/outfit/ghost_cultist
@@ -366,18 +354,18 @@
back = /obj/item/storage/backpack/satchel/leather
belt = /obj/item/gun/ballistic/revolver/mateba
- id = /obj/item/card/id/centcom
+ id = /obj/item/card/id/advanced/centcom
+ id_trim = /datum/id_trim/centcom/admiral
/datum/outfit/centcom/soviet/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
if(visualsOnly)
return
var/obj/item/card/id/W = H.wear_id
- W.access = get_all_accesses()
- W.access += get_centcom_access("Admiral")
- W.assignment = "Admiral"
+
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
..()
/datum/outfit/mobster
@@ -390,16 +378,17 @@
ears = /obj/item/radio/headset
glasses = /obj/item/clothing/glasses/sunglasses
l_hand = /obj/item/gun/ballistic/automatic/tommygun
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
+ id_trim = /datum/id_trim/mobster
/datum/outfit/mobster/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
if(visualsOnly)
return
var/obj/item/card/id/W = H.wear_id
- W.assignment = "Assistant"
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
/datum/outfit/plasmaman
name = "Plasmaman"
@@ -426,7 +415,7 @@
suit_store = /obj/item/tank/internals/emergency_oxygen/double
belt = /obj/item/gun/ballistic/revolver/mateba
l_hand = /obj/item/gun/energy/pulse/loyalpin
- id = /obj/item/card/id/ert/deathsquad
+ id = /obj/item/card/id/advanced/black/deathsquad
ears = /obj/item/radio/headset/headset_cent/alt
skillchips = list(/obj/item/skillchip/disk_verifier)
@@ -438,6 +427,8 @@
/obj/item/flashlight=1,\
/obj/item/grenade/c4/x4=1)
+ id_trim = /datum/id_trim/centcom/deathsquad
+
/datum/outfit/centcom/death_commando/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
if(visualsOnly)
return
@@ -446,11 +437,9 @@
R.set_frequency(FREQ_CENTCOM)
R.freqlock = TRUE
var/obj/item/card/id/W = H.wear_id
- W.access = get_all_accesses()//They get full station access.
- W.access += get_centcom_access("Death Commando")//Let's add their alloted CentCom access.
- W.assignment = "Death Commando"
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
..()
/datum/outfit/centcom/death_commando/officer
@@ -476,7 +465,7 @@
gloves = /obj/item/clothing/gloves/combat
belt = /obj/item/storage/belt/utility/chief/full
shoes = /obj/item/clothing/shoes/magboots/advance
- id = /obj/item/card/id/debug
+ id = /obj/item/card/id/advanced/debug
suit_store = /obj/item/tank/internals/oxygen
back = /obj/item/storage/backpack/holding
box = /obj/item/storage/box/debugtools
@@ -494,6 +483,7 @@
var/obj/item/card/id/W = H.wear_id
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
/datum/outfit/admin //for admeem shenanigans and testing things that arent related to equipment, not a subtype of debug just in case debug changes things
name = "Admin outfit"
@@ -505,7 +495,7 @@
gloves = /obj/item/clothing/gloves/combat
belt = /obj/item/storage/belt/utility/chief/full
shoes = /obj/item/clothing/shoes/magboots/advance
- id = /obj/item/card/id/debug
+ id = /obj/item/card/id/advanced/debug
suit_store = /obj/item/tank/internals/oxygen
back = /obj/item/storage/backpack/holding
box = /obj/item/storage/box/debugtools
@@ -524,3 +514,4 @@
var/obj/item/card/id/W = H.wear_id
W.registered_name = H.real_name
W.update_label()
+ W.update_icon()
diff --git a/code/modules/clothing/outfits/vr.dm b/code/modules/clothing/outfits/vr.dm
index 520c4c0f8b7..0bb1a8b4fb5 100644
--- a/code/modules/clothing/outfits/vr.dm
+++ b/code/modules/clothing/outfits/vr.dm
@@ -3,27 +3,24 @@
uniform = /obj/item/clothing/under/color/random
shoes = /obj/item/clothing/shoes/sneakers/black
ears = /obj/item/radio/headset
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
+ id_trim = /datum/id_trim/vr
/datum/outfit/vr/pre_equip(mob/living/carbon/human/H)
H.dna.species.before_equip_job(null, H)
-/datum/outfit/vr/post_equip(mob/living/carbon/human/H)
- var/obj/item/card/id/id = H.wear_id
- if (istype(id))
- id.access |= get_all_accesses()
-
/datum/outfit/vr/syndicate
name = "Syndicate VR Operative - Basic"
uniform = /obj/item/clothing/under/syndicate
shoes = /obj/item/clothing/shoes/combat
gloves = /obj/item/clothing/gloves/tackler/combat/insulated
back = /obj/item/storage/backpack
- id = /obj/item/card/id/syndicate
+ id = /obj/item/card/id/advanced/chameleon/black
belt = /obj/item/gun/ballistic/automatic/pistol
l_pocket = /obj/item/paper/fluff/vr/fluke_ops
backpack_contents = list(/obj/item/storage/box/survival/syndie=1,\
/obj/item/kitchen/knife/combat/survival)
+ id_trim = /datum/id_trim/vr/operative
/datum/outfit/vr/syndicate/post_equip(mob/living/carbon/human/H)
. = ..()
diff --git a/code/modules/clothing/outfits/vv_outfit.dm b/code/modules/clothing/outfits/vv_outfit.dm
index 0c5d99cc748..7c4fcc96dbd 100644
--- a/code/modules/clothing/outfits/vv_outfit.dm
+++ b/code/modules/clothing/outfits/vv_outfit.dm
@@ -84,8 +84,11 @@
if(id_slot)
O.stored_access |= id_slot.GetAccess()
var/obj/item/card/id/ID = id_slot.GetID()
- if(ID && ID.registered_name == real_name)
- O.update_id_name = TRUE
+ if(ID)
+ if(ID.registered_name == real_name)
+ O.update_id_name = TRUE
+ if(ID.trim)
+ O.id_trim = ID.trim.type
//Copy hands
if(held_items.len >= 2) //Not in the mood to let outfits transfer amputees
var/obj/item/left_hand = held_items[1]
@@ -144,10 +147,11 @@
if(id_slot)
var/obj/item/card/id/card = id_slot.GetID()
if(istype(card))
- card.access |= stored_access
+ card.add_access(stored_access, mode = FORCE_ADD_ALL)
if(update_id_name)
card.registered_name = H.real_name
card.update_label()
+ card.update_icon()
/datum/outfit/varedit/get_json_data()
. = .. ()
diff --git a/code/modules/economy/account.dm b/code/modules/economy/account.dm
index 71c856d738f..9a43e0fc1c2 100644
--- a/code/modules/economy/account.dm
+++ b/code/modules/economy/account.dm
@@ -103,10 +103,9 @@
return
for(var/obj/A in bank_cards)
var/icon_source = A
- if(istype(A, /obj/item/card/id))
- var/obj/item/card/id/id_card = A
- if(id_card.uses_overlays)
- icon_source = id_card.get_cached_flat_icon()
+ if(istype(A, /obj/item/card/id/advanced))
+ var/obj/item/card/id/advanced/id_card = A
+ icon_source = id_card.get_cached_flat_icon()
var/mob/card_holder = recursive_loc_check(A, /mob)
if(ismob(card_holder)) //If on a mob
if(!card_holder.client || (!(card_holder.client.prefs.chat_toggles & CHAT_BANKCARD) && !force))
diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm
index 49f92e7522f..46e6ac80384 100644
--- a/code/modules/jobs/access.dm
+++ b/code/modules/jobs/access.dm
@@ -102,291 +102,19 @@
/obj/proc/check_access_ntnet(list/passkey)
return check_access_list(passkey)
-/proc/get_centcom_access(job)
- switch(job)
- if("VIP Guest")
- return list(ACCESS_CENT_GENERAL)
- if("Custodian")
- return list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING, ACCESS_CENT_STORAGE)
- if("Thunderdome Overseer")
- return list(ACCESS_CENT_GENERAL, ACCESS_CENT_THUNDER)
- if("CentCom Official")
- return list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING)
- if("CentCom Intern")
- return list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING)
- if("CentCom Head Intern")
- return list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING)
- if("Medical Officer")
- return list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING, ACCESS_CENT_MEDICAL)
- if("Death Commando")
- return list(ACCESS_CENT_GENERAL, ACCESS_CENT_SPECOPS, ACCESS_CENT_LIVING, ACCESS_CENT_STORAGE)
- if("Research Officer")
- return list(ACCESS_CENT_GENERAL, ACCESS_CENT_SPECOPS, ACCESS_CENT_MEDICAL, ACCESS_CENT_TELEPORTER, ACCESS_CENT_STORAGE)
- if("Special Ops Officer")
- return get_all_centcom_access()
- if("Admiral")
- return get_all_centcom_access()
- if("CentCom Commander")
- return get_all_centcom_access()
- if("Emergency Response Team Commander")
- return get_ert_access("commander")
- if("Security Response Officer")
- return get_ert_access("sec")
- if("Engineer Response Officer")
- return get_ert_access("eng")
- if("Medical Response Officer")
- return get_ert_access("med")
- if("CentCom Bartender")
- return list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING, ACCESS_CENT_BAR)
-
-/proc/get_all_accesses()
- return list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_FORENSICS_LOCKERS, ACCESS_COURT,
- ACCESS_MEDICAL, ACCESS_GENETICS, ACCESS_MORGUE, ACCESS_RD,
- ACCESS_RND, ACCESS_TOXINS, ACCESS_CHEMISTRY, ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_MAINT_TUNNELS,
- ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD,
- ACCESS_TELEPORTER, ACCESS_EVA, ACCESS_HEADS, ACCESS_CAPTAIN, ACCESS_ALL_PERSONAL_LOCKERS,
- ACCESS_TECH_STORAGE, ACCESS_CHAPEL_OFFICE, ACCESS_ATMOSPHERICS, ACCESS_KITCHEN,
- ACCESS_BAR, ACCESS_JANITOR, ACCESS_CREMATORIUM, ACCESS_ROBOTICS, ACCESS_CARGO, ACCESS_CONSTRUCTION, ACCESS_AUX_BASE,
- ACCESS_HYDROPONICS, ACCESS_LIBRARY, ACCESS_LAWYER, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_QM, ACCESS_SURGERY, ACCESS_PSYCHOLOGY,
- ACCESS_THEATRE, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_MAILSORTING, ACCESS_WEAPONS,
- ACCESS_MECH_MINING, ACCESS_MECH_ENGINE, ACCESS_MECH_SCIENCE, ACCESS_MECH_SECURITY, ACCESS_MECH_MEDICAL,
- ACCESS_VAULT, ACCESS_MINING_STATION, ACCESS_XENOBIOLOGY, ACCESS_CE, ACCESS_HOP, ACCESS_HOS, ACCESS_PHARMACY, ACCESS_RC_ANNOUNCE,
- ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM, ACCESS_MINISAT, ACCESS_NETWORK, ACCESS_TOXINS_STORAGE)
-
-/proc/get_all_centcom_access()
- return list(ACCESS_CENT_GENERAL, ACCESS_CENT_THUNDER, ACCESS_CENT_SPECOPS, ACCESS_CENT_MEDICAL, ACCESS_CENT_LIVING, ACCESS_CENT_STORAGE, ACCESS_CENT_TELEPORTER, ACCESS_CENT_CAPTAIN)
-
-/proc/get_ert_access(class)
- switch(class)
- if("commander")
- return get_all_centcom_access()
- if("sec")
- return list(ACCESS_CENT_GENERAL, ACCESS_CENT_SPECOPS, ACCESS_CENT_LIVING)
- if("eng")
- return list(ACCESS_CENT_GENERAL, ACCESS_CENT_SPECOPS, ACCESS_CENT_LIVING, ACCESS_CENT_STORAGE)
- if("med")
- return list(ACCESS_CENT_GENERAL, ACCESS_CENT_SPECOPS, ACCESS_CENT_MEDICAL, ACCESS_CENT_LIVING)
-
-/proc/get_all_syndicate_access()
- return list(ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER)
-
-/proc/get_region_accesses(code)
- switch(code)
- if(0)
- return get_all_accesses()
- if(1) //station general
- return list(ACCESS_KITCHEN,ACCESS_BAR, ACCESS_HYDROPONICS, ACCESS_JANITOR, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_LIBRARY, ACCESS_THEATRE, ACCESS_LAWYER)
- if(2) //security
- return list(ACCESS_SEC_DOORS, ACCESS_WEAPONS, ACCESS_SECURITY, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_FORENSICS_LOCKERS, ACCESS_COURT, ACCESS_MECH_SECURITY, ACCESS_HOS)
- if(3) //medbay
- return list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_SURGERY, ACCESS_MECH_MEDICAL, ACCESS_CMO, ACCESS_PHARMACY, ACCESS_PSYCHOLOGY)
- if(4) //research
- return list(ACCESS_RESEARCH, ACCESS_RND, ACCESS_TOXINS, ACCESS_TOXINS_STORAGE, ACCESS_GENETICS, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_MECH_SCIENCE, ACCESS_MINISAT, ACCESS_RD, ACCESS_NETWORK)
- if(5) //engineering and maintenance
- return list(ACCESS_CONSTRUCTION, ACCESS_AUX_BASE, ACCESS_MAINT_TUNNELS, ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_TECH_STORAGE, ACCESS_ATMOSPHERICS, ACCESS_MECH_ENGINE, ACCESS_TCOMSAT, ACCESS_MINISAT, ACCESS_CE)
- if(6) //supply
- return list(ACCESS_MAILSORTING, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MECH_MINING, ACCESS_MINERAL_STOREROOM, ACCESS_CARGO, ACCESS_QM, ACCESS_VAULT)
- if(7) //command
- return list(ACCESS_HEADS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_TELEPORTER, ACCESS_EVA, ACCESS_GATEWAY, ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_HOP, ACCESS_CAPTAIN, ACCESS_VAULT)
-
-/proc/get_region_accesses_name(code)
- switch(code)
- if(0)
- return "All"
- if(1) //station general
- return "General"
- if(2) //security
- return "Security"
- if(3) //medbay
- return "Medbay"
- if(4) //research
- return "Research"
- if(5) //engineering and maintenance
- return "Engineering"
- if(6) //supply
- return "Supply"
- if(7) //command
- return "Command"
-
-/proc/get_access_desc(A)
- switch(A)
- if(ACCESS_CARGO)
- return "Cargo Bay"
- if(ACCESS_SECURITY)
- return "Security"
- if(ACCESS_BRIG)
- return "Holding Cells"
- if(ACCESS_COURT)
- return "Courtroom"
- if(ACCESS_FORENSICS_LOCKERS)
- return "Forensics"
- if(ACCESS_MEDICAL)
- return "Medical"
- if(ACCESS_GENETICS)
- return "Genetics Lab"
- if(ACCESS_MORGUE)
- return "Morgue"
- if(ACCESS_RND)
- return "R&D Lab"
- if(ACCESS_TOXINS)
- return "Toxins Lab"
- if(ACCESS_TOXINS_STORAGE)
- return "Toxins Storage"
- if(ACCESS_CHEMISTRY)
- return "Chemistry Lab"
- if(ACCESS_RD)
- return "RD Office"
- if(ACCESS_BAR)
- return "Bar"
- if(ACCESS_JANITOR)
- return "Custodial Closet"
- if(ACCESS_ENGINE)
- return "Engineering"
- if(ACCESS_ENGINE_EQUIP)
- return "Power and Engineering Equipment"
- if(ACCESS_MAINT_TUNNELS)
- return "Maintenance"
- if(ACCESS_EXTERNAL_AIRLOCKS)
- return "External Airlocks"
- if(ACCESS_CHANGE_IDS)
- return "ID Console"
- if(ACCESS_AI_UPLOAD)
- return "AI Chambers"
- if(ACCESS_TELEPORTER)
- return "Teleporter"
- if(ACCESS_EVA)
- return "EVA"
- if(ACCESS_HEADS)
- return "Bridge"
- if(ACCESS_CAPTAIN)
- return "Captain"
- if(ACCESS_ALL_PERSONAL_LOCKERS)
- return "Personal Lockers"
- if(ACCESS_CHAPEL_OFFICE)
- return "Chapel Office"
- if(ACCESS_TECH_STORAGE)
- return "Technical Storage"
- if(ACCESS_ATMOSPHERICS)
- return "Atmospherics"
- if(ACCESS_CREMATORIUM)
- return "Crematorium"
- if(ACCESS_ARMORY)
- return "Armory"
- if(ACCESS_CONSTRUCTION)
- return "Construction"
- if(ACCESS_KITCHEN)
- return "Kitchen"
- if(ACCESS_HYDROPONICS)
- return "Hydroponics"
- if(ACCESS_LIBRARY)
- return "Library"
- if(ACCESS_LAWYER)
- return "Law Office"
- if(ACCESS_ROBOTICS)
- return "Robotics"
- if(ACCESS_VIROLOGY)
- return "Virology"
- if(ACCESS_PSYCHOLOGY)
- return "Psychology"
- if(ACCESS_CMO)
- return "CMO Office"
- if(ACCESS_QM)
- return "Quartermaster"
- if(ACCESS_SURGERY)
- return "Surgery"
- if(ACCESS_THEATRE)
- return "Theatre"
- if(ACCESS_RESEARCH)
- return "Science"
- if(ACCESS_MINING)
- return "Mining"
- if(ACCESS_MAILSORTING)
- return "Cargo Office"
- if(ACCESS_VAULT)
- return "Main Vault"
- if(ACCESS_MINING_STATION)
- return "Mining EVA"
- if(ACCESS_XENOBIOLOGY)
- return "Xenobiology Lab"
- if(ACCESS_HOP)
- return "HoP Office"
- if(ACCESS_HOS)
- return "HoS Office"
- if(ACCESS_CE)
- return "CE Office"
- if(ACCESS_PHARMACY)
- return "Pharmacy"
- if(ACCESS_RC_ANNOUNCE)
- return "RC Announcements"
- if(ACCESS_KEYCARD_AUTH)
- return "Keycode Auth."
- if(ACCESS_TCOMSAT)
- return "Telecommunications"
- if(ACCESS_GATEWAY)
- return "Gateway"
- if(ACCESS_SEC_DOORS)
- return "Brig"
- if(ACCESS_MINERAL_STOREROOM)
- return "Mineral Storage"
- if(ACCESS_MINISAT)
- return "AI Satellite"
- if(ACCESS_WEAPONS)
- return "Weapon Permit"
- if(ACCESS_NETWORK)
- return "Network Access"
- if(ACCESS_MECH_MINING)
- return "Mining Mech Access"
- if(ACCESS_MECH_MEDICAL)
- return "Medical Mech Access"
- if(ACCESS_MECH_SECURITY)
- return "Security Mech Access"
- if(ACCESS_MECH_SCIENCE)
- return "Science Mech Access"
- if(ACCESS_MECH_ENGINE)
- return "Engineering Mech Access"
- if(ACCESS_AUX_BASE)
- return "Auxiliary Base"
-
-/proc/get_centcom_access_desc(A)
- switch(A)
- if(ACCESS_CENT_GENERAL)
- return "Code Grey"
- if(ACCESS_CENT_THUNDER)
- return "Code Yellow"
- if(ACCESS_CENT_STORAGE)
- return "Code Orange"
- if(ACCESS_CENT_LIVING)
- return "Code Green"
- if(ACCESS_CENT_MEDICAL)
- return "Code White"
- if(ACCESS_CENT_TELEPORTER)
- return "Code Blue"
- if(ACCESS_CENT_SPECOPS)
- return "Code Black"
- if(ACCESS_CENT_CAPTAIN)
- return "Code Gold"
- if(ACCESS_CENT_BAR)
- return "Code Scotch"
-
-/proc/get_all_jobs()
- return list("Assistant", "Captain", "Head of Personnel", "Bartender", "Cook", "Botanist", "Quartermaster", "Cargo Technician",
- "Shaft Miner", "Clown", "Mime", "Janitor", "Curator", "Lawyer", "Chaplain", "Chief Engineer", "Station Engineer",
- "Atmospheric Technician", "Chief Medical Officer", "Medical Doctor", "Paramedic", "Chemist", "Geneticist", "Virologist", "Psychologist",
- "Research Director", "Scientist", "Roboticist", "Head of Security", "Warden", "Detective", "Security Officer", "Prisoner")
-
-/proc/get_all_job_icons() //For all existing HUD icons
- return get_all_jobs() + list("Emergency Response Team Commander", "Security Response Officer", "Engineering Response Officer", "Medical Response Officer", "Entertainment Response Officer", "Religious Response Officer", "Janitorial Response Officer", "Death Commando")
-
-/proc/get_all_centcom_jobs()
- return list("Central Command","VIP Guest","Custodian","Thunderdome Overseer","CentCom Official","Medical Officer","Research Officer","Special Ops Officer","Admiral","CentCom Commander","CentCom Bartender","Private Security Force")
-
/obj/item/proc/GetJobName() //Used in secHUD icon generation
- var/obj/item/card/id/I = GetID()
- if(!I)
+ var/obj/item/card/id/id_card = GetID()
+
+ if(!id_card)
return
- var/jobName = I.assignment
- if(jobName in get_all_job_icons()) //Check if the job has a hud icon
- return jobName
- if(jobName in get_all_centcom_jobs()) //Return with the NT logo if it is a CentCom job
+
+ var/card_assignment = id_card.trim?.assignment
+
+ if(!card_assignment)
+ card_assignment = id_card.assignment
+
+ if(card_assignment in (SSjob.station_jobs + SSjob.additional_jobs_with_icons)) //Check if the job has a hud icon
+ return card_assignment
+ if(card_assignment in SSjob.centcom_jobs) //Return with the NT logo if it is a CentCom job
return "CentCom"
return "Unknown" //Return unknown if none of the above apply
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index ed919ac8649..9f6098c2680 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -2,10 +2,6 @@
//The name of the job , used for preferences, bans and more. Make sure you know what you're doing before changing this.
var/title = "NOPE"
- //Job access. The use of minimal_access or access is determined by a config setting: config.jobs_have_minimal_access
- var/list/minimal_access = list() //Useful for servers which prefer to only have access given to the places a job absolutely needs (Larger server population)
- var/list/access = list() //Useful for servers which either have fewer players, so each person needs to fill more than one role, or servers which like to give more access, so players can't hide forever in their super secure departments (I'm looking at you, chemistry!)
-
/// Innate skill levels unlocked at roundstart. Based on config.jobs_have_minimal_access config setting, for example with a skeleton crew. Format is list(/datum/skill/foo = SKILL_EXP_NOVICE) with exp as an integer or as per code/_DEFINES/skills.dm
var/list/skills
/// Innate skill levels unlocked at roundstart. Based on config.jobs_have_minimal_access config setting, for example with a full crew. Format is list(/datum/skill/foo = SKILL_EXP_NOVICE) with exp as an integer or as per code/_DEFINES/skills.dm
@@ -76,18 +72,28 @@
/datum/job/New()
. = ..()
- var/list/jobs_changes = GetMapChanges()
+ var/list/jobs_changes = get_map_changes()
if(!jobs_changes)
return
- if(isnum(jobs_changes["additional_access"]))
- access += jobs_changes["additional_access"]
- if(isnum(jobs_changes["additional_minimal_access"]))
- minimal_access += jobs_changes["additional_minimal_access"]
if(isnum(jobs_changes["spawn_positions"]))
spawn_positions = jobs_changes["spawn_positions"]
if(isnum(jobs_changes["total_positions"]))
total_positions = jobs_changes["total_positions"]
+/// Loads up map configs if necessary and returns job changes for this job.
+/datum/job/proc/get_map_changes()
+ var/string_type = "[type]"
+ var/list/splits = splittext(string_type, "/")
+ var/endpart = splits[splits.len]
+
+ SSmapping.HACK_LoadMapConfig()
+
+ var/list/job_changes = SSmapping.config.job_changes
+ if(!(endpart in job_changes))
+ return list()
+
+ return job_changes[endpart]
+
//Only override this proc
//H is usually a human unless an /equip override transformed it
/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE)
@@ -121,7 +127,7 @@
for(var/i in roundstart_experience)
experiencer.mind.adjust_experience(i, roundstart_experience[i], TRUE)
-/datum/job/proc/announce(mob/living/carbon/human/H)
+/datum/job/proc/announce(mob/living/carbon/human/H, announce_captaincy = FALSE)
if(head_announce)
announce_head(H, head_announce)
@@ -138,7 +144,7 @@
return antag_rep
//Don't override this unless the job transforms into a non-human (Silicons do this for example)
-/datum/job/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, datum/outfit/outfit_override = null, client/preference_source)
+/datum/job/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, announce = TRUE, latejoin = FALSE, datum/outfit/outfit_override = null, client/preference_source, is_captain = FALSE)
if(!H)
return FALSE
if(CONFIG_GET(flag/enforce_human_authority) && (title in GLOB.command_positions))
@@ -156,24 +162,14 @@
if(outfit_override || outfit)
H.equipOutfit(outfit_override ? outfit_override : outfit, visualsOnly)
+ if(!visualsOnly && is_captain)
+ var/is_acting_captain = (title != "Captain")
+ SSjob.promote_to_captain(H, is_acting_captain)
+
H.dna.species.after_equip_job(src, H, visualsOnly)
if(!visualsOnly && announce)
- announce(H)
-
-/datum/job/proc/get_access()
- if(!config) //Needed for robots.
- return src.minimal_access.Copy()
-
- . = list()
-
- if(CONFIG_GET(flag/jobs_have_minimal_access))
- . = src.minimal_access.Copy()
- else
- . = src.access.Copy()
-
- if(CONFIG_GET(flag/everyone_has_maint_access)) //Config has global maint access set
- . |= list(ACCESS_MAINT_TUNNELS)
+ announce(H, is_captain)
/datum/job/proc/announce_head(mob/living/carbon/human/H, channels) //tells the given channel that the given mob is the new department head. See communications.dm for valid channels.
if(H && GLOB.announcement_systems.len)
@@ -203,27 +199,11 @@
return TRUE
/datum/job/proc/map_check()
- var/list/job_changes = GetMapChanges()
+ var/list/job_changes = get_map_changes()
if(!job_changes)
return FALSE
return TRUE
-/**
- * Gets the changes dictionary made to the job template by the map config. Returns null if job is removed.
- */
-/datum/job/proc/GetMapChanges()
- var/string_type = "[type]"
- var/list/splits = splittext(string_type, "/")
- var/endpart = splits[splits.len]
-
- SSmapping.HACK_LoadMapConfig()
-
- var/list/job_changes = SSmapping.config.job_changes
- if(!(endpart in job_changes))
- return list()
-
- return job_changes[endpart]
-
/datum/job/proc/radio_help_message(mob/M)
to_chat(M, "Prefix your message with :h to speak on your department's radio. To see other prefixes, look closely at your headset.")
@@ -233,7 +213,7 @@
var/jobtype = null
uniform = /obj/item/clothing/under/color/grey
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
ears = /obj/item/radio/headset
belt = /obj/item/pda
back = /obj/item/storage/backpack
@@ -283,13 +263,12 @@
var/obj/item/card/id/C = H.wear_id
if(istype(C))
- C.access = J.get_access()
shuffle_inplace(C.access) // Shuffle access list to make NTNet passkeys less predictable
C.registered_name = H.real_name
- C.assignment = J.title
if(H.age)
C.registered_age = H.age
C.update_label()
+ C.update_icon()
var/datum/bank_account/B = SSeconomy.bank_accounts_by_id["[H.account_id]"]
if(B && B.account_id == H.account_id)
C.registered_account = B
@@ -313,9 +292,3 @@
types += satchel
types += duffelbag
return types
-
-//Warden and regular officers add this result to their get_access()
-/datum/job/proc/check_config_for_sec_maint()
- if(CONFIG_GET(flag/security_has_maint_access))
- return list(ACCESS_MAINT_TUNNELS)
- return list()
diff --git a/code/modules/jobs/job_types/assistant.dm b/code/modules/jobs/job_types/assistant.dm
index 5097a756552..fc84ab2d867 100644
--- a/code/modules/jobs/job_types/assistant.dm
+++ b/code/modules/jobs/job_types/assistant.dm
@@ -8,8 +8,6 @@ Assistant
spawn_positions = 5
supervisors = "absolutely everyone"
selection_color = "#dddddd"
- access = list() //See /datum/job/assistant/get_access()
- minimal_access = list() //See /datum/job/assistant/get_access()
outfit = /datum/outfit/job/assistant
antag_rep = 7
paycheck = PAYCHECK_ASSISTANT // Get a job. Job reassignment changes your paycheck now. Get over it.
@@ -20,16 +18,10 @@ Assistant
paycheck_department = ACCOUNT_CIV
display_order = JOB_DISPLAY_ORDER_ASSISTANT
-/datum/job/assistant/get_access()
- if(CONFIG_GET(flag/assistants_have_maint_access) || !CONFIG_GET(flag/jobs_have_minimal_access)) //Config has assistant maint access set
- . = ..()
- . |= list(ACCESS_MAINT_TUNNELS)
- else
- return ..()
-
/datum/outfit/job/assistant
name = "Assistant"
jobtype = /datum/job/assistant
+ id_trim = /datum/id_trim/job/assistant
/datum/outfit/job/assistant/pre_equip(mob/living/carbon/human/H)
..()
diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm
index f41358c0cd4..c42726ac58f 100644
--- a/code/modules/jobs/job_types/atmospheric_technician.dm
+++ b/code/modules/jobs/job_types/atmospheric_technician.dm
@@ -1,4 +1,4 @@
-/datum/job/atmos
+/datum/job/atmospheric_technician
title = "Atmospheric Technician"
department_head = list("Chief Engineer")
faction = "Station"
@@ -11,9 +11,6 @@
outfit = /datum/outfit/job/atmos
- access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, ACCESS_MECH_ENGINE, ACCESS_AUX_BASE,
- ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_ATMOSPHERICS, ACCESS_MAINT_TUNNELS, ACCESS_AUX_BASE, ACCESS_CONSTRUCTION, ACCESS_MECH_ENGINE, ACCESS_MINERAL_STOREROOM)
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_ENG
@@ -25,7 +22,7 @@
/datum/outfit/job/atmos
name = "Atmospheric Technician"
- jobtype = /datum/job/atmos
+ jobtype = /datum/job/atmospheric_technician
belt = /obj/item/storage/belt/utility/atmostech
l_pocket = /obj/item/pda/atmos
@@ -40,6 +37,8 @@
pda_slot = ITEM_SLOT_LPOCKET
backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced/atmos=1)
+ id_trim = /datum/id_trim/job/atmospheric_technician
+
/datum/outfit/job/atmos/rig
name = "Atmospheric Technician (Hardsuit)"
diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm
index 9ac6fce45ca..00b261e8e3d 100644
--- a/code/modules/jobs/job_types/bartender.dm
+++ b/code/modules/jobs/job_types/bartender.dm
@@ -9,8 +9,6 @@
outfit = /datum/outfit/job/bartender
- access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM, ACCESS_THEATRE)
- minimal_access = list(ACCESS_BAR, ACCESS_MINERAL_STOREROOM, ACCESS_THEATRE)
paycheck = PAYCHECK_EASY
paycheck_department = ACCOUNT_SRV
display_order = JOB_DISPLAY_ORDER_BARTENDER
@@ -28,6 +26,7 @@
suit = /obj/item/clothing/suit/armor/vest
backpack_contents = list(/obj/item/storage/box/beanbag=1)
shoes = /obj/item/clothing/shoes/laceup
+ id_trim = /datum/id_trim/job/bartender
/datum/outfit/job/bartender/post_equip(mob/living/carbon/human/H, visualsOnly)
. = ..()
diff --git a/code/modules/jobs/job_types/botanist.dm b/code/modules/jobs/job_types/botanist.dm
index 5ae2c63b6fb..29f37048475 100644
--- a/code/modules/jobs/job_types/botanist.dm
+++ b/code/modules/jobs/job_types/botanist.dm
@@ -1,4 +1,4 @@
-/datum/job/hydro
+/datum/job/botanist
title = "Botanist"
department_head = list("Head of Personnel")
faction = "Station"
@@ -9,8 +9,6 @@
outfit = /datum/outfit/job/botanist
- access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_HYDROPONICS, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
paycheck = PAYCHECK_EASY
paycheck_department = ACCOUNT_SRV
display_order = JOB_DISPLAY_ORDER_BOTANIST
@@ -19,7 +17,7 @@
/datum/outfit/job/botanist
name = "Botanist"
- jobtype = /datum/job/hydro
+ jobtype = /datum/job/botanist
belt = /obj/item/pda/botanist
ears = /obj/item/radio/headset/headset_srv
@@ -32,3 +30,4 @@
satchel = /obj/item/storage/backpack/satchel/hyd
duffelbag = /obj/item/storage/backpack/duffelbag/hydroponics
+ id_trim = /datum/id_trim/job/botanist
diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm
old mode 100755
new mode 100644
index 21fa555fbb3..2603e8ff151
--- a/code/modules/jobs/job_types/captain.dm
+++ b/code/modules/jobs/job_types/captain.dm
@@ -15,8 +15,6 @@
outfit = /datum/outfit/job/captain
- access = list() //See get_access()
- minimal_access = list() //See get_access()
paycheck = PAYCHECK_COMMAND
paycheck_department = ACCOUNT_SEC
@@ -25,18 +23,16 @@
display_order = JOB_DISPLAY_ORDER_CAPTAIN
departments = DEPARTMENT_COMMAND
-/datum/job/captain/get_access()
- return get_all_accesses()
-
-/datum/job/captain/announce(mob/living/carbon/human/H)
+/datum/job/captain/announce(mob/living/carbon/human/H, announce_captaincy = TRUE)
..()
- SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Captain [H.real_name] on deck!"))
+ if(announce_captaincy)
+ SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Captain [H.real_name] on deck!"))
/datum/outfit/job/captain
name = "Captain"
jobtype = /datum/job/captain
- id = /obj/item/card/id/gold
+ id = /obj/item/card/id/advanced/gold
belt = /obj/item/pda/captain
glasses = /obj/item/clothing/glasses/sunglasses
ears = /obj/item/radio/headset/heads/captain/alt
@@ -58,6 +54,8 @@
chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/captain)
+ id_trim = /datum/id_trim/job/captain
+
/datum/outfit/job/captain/hardsuit
name = "Captain (Hardsuit)"
diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm
index fe3420953f8..f124da49d72 100644
--- a/code/modules/jobs/job_types/cargo_technician.dm
+++ b/code/modules/jobs/job_types/cargo_technician.dm
@@ -1,4 +1,4 @@
-/datum/job/cargo_tech
+/datum/job/cargo_technician
title = "Cargo Technician"
department_head = list("Head of Personnel")
faction = "Station"
@@ -9,8 +9,6 @@
outfit = /datum/outfit/job/cargo_tech
- access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MECH_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM, ACCESS_MECH_MINING)
paycheck = PAYCHECK_EASY
paycheck_department = ACCOUNT_CAR
display_order = JOB_DISPLAY_ORDER_CARGO_TECHNICIAN
@@ -19,10 +17,11 @@
/datum/outfit/job/cargo_tech
name = "Cargo Technician"
- jobtype = /datum/job/cargo_tech
+ jobtype = /datum/job/cargo_technician
belt = /obj/item/pda/cargo
ears = /obj/item/radio/headset/headset_cargo
uniform = /obj/item/clothing/under/rank/cargo/tech
l_hand = /obj/item/export_scanner
backpack_contents = list(/obj/item/modular_computer/tablet/preset/cargo=1)
+ id_trim = /datum/id_trim/job/cargo_technician
diff --git a/code/modules/jobs/job_types/chaplain.dm b/code/modules/jobs/job_types/chaplain.dm
index 613d38ef8de..3f2da02d779 100644
--- a/code/modules/jobs/job_types/chaplain.dm
+++ b/code/modules/jobs/job_types/chaplain.dm
@@ -9,8 +9,6 @@
outfit = /datum/outfit/job/chaplain
- access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE)
- minimal_access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE)
paycheck = PAYCHECK_EASY
paycheck_department = ACCOUNT_SRV
@@ -136,3 +134,5 @@
satchel = /obj/item/storage/backpack/cultpack
chameleon_extras = /obj/item/stamp/chap
+
+ id_trim = /datum/id_trim/job/chaplain
diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm
index 758877f1756..721d7019645 100644
--- a/code/modules/jobs/job_types/chemist.dm
+++ b/code/modules/jobs/job_types/chemist.dm
@@ -11,8 +11,6 @@
outfit = /datum/outfit/job/chemist
- access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_PHARMACY, ACCESS_VIROLOGY, ACCESS_MECH_MEDICAL, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_MECH_MEDICAL, ACCESS_MINERAL_STOREROOM, ACCESS_PHARMACY)
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_MED
@@ -41,3 +39,5 @@
chameleon_extras = /obj/item/gun/syringe
+ id_trim = /datum/id_trim/job/chemist
+
diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm
index 4eae471579e..8c7e0297511 100644
--- a/code/modules/jobs/job_types/chief_engineer.dm
+++ b/code/modules/jobs/job_types/chief_engineer.dm
@@ -17,14 +17,6 @@
outfit = /datum/outfit/job/ce
departments = DEPARTMENT_ENGINEERING | DEPARTMENT_COMMAND
- access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
- ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EVA, ACCESS_AUX_BASE,
- ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT, ACCESS_MECH_ENGINE,
- ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM, ACCESS_TELEPORTER)
- minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
- ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EVA, ACCESS_AUX_BASE,
- ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT, ACCESS_MECH_ENGINE,
- ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
paycheck = PAYCHECK_COMMAND
paycheck_department = ACCOUNT_ENG
@@ -33,11 +25,16 @@
display_order = JOB_DISPLAY_ORDER_CHIEF_ENGINEER
bounty_types = CIV_JOB_ENG
+/datum/job/chief_engineer/announce(mob/living/carbon/human/H, announce_captaincy = FALSE)
+ ..()
+ if(announce_captaincy)
+ SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Due to staffing shortages, newly promoted Acting Captain [H.real_name] on deck!"))
+
/datum/outfit/job/ce
name = "Chief Engineer"
jobtype = /datum/job/chief_engineer
- id = /obj/item/card/id/silver
+ id = /obj/item/card/id/advanced/silver
belt = /obj/item/storage/belt/utility/chief/full
l_pocket = /obj/item/pda/heads/ce
ears = /obj/item/radio/headset/heads/ce
@@ -56,6 +53,8 @@
skillchips = list(/obj/item/skillchip/job/engineer)
+ id_trim = /datum/id_trim/job/chief_engineer
+
/datum/outfit/job/ce/rig
name = "Chief Engineer (Hardsuit)"
diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm
index d4f7af74494..bf0e4f4a671 100644
--- a/code/modules/jobs/job_types/chief_medical_officer.dm
+++ b/code/modules/jobs/job_types/chief_medical_officer.dm
@@ -1,4 +1,4 @@
-/datum/job/cmo
+/datum/job/chief_medical_officer
title = "Chief Medical Officer"
department_head = list("Captain")
auto_deadmin_role_flags = DEADMIN_POSITION_HEAD
@@ -17,12 +17,6 @@
outfit = /datum/outfit/job/cmo
departments = DEPARTMENT_MEDICAL | DEPARTMENT_COMMAND
- access = list(ACCESS_MEDICAL, ACCESS_PSYCHOLOGY, ACCESS_MORGUE, ACCESS_PHARMACY, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM,
- ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE, ACCESS_MECH_MEDICAL,
- ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS, ACCESS_EVA, ACCESS_TELEPORTER)
- minimal_access = list(ACCESS_MEDICAL, ACCESS_PSYCHOLOGY, ACCESS_MORGUE, ACCESS_PHARMACY, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM,
- ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE, ACCESS_MECH_MEDICAL,
- ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS, ACCESS_EVA)
paycheck = PAYCHECK_COMMAND
paycheck_department = ACCOUNT_MED
@@ -31,11 +25,16 @@
display_order = JOB_DISPLAY_ORDER_CHIEF_MEDICAL_OFFICER
bounty_types = CIV_JOB_MED
+/datum/job/chief_medical_officer/announce(mob/living/carbon/human/H, announce_captaincy = FALSE)
+ ..()
+ if(announce_captaincy)
+ SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Due to staffing shortages, newly promoted Acting Captain [H.real_name] on deck!"))
+
/datum/outfit/job/cmo
name = "Chief Medical Officer"
- jobtype = /datum/job/cmo
+ jobtype = /datum/job/chief_medical_officer
- id = /obj/item/card/id/silver
+ id = /obj/item/card/id/advanced/silver
belt = /obj/item/pda/heads/cmo
l_pocket = /obj/item/pinpointer/crew
ears = /obj/item/radio/headset/heads/cmo
@@ -55,6 +54,8 @@
chameleon_extras = list(/obj/item/gun/syringe, /obj/item/stamp/cmo)
+ id_trim = /datum/id_trim/job/chief_medical_officer
+
/datum/outfit/job/cmo/hardsuit
name = "Chief Medical Officer (Hardsuit)"
diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm
index 7382d5864e2..6aa04273f56 100644
--- a/code/modules/jobs/job_types/clown.dm
+++ b/code/modules/jobs/job_types/clown.dm
@@ -9,8 +9,6 @@
outfit = /datum/outfit/job/clown
- access = list(ACCESS_THEATRE)
- minimal_access = list(ACCESS_THEATRE)
paycheck = PAYCHECK_MINIMAL
paycheck_department = ACCOUNT_SRV
@@ -51,12 +49,13 @@
chameleon_extras = /obj/item/stamp/clown
+ id_trim = /datum/id_trim/job/clown
+
/datum/outfit/job/clown/pre_equip(mob/living/carbon/human/H, visualsOnly)
. = ..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_BANANIUM_SHIPMENTS))
backpack_contents[/obj/item/stack/sheet/mineral/bananium/five] = 1
-
/datum/outfit/job/clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
..()
if(visualsOnly)
diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm
index cd39a3d43e4..a4085b8e7a2 100644
--- a/code/modules/jobs/job_types/cook.dm
+++ b/code/modules/jobs/job_types/cook.dm
@@ -10,8 +10,6 @@
outfit = /datum/outfit/job/cook
- access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
paycheck = PAYCHECK_EASY
paycheck_department = ACCOUNT_SRV
@@ -37,6 +35,8 @@
)
skillchips = list(/obj/item/skillchip/job/chef)
+ id_trim = /datum/id_trim/job/cook
+
/datum/outfit/job/cook/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
..()
var/datum/job/cook/J = SSjob.GetJobType(jobtype)
diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm
index 8f4834e0c28..bc11268c004 100644
--- a/code/modules/jobs/job_types/curator.dm
+++ b/code/modules/jobs/job_types/curator.dm
@@ -9,8 +9,6 @@
outfit = /datum/outfit/job/curator
- access = list(ACCESS_LIBRARY, ACCESS_AUX_BASE, ACCESS_MINING_STATION)
- minimal_access = list(ACCESS_LIBRARY, ACCESS_AUX_BASE, ACCESS_MINING_STATION)
paycheck = PAYCHECK_EASY
paycheck_department = ACCOUNT_SRV
@@ -35,6 +33,8 @@
/obj/item/barcodescanner = 1
)
+ id_trim = /datum/id_trim/job/curator
+
/datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
..()
diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm
index 449a9c97a38..5b085edeb45 100644
--- a/code/modules/jobs/job_types/detective.dm
+++ b/code/modules/jobs/job_types/detective.dm
@@ -14,8 +14,6 @@
outfit = /datum/outfit/job/detective
departments = DEPARTMENT_SECURITY
- access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_MECH_SECURITY, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_MECH_SECURITY, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_SEC
@@ -47,6 +45,8 @@
chameleon_extras = list(/obj/item/gun/ballistic/revolver/detective, /obj/item/clothing/glasses/sunglasses)
+ id_trim = /datum/id_trim/job/detective
+
/datum/outfit/job/detective/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
..()
var/obj/item/clothing/mask/cigarette/cig = H.wear_mask
diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm
index acf84f77b03..77eae91e6bd 100644
--- a/code/modules/jobs/job_types/geneticist.dm
+++ b/code/modules/jobs/job_types/geneticist.dm
@@ -12,8 +12,6 @@
outfit = /datum/outfit/job/geneticist
departments = DEPARTMENT_MEDICAL
- access = list(ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_MECH_SCIENCE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_ROBOTICS, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE, ACCESS_RND)
- minimal_access = list(ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_MECH_SCIENCE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_RND)
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_SCI
@@ -35,3 +33,5 @@
backpack = /obj/item/storage/backpack/genetics
satchel = /obj/item/storage/backpack/satchel/gen
duffelbag = /obj/item/storage/backpack/duffelbag/genetics
+
+ id_trim = /datum/id_trim/job/geneticist
diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm
index 002e932e739..9a16df83d73 100644
--- a/code/modules/jobs/job_types/head_of_personnel.dm
+++ b/code/modules/jobs/job_types/head_of_personnel.dm
@@ -1,4 +1,4 @@
-/datum/job/hop
+/datum/job/head_of_personnel
title = "Head of Personnel"
auto_deadmin_role_flags = DEADMIN_POSITION_HEAD
department_head = list("Captain")
@@ -17,20 +17,6 @@
outfit = /datum/outfit/job/hop
departments = DEPARTMENT_COMMAND | DEPARTMENT_SERVICE
- access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS,
- ACCESS_MEDICAL, ACCESS_PSYCHOLOGY, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,
- ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
- ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER,
- ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION,
- ACCESS_MECH_MINING, ACCESS_MECH_ENGINE, ACCESS_MECH_SCIENCE, ACCESS_MECH_SECURITY, ACCESS_MECH_MEDICAL,
- ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM, ACCESS_AUX_BASE, ACCESS_TELEPORTER)
- minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS,
- ACCESS_MEDICAL, ACCESS_PSYCHOLOGY, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,
- ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
- ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_LAWYER,
- ACCESS_MECH_MINING, ACCESS_MECH_ENGINE, ACCESS_MECH_SCIENCE, ACCESS_MECH_SECURITY, ACCESS_MECH_MEDICAL,
- ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION,
- ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM, ACCESS_AUX_BASE, ACCESS_TELEPORTER)
paycheck = PAYCHECK_COMMAND
paycheck_department = ACCOUNT_SRV
bounty_types = CIV_JOB_RANDOM
@@ -39,11 +25,16 @@
display_order = JOB_DISPLAY_ORDER_HEAD_OF_PERSONNEL
+/datum/job/head_of_personnel/announce(mob/living/carbon/human/H, announce_captaincy = FALSE)
+ ..()
+ if(announce_captaincy)
+ SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Due to staffing shortages, newly promoted Acting Captain [H.real_name] on deck!"))
+
/datum/outfit/job/hop
name = "Head of Personnel"
- jobtype = /datum/job/hop
+ jobtype = /datum/job/head_of_personnel
- id = /obj/item/card/id/silver
+ id = /obj/item/card/id/advanced/silver
belt = /obj/item/pda/heads/hop
ears = /obj/item/radio/headset/heads/hop
uniform = /obj/item/clothing/under/rank/civilian/head_of_personnel
@@ -54,8 +45,33 @@
chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/hop)
+ id_trim = /datum/id_trim/job/head_of_personnel
+
/datum/outfit/job/hop/pre_equip(mob/living/carbon/human/H)
..()
if(locate(/datum/holiday/ianbirthday) in SSevents.holidays)
undershirt = /datum/sprite_accessory/undershirt/ian
+
+/obj/item/paper/fluff/ids_for_dummies
+ name = "Memo: New IDs and You"
+ desc = "It looks like this was left by the last Head of Personnel to man this station. It explains some information about new IDs."
+ info = {"
+
Dummy's Guide To New IDs
+
The Basics
+
Card Trim - This is the job assigned to the card. The card's trim decides what Basic accesses the card can hold. Basic accesses cost nothing! Grey ID cards cannot hold Head of Staff or Captain trims. Silver ID cards can hold Head of Staff trims but not Captain trims and are in a box in the Head of Personnel's office and orderable from cargo. Gold ID cards can hold all access. The only guaranteed Gold ID card is the Captain's Spare, held in a golden safe on the bridge with access codes given to the station's highest ranking officer. All other gold ID cards are carried exclusively by Captains.
+
Wildcards - These are any additional accesses a card has that are not part of the card's trim. Lower quality ID cards have fewer wildcards and the wildcards they do have are of lower rarity.
+
Job Changes - To change a job, you need to go to the PDA & ID Painter that's in every Head of Personnel office. This can be used to apply a new trim to an ID card, but this will wipe all that card's accesses in the process. You then take this ID card to any modular computer with the Plexus Access Management app and when logged in with the appropriate Head of Staff or ID Console access can then select from Templates to quick-fill accesses or apply them manually.
+
Firing Staff - Terminating a staff member's employment with wipe any trim from their card, remove all access and instantly set them as demoted.
+
Changing Jobs - Step by Step
+
+
Grab an appropriate ID card. Head of Staff jobs require a silver ID card. Captain requires a gold ID card.
+
Insert the ID card into the combined PDA Painter and ID Trimmer in the HoP office.
+
Select to appropriate trim then hit the button to apply it to the card. This will wipe all the card's access.
+
Remove the ID from the PDA/ID Painter and open up any modular computer with the Plexagon Access Management application downloaded.
+
Login to the app using an ID card with any Head of Staff private office access for limited access or the ID Console access for unlimited access.
+
Select a template from the drop-down. This will apply as many basic accesses as possible based on the trim of the ID card and may apply wildcard accesses for Head of Staff and Captain trims. For best results, match the template to the ID card's trim.
+
Manually tweak any other accesses as necessary. Add wildcard accesses. Tweak basic accesses.
+
Don't forget to set a custom occupation! SecHUDs now interface direct with the ID card's trim and display the trim's job icon even when a custom assignment is set.
+
+ "}
diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm
index b5fdd8bee17..a67b21ab587 100644
--- a/code/modules/jobs/job_types/head_of_security.dm
+++ b/code/modules/jobs/job_types/head_of_security.dm
@@ -1,4 +1,4 @@
-/datum/job/hos
+/datum/job/head_of_security
title = "Head of Security"
auto_deadmin_role_flags = DEADMIN_POSITION_HEAD|DEADMIN_POSITION_SECURITY
department_head = list("Captain")
@@ -20,25 +20,22 @@
mind_traits = list(TRAIT_DONUT_LOVER)
liver_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM, TRAIT_ROYAL_METABOLISM)
- access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MECH_SECURITY,
- ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_AUX_BASE,
- ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING, ACCESS_EVA, ACCESS_TELEPORTER,
- ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MECH_SECURITY,
- ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_AUX_BASE,
- ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING, ACCESS_EVA,
- ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
paycheck = PAYCHECK_COMMAND
paycheck_department = ACCOUNT_SEC
display_order = JOB_DISPLAY_ORDER_HEAD_OF_SECURITY
bounty_types = CIV_JOB_SEC
+/datum/job/head_of_security/announce(mob/living/carbon/human/H, announce_captaincy = FALSE)
+ ..()
+ if(announce_captaincy)
+ SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Due to staffing shortages, newly promoted Acting Captain [H.real_name] on deck!"))
+
/datum/outfit/job/hos
name = "Head of Security"
- jobtype = /datum/job/hos
+ jobtype = /datum/job/head_of_security
- id = /obj/item/card/id/silver
+ id = /obj/item/card/id/advanced/silver
belt = /obj/item/pda/heads/hos
ears = /obj/item/radio/headset/heads/hos/alt
uniform = /obj/item/clothing/under/rank/security/head_of_security
@@ -61,6 +58,8 @@
chameleon_extras = list(/obj/item/gun/energy/e_gun/hos, /obj/item/stamp/hos)
+ id_trim = /datum/id_trim/job/head_of_security
+
/datum/outfit/job/hos/hardsuit
name = "Head of Security (Hardsuit)"
diff --git a/code/modules/jobs/job_types/janitor.dm b/code/modules/jobs/job_types/janitor.dm
index bfb108eab53..1db8a299a4e 100644
--- a/code/modules/jobs/job_types/janitor.dm
+++ b/code/modules/jobs/job_types/janitor.dm
@@ -9,8 +9,6 @@
outfit = /datum/outfit/job/janitor
- access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
paycheck = PAYCHECK_EASY
paycheck_department = ACCOUNT_SRV
@@ -26,6 +24,8 @@
uniform = /obj/item/clothing/under/rank/civilian/janitor
backpack_contents = list(/obj/item/modular_computer/tablet/preset/advanced=1)
+ id_trim = /datum/id_trim/job/janitor
+
/datum/outfit/job/janitor/pre_equip(mob/living/carbon/human/H, visualsOnly)
. = ..()
if(GARBAGEDAY in SSevents.holidays)
diff --git a/code/modules/jobs/job_types/lawyer.dm b/code/modules/jobs/job_types/lawyer.dm
index a4dfbfcd3a4..73fd263e5be 100644
--- a/code/modules/jobs/job_types/lawyer.dm
+++ b/code/modules/jobs/job_types/lawyer.dm
@@ -10,8 +10,6 @@
outfit = /datum/outfit/job/lawyer
- access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS)
- minimal_access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS)
paycheck = PAYCHECK_EASY
paycheck_department = ACCOUNT_SRV
@@ -36,6 +34,7 @@
chameleon_extras = /obj/item/stamp/law
+ id_trim = /datum/id_trim/job/lawyer
/datum/outfit/job/lawyer/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
if(visualsOnly)
diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm
index ce74e3aa463..993d811d106 100644
--- a/code/modules/jobs/job_types/medical_doctor.dm
+++ b/code/modules/jobs/job_types/medical_doctor.dm
@@ -9,8 +9,6 @@
outfit = /datum/outfit/job/doctor
- access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_PHARMACY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_MECH_MEDICAL, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_MECH_MEDICAL, ACCESS_MINERAL_STOREROOM, ACCESS_PHARMACY)
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_MED
@@ -40,3 +38,5 @@
skillchips = list(/obj/item/skillchip/entrails_reader, /obj/item/skillchip/quickcarry)
chameleon_extras = /obj/item/gun/syringe
+
+ id_trim = /datum/id_trim/job/medical_doctor
diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm
index e6b7dd647de..a142cd58cba 100644
--- a/code/modules/jobs/job_types/mime.dm
+++ b/code/modules/jobs/job_types/mime.dm
@@ -9,8 +9,6 @@
outfit = /datum/outfit/job/mime
- access = list(ACCESS_THEATRE)
- minimal_access = list(ACCESS_THEATRE)
paycheck = PAYCHECK_MINIMAL
paycheck_department = ACCOUNT_SRV
@@ -42,6 +40,8 @@
chameleon_extras = /obj/item/stamp/mime
+ id_trim = /datum/id_trim/job/mime
+
/datum/outfit/job/mime/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
..()
diff --git a/code/modules/jobs/job_types/paramedic.dm b/code/modules/jobs/job_types/paramedic.dm
index 96dfaf37d1e..0daf982d7c3 100644
--- a/code/modules/jobs/job_types/paramedic.dm
+++ b/code/modules/jobs/job_types/paramedic.dm
@@ -9,10 +9,6 @@
outfit = /datum/outfit/job/paramedic
- access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_MECH_MEDICAL, ACCESS_MINERAL_STOREROOM, ACCESS_MAINT_TUNNELS,
- ACCESS_EVA, ACCESS_ENGINE, ACCESS_CONSTRUCTION, ACCESS_CARGO, ACCESS_HYDROPONICS, ACCESS_RESEARCH, ACCESS_AUX_BASE)
- minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_MECH_MEDICAL, ACCESS_MINERAL_STOREROOM, ACCESS_MAINT_TUNNELS, ACCESS_EVA,
- ACCESS_ENGINE, ACCESS_CONSTRUCTION, ACCESS_CARGO, ACCESS_HYDROPONICS, ACCESS_RESEARCH, ACCESS_AUX_BASE)
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_MED
@@ -33,7 +29,7 @@
suit = /obj/item/clothing/suit/toggle/labcoat/paramedic
gloves = /obj/item/clothing/gloves/color/latex/nitrile
belt = /obj/item/storage/belt/medical/paramedic
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
l_pocket = /obj/item/pda/medical
suit_store = /obj/item/flashlight/pen/paramedic
backpack_contents = list(/obj/item/roller=1)
@@ -47,3 +43,5 @@
box = /obj/item/storage/box/survival/medical
chameleon_extras = /obj/item/gun/syringe
+
+ id_trim = /datum/id_trim/job/paramedic
diff --git a/code/modules/jobs/job_types/prisoner.dm b/code/modules/jobs/job_types/prisoner.dm
index 0b79464487f..7c7a879f2d9 100644
--- a/code/modules/jobs/job_types/prisoner.dm
+++ b/code/modules/jobs/job_types/prisoner.dm
@@ -17,6 +17,8 @@
uniform = /obj/item/clothing/under/rank/prisoner
shoes = /obj/item/clothing/shoes/sneakers/orange
- id = /obj/item/card/id/prisoner
+ id = /obj/item/card/id/advanced/prisoner
ears = null
belt = null
+
+ id_trim = /datum/id_trim/job/prisoner
diff --git a/code/modules/jobs/job_types/psychologist.dm b/code/modules/jobs/job_types/psychologist.dm
index 5a117db8a1f..59df39cfc72 100644
--- a/code/modules/jobs/job_types/psychologist.dm
+++ b/code/modules/jobs/job_types/psychologist.dm
@@ -9,8 +9,6 @@
outfit = /datum/outfit/job/psychologist
- access = list(ACCESS_MEDICAL, ACCESS_PSYCHOLOGY)
- minimal_access = list(ACCESS_MEDICAL, ACCESS_PSYCHOLOGY)
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_SRV
@@ -26,7 +24,7 @@
ears = /obj/item/radio/headset/headset_srvmed
uniform = /obj/item/clothing/under/suit/black
shoes = /obj/item/clothing/shoes/laceup
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
belt = /obj/item/pda/medical
pda_slot = ITEM_SLOT_BELT
l_hand = /obj/item/clipboard
@@ -38,3 +36,5 @@
backpack = /obj/item/storage/backpack/medic
satchel = /obj/item/storage/backpack/satchel/med
duffelbag = /obj/item/storage/backpack/duffelbag/med
+
+ id_trim = /datum/id_trim/job/psychologist
diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm
index 3a0ef3d216d..4a9eadc734c 100644
--- a/code/modules/jobs/job_types/quartermaster.dm
+++ b/code/modules/jobs/job_types/quartermaster.dm
@@ -1,4 +1,4 @@
-/datum/job/qm
+/datum/job/quartermaster
title = "Quartermaster"
department_head = list("Head of Personnel")
faction = "Station"
@@ -10,8 +10,6 @@
outfit = /datum/outfit/job/quartermaster
- access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MECH_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT, ACCESS_AUX_BASE)
- minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MECH_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT, ACCESS_AUX_BASE)
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_CAR
@@ -21,9 +19,14 @@
bounty_types = CIV_JOB_RANDOM
departments = DEPARTMENT_CARGO
+/datum/job/quartermaster/announce(mob/living/carbon/human/H, announce_captaincy = FALSE)
+ ..()
+ if(announce_captaincy)
+ SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Due to extreme staffing shortages, newly promoted Acting Captain [H.real_name] on deck!"))
+
/datum/outfit/job/quartermaster
name = "Quartermaster"
- jobtype = /datum/job/qm
+ jobtype = /datum/job/quartermaster
belt = /obj/item/pda/quartermaster
ears = /obj/item/radio/headset/headset_cargo
@@ -35,3 +38,4 @@
chameleon_extras = /obj/item/stamp/qm
+ id_trim = /datum/id_trim/job/quartermaster
diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm
index 047f801e1ad..fd50251fd2a 100644
--- a/code/modules/jobs/job_types/research_director.dm
+++ b/code/modules/jobs/job_types/research_director.dm
@@ -1,4 +1,4 @@
-/datum/job/rd
+/datum/job/research_director
title = "Research Director"
auto_deadmin_role_flags = DEADMIN_POSITION_HEAD
department_head = list("Captain")
@@ -17,29 +17,22 @@
outfit = /datum/outfit/job/rd
departments = DEPARTMENT_SCIENCE | DEPARTMENT_COMMAND
- access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_RND, ACCESS_GENETICS, ACCESS_MORGUE,
- ACCESS_TOXINS, ACCESS_TELEPORTER, ACCESS_SEC_DOORS, ACCESS_MECH_SCIENCE,
- ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD,
- ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM,
- ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK,
- ACCESS_TOXINS_STORAGE, ACCESS_AUX_BASE, ACCESS_EVA)
- minimal_access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_RND, ACCESS_GENETICS, ACCESS_MORGUE,
- ACCESS_TOXINS, ACCESS_TELEPORTER, ACCESS_SEC_DOORS, ACCESS_MECH_SCIENCE,
- ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD,
- ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM,
- ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK,
- ACCESS_TOXINS_STORAGE, ACCESS_AUX_BASE, ACCESS_EVA)
paycheck = PAYCHECK_COMMAND
paycheck_department = ACCOUNT_SCI
display_order = JOB_DISPLAY_ORDER_RESEARCH_DIRECTOR
bounty_types = CIV_JOB_SCI
+/datum/job/research_director/announce(mob/living/carbon/human/H, announce_captaincy = FALSE)
+ ..()
+ if(announce_captaincy)
+ SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, .proc/minor_announce, "Due to staffing shortages, newly promoted Acting Captain [H.real_name] on deck!"))
+
/datum/outfit/job/rd
name = "Research Director"
- jobtype = /datum/job/rd
+ jobtype = /datum/job/research_director
- id = /obj/item/card/id/silver
+ id = /obj/item/card/id/advanced/silver
belt = /obj/item/pda/heads/rd
ears = /obj/item/radio/headset/heads/rd
uniform = /obj/item/clothing/under/rank/rnd/research_director
@@ -57,6 +50,8 @@
chameleon_extras = /obj/item/stamp/rd
+ id_trim = /datum/id_trim/job/research_director
+
/datum/outfit/job/rd/rig
name = "Research Director (Hardsuit)"
diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm
index 6974d560a24..c57ccdc978f 100644
--- a/code/modules/jobs/job_types/roboticist.dm
+++ b/code/modules/jobs/job_types/roboticist.dm
@@ -13,10 +13,6 @@
outfit = /datum/outfit/job/roboticist
departments = DEPARTMENT_SCIENCE
- access = list(ACCESS_ROBOTICS, ACCESS_RND, ACCESS_TOXINS, ACCESS_TOXINS_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_MECH_SCIENCE,
- ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_XENOBIOLOGY, ACCESS_GENETICS, ACCESS_AUX_BASE)
- minimal_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MECH_SCIENCE, ACCESS_MINERAL_STOREROOM,
- ACCESS_RND, ACCESS_AUX_BASE)
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_SCI
@@ -39,3 +35,5 @@
pda_slot = ITEM_SLOT_LPOCKET
skillchips = list(/obj/item/skillchip/job/roboticist)
+
+ id_trim = /datum/id_trim/job/roboticist
diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm
index de1eb4e3bfa..574fdfdb95e 100644
--- a/code/modules/jobs/job_types/scientist.dm
+++ b/code/modules/jobs/job_types/scientist.dm
@@ -9,13 +9,8 @@
exp_requirements = 60
exp_type = EXP_TYPE_CREW
-
outfit = /datum/outfit/job/scientist
- access = list(ACCESS_ROBOTICS, ACCESS_RND, ACCESS_TOXINS, ACCESS_TOXINS_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY,
- ACCESS_MECH_SCIENCE, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE, ACCESS_GENETICS, ACCESS_AUX_BASE)
- minimal_access = list(ACCESS_RND, ACCESS_TOXINS, ACCESS_TOXINS_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MECH_SCIENCE,
- ACCESS_MINERAL_STOREROOM, ACCESS_AUX_BASE)
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_SCI
@@ -37,6 +32,8 @@
satchel = /obj/item/storage/backpack/satchel/tox
duffelbag = /obj/item/storage/backpack/duffelbag/toxins
+ id_trim = /datum/id_trim/job/scientist
+
/datum/outfit/job/scientist/pre_equip(mob/living/carbon/human/H)
..()
if(prob(0.4))
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index 9372b6f25ad..f9436b134d3 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -1,4 +1,4 @@
-/datum/job/officer
+/datum/job/security_officer
title = "Security Officer"
auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY
department_head = list("Head of Security")
@@ -13,8 +13,6 @@
outfit = /datum/outfit/job/security
- access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MECH_SECURITY, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MECH_SECURITY, ACCESS_MINERAL_STOREROOM) // See /datum/job/officer/get_access()
paycheck = PAYCHECK_HARD
paycheck_department = ACCOUNT_SEC
@@ -25,14 +23,9 @@
bounty_types = CIV_JOB_SEC
departments = DEPARTMENT_SECURITY
-/datum/job/officer/get_access()
- var/list/L = list()
- L |= ..() | check_config_for_sec_maint()
- return L
-
GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY))
-/datum/job/officer/after_spawn(mob/living/carbon/human/H, mob/M)
+/datum/job/security_officer/after_spawn(mob/living/carbon/human/H, mob/M)
. = ..()
// Assign department security
var/department
@@ -46,31 +39,31 @@ GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, S
department = pick_n_take(GLOB.available_depts)
var/ears = null
var/accessory = null
- var/list/dep_access = null
+ var/list/dep_trim = null
var/destination = null
var/spawn_point = null
switch(department)
if(SEC_DEPT_SUPPLY)
ears = /obj/item/radio/headset/headset_sec/alt/department/supply
- dep_access = list(ACCESS_MAILSORTING, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_CARGO, ACCESS_AUX_BASE)
+ dep_trim = /datum/id_trim/job/security_officer/supply
destination = /area/security/checkpoint/supply
spawn_point = locate(/obj/effect/landmark/start/depsec/supply) in GLOB.department_security_spawns
accessory = /obj/item/clothing/accessory/armband/cargo
if(SEC_DEPT_ENGINEERING)
ears = /obj/item/radio/headset/headset_sec/alt/department/engi
- dep_access = list(ACCESS_CONSTRUCTION, ACCESS_ENGINE, ACCESS_ATMOSPHERICS, ACCESS_AUX_BASE)
+ dep_trim = /datum/id_trim/job/security_officer/engineering
destination = /area/security/checkpoint/engineering
spawn_point = locate(/obj/effect/landmark/start/depsec/engineering) in GLOB.department_security_spawns
accessory = /obj/item/clothing/accessory/armband/engine
if(SEC_DEPT_MEDICAL)
ears = /obj/item/radio/headset/headset_sec/alt/department/med
- dep_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY)
+ dep_trim = /datum/id_trim/job/security_officer/medical
destination = /area/security/checkpoint/medical
spawn_point = locate(/obj/effect/landmark/start/depsec/medical) in GLOB.department_security_spawns
accessory = /obj/item/clothing/accessory/armband/medblue
if(SEC_DEPT_SCIENCE)
ears = /obj/item/radio/headset/headset_sec/alt/department/sci
- dep_access = list(ACCESS_RESEARCH, ACCESS_RND, ACCESS_AUX_BASE)
+ dep_trim = /datum/id_trim/job/security_officer/science
destination = /area/security/checkpoint/science
spawn_point = locate(/obj/effect/landmark/start/depsec/science) in GLOB.department_security_spawns
accessory = /obj/item/clothing/accessory/armband/science
@@ -83,8 +76,11 @@ GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, S
qdel(H.ears)
H.equip_to_slot_or_del(new ears(H),ITEM_SLOT_EARS)
- var/obj/item/card/id/W = H.wear_id
- W.access |= dep_access
+ // If there's a departmental sec trim to apply to the card, overwrite.
+ if(dep_trim)
+ var/obj/item/card/id/worn_id = H.wear_id
+ SSid_access.apply_trim_to_card(worn_id, dep_trim)
+ H.sec_hud_set_ID()
var/teleport = 0
if(!CONFIG_GET(flag/sec_start_brig))
@@ -112,7 +108,7 @@ GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, S
/datum/outfit/job/security
name = "Security Officer"
- jobtype = /datum/job/officer
+ jobtype = /datum/job/security_officer
belt = /obj/item/pda/security
ears = /obj/item/radio/headset/headset_sec/alt
@@ -136,6 +132,7 @@ GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, S
chameleon_extras = list(/obj/item/gun/energy/disabler, /obj/item/clothing/glasses/hud/security/sunglasses, /obj/item/clothing/head/helmet)
//The helmet is necessary because /obj/item/clothing/head/helmet/sec is overwritten in the chameleon list by the standard helmet, which has the same name and icon state
+ id_trim = /datum/id_trim/job/security_officer
/obj/item/radio/headset/headset_sec/alt/department/Initialize()
. = ..()
diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm
index 66072891370..db6783a10a8 100644
--- a/code/modules/jobs/job_types/shaft_miner.dm
+++ b/code/modules/jobs/job_types/shaft_miner.dm
@@ -1,4 +1,4 @@
-/datum/job/mining
+/datum/job/shaft_miner
title = "Shaft Miner"
department_head = list("Head of Personnel")
faction = "Station"
@@ -9,8 +9,6 @@
outfit = /datum/outfit/job/miner
- access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MECH_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_AUX_BASE)
- minimal_access = list(ACCESS_MINING, ACCESS_MECH_MINING, ACCESS_MINING_STATION, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM, ACCESS_AUX_BASE)
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_CAR
@@ -20,7 +18,7 @@
/datum/outfit/job/miner
name = "Shaft Miner"
- jobtype = /datum/job/mining
+ jobtype = /datum/job/shaft_miner
belt = /obj/item/pda/shaftminer
ears = /obj/item/radio/headset/headset_cargo/mining
@@ -42,6 +40,8 @@
chameleon_extras = /obj/item/gun/energy/kinetic_accelerator
+ id_trim = /datum/id_trim/job/shaft_miner
+
/datum/outfit/job/miner/equipped
name = "Shaft Miner (Equipment)"
suit = /obj/item/clothing/suit/hooded/explorer
diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm
index 390861d6343..fff1cf42b87 100644
--- a/code/modules/jobs/job_types/station_engineer.dm
+++ b/code/modules/jobs/job_types/station_engineer.dm
@@ -1,4 +1,4 @@
-/datum/job/engineer
+/datum/job/station_engineer
title = "Station Engineer"
department_head = list("Chief Engineer")
faction = "Station"
@@ -11,10 +11,6 @@
outfit = /datum/outfit/job/engineer
- access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, ACCESS_MECH_ENGINE, ACCESS_AUX_BASE,
- ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, ACCESS_MECH_ENGINE, ACCESS_AUX_BASE,
- ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_ENG
@@ -26,7 +22,7 @@
/datum/outfit/job/engineer
name = "Station Engineer"
- jobtype = /datum/job/engineer
+ jobtype = /datum/job/station_engineer
belt = /obj/item/storage/belt/utility/full/engi
l_pocket = /obj/item/pda/engineering
@@ -45,6 +41,8 @@
skillchips = list(/obj/item/skillchip/job/engineer)
+ id_trim = /datum/id_trim/job/station_engineer
+
/datum/outfit/job/engineer/gloved
name = "Station Engineer (Gloves)"
gloves = /obj/item/clothing/gloves/color/yellow
@@ -57,3 +55,8 @@
head = null
internals_slot = ITEM_SLOT_SUITSTORE
+/datum/outfit/job/engineer/gloved/gunner
+ id_trim = /datum/id_trim/job/station_engineer/gunner
+
+/datum/outfit/job/engineer/gloved/rig/gunner
+ id_trim = /datum/id_trim/job/station_engineer/gunner
diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm
index 926735e3083..ff5e3443bbe 100644
--- a/code/modules/jobs/job_types/virologist.dm
+++ b/code/modules/jobs/job_types/virologist.dm
@@ -11,8 +11,6 @@
outfit = /datum/outfit/job/virologist
- access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_MECH_MEDICAL, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_MEDICAL, ACCESS_VIROLOGY, ACCESS_MECH_MEDICAL, ACCESS_MINERAL_STOREROOM)
paycheck = PAYCHECK_MEDIUM
paycheck_department = ACCOUNT_MED
@@ -38,3 +36,5 @@
satchel = /obj/item/storage/backpack/satchel/vir
duffelbag = /obj/item/storage/backpack/duffelbag/virology
box = /obj/item/storage/box/survival/medical
+
+ id_trim = /datum/id_trim/job/virologist
diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm
index 175807bde86..878621c1faf 100644
--- a/code/modules/jobs/job_types/warden.dm
+++ b/code/modules/jobs/job_types/warden.dm
@@ -13,8 +13,6 @@
outfit = /datum/outfit/job/warden
- access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MECH_SECURITY, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_MECH_SECURITY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) // See /datum/job/warden/get_access()
paycheck = PAYCHECK_HARD
paycheck_department = ACCOUNT_SEC
@@ -25,11 +23,6 @@
bounty_types = CIV_JOB_SEC
departments = DEPARTMENT_SECURITY
-/datum/job/warden/get_access()
- var/list/L = list()
- L = ..() | check_config_for_sec_maint()
- return L
-
/datum/outfit/job/warden
name = "Warden"
jobtype = /datum/job/warden
@@ -54,3 +47,4 @@
implants = list(/obj/item/implant/mindshield)
+ id_trim = /datum/id_trim/job/warden
diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm
index e6b7119b8a9..ac845e9da81 100644
--- a/code/modules/mining/laborcamp/laborstacker.dm
+++ b/code/modules/mining/laborcamp/laborstacker.dm
@@ -56,8 +56,8 @@ GLOBAL_LIST(labor_sheet_values)
if(isliving(usr))
var/mob/living/L = usr
I = L.get_idcard(TRUE)
- if(istype(I, /obj/item/card/id/prisoner))
- var/obj/item/card/id/prisoner/P = I
+ if(istype(I, /obj/item/card/id/advanced/prisoner))
+ var/obj/item/card/id/advanced/prisoner/P = I
data["id_points"] = P.points
if(P.points >= P.goal)
can_go_home = TRUE
@@ -86,8 +86,8 @@ GLOBAL_LIST(labor_sheet_values)
if(isliving(M))
var/mob/living/L = M
I = L.get_idcard(TRUE)
- if(istype(I, /obj/item/card/id/prisoner))
- var/obj/item/card/id/prisoner/P = I
+ if(istype(I, /obj/item/card/id/advanced/prisoner))
+ var/obj/item/card/id/advanced/prisoner/P = I
P.points += stacking_machine.points
stacking_machine.points = 0
to_chat(M, "Points transferred.")
@@ -157,8 +157,8 @@ GLOBAL_LIST(labor_sheet_values)
/obj/machinery/mineral/labor_points_checker/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/card/id))
- if(istype(I, /obj/item/card/id/prisoner))
- var/obj/item/card/id/prisoner/prisoner_id = I
+ if(istype(I, /obj/item/card/id/advanced/prisoner))
+ var/obj/item/card/id/advanced/prisoner/prisoner_id = I
to_chat(user, "ID: [prisoner_id.registered_name]")
to_chat(user, "Points Collected:[prisoner_id.points]")
to_chat(user, "Point Quota: [prisoner_id.goal]")
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index 9f1218f34bd..8859d7a2cdd 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -212,7 +212,7 @@
/obj/machinery/mineral/equipment_vendor/golem/Initialize()
desc += "\nIt seems a few selections have been added."
prize_list += list(
- new /datum/data/mining_equipment("Extra Id", /obj/item/card/id/mining, 250),
+ new /datum/data/mining_equipment("Extra Id", /obj/item/card/id/advanced/mining, 250),
new /datum/data/mining_equipment("Science Goggles", /obj/item/clothing/glasses/science, 250),
new /datum/data/mining_equipment("Monkey Cube", /obj/item/food/monkeycube, 300),
new /datum/data/mining_equipment("Toolbelt", /obj/item/storage/belt/utility, 350),
@@ -257,24 +257,6 @@
..()
to_chat(user, "There's [points] point\s on the card.")
-///Conscript kit
-/obj/item/card/mining_access_card
- name = "mining access card"
- desc = "A small card, that when used on any ID, will add mining access."
- icon_state = "data_1"
-
-/obj/item/card/mining_access_card/afterattack(atom/movable/AM, mob/user, proximity)
- . = ..()
- if(istype(AM, /obj/item/card/id) && proximity)
- var/obj/item/card/id/I = AM
- I.access |= ACCESS_MINING
- I.access |= ACCESS_MINING_STATION
- I.access |= ACCESS_MECH_MINING
- I.access |= ACCESS_MINERAL_STOREROOM
- I.access |= ACCESS_CARGO
- to_chat(user, "You upgrade [I] with mining access.")
- qdel(src)
-
/obj/item/storage/backpack/duffelbag/mining_conscript
name = "mining conscription kit"
desc = "A kit containing everything a crewmember needs to support a shaft miner in the field."
@@ -288,7 +270,7 @@
new /obj/item/clothing/suit/hooded/explorer(src)
new /obj/item/encryptionkey/headset_mining(src)
new /obj/item/clothing/mask/gas/explorer(src)
- new /obj/item/card/mining_access_card(src)
+ new /obj/item/card/id/advanced/mining(src)
new /obj/item/gun/energy/kinetic_accelerator(src)
new /obj/item/kitchen/knife/combat/survival(src)
new /obj/item/flashlight/seclite(src)
diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm
index 3d8ad9f9d2d..154a81ad02c 100644
--- a/code/modules/mining/minebot.dm
+++ b/code/modules/mining/minebot.dm
@@ -55,13 +55,11 @@
var/obj/item/implant/radio/mining/imp = new(src)
imp.implant(src)
- access_card = new /obj/item/card/id(src)
- var/datum/job/mining/M = new
- access_card.access = M.get_access()
+ access_card = new /obj/item/card/id/advanced/gold(src)
+ SSid_access.apply_trim_to_card(access_card, /datum/id_trim/job/shaft_miner)
SetCollectBehavior()
-
/mob/living/simple_animal/hostile/mining_drone/Destroy()
for (var/datum/action/innate/minedrone/action in actions)
qdel(action)
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index 1ee2a966097..0e3d174e5a8 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -316,7 +316,16 @@
SSjob.AssignRole(src, rank, 1)
var/mob/living/character = create_character(TRUE) //creates the human and transfers vars and mind
- var/equip = SSjob.EquipRank(character, rank, TRUE)
+
+ var/is_captain = FALSE
+ // If we don't have an assigned cap yet, check if this person qualifies for some from of captaincy.
+ if(!SSjob.assigned_captain && ishuman(character) && SSjob.chain_of_command[rank] && !is_banned_from(ckey, list("Captain")))
+ is_captain = TRUE
+ // If we already have a captain, are they a "Captain" rank and are we allowing multiple of them to be assigned?
+ else if(SSjob.always_promote_captain_job && (rank == "Captain"))
+ is_captain = TRUE
+
+ var/equip = SSjob.EquipRank(character, rank, TRUE, is_captain)
if(isliving(equip)) //Borgs get borged in the equip, so we need to make sure we handle the new mob.
character = equip
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index baae6952bf6..f2af6ff2475 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -55,8 +55,6 @@
if(num_hands)
. += "[t_He] [t_has] [num_hands > 1 ? "" : "a"] blood-stained hand[num_hands > 1 ? "s" : ""]!"
- //handcuffed?
-
//handcuffed?
if(handcuffed)
if(istype(handcuffed, /obj/item/restraints/handcuffs/cable))
@@ -94,6 +92,12 @@
if(wear_id && !(wear_id.item_flags & EXAMINE_SKIP))
. += "[t_He] [t_is] wearing [wear_id.get_examine_string(user)]."
+ . += wear_id.get_id_examine_strings(user)
+ //var/list/extended_id_examine = wear_id.get_id_examine_strings(user)
+
+ //for(var/examine_string in extended_id_examine)
+ // . += examine_string
+
//Status effects
var/list/status_examines = status_effect_examines()
if (length(status_examines))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 92829523d88..4624aa98441 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -612,10 +612,6 @@
if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
threatcount -= 1
- //Agent cards lower threatlevel.
- if(istype(idcard, /obj/item/card/id/syndicate))
- threatcount -= 5
-
return threatcount
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 2365994163c..85584f5b247 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -90,8 +90,6 @@
/mob/living/carbon/human/can_track(mob/living/user)
- if(wear_id && istype(wear_id.GetID(), /obj/item/card/id/syndicate))
- return 0
if(istype(head, /obj/item/clothing/head))
var/obj/item/clothing/head/hat = head
if(hat.blockTracking)
diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm
index 69e8b043e66..e85564869a6 100644
--- a/code/modules/mob/living/carbon/human/human_update_icons.dm
+++ b/code/modules/mob/living/carbon/human/human_update_icons.dm
@@ -143,6 +143,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_wear_id()
remove_overlay(ID_LAYER)
+ remove_overlay(ID_CARD_LAYER)
if(client && hud_used)
var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_ID) + 1]
@@ -157,13 +158,24 @@ There are several things that need to be remembered:
update_observer_view(wear_id)
//TODO: add an icon file for ID slot stuff, so it's less snowflakey
- id_overlay = wear_id.build_worn_icon(default_layer = ID_LAYER, default_icon_file = 'icons/mob/mob.dmi')
+ id_overlay = wear_id.build_worn_icon(default_layer = ID_LAYER, default_icon_file = 'icons/mob/clothing/id.dmi')
if(OFFSET_ID in dna.species.offset_features)
id_overlay.pixel_x += dna.species.offset_features[OFFSET_ID][1]
id_overlay.pixel_y += dna.species.offset_features[OFFSET_ID][2]
overlays_standing[ID_LAYER] = id_overlay
+ var/obj/item/card/id/shown_id = wear_id.GetID()
+ if(shown_id)
+ var/mutable_appearance/id_card_overlay = overlays_standing[ID_CARD_LAYER]
+ id_card_overlay = shown_id.build_worn_icon(default_layer = ID_CARD_LAYER, default_icon_file = 'icons/mob/clothing/id_card.dmi')
+ if(OFFSET_ID in dna.species.offset_features)
+ id_card_overlay.pixel_x += dna.species.offset_features[OFFSET_ID][1]
+ id_card_overlay.pixel_y += dna.species.offset_features[OFFSET_ID][2]
+
+ overlays_standing[ID_CARD_LAYER] = id_card_overlay
+
apply_overlay(ID_LAYER)
+ apply_overlay(ID_CARD_LAYER)
/mob/living/carbon/human/update_inv_gloves()
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index ce13bf6bba3..66d54555ace 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -152,9 +152,10 @@
/mob/living/simple_animal/bot/Initialize()
. = ..()
GLOB.bots_list += src
- access_card = new /obj/item/card/id(src)
-//This access is so bots can be immediately set to patrol and leave Robotics, instead of having to be let out first.
- access_card.access += ACCESS_ROBOTICS
+ // Give bots a fancy new ID card that can hold any access.
+ access_card = new /obj/item/card/id/advanced/simple_bot(src)
+ // This access is so bots can be immediately set to patrol and leave Robotics, instead of having to be let out first.
+ access_card.set_access(list(ACCESS_ROBOTICS))
set_custom_texts()
Radio = new/obj/item/radio(src)
if(radio_key)
@@ -552,15 +553,13 @@ Pass a positive integer as an argument to override a bot's default speed.
/mob/living/simple_animal/bot/proc/check_bot_access()
if(mode != BOT_SUMMON && mode != BOT_RESPONDING)
- access_card.access = prev_access
+ access_card.set_access(prev_access)
/mob/living/simple_animal/bot/proc/call_bot(caller, turf/waypoint, message=TRUE)
bot_reset() //Reset a bot before setting it to call mode.
- //For giving the bot temporary all-access.
- var/obj/item/card/id/all_access = new /obj/item/card/id
- var/datum/job/captain/All = new/datum/job/captain
- all_access.access = All.get_access()
+ //For giving the bot temporary all-access. This method is bad and makes me feel bad. Refactoring access to a component is for another PR.
+ var/obj/item/card/id/all_access = new /obj/item/card/id/advanced/gold/captains_spare()
set_path(get_path_to(src, waypoint, 200, id=all_access))
calling_ai = caller //Link the AI to the bot!
@@ -604,7 +603,7 @@ Pass a positive integer as an argument to override a bot's default speed.
set_path(null)
summon_target = null
pathset = 0
- access_card.access = prev_access
+ access_card.set_access(prev_access)
tries = 0
mode = BOT_IDLE
diag_hud_set_botstat()
@@ -742,7 +741,7 @@ Pass a positive integer as an argument to override a bot's default speed.
bot_reset()
summon_target = get_turf(user)
if(user_access.len != 0)
- access_card.access = user_access + prev_access //Adds the user's access, if any.
+ access_card.set_access(user_access + prev_access) //Adds the user's access, if any.
mode = BOT_SUMMON
speak("Responding.", radio_channel)
@@ -997,7 +996,7 @@ Pass a positive integer as an argument to override a bot's default speed.
. = ..()
if(!. || !client)
return FALSE
- access_card.access += player_access
+ access_card.add_access(player_access)
diag_hud_set_botmode()
/mob/living/simple_animal/bot/Logout()
diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
index 127f5d83154..40e60f6a4a4 100644
--- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -105,9 +105,10 @@
get_targets()
icon_state = "cleanbot[on]"
- var/datum/job/janitor/J = new/datum/job/janitor
- access_card.access += J.get_access()
- prev_access = access_card.access
+ // Doing this hurts my soul, but simplebot access reworks are for another day.
+ var/datum/id_trim/job/jani_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/janitor]
+ access_card.add_access(jani_trim.access + jani_trim.wildcard_access)
+ prev_access = access_card.access.Copy()
stolen_valor = list()
prefixes = list(command, security, engineering)
diff --git a/code/modules/mob/living/simple_animal/bot/firebot.dm b/code/modules/mob/living/simple_animal/bot/firebot.dm
index 2ad3ba0fe99..4bcb7045032 100644
--- a/code/modules/mob/living/simple_animal/bot/firebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/firebot.dm
@@ -41,10 +41,12 @@
/mob/living/simple_animal/bot/firebot/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
- update_appearance()
- var/datum/job/engineer/J = new/datum/job/engineer
- access_card.access += J.get_access()
- prev_access = access_card.access
+ update_appearance(UPDATE_ICON)
+
+ // Doing this hurts my soul, but simplebot access reworks are for another day.
+ var/datum/id_trim/job/engi_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/station_engineer]
+ access_card.add_access(engi_trim.access + engi_trim.wildcard_access)
+ prev_access = access_card.access.Copy()
create_extinguisher()
diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm
index c0ba903a853..0e3ef0b4740 100644
--- a/code/modules/mob/living/simple_animal/bot/floorbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm
@@ -43,10 +43,13 @@
. = ..()
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
toolbox_color = new_toolbox_color
- update_appearance()
- var/datum/job/engineer/J = new/datum/job/engineer
- access_card.access += J.get_access()
- prev_access = access_card.access
+ update_appearance(UPDATE_ICON)
+
+ // Doing this hurts my soul, but simplebot access reworks are for another day.
+ var/datum/id_trim/job/engi_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/station_engineer]
+ access_card.add_access(engi_trim.access + engi_trim.wildcard_access)
+ prev_access = access_card.access.Copy()
+
if(toolbox_color == "s")
health = 100
maxHealth = 100
diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm
index 511c1f448a8..3c1f50b255b 100644
--- a/code/modules/mob/living/simple_animal/bot/honkbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm
@@ -41,9 +41,11 @@
. = ..()
update_appearance()
auto_patrol = TRUE
- var/datum/job/clown/J = new/datum/job/clown
- access_card.access += J.get_access()
- prev_access = access_card.access
+
+ // Doing this hurts my soul, but simplebot access reworks are for another day.
+ var/datum/id_trim/job/clown_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/clown]
+ access_card.add_access(clown_trim.access + clown_trim.wildcard_access)
+ prev_access = access_card.access.Copy()
/mob/living/simple_animal/bot/honkbot/proc/limiting_spam_false() //used for addtimer
limiting_spam = FALSE
diff --git a/code/modules/mob/living/simple_animal/bot/hygienebot.dm b/code/modules/mob/living/simple_animal/bot/hygienebot.dm
index f324849b5f6..2b35777cb5f 100644
--- a/code/modules/mob/living/simple_animal/bot/hygienebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/hygienebot.dm
@@ -40,10 +40,12 @@
/mob/living/simple_animal/bot/hygienebot/Initialize()
. = ..()
- update_appearance()
- var/datum/job/janitor/J = new/datum/job/janitor
- access_card.access += J.get_access()
- prev_access = access_card.access
+ update_appearance(UPDATE_ICON)
+
+ // Doing this hurts my soul, but simplebot access reworks are for another day.
+ var/datum/id_trim/job/jani_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/janitor]
+ access_card.add_access(jani_trim.access + jani_trim.wildcard_access)
+ prev_access = access_card.access.Copy()
/mob/living/simple_animal/bot/hygienebot/explode()
walk_to(src,0)
diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm
index 8a0281af41c..0b066ca0017 100644
--- a/code/modules/mob/living/simple_animal/bot/medbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/medbot.dm
@@ -107,10 +107,12 @@
/mob/living/simple_animal/bot/medbot/Initialize(mapload, new_skin)
. = ..()
- var/datum/job/paramedic/J = new /datum/job/paramedic
- access_card.access += J.get_access()
- prev_access = access_card.access
- qdel(J)
+
+ // Doing this hurts my soul, but simplebot access reworks are for another day.
+ var/datum/id_trim/job/para_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/paramedic]
+ access_card.add_access(para_trim.access + para_trim.wildcard_access)
+ prev_access = access_card.access.Copy()
+
skin = new_skin
update_appearance()
linked_techweb = SSresearch.science_tech
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index eaa6c9a4517..a79ea75efe8 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -64,9 +64,12 @@
new /mob/living/simple_animal/bot/mulebot/paranormal(loc)
return INITIALIZE_HINT_QDEL
wires = new /datum/wires/mulebot(src)
- var/datum/job/cargo_tech/J = new/datum/job/cargo_tech
- access_card.access = J.get_access()
- prev_access = access_card.access
+
+ // Doing this hurts my soul, but simplebot access reworks are for another day.
+ var/datum/id_trim/job/cargo_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/cargo_technician]
+ access_card.add_access(cargo_trim.access + cargo_trim.wildcard_access)
+ prev_access = access_card.access.Copy()
+
cell = new /obj/item/stock_parts/cell/upgraded(src, 2000)
var/static/mulebot_count = 0
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index 76da77aacf6..0c969ef54ba 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -77,10 +77,12 @@
/mob/living/simple_animal/bot/secbot/Initialize()
. = ..()
weapon = new baton_type()
- update_appearance()
- var/datum/job/detective/J = new/datum/job/detective
- access_card.access += J.get_access()
- prev_access = access_card.access
+ update_appearance(UPDATE_ICON)
+
+ // Doing this hurts my soul, but simplebot access reworks are for another day.
+ var/datum/id_trim/job/det_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/detective]
+ access_card.add_access(det_trim.access + det_trim.wildcard_access)
+ prev_access = access_card.access.Copy()
//SECHUD
var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
diff --git a/code/modules/mob/living/simple_animal/corpse.dm b/code/modules/mob/living/simple_animal/corpse.dm
index 578240a3816..83fd6fb57b4 100644
--- a/code/modules/mob/living/simple_animal/corpse.dm
+++ b/code/modules/mob/living/simple_animal/corpse.dm
@@ -10,7 +10,6 @@
/obj/effect/mob_spawn/human/corpse/syndicatesoldier
name = "Syndicate Operative"
- id_job = "Operative"
hairstyle = "Bald"
facial_hairstyle = "Shaved"
outfit = /datum/outfit/syndicatesoldiercorpse
@@ -25,11 +24,11 @@
mask = /obj/item/clothing/mask/gas
head = /obj/item/clothing/head/helmet/swat
back = /obj/item/storage/backpack
- id = /obj/item/card/id/syndicate
+ id = /obj/item/card/id/advanced/chameleon
+ id_trim = /datum/id_trim/chameleon/operative
/obj/effect/mob_spawn/human/corpse/syndicatecommando
name = "Syndicate Commando"
- id_job = "Operative"
hairstyle = "Bald"
facial_hairstyle = "Shaved"
outfit = /datum/outfit/syndicatecommandocorpse
@@ -44,12 +43,12 @@
mask = /obj/item/clothing/mask/gas/syndicate
back = /obj/item/tank/jetpack/oxygen
r_pocket = /obj/item/tank/internals/emergency_oxygen
- id = /obj/item/card/id/syndicate
+ id = /obj/item/card/id/advanced/chameleon
+ id_trim = /datum/id_trim/chameleon/operative
/obj/effect/mob_spawn/human/corpse/syndicatestormtrooper
name = "Syndicate Stormtrooper"
- id_job = "Operative"
hairstyle = "Bald"
facial_hairstyle = "Shaved"
outfit = /datum/outfit/syndicatestormtroopercorpse
@@ -63,8 +62,8 @@
ears = /obj/item/radio/headset
mask = /obj/item/clothing/mask/gas/syndicate
back = /obj/item/tank/jetpack/oxygen/harness
- id = /obj/item/card/id/syndicate
-
+ id = /obj/item/card/id/advanced/chameleon
+ id_trim = /datum/id_trim/chameleon/operative
/obj/effect/mob_spawn/human/clown/corpse
roundstart = FALSE
@@ -167,8 +166,6 @@
/obj/effect/mob_spawn/human/corpse/nanotrasensoldier
name = "\improper Nanotrasen Private Security Officer"
- id_job = "Private Security Force"
- id_access = "Security Officer"
outfit = /datum/outfit/nanotrasensoldiercorpse2
hairstyle = "Bald"
facial_hairstyle = "Shaved"
@@ -183,12 +180,11 @@
mask = /obj/item/clothing/mask/gas/sechailer/swat
head = /obj/item/clothing/head/helmet/swat/nanotrasen
back = /obj/item/storage/backpack/security
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced/centcom
+ id_trim = /datum/id_trim/centcom/corpse/private_security/tradepost_officer
/obj/effect/mob_spawn/human/corpse/nanotrasenassaultsoldier
name = "Nanotrasen Private Security Officer"
- id_job = "Nanotrasen Assault Force"
- id_access = "Security Officer"
outfit = /datum/outfit/nanotrasenassaultsoldiercorpse
hairstyle = "Bald"
facial_hairstyle = "Shaved"
@@ -203,12 +199,11 @@
mask = /obj/item/clothing/mask/gas/sechailer/swat
head = /obj/item/clothing/head/helmet/swat/nanotrasen
back = /obj/item/storage/backpack/security
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced/centcom
+ id_trim = /datum/id_trim/centcom/corpse/assault
/obj/effect/mob_spawn/human/corpse/cat_butcher
name = "The Cat Surgeon"
- id_job = "Cat Surgeon"
- id_access_list = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_MAINT)
hairstyle = "Cut Hair"
facial_hairstyle = "Watson Mustache"
skin_tone = "caucasian1"
@@ -222,8 +217,9 @@
gloves = /obj/item/clothing/gloves/color/latex/nitrile
ears = /obj/item/radio/headset
back = /obj/item/storage/backpack/satchel/med
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
glasses = /obj/item/clothing/glasses/hud/health
+ id_trim = /datum/id_trim/away/cat_surgeon
/obj/effect/mob_spawn/human/corpse/bee_terrorist
name = "BLF Operative"
@@ -237,6 +233,6 @@
gloves = /obj/item/clothing/gloves/color/yellow
ears = /obj/item/radio/headset
belt = /obj/item/storage/belt/fannypack/yellow/bee_terrorist
- id = /obj/item/card/id
+ id = /obj/item/card/id/advanced
l_pocket = /obj/item/paper/fluff/bee_objectives
mask = /obj/item/clothing/mask/animal/rat/bee
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
index 693b5e86078..3dc85a604f0 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
@@ -125,9 +125,11 @@
/mob/living/simple_animal/drone/Initialize()
. = ..()
GLOB.drones_list += src
- access_card = new /obj/item/card/id(src)
- var/datum/job/captain/C = new /datum/job/captain
- access_card.access = C.get_access()
+ access_card = new /obj/item/card/id/advanced/simple_bot(src)
+
+ // Doing this hurts my soul, but simple_animal access reworks are for another day.
+ var/datum/id_trim/job/cap_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/captain]
+ access_card.add_access(cap_trim.access + cap_trim.wildcard_access)
if(default_storage)
var/obj/item/I = new default_storage(src)
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
index 4e2d30f2bd1..5719ae251e3 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
@@ -371,7 +371,6 @@
r_pocket = /obj/item/tank/internals/emergency_oxygen
mask = /obj/item/clothing/mask/breath
if("Operative")
- id_job = "Operative"
outfit = /datum/outfit/syndicatecommandocorpse
if("Shadow")
mob_species = /datum/species/shadow
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index d110e613f58..495e271e82a 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1128,6 +1128,7 @@
if(ID.registered_name == oldname)
ID.registered_name = newname
ID.update_label()
+ ID.update_icon()
if(ID.registered_account?.account_holder == oldname)
ID.registered_account.account_holder = newname
if(!search_pda)
diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm
index fc289de56c7..481e866f7a5 100644
--- a/code/modules/modular_computers/computers/item/computer.dm
+++ b/code/modules/modular_computers/computers/item/computer.dm
@@ -97,14 +97,60 @@
/obj/item/modular_computer/GetID()
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
- if(card_slot)
- return card_slot.GetID()
+ var/obj/item/computer_hardware/card_slot/card_slot2 = all_components[MC_CARD2]
+
+ var/obj/item/card/id/first_id = card_slot?.GetID()
+ var/obj/item/card/id/second_id = card_slot2?.GetID()
+
+ // We have two IDs, pick the one with the most command accesses, preferring the primary slot.
+ if(first_id && second_id)
+ var/first_id_tally = SSid_access.tally_access(first_id, ACCESS_FLAG_COMMAND)
+ var/second_id_tally = SSid_access.tally_access(second_id, ACCESS_FLAG_COMMAND)
+
+ return (first_id_tally >= second_id_tally) ? first_id : second_id
+
+ // If we don't have both ID slots filled, pick the one that is filled.
+ if(first_id)
+ return first_id
+ if(second_id)
+ return second_id
+
+ // Otherwise, we have no ID at all.
return ..()
+/obj/item/modular_computer/get_id_examine_strings(mob/user)
+ . = ..()
+
+ var/obj/item/computer_hardware/card_slot/card_slot2 = all_components[MC_CARD2]
+ var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
+
+ var/obj/item/card/id/id_card1 = card_slot?.GetID()
+ var/obj/item/card/id/id_card2 = card_slot2?.GetID()
+
+ if(id_card1 || id_card2)
+ if(id_card1 && id_card2)
+ . += "\The [src] is displaying [id_card1] and [id_card2]."
+ var/list/id_icons = list()
+ id_icons += id_card1.get_id_examine_strings(user)
+ id_icons += id_card2.get_id_examine_strings(user)
+ . += id_icons.Join(" ")
+ else if(id_card1)
+ . += "\The [src] is displaying [id_card1]."
+ . += id_card1.get_id_examine_strings(user)
+ else
+ . += "\The [src] is displaying [id_card2]."
+ . += id_card2.get_id_examine_strings(user)
+
/obj/item/modular_computer/RemoveID()
var/obj/item/computer_hardware/card_slot/card_slot2 = all_components[MC_CARD2]
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
- return (card_slot2?.try_eject() || card_slot?.try_eject()) //Try the secondary one first.
+
+ var/removed_id = (card_slot2?.try_eject() || card_slot?.try_eject())
+ if(removed_id)
+ update_slot_icon()
+ return removed_id
+
+ return ..()
/obj/item/modular_computer/InsertID(obj/item/inserting_item)
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
@@ -117,7 +163,9 @@
return FALSE
if((card_slot?.try_insert(inserting_id)) || (card_slot2?.try_insert(inserting_id)))
+ update_slot_icon()
return TRUE
+
return FALSE
/obj/item/modular_computer/MouseDrop(obj/over_object, src_location, over_location)
diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm
index 8bc3db57576..8aba016aa38 100644
--- a/code/modules/modular_computers/file_system/programs/card.dm
+++ b/code/modules/modular_computers/file_system/programs/card.dm
@@ -1,11 +1,3 @@
-#define CARDCON_DEPARTMENT_SERVICE "Service"
-#define CARDCON_DEPARTMENT_SECURITY "Security"
-#define CARDCON_DEPARTMENT_MEDICAL "Medical"
-#define CARDCON_DEPARTMENT_SUPPLY "Supply"
-#define CARDCON_DEPARTMENT_SCIENCE "Science"
-#define CARDCON_DEPARTMENT_ENGINEERING "Engineering"
-#define CARDCON_DEPARTMENT_COMMAND "Command"
-
/datum/computer_file/program/card_mod
filename = "plexagonidwriter"
filedesc = "Plexagon Access Management"
@@ -18,78 +10,67 @@
tgui_id = "NtosCard"
program_icon = "id-card"
+ /// If TRUE, this program only modifies Centcom accesses.
var/is_centcom = FALSE
+ /// If TRUE, this program is authenticated with limited departmental access.
var/minor = FALSE
- var/authenticated = FALSE
- var/list/region_access
- var/list/head_subordinates
- ///Which departments this computer has access to. Defined as access regions. null = all departments
+ /// The name/assignment combo of the ID card used to authenticate.
+ var/authenticated_user
+ /// The regions this program has access to based on the authenticated ID.
+ var/list/region_access = list()
+ /// List of subordinate jobs for head roles on the authenticated ID.
+ var/list/head_subordinates = list()
+ /// List of job templates that can be applied to ID cards from this program.
+ var/list/job_templates = list()
+ /// Which departments this program has access to. See region defines.
var/target_dept
- //For some reason everything was exploding if this was static.
- var/list/sub_managers
-
-/datum/computer_file/program/card_mod/New(obj/item/modular_computer/comp)
- . = ..()
- sub_managers = list(
- "[ACCESS_HOP]" = list(
- "department" = list(CARDCON_DEPARTMENT_SERVICE, CARDCON_DEPARTMENT_COMMAND),
- "region" = 1,
- "head" = "Head of Personnel"
- ),
- "[ACCESS_HOS]" = list(
- "department" = CARDCON_DEPARTMENT_SECURITY,
- "region" = 2,
- "head" = "Head of Security"
- ),
- "[ACCESS_CMO]" = list(
- "department" = CARDCON_DEPARTMENT_MEDICAL,
- "region" = 3,
- "head" = "Chief Medical Officer"
- ),
- "[ACCESS_RD]" = list(
- "department" = CARDCON_DEPARTMENT_SCIENCE,
- "region" = 4,
- "head" = "Research Director"
- ),
- "[ACCESS_CE]" = list(
- "department" = CARDCON_DEPARTMENT_ENGINEERING,
- "region" = 5,
- "head" = "Chief Engineer"
- )
- )
-
+/**
+ * Authenticates the program based on the specific ID card.
+ *
+ * If the card has ACCESS_CHANGE_IDs, it authenticates with all options.
+ * Otherwise, it authenticates depending on SSid_access.sub_department_managers_tgui
+ * compared to the access on the supplied ID card.
+ * Arguments:
+ * * user - Program's user.
+ * * id_card - The ID card to attempt to authenticate under.
+ */
/datum/computer_file/program/card_mod/proc/authenticate(mob/user, obj/item/card/id/id_card)
if(!id_card)
return
- region_access = list()
+ region_access.Cut()
+ // If the console isn't locked to a specific department and we have ACCESS_CHANGE_IDS in our auth card, we're not minor.
if(!target_dept && (ACCESS_CHANGE_IDS in id_card.access))
minor = FALSE
- authenticated = TRUE
+ authenticated_user = "[id_card.name]"
+ job_templates = SSid_access.station_job_templates.Copy()
update_static_data(user)
return TRUE
+ // Otherwise, we're minor and now we have to build a list of restricted departments we can change access for.
+ job_templates.Cut()
var/list/head_types = list()
- for(var/access_text in sub_managers)
- var/list/info = sub_managers[access_text]
- var/access = text2num(access_text)
- if((access in id_card.access) && ((info["region"] in target_dept) || !length(target_dept)))
- region_access += info["region"]
- //I don't even know what I'm doing anymore
- head_types += info["head"]
+ var/list/managers = SSid_access.sub_department_managers_tgui
+ for(var/access_as_text in managers)
+ var/list/info = managers[access_as_text]
+ var/access = text2num(access_as_text)
+ if((access in id_card.access) && ((target_dept in info["regions"]) || !target_dept))
+ region_access |= info["regions"]
+ head_types |= info["head"]
+ job_templates |= info["templates"]
- head_subordinates = list()
+ head_subordinates.Cut()
if(length(head_types))
- for(var/j in SSjob.occupations)
- var/datum/job/job = j
- for(var/head in head_types)//god why
+ for(var/occupation in SSjob.occupations)
+ var/datum/job/job = occupation
+ for(var/head in head_types)
if(head in job.department_head)
head_subordinates += job.title
if(length(region_access))
minor = TRUE
- authenticated = TRUE
+ authenticated_user = "[id_card.name] \[LIMITED ACCESS\]"
update_static_data(user)
return TRUE
@@ -112,26 +93,28 @@
var/mob/user = usr
var/obj/item/card/id/user_id_card = card_slot.stored_card
-
var/obj/item/card/id/target_id_card = card_slot2.stored_card
switch(action)
+ // Log in.
if("PRG_authenticate")
if(!computer || !user_id_card)
playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
- return
+ return TRUE
if(authenticate(user, user_id_card))
playsound(computer, 'sound/machines/terminal_on.ogg', 50, FALSE)
return TRUE
+ // Log out.
if("PRG_logout")
- authenticated = FALSE
+ authenticated_user = null
playsound(computer, 'sound/machines/terminal_off.ogg', 50, FALSE)
return TRUE
+ // Print a report.
if("PRG_print")
if(!computer || !printer)
- return
- if(!authenticated)
- return
+ return TRUE
+ if(!authenticated_user)
+ return TRUE
var/contents = {"
Access Report
Prepared By: [user_id_card?.registered_name ? user_id_card.registered_name : "Unknown"] For: [target_id_card.registered_name ? target_id_card.registered_name : "Unregistered"]
@@ -140,21 +123,32 @@
Access:
"}
- var/known_access_rights = get_all_accesses()
+ var/list/known_access_rights = SSid_access.get_region_access_list(list(REGION_ALL_STATION))
for(var/A in target_id_card.access)
if(A in known_access_rights)
- contents += " [get_access_desc(A)]"
+ contents += " [SSid_access.get_access_desc(A)]"
if(!printer.print_text(contents,"access report"))
to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.")
- return
+ return TRUE
else
playsound(computer, 'sound/machines/terminal_on.ogg', 50, FALSE)
computer.visible_message("\The [computer] prints out a paper.")
return TRUE
- if("PRG_eject")
+ // Eject the ID used to log on to the ID app.
+ if("PRG_ejectauthid")
+ if(!computer || !card_slot)
+ return TRUE
+ if(user_id_card)
+ return card_slot.try_eject(user)
+ else
+ var/obj/item/I = user.get_active_held_item()
+ if(istype(I, /obj/item/card/id))
+ return card_slot.try_insert(I, user)
+ // Eject the ID being modified.
+ if("PRG_ejectmodid")
if(!computer || !card_slot2)
- return
+ return TRUE
if(target_id_card)
GLOB.data_core.manifest_modify(target_id_card.registered_name, target_id_card.assignment)
return card_slot2.try_eject(user)
@@ -162,156 +156,113 @@
var/obj/item/I = user.get_active_held_item()
if(istype(I, /obj/item/card/id))
return card_slot2.try_insert(I, user)
- return FALSE
+ return TRUE
+ // Used to fire someone. Wipes all access from their card and modifies their assignment.
if("PRG_terminate")
- if(!computer || !authenticated)
- return
+ if(!computer || !authenticated_user)
+ return TRUE
if(minor)
- if(!(target_id_card.assignment in head_subordinates) && target_id_card.assignment != "Assistant")
- return
+ if(!(target_id_card.trim?.assignment in head_subordinates) && target_id_card.trim?.assignment != "Assistant")
+ to_chat(usr, "Software error: You do not have the necessary permissions to demote this card.")
+ return TRUE
+
+ // Set the new assignment then remove the trim.
+ target_id_card.assignment = "Demoted"
+ SSid_access.remove_trim_from_card(target_id_card)
- target_id_card.access -= get_all_centcom_access() + get_all_accesses()
- target_id_card.assignment = "Unassigned"
- target_id_card.update_label()
playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
return TRUE
+ // Change ID card assigned name.
if("PRG_edit")
- if(!computer || !authenticated || !target_id_card)
- return
+ if(!computer || !authenticated_user || !target_id_card)
+ return TRUE
+
+ var/old_name = target_id_card.registered_name
// Sanitize the name first. We're not using the full sanitize_name proc as ID cards can have a wider variety of things on them that
// would not pass as a formal character name, but would still be valid on an ID card created by a player.
var/new_name = sanitize(params["name"])
+
+ if(!new_name)
+ target_id_card.registered_name = null
+ playsound(computer, "terminal_type", 50, FALSE)
+ target_id_card.update_label()
+ // We had a name before and now we have no name, so this will unassign the card and we update the icon.
+ if(old_name)
+ target_id_card.update_icon()
+ return TRUE
+
// However, we are going to reject bad names overall including names with invalid characters in them, while allowing numbers.
new_name = reject_bad_name(new_name, allow_numbers = TRUE)
if(!new_name)
to_chat(usr, "Software error: The ID card rejected the new name as it contains prohibited characters.")
- return
+ return TRUE
target_id_card.registered_name = new_name
- target_id_card.update_label()
playsound(computer, "terminal_type", 50, FALSE)
+ target_id_card.update_label()
+ // Card wasn't assigned before and now it is, so update the icon accordingly.
+ if(!old_name)
+ target_id_card.update_icon()
return TRUE
+ // Change age
if("PRG_age")
- if(!computer || !authenticated || !target_id_card)
- return
+ if(!computer || !authenticated_user || !target_id_card)
+ return TRUE
target_id_card.registered_age = params["id_age"]
playsound(computer, "terminal_type", 50, FALSE)
return TRUE
+ // Change assignment
if("PRG_assign")
- if(!computer || !authenticated || !target_id_card)
- return
- var/target = params["assign_target"]
- if(!target)
- return
-
- if(target == "Custom")
- // Sanitize the custom assignment name first.
- var/custom_name = sanitize(params["custom_name"])
- // However, we are going to assignments containing bad text overall.
- custom_name = reject_bad_text(custom_name)
-
- if(!custom_name)
- to_chat(usr, "Software error: The ID card rejected the new custom assignment as it contains prohibited characters.")
- else
- target_id_card.assignment = custom_name
- target_id_card.update_label()
- else
- if(minor && !(target in head_subordinates))
- return
- var/list/new_access = list()
- if(is_centcom)
- new_access = get_centcom_access(target)
- else
- var/datum/job/job
- for(var/jobtype in subtypesof(/datum/job))
- var/datum/job/J = new jobtype
- if(J.title == target)
- job = J
- break
- if(!job)
- to_chat(user, "No class exists for this job: [target]")
- return
- new_access = job.get_access()
- for(var/logged_access in ACCESS_ALERT_ADMINS)
- if(logged_access in new_access)
- message_admins("[ADMIN_LOOKUPFLW(user)] assigned the job [job.title] to an ID card [ADMIN_VV(target_id_card)] [(target_id_card.registered_name) ? "belonging to [target_id_card.registered_name]." : "with no registered name."]")
- break
- LOG_ID_ACCESS_CHANGE(usr, target_id_card, "assigned the job [job.title]")
- target_id_card.access -= get_all_centcom_access() + get_all_accesses()
- target_id_card.access |= new_access
- target_id_card.assignment = target
- target_id_card.update_label()
- playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
- return TRUE
- if("PRG_access")
- if(!computer || !authenticated)
- return
- var/access_type = text2num(params["access_target"])
- if(access_type in (is_centcom ? get_all_centcom_access() : get_all_accesses()))
- if(access_type in target_id_card.access)
- target_id_card.access -= access_type
- else
- target_id_card.access |= access_type
- if(access_type in ACCESS_ALERT_ADMINS)
- message_admins("[ADMIN_LOOKUPFLW(user)] just added [get_access_desc(access_type)] to an ID card [ADMIN_VV(target_id_card)] [(target_id_card.registered_name) ? "belonging to [target_id_card.registered_name]." : "with no registered name."]")
- LOG_ID_ACCESS_CHANGE(user, target_id_card, "added [get_access_desc(access_type)]")
- playsound(computer, "terminal_type", 50, FALSE)
+ if(!computer || !authenticated_user || !target_id_card)
return TRUE
- if("PRG_grantall")
- if(!computer || !authenticated || minor)
- return
- target_id_card.access |= (is_centcom ? get_all_centcom_access() : get_all_accesses())
-
- message_admins("[ADMIN_LOOKUPFLW(user)] just added All Access to an ID card [ADMIN_VV(target_id_card)] [(target_id_card.registered_name) ? "belonging to [target_id_card.registered_name]." : "with no registered name."]")
- LOG_ID_ACCESS_CHANGE(user, target_id_card, "added All Access")
-
- playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
+ target_id_card.assignment = params["assignment"]
+ playsound(computer, "terminal_type", 50, FALSE)
+ target_id_card.update_label()
return TRUE
- if("PRG_denyall")
- if(!computer || !authenticated || minor)
- return
- target_id_card.access.Cut()
- playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
+ // Add/remove access.
+ if("PRG_access")
+ if(!computer || !authenticated_user || !target_id_card)
+ return TRUE
+ playsound(computer, "terminal_type", 50, FALSE)
+ var/access_type = params["access_target"]
+ var/try_wildcard = params["access_wildcard"]
+ if(access_type in (is_centcom ? SSid_access.get_region_access_list(list(REGION_CENTCOM)) : SSid_access.get_region_access_list(list(REGION_ALL_STATION))))
+ if(access_type in target_id_card.access)
+ target_id_card.remove_access(list(access_type))
+ LOG_ID_ACCESS_CHANGE(user, target_id_card, "removed [SSid_access.get_access_desc(access_type)]")
+ return TRUE
+
+ if(!target_id_card.add_access(list(access_type), try_wildcard))
+ to_chat(usr, "ID error: ID card rejected your attempted access modification.")
+ LOG_ID_ACCESS_CHANGE(user, target_id_card, "failed to add [SSid_access.get_access_desc(access_type)][try_wildcard ? " with wildcard [try_wildcard]" : ""]")
+ return TRUE
+
+ if(access_type in ACCESS_ALERT_ADMINS)
+ message_admins("[ADMIN_LOOKUPFLW(user)] just added [SSid_access.get_access_desc(access_type)] to an ID card [ADMIN_VV(target_id_card)] [(target_id_card.registered_name) ? "belonging to [target_id_card.registered_name]." : "with no registered name."]")
+ LOG_ID_ACCESS_CHANGE(user, target_id_card, "added [SSid_access.get_access_desc(access_type)]")
return TRUE
- if("PRG_grantregion")
- if(!computer || !authenticated)
- return
- var/region = text2num(params["region"])
- if(isnull(region))
- return
+ // Apply template to ID card.
+ if("PRG_template")
+ if(!computer || !authenticated_user || !target_id_card)
+ return TRUE
- if(is_centcom)
- target_id_card.access |= get_all_centcom_access()
- message_admins("[ADMIN_LOOKUPFLW(user)] just added CentCom Access to an ID card [ADMIN_VV(target_id_card)] [(target_id_card.registered_name) ? "belonging to [target_id_card.registered_name]." : "with no registered name."]")
- LOG_ID_ACCESS_CHANGE(user, target_id_card, "added CentCom access")
- else
- var/list/region_accesses = get_region_accesses(region)
- target_id_card.access |= region_accesses
+ playsound(computer, "terminal_type", 50, FALSE)
+ var/template_name = params["name"]
- for(var/logged_access in ACCESS_ALERT_ADMINS)
- if(logged_access in region_accesses)
- message_admins("[ADMIN_LOOKUPFLW(user)] just added [get_region_accesses_name(region)] region access to an ID card [ADMIN_VV(target_id_card)] [(target_id_card.registered_name) ? "belonging to [target_id_card.registered_name]." : "with no registered name."]")
+ if(!template_name)
+ return TRUE
- LOG_ID_ACCESS_CHANGE(user, target_id_card, "added [get_region_accesses_name(region)] region access")
+ for(var/trim_path in job_templates)
+ var/datum/id_trim/trim = SSid_access.trim_singletons_by_path[trim_path]
+ if(trim.assignment != template_name)
+ continue
+ SSid_access.add_trim_access_to_card(target_id_card, trim_path)
+ return TRUE
- playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
return TRUE
- if("PRG_denyregion")
- if(!computer || !authenticated)
- return
- var/region = text2num(params["region"])
- if(isnull(region))
- return
- if(is_centcom)
- target_id_card.access -= get_all_centcom_access()
- target_id_card.access -= get_region_accesses(region)
- playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
- return TRUE
-
-
/datum/computer_file/program/card_mod/ui_static_data(mob/user)
var/list/data = list()
@@ -319,69 +270,25 @@
data["centcom_access"] = is_centcom
data["minor"] = target_dept || minor ? TRUE : FALSE
- var/list/departments = target_dept
- if(is_centcom)
- departments = list("CentCom" = get_all_centcom_jobs())
- else if(isnull(departments))
- departments = list(
- CARDCON_DEPARTMENT_COMMAND = list("Captain"),//lol
- CARDCON_DEPARTMENT_ENGINEERING = GLOB.engineering_positions,
- CARDCON_DEPARTMENT_MEDICAL = GLOB.medical_positions,
- CARDCON_DEPARTMENT_SCIENCE = GLOB.science_positions,
- CARDCON_DEPARTMENT_SECURITY = GLOB.security_positions,
- CARDCON_DEPARTMENT_SUPPLY = GLOB.supply_positions,
- CARDCON_DEPARTMENT_SERVICE = GLOB.service_positions
- )
- data["jobs"] = list()
- for(var/department in departments)
- var/list/job_list = departments[department]
- var/list/department_jobs = list()
- for(var/job in job_list)
- if(minor && !(job in head_subordinates))
- continue
- department_jobs += list(list(
- "display_name" = replacetext(job, " ", " "),
- "job" = job
- ))
- if(length(department_jobs))
- data["jobs"][department] = department_jobs
-
var/list/regions = list()
+ var/list/tgui_region_data = SSid_access.all_region_access_tgui
if(is_centcom)
- var/list/accesses = list()
- for(var/access in get_all_centcom_access())
- if (get_centcom_access_desc(access))
- accesses += list(list(
- "desc" = replacetext(get_centcom_access_desc(access), " ", " "),
- "ref" = access,
- ))
-
- regions += list(list(
- "name" = "CentCom",
- "regid" = 0,
- "accesses" = accesses
- ))
+ regions += list(tgui_region_data[REGION_CENTCOM])
else
- for(var/i in 1 to 7)
- if((minor || target_dept) && !(i in region_access))
+ for(var/region in SSid_access.station_regions)
+ if((minor || target_dept) && !(region in region_access))
continue
-
- var/list/accesses = list()
- for(var/access in get_region_accesses(i))
- if (get_access_desc(access))
- accesses += list(list(
- "desc" = replacetext(get_access_desc(access), " ", " "),
- "ref" = access,
- ))
-
- regions += list(list(
- "name" = get_region_accesses_name(i),
- "regid" = i,
- "accesses" = accesses
- ))
+ regions += tgui_region_data[region]
data["regions"] = regions
+
+ data["accessFlags"] = SSid_access.flags_by_access
+ data["wildcardFlags"] = SSid_access.wildcard_flags_by_wildcard
+ data["accessFlagNames"] = SSid_access.access_flag_string_by_flag
+ data["showBasic"] = TRUE
+ data["templates"] = job_templates
+
return data
/datum/computer_file/program/card_mod/ui_data(mob/user)
@@ -389,22 +296,29 @@
data["station_name"] = station_name()
+ var/obj/item/computer_hardware/card_slot/card_slot
var/obj/item/computer_hardware/card_slot/card_slot2
var/obj/item/computer_hardware/printer/printer
if(computer)
+ card_slot = computer.all_components[MC_CARD]
card_slot2 = computer.all_components[MC_CARD2]
printer = computer.all_components[MC_PRINT]
+ data["have_auth_card"] = !!(card_slot)
data["have_id_slot"] = !!(card_slot2)
data["have_printer"] = !!(printer)
else
data["have_id_slot"] = FALSE
data["have_printer"] = FALSE
- data["authenticated"] = authenticated
if(!card_slot2)
return data //We're just gonna error out on the js side at this point anyway
+ var/obj/item/card/id/auth_card = card_slot.stored_card
+ data["authIDName"] = auth_card ? auth_card.name : "-----"
+
+ data["authenticatedUser"] = authenticated_user
+
var/obj/item/card/id/id_card = card_slot2.stored_card
data["has_id"] = !!id_card
data["id_name"] = id_card ? id_card.name : "-----"
@@ -412,16 +326,17 @@
data["id_rank"] = id_card.assignment ? id_card.assignment : "Unassigned"
data["id_owner"] = id_card.registered_name ? id_card.registered_name : "-----"
data["access_on_card"] = id_card.access
+ data["wildcardSlots"] = id_card.wildcard_slots
data["id_age"] = id_card.registered_age
+ if(id_card.trim)
+ var/datum/id_trim/card_trim = id_card.trim
+ data["hasTrim"] = TRUE
+ data["trimAssignment"] = card_trim.assignment ? card_trim.assignment : ""
+ data["trimAccess"] = card_trim.access ? card_trim.access : list()
+ else
+ data["hasTrim"] = FALSE
+ data["trimAssignment"] = ""
+ data["trimAccess"] = list()
+
return data
-
-
-
-#undef CARDCON_DEPARTMENT_SERVICE
-#undef CARDCON_DEPARTMENT_SECURITY
-#undef CARDCON_DEPARTMENT_MEDICAL
-#undef CARDCON_DEPARTMENT_SCIENCE
-#undef CARDCON_DEPARTMENT_SUPPLY
-#undef CARDCON_DEPARTMENT_ENGINEERING
-#undef CARDCON_DEPARTMENT_COMMAND
diff --git a/code/modules/modular_computers/hardware/card_slot.dm b/code/modules/modular_computers/hardware/card_slot.dm
index db5a660a2e6..725b0128ca5 100644
--- a/code/modules/modular_computers/hardware/card_slot.dm
+++ b/code/modules/modular_computers/hardware/card_slot.dm
@@ -65,6 +65,8 @@
var/mob/living/carbon/human/H = user
H.sec_hud_set_ID()
+ holder.update_slot_icon()
+
return TRUE
@@ -86,11 +88,16 @@
for(var/p in holder.idle_threads)
var/datum/computer_file/program/computer_program = p
computer_program.event_idremoved(1)
+
+ holder.update_slot_icon()
+
if(ishuman(user))
var/mob/living/carbon/human/human_user = user
human_user.sec_hud_set_ID()
+
to_chat(user, "You remove the card from \the [src].")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
+
return TRUE
/obj/item/computer_hardware/card_slot/attackby(obj/item/I, mob/living/user)
diff --git a/code/modules/paperwork/handlabeler.dm b/code/modules/paperwork/handlabeler.dm
index 5f7974f4fe9..0618fe7173b 100644
--- a/code/modules/paperwork/handlabeler.dm
+++ b/code/modules/paperwork/handlabeler.dm
@@ -25,6 +25,7 @@
their_card.registered_name = user.real_name
their_card.update_label()
+ their_card.update_icon()
// NOT EVEN DEATH WILL TAKE AWAY THE STAIN
user.mind.name += " (suicide)"
diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm
index 15e6c109b34..e57f0ad81ec 100644
--- a/code/modules/research/designs/misc_designs.dm
+++ b/code/modules/research/designs/misc_designs.dm
@@ -288,11 +288,11 @@
/datum/design/id
name = "Identification Card"
- desc = "A card used to provide ID and determine access across the station."
+ desc = "A card used to provide ID and determine access across the station. Has an integrated digital display and advanced microchips."
id = "idcard"
build_type = PROTOLATHE
materials = list(/datum/material/iron=200, /datum/material/glass = 100)
- build_path = /obj/item/card/id
+ build_path = /obj/item/card/id/advanced
category = list("Electronics")
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 1789609da15..89dcfe3cda3 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -734,7 +734,9 @@
var/obj/item/implant/radio/syndicate/imp = new(src)
imp.implant(SM, user)
- SM.access_card = new /obj/item/card/id/syndicate(SM)
+ // Ugly as sin. Simble mob accesses are for another time.
+ SM.access_card = new /obj/item/card/id/advanced/chameleon(SM)
+ SSid_access.apply_trim_to_card(SM, /datum/id_trim/chameleon)
ADD_TRAIT(SM.access_card, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
/obj/item/slimepotion/transference
diff --git a/code/modules/ruins/lavaland_ruin_code.dm b/code/modules/ruins/lavaland_ruin_code.dm
index 6c88c523470..706117b1fed 100644
--- a/code/modules/ruins/lavaland_ruin_code.dm
+++ b/code/modules/ruins/lavaland_ruin_code.dm
@@ -133,8 +133,9 @@
ears = /obj/item/radio/headset/syndicate/alt
back = /obj/item/storage/backpack
r_pocket = /obj/item/gun/ballistic/automatic/pistol
- id = /obj/item/card/id/syndicate/anyone
+ id = /obj/item/card/id/advanced/chameleon
implants = list(/obj/item/implant/weapons_auth)
+ id_trim = /datum/id_trim/chameleon/operative
/datum/outfit/lavaland_syndicate/post_equip(mob/living/carbon/human/H)
H.faction |= ROLE_SYNDICATE
diff --git a/code/modules/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/ruins/spaceruin_code/hilbertshotel.dm
index d4aa0a748df..60632c71db1 100644
--- a/code/modules/ruins/spaceruin_code/hilbertshotel.dm
+++ b/code/modules/ruins/spaceruin_code/hilbertshotel.dm
@@ -496,15 +496,16 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
ghost_usable = FALSE
oxy_damage = 500
mob_species = /datum/species/skeleton
- id_job = "Head Researcher"
- id_access = ACCESS_RESEARCH
- id_access_list = list(ACCESS_AWAY_GENERIC3, ACCESS_RESEARCH)
instant = TRUE
- id = /obj/item/card/id/silver
+ outfit = /datum/outfit/doctorhilbert
+
+/datum/outfit/doctorhilbert
+ id = /obj/item/card/id/advanced/silver
uniform = /obj/item/clothing/under/rank/rnd/research_director/doctor_hilbert
shoes = /obj/item/clothing/shoes/sneakers/brown
back = /obj/item/storage/backpack/satchel/leather
suit = /obj/item/clothing/suit/toggle/labcoat
+ id_trim = /datum/id_trim/away/hilbert
/obj/item/paper/crumpled/docslogs
name = "Research Logs"
diff --git a/code/modules/shuttle/arrivals.dm b/code/modules/shuttle/arrivals.dm
index e0c982907d4..2da7802598b 100644
--- a/code/modules/shuttle/arrivals.dm
+++ b/code/modules/shuttle/arrivals.dm
@@ -194,6 +194,14 @@
while(mode != SHUTTLE_CALL && !damaged)
stoplag()
+/**
+ * Queues an announcement arrival.
+ *
+ * Arguments:
+ * * mob - The arriving mob.
+ * * rank - The job of the arriving mob.
+ * * announce_acting_captain - Bool. If TRUE, the arriving mob is also an acting captain.
+ */
/obj/docking_port/mobile/arrivals/proc/QueueAnnounce(mob, rank)
if(mode != SHUTTLE_CALL)
AnnounceArrival(mob, rank)
diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm
index 77b5a8dcd73..0ff61ce7a6e 100644
--- a/code/modules/shuttle/special.dm
+++ b/code/modules/shuttle/special.dm
@@ -144,7 +144,7 @@
/mob/living/simple_animal/drone/snowflake/bardrone/Initialize()
. = ..()
- access_card.access |= ACCESS_CENT_BAR
+ access_card.add_access(list(ACCESS_CENT_BAR))
become_area_sensitive(ROUNDSTART_TRAIT)
RegisterSignal(src, COMSIG_ENTER_AREA, .proc/check_barstaff_godmode)
check_barstaff_godmode()
@@ -161,10 +161,12 @@
/mob/living/simple_animal/hostile/alien/maid/barmaid/Initialize()
. = ..()
- access_card = new /obj/item/card/id(src)
- var/datum/job/captain/C = new /datum/job/captain
- access_card.access = C.get_access()
- access_card.access |= ACCESS_CENT_BAR
+ // Simple bot ID card that can hold all accesses. Someone turn access into a component at some point, please.
+ access_card = new /obj/item/card/id/advanced/simple_bot(src)
+
+ var/datum/id_trim/job/cap_trim = SSid_access.trim_singletons_by_path[/datum/id_trim/job/captain]
+ access_card.add_access(cap_trim.access + cap_trim.wildcard_access + list(ACCESS_CENT_BAR))
+
ADD_TRAIT(access_card, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
become_area_sensitive(ROUNDSTART_TRAIT)
RegisterSignal(src, COMSIG_ENTER_AREA, .proc/check_barstaff_godmode)
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index d774c37f3bb..fa571a281a3 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -1176,12 +1176,11 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
/datum/uplink_item/stealthy_tools/agent_card
name = "Agent Identification Card"
- desc = "Agent cards prevent artificial intelligences from tracking the wearer, and can copy access \
- from other identification cards. The access is cumulative, so scanning one card does not erase the \
- access gained from another. In addition, they can be forged to display a new assignment and name. \
+ desc = "Agent cards prevent artificial intelligences from tracking the wearer, and hold up to 5 wildcards \
+ from other identification cards. In addition, they can be forged to display a new assignment, name and trim. \
This can be done an unlimited amount of times. Some Syndicate areas and devices can only be accessed \
with these cards."
- item = /obj/item/card/id/syndicate
+ item = /obj/item/card/id/advanced/chameleon
cost = 2
/datum/uplink_item/stealthy_tools/ai_detector
diff --git a/code/modules/vehicles/mecha/mecha_topic.dm b/code/modules/vehicles/mecha/mecha_topic.dm
index d597875fd04..8a4604e1104 100644
--- a/code/modules/vehicles/mecha/mecha_topic.dm
+++ b/code/modules/vehicles/mecha/mecha_topic.dm
@@ -173,12 +173,12 @@