Skip to content

Commit

Permalink
Merge pull request #8722 from Spookerton/spkrtn/sys/sstyping
Browse files Browse the repository at this point in the history
Adds SSTyping
  • Loading branch information
Atermonera authored Oct 2, 2022
2 parents f32c8de + 6385d90 commit b087dd0
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 106 deletions.
9 changes: 9 additions & 0 deletions code/__defines/appearance.dm
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
// Consider these images/atoms as part of the UI/HUD
#define APPEARANCE_UI_IGNORE_ALPHA RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA
#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR

/// The atom is not clickable
#define XMOUSE_OPACITY_NEVER 0

/// The atom is clickable normally
#define XMOUSE_OPACITY_DEFAULT 1

/// The atom steals clicks from other clickables
#define XMOUSE_OPACITY_ALWAYS 2
234 changes: 234 additions & 0 deletions code/controllers/subsystems/typing.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
SUBSYSTEM_DEF(typing)
name = "Typing"
flags = SS_BACKGROUND | SS_NO_INIT
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
wait = 0.5 SECONDS

/// The skin control to poll for TYPING_STATE_INPUT status.
var/const/INPUT_HANDLE = "mainwindow.input"

var/const/INFLIGHT_TIMEOUT = 5 SECONDS

/// The status entry index of the related client's typing indicator visibility preference.
var/const/INDEX_PREFERENCE = 1

/// The status entry index of the inflight state.
var/const/INDEX_INFLIGHT = 2

/// The status entry index of the timeout threshold.
var/const/INDEX_TIMEOUT = 3

/// The status entry index of the input bar typing state.
var/const/INDEX_INPUT_STATE = 4

/// The status entry index of the verb input typing state.
var/const/INDEX_VERB_STATE = 5

/// The highest index in a status entry.
var/const/MAX_INDEX = 5

/*
* A list of (ckey = list(
preference = 0|1,
inflight = 0|1,
timeout = num,
istyping_input = 0|1,
istyping_hotkey = 0|1
), ...)
See .proc/GetEntry for details.
*/
var/static/list/status = list()

/// Matches input bar verbs that should set TYPING_STATE_INPUT.
var/static/regex/match_verbs = regex("^(Me|Say) +\"?\\w+")

/// A list of clients waiting to be polled for input state.
var/static/list/client/queue = list()


/datum/controller/subsystem/typing/Recover()
status = list()
queue = list()


/datum/controller/subsystem/typing/fire(resumed, no_mc_tick)
if (!resumed)
queue = list()
for (var/client/client as anything in GLOB.clients)
queue += client
if (!length(queue))
return
var/cut_until = 1
var/list/entry
for (var/client/client as anything in queue)
++cut_until
if (QDELETED(client))
continue
entry = GetEntry(client)
if (!entry[INDEX_PREFERENCE])
continue
if (!entry[INDEX_INFLIGHT])
UpdateInputState(client, entry)
else if (world.time < entry[INDEX_TIMEOUT])
entry[INDEX_INFLIGHT] = FALSE
if (no_mc_tick)
CHECK_TICK
else if (MC_TICK_CHECK)
queue.Cut(1, cut_until)
return
queue.Cut()


/// Return, generating if necessary, a ckey-indexed list holding typing status.
/datum/controller/subsystem/typing/proc/GetEntry(client/client)
PRIVATE_PROC(TRUE)
var/ckey
if (istext(client))
ckey = client
else if (istype(client))
ckey = client.ckey
else
return
var/list/entry = status[ckey]
if (!entry)
entry = new (MAX_INDEX)
entry[INDEX_PREFERENCE] = client.is_preference_enabled(/datum/client_preference/show_typing_indicator)
entry[INDEX_INFLIGHT] = FALSE
entry[INDEX_TIMEOUT] = world.time
entry[INDEX_INPUT_STATE] = FALSE
entry[INDEX_VERB_STATE] = FALSE
status[ckey] = entry
return entry


/// Updates client's preference bool for whether typing indicators should be shown.
/datum/controller/subsystem/typing/proc/UpdatePreference(client/client, preference)
var/list/entry = GetEntry(client)
entry[INDEX_PREFERENCE] = preference
UpdateIndicator(client, entry)


/// Updates client|ckey's verb typing state to new_state.
/datum/controller/subsystem/typing/proc/UpdateVerbState(client/client, state)
var/list/entry = GetEntry(client)
entry[INDEX_VERB_STATE] = state
UpdateIndicator(client, entry)


/// Request client's input bar state using winget and updating entry accordingly.
/datum/controller/subsystem/typing/proc/UpdateInputState(client/client, list/entry)
PRIVATE_PROC(TRUE)
set waitfor = FALSE
var/timeout = world.time + INFLIGHT_TIMEOUT
entry[INDEX_INFLIGHT] = TRUE
entry[INDEX_TIMEOUT] = timeout
var/content = winget(client, INPUT_HANDLE, "text")
if (timeout != entry[INDEX_TIMEOUT]) // We're stale. Touch nothing.
return
entry[INDEX_INFLIGHT] = FALSE
if (QDELETED(client) || !isliving(client.mob))
return
entry[INDEX_INPUT_STATE] = match_verbs.Find(content) != 0
UpdateIndicator(client, entry)


/// Attempt to update the mob's typing state and indicator according to new state.
/datum/controller/subsystem/typing/proc/UpdateIndicator(client/client, list/entry)
PRIVATE_PROC(TRUE)
var/mob/target = client.mob
var/display = target.stat == CONSCIOUS && entry[INDEX_PREFERENCE] && (entry[INDEX_INPUT_STATE] || entry[INDEX_VERB_STATE])
if (display == target.is_typing)
return
if (display)
if (!target.typing_indicator)
target.typing_indicator = new (null, target)
target.typing_indicator.icon_state = "[target.speech_bubble_appearance()]_typing"
target.typing_indicator.pixel_y = target.icon_expected_height - 32
target.vis_contents += target.typing_indicator
target.is_typing = TRUE
if (target.shadow)
target.vis_contents += target.typing_indicator
else
if (target.typing_indicator)
target.vis_contents -= target.typing_indicator
target.is_typing = FALSE
if (target.shadow)
target.vis_contents -= target.typing_indicator


/atom/movable/typing_indicator
icon = 'icons/mob/talk.dmi'
icon_state = "typing"
plane = PLANE_LIGHTING_ABOVE
mouse_opacity = XMOUSE_OPACITY_NEVER
simulated = FALSE
anchored = TRUE

var/mob/owner


/atom/movable/typing_indicator/Destroy()
if (owner)
owner.vis_contents -= src
owner.typing_indicator = null
owner = null
return ..()


/atom/movable/typing_indicator/Initialize(mapload, mob/_owner)
. = ..()
if (!istype(_owner))
return INITIALIZE_HINT_QDEL
owner = _owner


/// If this mob is or was piloted by a player with typing indicators enabled, an instance of one.
/mob/var/atom/movable/typing_indicator/typing_indicator


/// Whether this mob is currently typing, if piloted by a player.
/mob/var/is_typing


/mob/Destroy()
QDEL_NULL(typing_indicator)
return ..()


/mob/Logout()
if (typing_indicator)
vis_contents -= typing_indicator
is_typing = FALSE
..()


/mob/verb/say_wrapper()
set name = ".Say"
set hidden = TRUE
SStyping.UpdateVerbState(client, TRUE)
var/message = input("","say (text)") as null | text
SStyping.UpdateVerbState(client, FALSE)
if (message)
say_verb(message)


/mob/verb/me_wrapper()
set name = ".Me"
set hidden = TRUE
SStyping.UpdateVerbState(client, TRUE)
var/message = input("","me (text)") as null | text
SStyping.UpdateVerbState(client, FALSE)
if (message)
me_verb(message)


// Retained for uses by non-player assets
/proc/generate_speech_bubble(atom/movable/loc, icon_state, layer = FLOAT_LAYER)
var/image/image = image('icons/mob/talk.dmi', loc, icon_state, layer)
image.appearance_flags |= KEEP_APART | RESET_COLOR | PIXEL_SCALE
if (ismovable(loc))
var/x_scale = loc.get_icon_scale_x()
if (abs(x_scale) < 2) // reset transform on bubbles, except for the Very Large
image.pixel_z = (loc.icon_expected_height * (x_scale - 1))
image.appearance_flags |= RESET_TRANSFORM
return image
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,7 @@ var/global/list/_client_preferences_by_type
disabled_description = "Hide"

/datum/client_preference/show_typing_indicator/toggled(var/mob/preference_mob, var/enabled)
if(!enabled)
preference_mob.set_typing_indicator(FALSE)
SStyping.UpdatePreference(preference_mob.client, enabled)

/datum/client_preference/show_ooc
description ="OOC chat"
Expand Down
20 changes: 0 additions & 20 deletions code/modules/mob/living/carbon/brain/brain.dm
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,3 @@

/mob/living/carbon/brain/isSynthetic()
return istype(loc, /obj/item/mmi)

/mob/living/carbon/brain/set_typing_indicator(var/state)
if(isturf(loc))
return ..()

if(!is_preference_enabled(/datum/client_preference/show_typing_indicator))
loc.cut_overlay(typing_indicator, TRUE)
return

if(!typing_indicator)
init_typing_indicator("[speech_bubble_appearance()]_typing")

if(state && !typing)
loc.add_overlay(typing_indicator, TRUE)
typing = TRUE
else if(typing)
loc.cut_overlay(typing_indicator, TRUE)
typing = FALSE

return state
5 changes: 1 addition & 4 deletions code/modules/mob/mob_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,6 @@

var/get_rig_stats = 0 //Moved from computer.dm

var/typing
var/obj/effect/decal/typing_indicator

var/low_priority = FALSE //Skip processing life() if there's just no players on this Z-level

var/default_pixel_x = 0 //For offsetting mobs
Expand All @@ -225,4 +222,4 @@

var/registered_z

var/in_enclosed_vehicle = 0 //For mechs and fighters ambiance. Can be used in other cases.
var/in_enclosed_vehicle = 0 //For mechs and fighters ambiance. Can be used in other cases.
13 changes: 5 additions & 8 deletions code/modules/mob/say.dm
Original file line number Diff line number Diff line change
@@ -1,35 +1,32 @@
/mob/proc/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
return


/mob/verb/whisper(message as text)
set name = "Whisper"
set category = "IC"
usr.say(message, whispering = TRUE)

usr.say(message,whispering=1)

/mob/verb/say_verb(message as text)
set name = "Say"
set category = "IC"

set_typing_indicator(FALSE)
usr.say(message)


/mob/verb/me_verb(message as message)
set name = "Me"
set category = "IC"

if(say_disabled) //This is here to try to identify lag problems
to_chat(usr, "<font color='red'>Speech is currently admin-disabled.</font>")
to_chat(usr, SPAN_WARNING("Speech is currently admin-disabled."))
return

message = sanitize(message)

set_typing_indicator(FALSE)
if(use_me)
custom_emote(usr.emote_type, message)
else
usr.emote(message)


/mob/proc/say_dead(var/message)
if(say_disabled) //This is here to try to identify lag problems
to_chat(usr, "<span class='danger'>Speech is currently admin-disabled.</span>")
Expand Down
59 changes: 0 additions & 59 deletions code/modules/mob/typing_indicator.dm

This file was deleted.

Loading

0 comments on commit b087dd0

Please sign in to comment.