Ports "Chat Subsystem ported from TerraGov-Marine-Corps"

This commit is contained in:
Ghommie
2019-10-07 23:58:15 +02:00
parent 7dada70447
commit fce6f13471
9 changed files with 105 additions and 28 deletions

View File

@@ -499,3 +499,6 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define VOMIT_TOXIC 1
#define VOMIT_PURPLE 2
//Misc text define. Does 4 spaces. Used as a makeshift tabulator.
#define FOURSPACES "    "

View File

@@ -83,7 +83,9 @@
#define INIT_ORDER_SHUTTLE -21
#define INIT_ORDER_MINOR_MAPPING -40
#define INIT_ORDER_PATH -50
#define INIT_ORDER_PERSISTENCE -100
#define INIT_ORDER_PERSISTENCE -95
#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init.
// Subsystem fire priority, from lowest to highest priority
// If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child)
@@ -114,6 +116,7 @@
#define FIRE_PRIORITY_MOBS 100
#define FIRE_PRIORITY_TGUI 110
#define FIRE_PRIORITY_TICKER 200
#define FIRE_PRIORITY_CHAT 400
#define FIRE_PRIORITY_OVERLAYS 500
#define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost.

View File

@@ -280,41 +280,41 @@
if(GLOB.round_id)
var/statspage = CONFIG_GET(string/roundstatsurl)
var/info = statspage ? "<a href='?action=openLink&link=[url_encode(statspage)][GLOB.round_id]'>[GLOB.round_id]</a>" : GLOB.round_id
parts += "[GLOB.TAB]Round ID: <b>[info]</b>"
parts += "[FOURSPACES]Round ID: <b>[info]</b>"
var/list/voting_results = SSvote.stored_gamemode_votes
if(length(voting_results))
parts += "[GLOB.TAB]Voting: "
parts += "[FOURSPACES]Voting: "
var/total_score = 0
for(var/choice in voting_results)
var/score = voting_results[choice]
total_score += score
parts += "[GLOB.TAB][GLOB.TAB][choice]: [score]"
parts += "[FOURSPACES][FOURSPACES][choice]: [score]"
parts += "[GLOB.TAB]Shift Duration: <B>[DisplayTimeText(world.time - SSticker.round_start_time)]</B>"
parts += "[GLOB.TAB]Station Integrity: <B>[mode.station_was_nuked ? "<span class='redtext'>Destroyed</span>" : "[popcount["station_integrity"]]%"]</B>"
parts += "[FOURSPACES]Shift Duration: <B>[DisplayTimeText(world.time - SSticker.round_start_time)]</B>"
parts += "[FOURSPACES]Station Integrity: <B>[mode.station_was_nuked ? "<span class='redtext'>Destroyed</span>" : "[popcount["station_integrity"]]%"]</B>"
var/total_players = GLOB.joined_player_list.len
if(total_players)
parts+= "[GLOB.TAB]Total Population: <B>[total_players]</B>"
parts+= "[FOURSPACES]Total Population: <B>[total_players]</B>"
if(station_evacuated)
parts += "<BR>[GLOB.TAB]Evacuation Rate: <B>[popcount[POPCOUNT_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_ESCAPEES]/total_players)]%)</B>"
parts += "[GLOB.TAB](on emergency shuttle): <B>[popcount[POPCOUNT_SHUTTLE_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_SHUTTLE_ESCAPEES]/total_players)]%)</B>"
parts += "[GLOB.TAB]Survival Rate: <B>[popcount[POPCOUNT_SURVIVORS]] ([PERCENT(popcount[POPCOUNT_SURVIVORS]/total_players)]%)</B>"
parts += "<BR>[FOURSPACES]Evacuation Rate: <B>[popcount[POPCOUNT_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_ESCAPEES]/total_players)]%)</B>"
parts += "[FOURSPACES](on emergency shuttle): <B>[popcount[POPCOUNT_SHUTTLE_ESCAPEES]] ([PERCENT(popcount[POPCOUNT_SHUTTLE_ESCAPEES]/total_players)]%)</B>"
parts += "[FOURSPACES]Survival Rate: <B>[popcount[POPCOUNT_SURVIVORS]] ([PERCENT(popcount[POPCOUNT_SURVIVORS]/total_players)]%)</B>"
if(SSblackbox.first_death)
var/list/ded = SSblackbox.first_death
if(ded.len)
parts += "[GLOB.TAB]First Death: <b>[ded["name"]], [ded["role"]], at [ded["area"]]. Damage taken: [ded["damage"]].[ded["last_words"] ? " Their last words were: \"[ded["last_words"]]\"" : ""]</b>"
parts += "[FOURSPACES]First Death: <b>[ded["name"]], [ded["role"]], at [ded["area"]]. Damage taken: [ded["damage"]].[ded["last_words"] ? " Their last words were: \"[ded["last_words"]]\"" : ""]</b>"
//ignore this comment, it fixes the broken sytax parsing caused by the " above
else
parts += "[GLOB.TAB]<i>Nobody died this shift!</i>"
parts += "[FOURSPACES]<i>Nobody died this shift!</i>"
if(istype(SSticker.mode, /datum/game_mode/dynamic))
var/datum/game_mode/dynamic/mode = SSticker.mode
parts += "[GLOB.TAB]Threat level: [mode.threat_level]"
parts += "[GLOB.TAB]Threat left: [mode.threat]"
parts += "[GLOB.TAB]Executed rules:"
parts += "[FOURSPACES]Threat level: [mode.threat_level]"
parts += "[FOURSPACES]Threat left: [mode.threat]"
parts += "[FOURSPACES]Executed rules:"
for(var/datum/dynamic_ruleset/rule in mode.executed_rules)
parts += "[GLOB.TAB][GLOB.TAB][rule.ruletype] - <b>[rule.name]</b>: -[rule.cost] threat"
parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - <b>[rule.name]</b>: -[rule.cost] threat"
return parts.Join("<br>")
/client/proc/roundend_report_file()

View File

@@ -6,8 +6,6 @@ GLOBAL_VAR_INIT(timezoneOffset, 0) // The difference betwen midnight (of the hos
// However it'd be ok to use for accessing attack logs and such too, which are even laggier.
GLOBAL_VAR_INIT(fileaccess_timer, 0)
GLOBAL_VAR_INIT(TAB, "&nbsp;&nbsp;&nbsp;&nbsp;")
GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
GLOBAL_VAR_INIT(CELLRATE, 0.002) // conversion ratio between a watt-tick and kilojoule

View File

@@ -0,0 +1,67 @@
SUBSYSTEM_DEF(chat)
name = "Chat"
flags = SS_TICKER|SS_NO_INIT
wait = 1
priority = FIRE_PRIORITY_CHAT
init_order = INIT_ORDER_CHAT
var/list/payload = list()
/datum/controller/subsystem/chat/fire()
for(var/i in payload)
var/client/C = i
C << output(payload[C], "browseroutput:output")
payload -= C
if(MC_TICK_CHECK)
return
/datum/controller/subsystem/chat/proc/queue(target, message, handle_whitespace = TRUE)
if(!target || !message)
return
if(!istext(message))
stack_trace("to_chat called with invalid input type")
return
if(target == world)
target = GLOB.clients
//Some macros remain in the string even after parsing and fuck up the eventual output
message = replacetext(message, "\improper", "")
message = replacetext(message, "\proper", "")
if(handle_whitespace)
message = replacetext(message, "\n", "<br>")
message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
message += "<br>"
//url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
//Do the double-encoding here to save nanoseconds
var/twiceEncoded = url_encode(url_encode(message))
if(islist(target))
for(var/I in target)
var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
continue
if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
C.chatOutput.messageQueue += message
continue
payload[C] += twiceEncoded
else
var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible
if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
return
if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
C.chatOutput.messageQueue += message
return
payload[C] += twiceEncoded

View File

@@ -413,9 +413,9 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
dat += "CLOSED"
else
dat += "UNKNOWN"
dat += "</b>[GLOB.TAB][TicketHref("Refresh", ref_src)][GLOB.TAB][TicketHref("Re-Title", ref_src, "retitle")]"
dat += "</b>[FOURSPACES][TicketHref("Refresh", ref_src)][FOURSPACES][TicketHref("Re-Title", ref_src, "retitle")]"
if(state != AHELP_ACTIVE)
dat += "[GLOB.TAB][TicketHref("Reopen", ref_src, "reopen")]"
dat += "[FOURSPACES][TicketHref("Reopen", ref_src, "reopen")]"
dat += "<br><br>Opened at: [GAMETIMESTAMP("hh:mm:ss", closed_at)] (Approx [DisplayTimeText(world.time - opened_at)] ago)"
if(closed_at)
dat += "<br>Closed at: [GAMETIMESTAMP("hh:mm:ss", closed_at)] (Approx [DisplayTimeText(world.time - closed_at)] ago)"
@@ -423,7 +423,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
if(initiator)
dat += "<b>Actions:</b> [FullMonty(ref_src)]<br>"
else
dat += "<b>DISCONNECTED</b>[GLOB.TAB][ClosureLinks(ref_src)]<br>"
dat += "<b>DISCONNECTED</b>[FOURSPACES][ClosureLinks(ref_src)]<br>"
dat += "<br><b>Log:</b><br><br>"
for(var/I in _interactions)
dat += "[I]<br>"

View File

@@ -539,10 +539,10 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
var/list/parts = list()
parts += "The devil's true name is: [truename]"
parts += "The devil's bans were:"
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][ban]]"
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][bane]]"
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][obligation]]"
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][banish]]"
parts += "[FOURSPACES][GLOB.lawlorify[LORE][ban]]"
parts += "[FOURSPACES][GLOB.lawlorify[LORE][bane]]"
parts += "[FOURSPACES][GLOB.lawlorify[LORE][obligation]]"
parts += "[FOURSPACES][GLOB.lawlorify[LORE][banish]]"
return parts.Join("<br>")
/datum/antagonist/devil/roundend_report()

View File

@@ -181,8 +181,8 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
log_world("\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: [(src.owner.key ? src.owner.key : src.owner)] triggered JS error: [error]")
//Global chat procs
/proc/to_chat(target, message, handle_whitespace=TRUE)
if(!target)
/proc/to_chat_immediate(target, message, handle_whitespace=TRUE)
if(!target || !message)
return
//Ok so I did my best but I accept that some calls to this will be for shit like sound and images
@@ -204,7 +204,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
message = replacetext(message, "\proper", "")
if(handle_whitespace)
message = replacetext(message, "\n", "<br>")
message = replacetext(message, "\t", "[GLOB.TAB][GLOB.TAB]")
message = replacetext(message, "\t", "[FOURSPACES][FOURSPACES]")
if(islist(target))
// Do the double-encoding outside the loop to save nanoseconds
@@ -247,6 +247,11 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
// url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
C << output(url_encode(url_encode(message)), "browseroutput:output")
/proc/to_chat(target, message, handle_whitespace = TRUE)
if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.initialized)
to_chat_immediate(target, message, handle_whitespace)
return
SSchat.queue(target, message, handle_whitespace)
/datum/chatOutput/proc/swaptolightmode() //Dark mode light mode stuff. Yell at KMC if this breaks! (See darkmode.dm for documentation)
owner.force_white_theme()

View File

@@ -231,6 +231,7 @@
#include "code\controllers\subsystem\atoms.dm"
#include "code\controllers\subsystem\augury.dm"
#include "code\controllers\subsystem\blackbox.dm"
#include "code\controllers\subsystem\chat.dm"
#include "code\controllers\subsystem\communications.dm"
#include "code\controllers\subsystem\dbcore.dm"
#include "code\controllers\subsystem\dcs.dm"