diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 3e18e392a1..b3bffba7ff 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -317,6 +317,8 @@ var/global/list/##LIST_NAME = list();\
#define SPAN_OCCULT(X) "[X]"
+#define SPAN_GOOD(X) "[X]"
+
#define FONT_SMALL(X) "[X]"
#define FONT_NORMAL(X) "[X]"
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index df40972d86..610cdb202a 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -212,44 +212,37 @@ var/global/list/pre_init_created_atoms // atom creation ordering means some stuf
found += A.search_contents_for(path,filter_path)
return found
-//All atoms
-/atom/proc/examine(mob/user, var/infix = "", var/suffix = "")
- //This reformat names to get a/an properly working on item descriptions when they are bloody
+
+/atom/proc/examine(mob/user, infix = "", suffix = "")
var/f_name = "\a [src][infix]."
- if(src.blood_DNA && !istype(src, /obj/effect/decal))
- if(gender == PLURAL)
+ if (blood_DNA && !istype(src, /obj/effect/decal))
+ if (gender == PLURAL)
f_name = "some "
else
f_name = "a "
- if(blood_color != SYNTH_BLOOD_COLOUR)
+ if (blood_color != SYNTH_BLOOD_COLOUR)
f_name += "blood-stained [name][infix]!"
else
f_name += "oil-stained [name][infix]."
-
var/list/output = list("[bicon(src)] That's [f_name] [suffix]", desc)
-
- if(description_fluff || description_info)
- to_chat(user, span("notice", "This item has additional examine info. \[View\]"))
- if(description_antag && player_is_antag(user.mind))
- to_chat(user, span("notice", "This item has additional antag info. \[View\]"))
-
- if(user.client?.prefs.examine_text_mode == EXAMINE_MODE_INCLUDE_USAGE)
- output += description_info
-
- if(user.client?.prefs.examine_text_mode == EXAMINE_MODE_SWITCH_TO_PANEL)
- user.client.statpanel = "Examine" // Switch to stat panel
-
+ if (user.client?.prefs.examine_text_mode == EXAMINE_MODE_SWITCH_TO_PANEL)
+ user.client.statpanel = "Examine"
+ else if (user.client)
+ var/list/extras = list()
+ if (user.client.prefs.examine_text_mode == EXAMINE_MODE_INCLUDE_USAGE)
+ if (description_info)
+ output += description_info
+ else if (description_info)
+ extras += SPAN_NOTICE("usage")
+ if (description_fluff)
+ extras += SPAN_GOOD("lore")
+ if (description_antag && (isobserver(user) || player_is_antag(user.mind)))
+ extras += SPAN_WARNING("antag")
+ if (length(extras))
+ output += "Extra [english_list(extras)] information is available: [CreateAtomTopic(@"[Show Examine]", user, ATOM_TOPIC_EXAMINE)]"
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, output)
return output
-/atom/Topic(href,href_list[])
- . = ..()
- if (.)
- return
-
- switch(href_list["examine"])
- if("fluff")
- usr.client.statpanel = "Examine"
// Don't make these call bicon or anything, these are what bicon uses. They need to return an icon.
/atom/proc/examine_icon()
@@ -680,3 +673,70 @@ var/global/list/pre_init_created_atoms // atom creation ordering means some stuf
/atom/proc/get_visible_gender(mob/user, force)
return gender
+
+
+/**
+* Constructs an atom/Topic link for the callee.
+* label - The text content of the link.
+* user - The mob to verify is the source of this topic.
+* atom_act - The topic behavior key to actually trigger.
+* data - Extra params to send, if any. null, or params
+* text ";key=value;foo=bar", or a map ("key" = "value").
+* PREFER the map form for safety.
+*/
+/atom/proc/CreateAtomTopic(label, mob/user, atom_act, list/data)
+ if (!ismob(user) || !user.client)
+ return "(CreateAtomTopic: invalid user)"
+ if (!istext(atom_act) || !length(atom_act))
+ return "(CreateAtomTopic: invalid atom_act)"
+ var/params = ""
+ if (islist(data))
+ for (var/key in data)
+ params += ";[key]=[data[key]]"
+ else if (istext(data))
+ params = data
+ else if (!isnull(data))
+ return "(CreateAtomTopic: invalid data)"
+ return {"[label]"}
+
+
+/// The atom_act for the /atom/proc/AtomTopicExamine behavior.
+/atom/var/const/ATOM_TOPIC_EXAMINE = "examine"
+
+/// Called via atom/Topic. Sets the user's open statpanel to "Examine" if they have a client.
+/atom/proc/AtomTopicExamine(mob/user)
+ if (user.client)
+ user.client.statpanel = "Examine"
+
+
+/**
+* Receives Topic links from users. Generally, these should be
+* created using atom/CreateAtomTopic.
+* Expected keys:
+* "usr" - The ref of the user sending this topic. Validated
+* against the ref of usr.
+* "atom_act" - The behavior this topic expects to call.
+* atom/Topic permits arbitrary tail data so that complex
+* behavior may be implemented easily. This data can be
+* set easily through using CreateAtomTopic(..., list/data).
+* Return:
+* True if this topic is considered handled and should be
+* ignored by subtype implementations of Topic.
+*/
+/atom/Topic(href, list/query)
+ . = ..()
+ if (.)
+ return
+ var/atom_act = query["atom_act"]
+ if (!atom_act)
+ return
+ var/mob/user = usr
+ if (ref(user) != query["usr"])
+ return TRUE
+ switch (atom_act)
+ if (ATOM_TOPIC_EXAMINE)
+ AtomTopicExamine(user)
+ return TRUE
+ else
+ log_debug({"User [user] sent invalid atom_act "[atom_act]" in atom/Topic."})
+// NB: It is probably best to keep atom/Topic at the tail of this file.