diff --git a/baystation12.dme b/baystation12.dme
index 8cf41e3f2c..a193100c89 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -643,6 +643,7 @@
#include "code\game\objects\items\weapons\autopsy.dm"
#include "code\game\objects\items\weapons\candle.dm"
#include "code\game\objects\items\weapons\cards_ids.dm"
+#include "code\game\objects\items\weapons\cards_ids_syndicate.dm"
#include "code\game\objects\items\weapons\cigs_lighters.dm"
#include "code\game\objects\items\weapons\clown_items.dm"
#include "code\game\objects\items\weapons\cosmetics.dm"
diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm
index 1ebb3e4f14..c8a7fc1919 100644
--- a/code/_helpers/lists.dm
+++ b/code/_helpers/lists.dm
@@ -619,10 +619,13 @@ datum/proc/dd_SortValue()
/datum/alarm/dd_SortValue()
return "[sanitize_old(last_name)]"
+/proc/subtypes(prototype)
+ return (typesof(prototype) - prototype)
+
//creates every subtype of prototype (excluding prototype) and adds it to list L.
//if no list/L is provided, one is created.
/proc/init_subtypes(prototype, list/L)
if(!istype(L)) L = list()
- for(var/path in (typesof(prototype) - prototype))
+ for(var/path in subtypes(prototype))
L += new path()
return L
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index 64101d4433..d4af940168 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -623,8 +623,8 @@
return min(..(), .)
-/obj/machinery/alarm/Topic(href, href_list, var/nowindow = 0, var/datum/topic_state/state)
- if(..(href, href_list, nowindow, state))
+/obj/machinery/alarm/Topic(href, href_list, var/datum/topic_state/state)
+ if(..(href, href_list, state))
return 1
// hrefs that can always be called -walter0o
diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm
index 8f048db043..65324f5555 100644
--- a/code/game/machinery/camera/tracking.dm
+++ b/code/game/machinery/camera/tracking.dm
@@ -155,6 +155,11 @@
if(!istype(target)) return
var/mob/living/silicon/ai/U = usr
+ if(target == U.cameraFollow)
+ return
+
+ if(U.cameraFollow)
+ U.ai_cancel_tracking()
U.cameraFollow = target
U << "Now tracking [target.name] on camera."
target.tracking_initiated()
@@ -240,7 +245,8 @@ mob/living/proc/near_camera()
/mob/living/carbon/human/tracking_status()
//Cameras can't track people wearing an agent card or a ninja hood.
- if(wear_id && istype(wear_id.GetID(), /obj/item/weapon/card/id/syndicate))
+ var/obj/item/weapon/card/id/id = GetIdCard(src)
+ if(id && id.prevent_tracking())
return TRACKING_TERMINATE
if(istype(head, /obj/item/clothing/head/helmet/space/rig))
var/obj/item/clothing/head/helmet/space/rig/helmet = head
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 12e4396a18..e8364950af 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -674,7 +674,7 @@ About the new airlock wires panel:
return ..()
-/obj/machinery/door/airlock/Topic(href, href_list, var/nowindow = 0)
+/obj/machinery/door/airlock/Topic(href, href_list)
if(..())
return 1
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index 74d3a4c52f..c2e7cbace7 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -236,7 +236,7 @@ var/list/turret_icons
return ..()
-/obj/machinery/porta_turret/Topic(href, href_list, var/nowindow = 0)
+/obj/machinery/porta_turret/Topic(href, href_list)
if(..())
return 1
diff --git a/code/game/machinery/turret_control.dm b/code/game/machinery/turret_control.dm
index 77667fa6bc..2ea1424522 100644
--- a/code/game/machinery/turret_control.dm
+++ b/code/game/machinery/turret_control.dm
@@ -139,7 +139,7 @@
ui.open()
ui.set_auto_update(1)
-/obj/machinery/turretid/Topic(href, href_list, var/nowindow = 0)
+/obj/machinery/turretid/Topic(href, href_list)
if(..())
return 1
diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm
index 6b239c6b07..577ee1010b 100644
--- a/code/game/objects/items/devices/aicard.dm
+++ b/code/game/objects/items/devices/aicard.dm
@@ -46,7 +46,7 @@
ui.open()
ui.set_auto_update(1)
-/obj/item/device/aicard/Topic(href, href_list, nowindow, state)
+/obj/item/device/aicard/Topic(href, href_list, state)
if(..())
return 1
diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm
index 8e2121384c..ae6bcbdf0c 100644
--- a/code/game/objects/items/weapons/cards_ids.dm
+++ b/code/game/objects/items/weapons/cards_ids.dm
@@ -104,7 +104,6 @@
var/sex = "\[UNSET\]"
var/icon/front
var/icon/side
- var/dat
//alt titles are handled a bit weirdly in order to unobtrusively integrate into existing ID system
var/assignment = null //can be alt title or the actual job
@@ -119,11 +118,14 @@
else
usr << "It is too far away."
+/obj/item/weapon/card/id/proc/prevent_tracking()
+ return 0
+
/obj/item/weapon/card/id/proc/show(mob/user as mob)
user << browse_rsc(front, "front.png")
user << browse_rsc(side, "side.png")
var/datum/browser/popup = new(user, "idcard", name, 600, 250)
- popup.set_content(dat)
+ popup.set_content(dat())
popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
@@ -147,7 +149,8 @@
set_id_photo(H)
update_name()
- dat = ("
")
+/obj/item/weapon/card/id/proc/dat()
+ var/dat = ("")
dat += text("Name: [] ", registered_name)
dat += text("Sex: [] \n", sex)
dat += text("Age: [] \n", age)
@@ -155,8 +158,10 @@
dat += text("Fingerprint: [] \n", fingerprint_hash)
dat += text("Blood Type: [] \n", blood_type)
dat += text("DNA Hash: []
\n", dna_hash)
- dat +=" | Photo:
\
-  | "
+ if(front && side)
+ dat +=" | Photo:
  | "
+ dat += "
"
+ return dat
/obj/item/weapon/card/id/attack_self(mob/user as mob)
user.visible_message("\The [user] shows you: \icon[src] [src.name]. The assignment on the card: [src.assignment]",\
diff --git a/code/game/objects/items/weapons/cards_ids_syndicate.dm b/code/game/objects/items/weapons/cards_ids_syndicate.dm
index 56af71c48b..2475c93534 100644
--- a/code/game/objects/items/weapons/cards_ids_syndicate.dm
+++ b/code/game/objects/items/weapons/cards_ids_syndicate.dm
@@ -3,9 +3,10 @@ var/global/list/syndicate_ids = list()
/obj/item/weapon/card/id/syndicate
name = "agent card"
assignment = "Agent"
- var/list/initial_access = list(access_maint_tunnels, access_syndicate, access_external_airlocks)
origin_tech = list(TECH_ILLEGAL = 3)
+ var/electronic_warfare = 1
var/registered_user = null
+ var/list/initial_access = list(access_maint_tunnels, access_syndicate, access_external_airlocks)
/obj/item/weapon/card/id/syndicate/New(mob/user as mob)
syndicate_ids += src
@@ -17,26 +18,31 @@ var/global/list/syndicate_ids = list()
registered_user = null
return ..()
+// On mob destruction, ensure any references are cleared
/mob/Destroy()
- // On mob destruction, ensure any references are cleared
for(var/obj/item/weapon/card/id/syndicate/SID in syndicate_ids)
- if(SID.registered_user = user)
- registered_user = null
+ if(SID.registered_user == src)
+ SID.registered_user = null
return ..()
+/obj/item/weapon/card/id/syndicate/prevent_tracking()
+ return electronic_warfare
+
/obj/item/weapon/card/id/syndicate/afterattack(var/obj/item/weapon/O as obj, mob/user as mob, proximity)
if(!proximity) return
if(istype(O, /obj/item/weapon/card/id))
var/obj/item/weapon/card/id/I = O
src.access |= I.access
if(player_is_antag(user))
- user << "\The [src]'s microscanners activate as you pass it over the ID, copying its access."
+ user << "The microscanner activate as you pass it over the ID, copying its access."
/obj/item/weapon/card/id/syndicate/attack_self(mob/user as mob)
if(!registered_user)
registered_user = user
+ set_owner_info(user)
+ user << "The microscanner marks you as its owner, preventing others some accessing its internals."
if(registered_user == user)
- switch(alert("Would you like edit the ID, or show it?","Edit","Show"))
+ switch(alert("Would you like edit the ID, or show it?","Show or Edit?", "Edit","Show"))
if("Edit")
ui_interact(user)
if("Show")
@@ -46,7 +52,19 @@ var/global/list/syndicate_ids = list()
/obj/item/weapon/card/id/syndicate/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/data[0]
- data["hide_breakers"] = hide_breakers
+ var/entries[0]
+ entries[++entries.len] = list("name" = "Age", "value" = age)
+ entries[++entries.len] = list("name" = "Appearance", "value" = "Set")
+ entries[++entries.len] = list("name" = "Assignment", "value" = assignment)
+ entries[++entries.len] = list("name" = "Blood Type", "value" = blood_type)
+ entries[++entries.len] = list("name" = "DNA Hash", "value" = dna_hash)
+ entries[++entries.len] = list("name" = "Fingerprint Hash", "value" = fingerprint_hash)
+ entries[++entries.len] = list("name" = "Name", "value" = registered_name)
+ entries[++entries.len] = list("name" = "Photo", "value" = "Update")
+ entries[++entries.len] = list("name" = "Sex", "value" = sex)
+ entries[++entries.len] = list("name" = "Factory Reset", "value" = "Use With Care")
+ data["electronic_warfare"] = electronic_warfare
+ data["entries"] = entries
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
@@ -59,9 +77,128 @@ var/global/list/syndicate_ids = list()
return STATUS_CLOSE
return ..()
-/obj/item/weapon/card/id/syndicate/Topic(href, href_list, var/nowindow = 0, var/datum/topic_state/state)
+/obj/item/weapon/card/id/syndicate/Topic(href, href_list, var/datum/topic_state/state)
if(..())
return 1
- update_uis(src)
- return 1
+ var/user = usr
+ if(href_list["electronic_warfare"])
+ electronic_warfare = text2num(href_list["electronic_warfare"])
+ user << "Electronic warfare [electronic_warfare ? "enabled" : "disabled"]."
+ else if(href_list["set"])
+ switch(href_list["set"])
+ if("Age")
+ var/new_age = input(user,"What age would you like to put on this card?","Agent Card Age", age) as null|num
+ if(!isnull(new_age) && CanUseTopic(user, state))
+ if(new_age < 0)
+ age = initial(age)
+ else
+ age = new_age
+ user << "Age has been set to '[age]'."
+ . = 1
+ if("Appearance")
+ var/datum/card_state/choice = input(user, "Select the appearance for this card.", "Agent Card Appearance") as null|anything in id_card_states()
+ if(choice && CanUseTopic(user, state))
+ src.icon_state = choice.icon_state
+ src.item_state = choice.item_state
+ usr << "Appearance changed to [choice]."
+ . = 1
+ if("Assignment")
+ var/new_job = sanitize(input(user,"What assignment would you like to put on this card?\nChanging assignment will not grant or remove any access levels.","Agent Card Assignment", assignment) as null|text)
+ if(!isnull(new_job) && CanUseTopic(user, state))
+ src.assignment = new_job
+ user << "Occupation changed to '[new_job]'."
+ update_name()
+ . = 1
+ if("Blood Type")
+ var/default = blood_type
+ if(default == initial(blood_type) && ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.dna)
+ default = H.dna.b_type
+ var/new_blood_type = sanitize(input(user,"What blood type would you like to be written on this card?","Agent Card Blood Type",default) as null|text)
+ if(!isnull(new_blood_type) && CanUseTopic(user, state))
+ src.blood_type = new_blood_type
+ user << "Blood type changed to '[new_blood_type]'."
+ . = 1
+ if("DNA Hash")
+ var/default = dna_hash
+ if(default == initial(dna_hash) && ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.dna)
+ default = H.dna.unique_enzymes
+ var/new_dna_hash = sanitize(input(user,"What DNA hash would you like to be written on this card?","Agent Card DNA Hash",default) as null|text)
+ if(!isnull(new_dna_hash) && CanUseTopic(user, state))
+ src.dna_hash = new_dna_hash
+ user << "DNA hash changed to '[new_dna_hash]'."
+ . = 1
+ if("Fingerprint Hash")
+ var/default = fingerprint_hash
+ if(default == initial(fingerprint_hash) && ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.dna)
+ default = md5(H.dna.uni_identity)
+ var/new_fingerprint_hash = sanitize(input(user,"What fingerprint hash would you like to be written on this card?","Agent Card Fingerprint Hash",default) as null|text)
+ if(!isnull(new_fingerprint_hash) && CanUseTopic(user, state))
+ src.fingerprint_hash = new_fingerprint_hash
+ user << "Fingerprint hash changed to '[new_fingerprint_hash]'."
+ . = 1
+ if("Name")
+ var/new_name = sanitizeName(input(user,"What name would you like to put on this card?","Agent Card Name", registered_name) as null|text)
+ if(!isnull(new_name) && CanUseTopic(user, state))
+ src.registered_name = new_name
+ update_name()
+ user << "Name changed to '[new_name]'."
+ . = 1
+ if("Photo")
+ set_id_photo(user)
+ user << "Photo changed."
+ . = 1
+ if("Sex")
+ var/new_sex = sanitize(input(user,"What sex would you like to put on this card?","Agent Card Sex", sex) as null|text)
+ if(!isnull(new_sex) && CanUseTopic(user, state))
+ src.sex = new_sex
+ user << "Sex changed to '[new_sex]'."
+ . = 1
+ if("Factory Reset")
+ if(alert("This will factory reset the card, including access and owner. Continue?", "Factory Reset", "No", "Yes") == "Yes" && CanUseTopic(user, state))
+ age = initial(age)
+ access = initial_access.Copy()
+ assignment = initial(assignment)
+ blood_type = initial(blood_type)
+ dna_hash = initial(dna_hash)
+ electronic_warfare = initial(electronic_warfare)
+ fingerprint_hash = initial(fingerprint_hash)
+ icon_state = initial(icon_state)
+ name = initial(name)
+ registered_name = initial(registered_name)
+ registered_user = null
+ sex = initial(sex)
+ user << "All information has been deleted from \the [src]."
+ . = 1
+
+ // Always update the UI, or buttons will spin indefinitely
+ nanomanager.update_uis(src)
+
+/var/global/list/id_card_states
+/proc/id_card_states()
+ if(!id_card_states)
+ id_card_states = list()
+ for(var/path in typesof(/obj/item/weapon/card/id))
+ var/obj/item/weapon/card/id/ID = path
+ var/datum/card_state/CS = new()
+ CS.icon_state = initial(ID.icon_state)
+ CS.item_state = initial(ID.item_state)
+ CS.name = initial(ID.name) + " - " + initial(ID.icon_state)
+ id_card_states += CS
+ id_card_states = dd_sortedObjectList(id_card_states)
+
+ return id_card_states
+
+/datum/card_state
+ var/name
+ var/icon_state
+ var/item_state
+
+/datum/card_state/dd_SortValue()
+ return name
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index cb3214122a..5289d69c40 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -19,9 +19,8 @@
nanomanager.close_uis(src)
return ..()
-/obj/Topic(href, href_list, var/nowindow = 0, var/datum/topic_state/state = default_state)
- // Calling Topic without a corresponding window open causes runtime errors
- if(!nowindow && ..())
+/obj/Topic(href, href_list, var/datum/topic_state/state = default_state)
+ if(usr && ..())
return 1
// In the far future no checks are made in an overriding Topic() beyond if(..()) return
@@ -146,4 +145,4 @@
return
/obj/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
- return
+ return
diff --git a/code/modules/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm
index 4486a0fb82..574d5d0931 100644
--- a/code/modules/nano/modules/human_appearance.dm
+++ b/code/modules/nano/modules/human_appearance.dm
@@ -17,7 +17,7 @@
src.whitelist = species_whitelist
src.blacklist = species_blacklist
-/datum/nano_module/appearance_changer/Topic(ref, href_list, var/nowindow, var/datum/topic_state/state = default_state)
+/datum/nano_module/appearance_changer/Topic(ref, href_list, var/datum/topic_state/state = default_state)
if(..())
return 1
diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm
index 9108f23e62..4c61718fff 100644
--- a/code/modules/nano/nanoui.dm
+++ b/code/modules/nano/nanoui.dm
@@ -479,7 +479,7 @@ nanoui is used to open and update nano browser uis
set_map_z_level(text2num(href_list["mapZLevel"]))
map_update = 1
- if ((src_object && src_object.Topic(href, href_list, 0, state)) || map_update)
+ if ((src_object && src_object.Topic(href, href_list, state)) || map_update)
nanomanager.update_uis(src_object) // update all UIs attached to src_object
/**
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index c1a42eeb8a..745ae88409 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -850,7 +850,7 @@
return 0
return 1
-/obj/machinery/power/apc/Topic(href, href_list, var/nowindow = 0)
+/obj/machinery/power/apc/Topic(href, href_list)
if(..())
return 1
diff --git a/nano/templates/agent_id_card.tmpl b/nano/templates/agent_id_card.tmpl
new file mode 100644
index 0000000000..f8be8a0934
--- /dev/null
+++ b/nano/templates/agent_id_card.tmpl
@@ -0,0 +1,21 @@
+
+{{:helper.syndicateMode()}}
+Available Entries
+
+{{for data.entries}}
+
+ | {{:helper.link('', 'gear', {'set' : value.name})}} | {{:value.name}} | {{:value.value}} |
+
+{{/for}}
+
+
+
+
+ | Electronic warfare: |
+ {{:helper.link('Enable', null, {'electronic_warfare' : 1}, data.electronic_warfare ? 'selected' : null)}} |
+ {{:helper.link('Disable',null, {'electronic_warfare' : 0}, data.electronic_warfare ? null : 'selected')}} |
+
+