diff --git a/code/__DEFINES/~doppler_defines/admin.dm b/code/__DEFINES/~doppler_defines/admin.dm new file mode 100644 index 0000000000000..d9b0c563b5035 --- /dev/null +++ b/code/__DEFINES/~doppler_defines/admin.dm @@ -0,0 +1 @@ +#define MUTE_LOOC (1<<6) diff --git a/code/__DEFINES/~doppler_defines/banning.dm b/code/__DEFINES/~doppler_defines/banning.dm new file mode 100644 index 0000000000000..6e320960cbe95 --- /dev/null +++ b/code/__DEFINES/~doppler_defines/banning.dm @@ -0,0 +1 @@ +#define BAN_LOOC "LOOC" diff --git a/code/__DEFINES/~doppler_defines/keybindings.dm b/code/__DEFINES/~doppler_defines/keybindings.dm index ef4105eaad209..371523c945bc8 100644 --- a/code/__DEFINES/~doppler_defines/keybindings.dm +++ b/code/__DEFINES/~doppler_defines/keybindings.dm @@ -1,3 +1,7 @@ #define COMSIG_KB_LIVING_COMBAT_INDICATOR "keybinding_living_combat_indicator" #define COMSIG_KB_MOB_PIXEL_SHIFT_DOWN "keybinding_mob_pixel_shift_down" #define COMSIG_KB_MOB_PIXEL_SHIFT_UP "keybinding_mob_pixel_shift_up" +#define COMSIG_KB_CLIENT_LOOC_DOWN "keybinding_client_looc_down" +#define COMSIG_KB_CLIENT_WHISPER_DOWN "keybinding_client_whisper_down" +#define COMSIG_KB_CLIENT_DO_DOWN "keybinding_client_do_down" +#define COMSIG_KB_CLIENT_DO_LONGER_DOWN "keybinding_client_do_longer_down" diff --git a/code/__DEFINES/~doppler_defines/logging.dm b/code/__DEFINES/~doppler_defines/logging.dm new file mode 100644 index 0000000000000..639329454b5cc --- /dev/null +++ b/code/__DEFINES/~doppler_defines/logging.dm @@ -0,0 +1,11 @@ +// Logging types for log_message() +#define LOG_SUBTLE (1 << 23) + +//Individual logging panel pages +#undef INDIVIDUAL_EMOTE_LOG +#define INDIVIDUAL_EMOTE_LOG (LOG_EMOTE | LOG_SUBTLE) +#undef INDIVIDUAL_SHOW_ALL_LOG +#define INDIVIDUAL_SHOW_ALL_LOG (LOG_ATTACK | LOG_SAY | LOG_WHISPER | LOG_EMOTE | LOG_SUBTLE | LOG_DSAY | LOG_PDA | LOG_CHAT | LOG_COMMENT | LOG_TELECOMMS | LOG_OOC | LOG_ADMIN | LOG_OWNERSHIP | LOG_GAME | LOG_ADMIN_PRIVATE | LOG_ASAY | LOG_MECHA | LOG_VIRUS | LOG_SHUTTLE | LOG_ECON) + +// Game categories +#define LOG_CATEGORY_GAME_SUBTLE "game-subtle" diff --git a/code/__DEFINES/~doppler_defines/say.dm b/code/__DEFINES/~doppler_defines/say.dm new file mode 100644 index 0000000000000..a0e63033354ea --- /dev/null +++ b/code/__DEFINES/~doppler_defines/say.dm @@ -0,0 +1 @@ +#define LOOC_RANGE 7 diff --git a/code/__DEFINES/~doppler_defines/span.dm b/code/__DEFINES/~doppler_defines/span.dm index 4c3c1bd145f99..0cf649540d128 100644 --- a/code/__DEFINES/~doppler_defines/span.dm +++ b/code/__DEFINES/~doppler_defines/span.dm @@ -4,3 +4,5 @@ #define span_cyan(str) ("" + str + "") #define span_orange(str) ("" + str + "") #define span_yellow(str) ("" + str + "") +#define span_rlooc(str) ("" + str + "") +#define span_emote(str) ("" + str + "") diff --git a/code/__DEFINES/~doppler_defines/speech_channels.dm b/code/__DEFINES/~doppler_defines/speech_channels.dm new file mode 100644 index 0000000000000..1f5cf3d77a82b --- /dev/null +++ b/code/__DEFINES/~doppler_defines/speech_channels.dm @@ -0,0 +1,3 @@ +#define LOOC_CHANNEL "LOOC" // LOOC +#define WHIS_CHANNEL "Whis" // Whisper +#define DO_CHANNEL "Do" // Do diff --git a/code/__HELPERS/logging/_logging.dm b/code/__HELPERS/logging/_logging.dm index bfcaded67f021..a7cf77a6e9754 100644 --- a/code/__HELPERS/logging/_logging.dm +++ b/code/__HELPERS/logging/_logging.dm @@ -112,6 +112,10 @@ GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global")) log_emote(log_text, data) if(LOG_RADIO_EMOTE) log_radio_emote(log_text, data) + //DOPPLER EDIT ADDITION BEGIN + if(LOG_SUBTLE) + log_subtle(log_text, data) + //DOPPLER EDIT ADDITION END if(LOG_DSAY) log_dsay(log_text, data) if(LOG_PDA) diff --git a/code/__HELPERS/logging/mob.dm b/code/__HELPERS/logging/mob.dm index b6bebf74f689b..77de744eb1de2 100644 --- a/code/__HELPERS/logging/mob.dm +++ b/code/__HELPERS/logging/mob.dm @@ -46,6 +46,10 @@ colored_message = "(EMOTE) [colored_message]" if(LOG_RADIO_EMOTE) colored_message = "(RADIOEMOTE) [colored_message]" + //DOPPLER EDIT ADDITION BEGIN + if(LOG_SUBTLE) + colored_message = "(EMOTE) (SUBTLE) [colored_message]" + //DOPPLER EDIT ADDITION END var/list/timestamped_message = list("\[[time_stamp(format = "YYYY-MM-DD hh:mm:ss")]\] [key_name_and_tag(src)] [loc_name(src)] (Event #[LAZYLEN(logging[smessage_type])])" = colored_message) diff --git a/code/__HELPERS/~doppler_helpers/chat.dm b/code/__HELPERS/~doppler_helpers/chat.dm new file mode 100644 index 0000000000000..949fedddb171d --- /dev/null +++ b/code/__HELPERS/~doppler_helpers/chat.dm @@ -0,0 +1,12 @@ +/** + * Returns a boolean based on whether or not the string contains a comma or an apostrophe, + * to be used for emotes to decide whether or not to have a space between the name of the user + * and the emote. + * + * Requires the message to be HTML decoded beforehand. Not doing it here for performance reasons. + * + * Returns TRUE if there should be a space, FALSE if there shouldn't. + */ +/proc/should_have_space_before_emote(string) + var/static/regex/no_spacing_emote_characters = regex(@"(,|')") + return no_spacing_emote_characters.Find(string) ? FALSE : TRUE diff --git a/code/__HELPERS/~doppler_helpers/logging.dm b/code/__HELPERS/~doppler_helpers/logging.dm new file mode 100644 index 0000000000000..3284327796ce8 --- /dev/null +++ b/code/__HELPERS/~doppler_helpers/logging.dm @@ -0,0 +1,3 @@ +/// This logs subtle emotes in game.log +/proc/log_subtle(text, list/data) + logger.Log(LOG_CATEGORY_GAME_SUBTLE, text, data) diff --git a/code/__HELPERS/~doppler_helpers/verbs.dm b/code/__HELPERS/~doppler_helpers/verbs.dm new file mode 100644 index 0000000000000..4d78f127e3efa --- /dev/null +++ b/code/__HELPERS/~doppler_helpers/verbs.dm @@ -0,0 +1,32 @@ +/** Get all hearers in range, ignores walls and such. Code stolen from `/proc/get_hearers_in_view()` + * Much faster and less expensive than range() +*/ +/proc/get_hearers_in_looc_range(atom/source, range_radius = LOOC_RANGE) + var/turf/center_turf = get_turf(source) + if(!center_turf) + return + + . = list() + var/old_luminosity = center_turf.luminosity + if(range_radius <= 0) //special case for if only source cares + for(var/atom/movable/target as anything in center_turf) + var/list/recursive_contents = target.important_recursive_contents?[RECURSIVE_CONTENTS_HEARING_SENSITIVE] + if(recursive_contents) + . += recursive_contents + return . + + var/list/hearables_from_grid = SSspatial_grid.orthogonal_range_search(source, RECURSIVE_CONTENTS_HEARING_SENSITIVE, range_radius) + + if(!length(hearables_from_grid))//we know that something is returned by the grid, but we dont know if we need to actually filter down the output + return . + + var/list/assigned_oranges_ears = SSspatial_grid.assign_oranges_ears(hearables_from_grid) + + for(var/mob/oranges_ear/ear in range(range_radius, center_turf)) + . += ear.references + + for(var/mob/oranges_ear/remaining_ear as anything in assigned_oranges_ears) //we need to clean up our mess + remaining_ear.unassign() + + center_turf.luminosity = old_luminosity + return . diff --git a/code/_globalvars/~doppler_globalvars/configuration.dm b/code/_globalvars/~doppler_globalvars/configuration.dm new file mode 100644 index 0000000000000..a22eba72d9cf0 --- /dev/null +++ b/code/_globalvars/~doppler_globalvars/configuration.dm @@ -0,0 +1,2 @@ +// LOOC Module +GLOBAL_VAR_INIT(looc_allowed, TRUE) diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm index 8d77c6fc6bdbb..84355a8a490bf 100644 --- a/code/datums/emotes.dm +++ b/code/datums/emotes.dm @@ -107,6 +107,7 @@ var/is_important = emote_type & EMOTE_IMPORTANT var/is_visual = emote_type & EMOTE_VISIBLE var/is_audible = emote_type & EMOTE_AUDIBLE + var/space = should_have_space_before_emote(html_decode(msg)[1]) ? " " : "" // DOPPLER EDIT ADDITION // Emote doesn't get printed to chat, runechat only if(emote_type & EMOTE_RUNECHAT) @@ -155,6 +156,7 @@ deaf_message = "You see how [user] [msg]", self_message = msg, audible_message_flags = EMOTE_MESSAGE|ALWAYS_SHOW_SELF_MESSAGE, + separation = space, // DOPPLER EDIT ADDITION ) // Emote is entirely audible, no visible component else if(is_audible) @@ -162,6 +164,7 @@ message = msg, self_message = msg, audible_message_flags = EMOTE_MESSAGE, + separation = space, // DOPPLER EDIT ADDITION ) // Emote is entirely visible, no audible component else if(is_visual) @@ -169,10 +172,41 @@ message = msg, self_message = msg, visible_message_flags = EMOTE_MESSAGE|ALWAYS_SHOW_SELF_MESSAGE, + separation = space, // DOPPLER EDIT ADDITION ) else CRASH("Emote [type] has no valid emote type set!") + // DOPPLER EDIT ADDITION START - AI QOL - RELAY EMOTES OVER HOLOPADS + var/obj/effect/overlay/holo_pad_hologram/hologram = GLOB.hologram_impersonators[user] + if(hologram) + if(is_important) + for(var/mob/living/viewer in viewers(world.view, hologram)) + to_chat(viewer, msg) + else if(is_visual && is_audible) + hologram.audible_message( + message = msg, + deaf_message = "You see how [user] [msg]", + self_message = msg, + audible_message_flags = EMOTE_MESSAGE|ALWAYS_SHOW_SELF_MESSAGE, + separation = space, + ) + else if(is_audible) + hologram.audible_message( + message = msg, + self_message = msg, + audible_message_flags = EMOTE_MESSAGE, + separation = space, + ) + else if(is_visual) + hologram.visible_message( + message = msg, + self_message = msg, + visible_message_flags = EMOTE_MESSAGE|ALWAYS_SHOW_SELF_MESSAGE, + separation = space, + ) + // DOPPLER EDIT ADDITION END + if(!isnull(user.client)) var/dchatmsg = "[user] [msg]" for(var/mob/ghost as anything in GLOB.dead_mob_list - viewers(get_turf(user))) diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index bf3d97426fd24..9744a65f53d03 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -550,13 +550,15 @@ Possible to do for anyone motivated enough: if(AI) AI.eyeobj.setLoc(get_turf(src)) //ensure the AI camera moves to the holopad + hologram.Impersonation = AI //DOPPLER EDIT ADDITION -- Customization; puts the AI core as the impersonated mob so that the examine proc can be redirected else //make it like real life hologram.Impersonation = user - hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it. + //hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it. // DOPPLER EDIT -- Customization; Making holograms clickable/examinable hologram.layer = FLY_LAYER //Above all the other objects/mobs. Or the vast majority of them. SET_PLANE_EXPLICIT(hologram, ABOVE_GAME_PLANE, src) hologram.set_anchored(TRUE)//So space wind cannot drag it. - hologram.name = "[user.name] (Hologram)"//If someone decides to right click. + //hologram.name = "[user.name] (Hologram)"//If someone decides to right click. // DOPPLER EDIT + hologram.name = user.name //DOPPLER EDIT -- Make the name exact, so that the double-emotes are less jarring in the chat set_holo(user, hologram) set_holo(user, hologram) diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm index 74955324dffd4..c01d60f794b9a 100644 --- a/code/modules/admin/sql_ban_system.dm +++ b/code/modules/admin/sql_ban_system.dm @@ -398,6 +398,9 @@ ROLE_WIZARD, ROLE_VOIDWALKER, ), + "Doppler Ban Options" = list( + BAN_LOOC, // DOPPLER EDIT ADDITION - LOOC muting + ), // DOPPLER EDIT ADDITION - EXTRA_BANS ) for(var/department in long_job_lists) output += "
" diff --git a/code/modules/admin/verbs/admin.dm b/code/modules/admin/verbs/admin.dm index 88ee5148f7a3c..37c50f53225ce 100644 --- a/code/modules/admin/verbs/admin.dm +++ b/code/modules/admin/verbs/admin.dm @@ -181,6 +181,11 @@ ADMIN_VERB(drop_everything, R_ADMIN, "Drop Everything", ADMIN_VERB_NO_DESCRIPTIO if(MUTE_DEADCHAT) mute_string = "deadchat and DSAY" feedback_string = "Deadchat" + // DOPPLER EDIT ADDITION START - LOOC muting. + if(MUTE_LOOC) + mute_string = "LOOC" + feedback_string = "LOOC" + // DOPPLER EDIT ADDITION END - LOOC muting. if(MUTE_INTERNET_REQUEST) mute_string = "internet sound requests" feedback_string = "Internet Sound Requests" diff --git a/code/modules/admin/verbs/admingame.dm b/code/modules/admin/verbs/admingame.dm index 57311446961ed..5982f62e5a904 100644 --- a/code/modules/admin/verbs/admingame.dm +++ b/code/modules/admin/verbs/admingame.dm @@ -88,7 +88,10 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_ADMIN, "Show Player Panel", mo body += "PRAY | " body += "ADMINHELP | " body += "WEBREQ | " - body += "DEADCHAT\]" + //DOPPLER EDIT ADDITION BEGIN - LOOC muting. + body += "DEADCHAT | " + body += "LOOC\]" + //DOPPLER EDIT ADDITION END - LOOC muting. body += "(toggle all)" body += "

" diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm index 2d16cc169202a..831589ceaf632 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -175,7 +175,7 @@ return FALSE return ..() -/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE) +/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE, separation = " ") // DOPPLER EDIT ADDITION - separation if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit return return ..() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 8cffe1b766d60..7e0ba37d2bb13 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -266,7 +266,7 @@ * * ignored_mobs (optional) doesn't show any message to any mob in this list. * * visible_message_flags (optional) is the type of message being sent. */ -/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE) +/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE, separation = " ") // DOPPLER EDIT ADDITION - separation var/turf/T = get_turf(src) if(!T) return @@ -276,12 +276,23 @@ var/list/hearers = get_hearers_in_view(vision_distance, src) //caches the hearers and then removes ignored mobs. hearers -= ignored_mobs + //DOPPLER EDIT ADDITION BEGIN - AI QoL + for(var/mob/camera/ai_eye/ai_eye in hearers) + if(ai_eye.ai?.client && !(ai_eye.ai.stat == DEAD)) + hearers -= ai_eye + hearers |= ai_eye.ai + + for(var/obj/effect/overlay/holo_pad_hologram/holo in hearers) + if(holo.Impersonation?.client) + hearers |= holo.Impersonation + //DOPPLER EDIT ADDITION END - AI QoL + if(self_message) hearers -= src var/raw_msg = message if(visible_message_flags & EMOTE_MESSAGE) - message = "[src] [message]" + message = "[src][separation][message]" // DOPPLER EDIT ADDITION - Better emotes for(var/mob/M in hearers) if(!M.client) @@ -311,7 +322,7 @@ ///Adds the functionality to self_message. -/mob/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE) +/mob/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE, separation = " ") // DOPPLER EDIT ADDITION - separation . = ..() if(!self_message) return @@ -342,13 +353,25 @@ * * self_message (optional) is what the src mob hears. * * audible_message_flags (optional) is the type of message being sent. */ -/atom/proc/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, audible_message_flags = NONE) +/atom/proc/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, audible_message_flags = NONE, separation = " ") // DOPPLER EDIT ADDITION - separation var/list/hearers = get_hearers_in_view(hearing_distance, src) + + //DOPPLER EDIT ADDITION BEGIN - AI QoL + for(var/mob/camera/ai_eye/ai_eye in hearers) + if(ai_eye.ai?.client && !(ai_eye.ai.stat == DEAD)) + hearers -= ai_eye + hearers |= ai_eye.ai + + for(var/obj/effect/overlay/holo_pad_hologram/holo in hearers) + if(holo.Impersonation?.client) + hearers |= holo.Impersonation + //DOPPLER EDIT ADDITION END - AI QoL + if(self_message) hearers -= src var/raw_msg = message if(audible_message_flags & EMOTE_MESSAGE) - message = "[src] [message]" + message = "[src][separation][message]" //DOPPLER EDIT CHANGE for(var/mob/M in hearers) if(audible_message_flags & EMOTE_MESSAGE && runechat_prefs_check(M, audible_message_flags) && M.can_hear()) M.create_chat_message(src, raw_message = raw_msg, runechat_flags = audible_message_flags) @@ -365,7 +388,7 @@ * * deaf_message (optional) is what deaf people will see. * * hearing_distance (optional) is the range, how many tiles away the message can be heard. */ -/mob/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, audible_message_flags = NONE) +/mob/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, audible_message_flags = NONE, separation = " ") // DOPPLER EDIT ADDITION - separation . = ..() if(!self_message) return diff --git a/code/modules/tgui_input/say_modal/modal.dm b/code/modules/tgui_input/say_modal/modal.dm index bc3f8f314e021..b8087609022e2 100644 --- a/code/modules/tgui_input/say_modal/modal.dm +++ b/code/modules/tgui_input/say_modal/modal.dm @@ -86,7 +86,7 @@ if(!payload?["channel"]) CRASH("No channel provided to an open TGUI-Say") window_open = TRUE - if(payload["channel"] != OOC_CHANNEL && payload["channel"] != ADMIN_CHANNEL) + if(payload["channel"] != OOC_CHANNEL && payload["channel"] != ADMIN_CHANNEL && payload["channel"] != LOOC_CHANNEL) // DOPPLER EDIT CHANGE (Add LOOC_CHANNEL) start_thinking() if(!client.typing_indicators) log_speech_indicators("[key_name(client)] started typing at [loc_name(client.mob)], indicators DISABLED.") diff --git a/code/modules/tgui_input/say_modal/speech.dm b/code/modules/tgui_input/say_modal/speech.dm index 0d95b855a15ff..32d524eb0146a 100644 --- a/code/modules/tgui_input/say_modal/speech.dm +++ b/code/modules/tgui_input/say_modal/speech.dm @@ -10,7 +10,7 @@ /datum/tgui_say/proc/alter_entry(payload) var/entry = payload["entry"] /// No OOC leaks - if(!entry || payload["channel"] == OOC_CHANNEL || payload["channel"] == ME_CHANNEL) + if(!entry || payload["channel"] == OOC_CHANNEL || payload["channel"] == ME_CHANNEL || payload["channel"] == LOOC_CHANNEL) // DOPPLER EDIT CHANGE - VERBS return pick(hurt_phrases) /// Random trimming for larger sentences if(length(entry) > 50) @@ -47,6 +47,16 @@ if(ADMIN_CHANNEL) SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/cmd_admin_say, entry) return TRUE + // DOPPLER EDIT ADDITION START - VERBS + if(LOOC_CHANNEL) + client.looc(entry) + return TRUE + if(WHIS_CHANNEL) + client.mob.whisper_verb(entry) + return TRUE + if(DO_CHANNEL) + client.mob.do_verb(entry) + // DOPPLER EDIT ADDITION END return FALSE /** diff --git a/modular_doppler/administration/code/preferences.dm b/modular_doppler/administration/code/preferences.dm new file mode 100644 index 0000000000000..3720993e1c5e9 --- /dev/null +++ b/modular_doppler/administration/code/preferences.dm @@ -0,0 +1,8 @@ +/datum/preference/toggle/admin + abstract_type = /datum/preference/toggle/admin + +/datum/preference/toggle/admin/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + return is_admin(preferences.parent) diff --git a/modular_doppler/emotes/code/hologram.dm b/modular_doppler/emotes/code/hologram.dm new file mode 100644 index 0000000000000..08ce03c90c6ec --- /dev/null +++ b/modular_doppler/emotes/code/hologram.dm @@ -0,0 +1,14 @@ +GLOBAL_LIST_EMPTY(hologram_impersonators) + +/obj/machinery/holopad/set_holo(mob/living/user, obj/effect/overlay/holo_pad_hologram/holo) + if(holo.Impersonation) + GLOB.hologram_impersonators[user] = holo + holo.become_hearing_sensitive() // Well, we need to show up on "get_hearers_in_view()" + . = ..() + +/obj/machinery/holopad/clear_holo(mob/living/user) + var/obj/effect/overlay/holo_pad_hologram/hologram = GLOB.hologram_impersonators[user] + if(hologram) + hologram.lose_hearing_sensitivity() + GLOB.hologram_impersonators -= user + . = ..() diff --git a/modular_doppler/modular_hydroponics/readme.md b/modular_doppler/modular_hydroponics/readme.md index e69de29bb2d1d..7f3cff653c556 100644 --- a/modular_doppler/modular_hydroponics/readme.md +++ b/modular_doppler/modular_hydroponics/readme.md @@ -0,0 +1,23 @@ +## Title: Modular Hydrophonics + +MODULE ID: MODULAR_HYDROPONICS + +### Description: + +Module for Doppler's hydroponics custom content, like plants and related. + +### TG Proc Changes: + +### Defines: + +N/A + +### Master file additions + +N/A + +### Included files that are not contained in this module: + +N/A + +### Credits: diff --git a/modular_doppler/modular_mapping/readme.md b/modular_doppler/modular_mapping/readme.md index e69de29bb2d1d..38f7f00ddfcc9 100644 --- a/modular_doppler/modular_mapping/readme.md +++ b/modular_doppler/modular_mapping/readme.md @@ -0,0 +1,23 @@ +## Title: Modular Mapping + +MODULE ID: MODULAR_MAPPING + +### Description: + +Module for Doppler's custom ruins and everything related, like unique ruin items and structures, etc. + +### TG Proc Changes: + +### Defines: + +N/A + +### Master file additions + +N/A + +### Included files that are not contained in this module: + +N/A + +### Credits: diff --git a/modular_doppler/objects_and_structures/readme.md b/modular_doppler/objects_and_structures/readme.md index e69de29bb2d1d..97a20749a4741 100644 --- a/modular_doppler/objects_and_structures/readme.md +++ b/modular_doppler/objects_and_structures/readme.md @@ -0,0 +1,23 @@ +## Title: Objects and Structures + +MODULE ID: OBJECTS_AND_STRUCTURES + +### Description: + +Module for all objects and structures used for mapping that don't really have a place to go. + +### TG Proc Changes: + +### Defines: + +N/A + +### Master file additions + +N/A + +### Included files that are not contained in this module: + +N/A + +### Credits: diff --git a/modular_doppler/verbs/code/communication.dm b/modular_doppler/verbs/code/communication.dm new file mode 100644 index 0000000000000..458d603af862d --- /dev/null +++ b/modular_doppler/verbs/code/communication.dm @@ -0,0 +1,55 @@ +/datum/keybinding/client/communication/looc + hotkey_keys = list("CtrlO") + name = LOOC_CHANNEL + full_name = "Local OOC (LOOC)" + keybind_signal = COMSIG_KB_CLIENT_LOOC_DOWN + +/datum/keybinding/client/communication/looc/down(client/user) + . = ..() + if(.) + return + winset(user, null, "command=[user.tgui_say_create_open_command(LOOC_CHANNEL)]") + return TRUE + +/datum/keybinding/client/communication/whisper + hotkey_keys = list("CtrlT") + name = WHIS_CHANNEL + full_name = "IC Whisper" + keybind_signal = COMSIG_KB_CLIENT_WHISPER_DOWN + +/datum/keybinding/client/communication/whisper/down(client/user) + . = ..() + if(.) + return + winset(user, null, "command=[user.tgui_say_create_open_command(WHIS_CHANNEL)]") + return TRUE + +/datum/keybinding/client/communication/Do + hotkey_keys = list("K") + name = DO_CHANNEL + full_name = "Do" + keybind_signal = COMSIG_KB_CLIENT_DO_DOWN + +/datum/keybinding/client/communication/Do/down(client/user) + . = ..() + if(.) + return + winset(user, null, "command=[user.tgui_say_create_open_command(DO_CHANNEL)]") + return TRUE + +/datum/keybinding/client/communication/Do_longer + hotkey_keys = list("CtrlK") + name = "do_longer" + full_name = "Do (Longer)" + keybind_signal = COMSIG_KB_CLIENT_DO_LONGER_DOWN + +/datum/keybinding/client/communication/Do_longer/down(client/user) + . = ..() + if(.) + return + var/message_text = tgui_input_text(user, "Write out your Do action:", "Do (Longer)", null, MAX_MESSAGE_LEN, TRUE) + if (!message_text) + return + + user.mob.do_verb(message_text) + return TRUE diff --git a/modular_doppler/verbs/code/do_checks.dm b/modular_doppler/verbs/code/do_checks.dm new file mode 100644 index 0000000000000..cab5717df4c6e --- /dev/null +++ b/modular_doppler/verbs/code/do_checks.dm @@ -0,0 +1,20 @@ +/mob/living/proc/doverb_checks(message) + if(!length(message)) + return FALSE + + if(GLOB.say_disabled) //This is here to try to identify lag problems + to_chat(usr, span_danger("Speech is currently admin-disabled.")) + return FALSE + + //quickly calc our name stub again: duplicate this in say.dm override + var/name_stub = " ([usr])" + if(length(message) > (MAX_MESSAGE_LEN - length(name_stub))) + to_chat(usr, message) + to_chat(usr, span_warning("^^^----- The preceding message has been DISCARDED for being over the maximum length of [MAX_MESSAGE_LEN]. It has NOT been sent! -----^^^")) + return FALSE + + if(usr.stat != CONSCIOUS) + to_chat(usr, span_notice("You cannot send a Do in your current condition.")) + return FALSE + + return TRUE diff --git a/modular_doppler/verbs/code/do_verbs.dm b/modular_doppler/verbs/code/do_verbs.dm new file mode 100644 index 0000000000000..eae4adf25620d --- /dev/null +++ b/modular_doppler/verbs/code/do_verbs.dm @@ -0,0 +1,48 @@ +/mob/verb/do_verb(message as message) + set name = "Do" + set category = "IC" + set instant = TRUE + + if(GLOB.say_disabled) + to_chat(usr, span_danger("Speech is currently admin-disabled.")) + return + + if(message) + QUEUE_OR_CALL_VERB_FOR(VERB_CALLBACK(src, TYPE_VERB_REF(/mob/living, do_actual_verb), message), SSspeech_controller) + +/mob/living/verb/do_actual_verb(message as message) + if (!message || !doverb_checks(message)) + return + + if (!try_speak(message)) // ensure we pass the vibe check (filters, etc) + return + + var/name_stub = " ([usr])" + message = usr.say_emphasis(message) + message = trim(copytext_char(message, 1, (MAX_MESSAGE_LEN - length(name_stub)))) + var/message_with_name = message + name_stub + + usr.log_message(message, LOG_EMOTE) + + var/list/viewers = get_hearers_in_view(DEFAULT_MESSAGE_RANGE, usr) + + if(istype(usr, /mob/living/silicon/ai)) + var/mob/living/silicon/ai/ai = usr + viewers = get_hearers_in_view(DEFAULT_MESSAGE_RANGE, ai.eyeobj) + + var/obj/effect/overlay/holo_pad_hologram/hologram = GLOB.hologram_impersonators[usr] + if(hologram) + viewers |= get_hearers_in_view(1, hologram) + + for(var/mob/living/silicon/ai/ai as anything in GLOB.ai_list) + if(ai.client && !(ai in viewers) && (ai.eyeobj in viewers)) + viewers += ai + + for(var/mob/ghost as anything in GLOB.dead_mob_list) + if((ghost.client?.prefs.chat_toggles & CHAT_GHOSTSIGHT) && !(ghost in viewers)) + ghost.show_message(span_emote(message_with_name)) + + for(var/mob/receiver in viewers) + receiver.show_message(span_emote(message_with_name), alt_msg = span_emote(message_with_name)) + if (receiver.client?.prefs.read_preference(/datum/preference/toggle/enable_runechat)) + create_chat_message(usr, null, message, null, EMOTE_MESSAGE) diff --git a/modular_doppler/verbs/code/log_category_game.dm b/modular_doppler/verbs/code/log_category_game.dm new file mode 100644 index 0000000000000..cc00d85f63175 --- /dev/null +++ b/modular_doppler/verbs/code/log_category_game.dm @@ -0,0 +1,3 @@ +/datum/log_category/game_subtle + category = LOG_CATEGORY_GAME_SUBTLE + master_category = /datum/log_category/game diff --git a/modular_doppler/verbs/code/looc.dm b/modular_doppler/verbs/code/looc.dm new file mode 100644 index 0000000000000..b88810c1c9146 --- /dev/null +++ b/modular_doppler/verbs/code/looc.dm @@ -0,0 +1,100 @@ +/client/verb/looc(msg as text) + set name = "LOOC" + set desc = "Local OOC, seen only by those in view." + set category = "OOC" + + looc_message(msg) + +/client/verb/looc_wallpierce(msg as text) + set name = "LOOC (Wallpierce)" + set desc = "Local OOC, seen by anyone within 7 tiles of you." + set category = "OOC" + + looc_message(msg, TRUE) + +/client/proc/looc_message(msg, wall_pierce) + if(GLOB.say_disabled) + to_chat(usr, span_danger("Speech is currently admin-disabled.")) + return + + if(!mob) + return + + msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN) + if(!msg) + return + + if(!holder) + if(!GLOB.looc_allowed) + to_chat(src, span_danger("LOOC is globally muted.")) + return + if(handle_spam_prevention(msg, MUTE_OOC)) + return + if(findtext(msg, "byond://")) + to_chat(src, span_boldannounce("Advertising other servers is not allowed.")) + log_admin("[key_name(src)] has attempted to advertise in LOOC: [msg]") + return + if(prefs.muted & MUTE_LOOC) + to_chat(src, span_danger("You cannot use LOOC (muted).")) + return + if(is_banned_from(ckey, BAN_LOOC)) + to_chat(src, span_warning("You are LOOC banned!")) + return + if(mob.stat == DEAD) + to_chat(src, span_danger("You cannot use LOOC while dead.")) + return + if(istype(mob, /mob/dead)) + to_chat(src, span_danger("You cannot use LOOC while ghosting.")) + return + + msg = emoji_parse(msg) + + mob.log_talk(msg,LOG_OOC, tag="LOOC") + var/list/heard + if(wall_pierce) + heard = get_hearers_in_looc_range(mob.get_top_level_mob()) + else + heard = get_hearers_in_view(LOOC_RANGE, mob.get_top_level_mob()) + + //so the ai can post looc text + if(istype(mob, /mob/living/silicon/ai)) + var/mob/living/silicon/ai/ai = mob + if(wall_pierce) + heard = get_hearers_in_looc_range(ai.eyeobj) + else + heard = get_hearers_in_view(LOOC_RANGE, ai.eyeobj) + //so the ai can see looc text + for(var/mob/living/silicon/ai/ai as anything in GLOB.ai_list) + if(ai.client && !(ai in heard) && (ai.eyeobj in heard)) + heard += ai + + var/list/admin_seen = list() + for(var/mob/hearing in heard) + if(!hearing.client) + continue + var/client/hearing_client = hearing.client + + var/is_holder = hearing_client.holder + if (is_holder) + admin_seen[hearing_client] = TRUE + // dont continue here, still need to show runechat + + if (isobserver(hearing) && !is_holder) + continue //ghosts dont hear looc, apparantly + + // do the runetext here so admins can still get the runetext + if(mob.runechat_prefs_check(hearing) && hearing.client?.prefs.read_preference(/datum/preference/toggle/enable_looc_runechat)) + // EMOTE is close enough. We don't want it to treat the raw message with languages. + // I wish it didn't include the asterisk but it's modular this way. + hearing.create_chat_message(mob, raw_message = "(LOOC: [msg])", runechat_flags = EMOTE_MESSAGE) + + if (is_holder) + continue //admins are handled afterwards + + to_chat(hearing_client, span_looc(span_prefix("LOOC[wall_pierce ? " (WALL PIERCE)" : ""]: [src.mob.name]: [msg]"))) + + for(var/client/cli_client as anything in GLOB.admins) + if (admin_seen[cli_client]) + to_chat(cli_client, span_looc("[ADMIN_FLW(usr)] LOOC[wall_pierce ? " (WALL PIERCE)" : ""]: [src.key]/[src.mob.name]: [msg]")) + else if (cli_client.prefs.read_preference(/datum/preference/toggle/admin/see_looc)) + to_chat(cli_client, span_rlooc("[ADMIN_FLW(usr)] (R)LOOC[wall_pierce ? " (WALL PIERCE)" : ""]: [src.key]/[src.mob.name]: [msg]")) diff --git a/modular_doppler/verbs/code/preferences.dm b/modular_doppler/verbs/code/preferences.dm new file mode 100644 index 0000000000000..be6618bd8e655 --- /dev/null +++ b/modular_doppler/verbs/code/preferences.dm @@ -0,0 +1,11 @@ +/datum/preference/toggle/admin/see_looc + category = PREFERENCE_CATEGORY_GAME_PREFERENCES + default_value = TRUE + savefile_key = "looc_admin_pref" + savefile_identifier = PREFERENCE_PLAYER + +/datum/preference/toggle/enable_looc_runechat + category = PREFERENCE_CATEGORY_GAME_PREFERENCES + default_value = FALSE + savefile_key = "enable_looc_runechat" + savefile_identifier = PREFERENCE_PLAYER diff --git a/modular_doppler/verbs/code/say.dm b/modular_doppler/verbs/code/say.dm new file mode 100644 index 0000000000000..935d8d1331ef7 --- /dev/null +++ b/modular_doppler/verbs/code/say.dm @@ -0,0 +1,5 @@ +/mob/proc/get_top_level_mob() + if(ismob(loc) && (loc != src)) + var/mob/M = loc + return M.get_top_level_mob() + return src diff --git a/modular_doppler/verbs/code/subtle.dm b/modular_doppler/verbs/code/subtle.dm new file mode 100644 index 0000000000000..5667d37fab759 --- /dev/null +++ b/modular_doppler/verbs/code/subtle.dm @@ -0,0 +1,116 @@ +#define SUBTLE_DEFAULT_DISTANCE 1 +#define SUBTLE_SAME_TILE_DISTANCE 0 + +#define SUBTLE_ONE_TILE_TEXT "1-Tile Range" +#define SUBTLE_SAME_TILE_TEXT "Same Tile" + +/datum/emote/living/subtle + key = "subtle" + key_third_person = "subtle" + message = null + mob_type_blacklist_typecache = list(/mob/living/brain) + +/datum/emote/living/subtle/run_emote(mob/user, params, type_override = null) + if(!can_run_emote(user)) + to_chat(user, span_warning("You can't emote at this time.")) + return FALSE + var/subtle_message + var/subtle_emote = params + var/target + var/subtle_range = SUBTLE_DEFAULT_DISTANCE + + if(SSdbcore.IsConnected() && is_banned_from(user, "emote")) + to_chat(user, span_warning("You cannot send subtle emotes (banned).")) + return FALSE + else if(user.client?.prefs.muted & MUTE_IC) + to_chat(user, span_warning("You cannot send IC messages (muted).")) + return FALSE + else if(!subtle_emote) + subtle_emote = tgui_input_text(user, "Choose an emote to display.", "Subtle" , null, MAX_MESSAGE_LEN, TRUE) + if(!subtle_emote) + return FALSE + + var/list/in_view = get_hearers_in_view(subtle_range, user) + + var/obj/effect/overlay/holo_pad_hologram/hologram = GLOB.hologram_impersonators[user] + if(hologram) + in_view |= get_hearers_in_view(1, hologram) + + in_view -= GLOB.dead_mob_list + in_view.Remove(user) + + for(var/mob/camera/ai_eye/ai_eye in in_view) + in_view.Remove(ai_eye) + + var/list/targets = list(SUBTLE_ONE_TILE_TEXT, SUBTLE_SAME_TILE_TEXT) + in_view + target = tgui_input_list(user, "Pick a target", "Target Selection", targets) + if(!target) + return FALSE + + switch(target) + if(SUBTLE_ONE_TILE_TEXT) + target = SUBTLE_DEFAULT_DISTANCE + if(SUBTLE_SAME_TILE_TEXT) + target = SUBTLE_SAME_TILE_DISTANCE + subtle_message = subtle_emote + else + target = SUBTLE_DEFAULT_DISTANCE + subtle_message = subtle_emote + if(type_override) + emote_type = type_override + + if(!can_run_emote(user)) + to_chat(user, span_warning("You can't emote at this time.")) + return FALSE + + user.log_message(subtle_message, LOG_SUBTLE) + + var/space = should_have_space_before_emote(html_decode(subtle_emote)[1]) ? " " : "" + + subtle_message = span_emote("[user][space][user.say_emphasis(subtle_message)]") + + if(istype(target, /mob)) + var/mob/target_mob = target + user.show_message(subtle_message, alt_msg = subtle_message) + var/obj/effect/overlay/holo_pad_hologram/hologram = GLOB.hologram_impersonators[user] + if((get_dist(user.loc, target_mob.loc) <= subtle_range) || (hologram && get_dist(hologram.loc, target_mob.loc) <= subtle_range)) + target_mob.show_message(subtle_message, alt_msg = subtle_message) + else + to_chat(user, span_warning("Your emote was unable to be sent to your target: Too far away.")) + else if(istype(target, /obj/effect/overlay/holo_pad_hologram)) + var/obj/effect/overlay/holo_pad_hologram/hologram = target + if(hologram.Impersonation?.client) + hologram.Impersonation.show_message(subtle_message, alt_msg = subtle_message) + else + var/ghostless = get_hearers_in_view(target, user) - GLOB.dead_mob_list + + var/obj/effect/overlay/holo_pad_hologram/hologram = GLOB.hologram_impersonators[user] + if(hologram) + ghostless |= get_hearers_in_view(target, hologram) + + for(var/obj/effect/overlay/holo_pad_hologram/holo in ghostless) + if(holo?.Impersonation?.client) + ghostless |= holo.Impersonation + + for(var/mob/receiver in ghostless) + receiver.show_message(subtle_message, alt_msg = subtle_message) + + return TRUE + +/* +* VERB CODE +*/ + +/mob/living/verb/subtle() + set name = "Subtle (Anti-Ghost)" + set category = "IC" + if(GLOB.say_disabled) // This is here to try to identify lag problems + to_chat(usr, span_danger("Speech is currently admin-disabled.")) + return + usr.emote("subtle") + +#undef SUBTLE_DEFAULT_DISTANCE +#undef SUBTLE_SAME_TILE_DISTANCE + +#undef SUBTLE_ONE_TILE_TEXT +#undef SUBTLE_SAME_TILE_TEXT diff --git a/modular_doppler/verbs/readme.md b/modular_doppler/verbs/readme.md new file mode 100644 index 0000000000000..5d4750fcd11a4 --- /dev/null +++ b/modular_doppler/verbs/readme.md @@ -0,0 +1,58 @@ +## Title: More verbs and subtler. + +MODULE ID: VERBS + +### Description: + +Adds the following new verbs: +- LOOC: OOC with a default range of 7 tiles. +- LOOC (Wallpierce): Like LOOC but a wall piercing version. +- Subtle (Anti-Ghost): Like Me but invisible to ghosts. Range can be 1 tile, choosing a character in this range or same tile. +- Do: Like Me but not centered on character. Perfect for narrations. Default range of 7 tiles. +- Do (Longer): Like Do but in a TGUI format. + +Adds keybinds for LOOC, Do, Do (Longer) and Whisper. + +### TG Proc Changes: + +| proc | file | +| ----------------------------------------------------- | --------------------------------------------- | +| `/proc/cmd_admin_mute(whom, mute_type, automute = 0)` | `code\modules\admin\verbs\admin.dm` | +| `ADMIN_VERB_ONLY_CONTEXT_MENU(..., ..., ..., ...)` | `code\modules\admin\verbs\admingame.dm` | +| `/datum/tgui_say/proc/open(payload)` | `code\modules\tgui_input\say_modal\modal.dm` | +| `/datum/tgui_say/proc/alter_entry(payload)` | `code\modules\tgui_input\say_modal\speech.dm` | + +### Defines: + +- `code\__DEFINES\~doppler_defines\admin.dm` looc mute +- `code\__DEFINES\~doppler_defines\banning.dm` looc ban define +- `code\__DEFINES\~doppler_defines\keybindings.dm` looc, whisper and do keybinds +- `code\__DEFINES\~doppler_defines\logging.dm` subtle log define +- `code\__DEFINES\~doppler_defines\say.dm` looc range define +- `code\__DEFINES\~doppler_defines\span.dm` looc(wallpierce), do, subtle and span defines +- `code\__DEFINES\~doppler_defines\speech_channels.dm` looc, whis and do channel defines + + +### Included files that are not contained in this module: + +- `code\__HELPERS\logging\_logging.dm` subtle logging +- `code\__HELPERS\logging\mob.dm` subtle messages readibility for admins +- `code\__HELPERS\~doppler_helpers\chat.dm` subtle formatting helper +- `code\__HELPERS\~doppler_helpers\logging.dm` subtle helper for logging +- `code\__HELPERS\~doppler_helpers\verbs.dm` looc range hearing helper +- `code\_globalvars\~doppler_globalvars\configuration.dm` looc configuration global var init +- `code\modules\admin\sql_ban_system.dm` looc ban option in admin banning panel +- `code\modules\admin\verbs\admingame.dm` looc mute message +- `modular_doppler\administration\code\preferences.dm` toggle admin preference datum +- `tgui\packages\tgui\interfaces\PreferencesMenu\preferences\features\dopplershift_preferences\looc.tsx` looc preferences visual components +- `tgui\packages\tgui-panel\chat\constants.ts` +- `tgui\packages\tgui-panel\styles\tgchat\chat-dark.scss` multiple font colors for dark theme +- `tgui\packages\tgui-panel\styles\tgchat\chat-light.scss` multiple font colors for light theme +- `tgui\packages\tgui-say\ChannelIterator.test.ts` whis, looc and do channel cycler test +- `tgui\packages\tgui-say\ChannelIterator.ts` whis, looc and do channel types and channel iterators +- `tgui\packages\tgui-say\styles\colors.scss` whis, looc and do font colors + +### Credits: +Gandalf2k15 - porting and refactoring +yooriss - do verb +Kaostico - edition diff --git a/tgstation.dme b/tgstation.dme index 9b8c6f4ecb405..648e2846d33a4 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -397,9 +397,11 @@ #include "code\__DEFINES\traits\macros.dm" #include "code\__DEFINES\traits\sources.dm" #include "code\__DEFINES\~doppler_defines\access.dm" +#include "code\__DEFINES\~doppler_defines\admin.dm" #include "code\__DEFINES\~doppler_defines\armor_defines.dm" #include "code\__DEFINES\~doppler_defines\atom_hud.dm" #include "code\__DEFINES\~doppler_defines\automapper.dm" +#include "code\__DEFINES\~doppler_defines\banning.dm" #include "code\__DEFINES\~doppler_defines\cells.dm" #include "code\__DEFINES\~doppler_defines\colony_fabricator_misc.dm" #include "code\__DEFINES\~doppler_defines\declarations.dm" @@ -411,6 +413,7 @@ #include "code\__DEFINES\~doppler_defines\keybindings.dm" #include "code\__DEFINES\~doppler_defines\living.dm" #include "code\__DEFINES\~doppler_defines\loadout.dm" +#include "code\__DEFINES\~doppler_defines\logging.dm" #include "code\__DEFINES\~doppler_defines\manufacturer_strings.dm" #include "code\__DEFINES\~doppler_defines\mobfactions.dm" #include "code\__DEFINES\~doppler_defines\mutant_variations.dm" @@ -419,10 +422,12 @@ #include "code\__DEFINES\~doppler_defines\reagent_forging_tools.dm" #include "code\__DEFINES\~doppler_defines\reskin_defines.dm" #include "code\__DEFINES\~doppler_defines\role_preferences.dm" +#include "code\__DEFINES\~doppler_defines\say.dm" #include "code\__DEFINES\~doppler_defines\signals.dm" #include "code\__DEFINES\~doppler_defines\sound.dm" #include "code\__DEFINES\~doppler_defines\span.dm" #include "code\__DEFINES\~doppler_defines\species.dm" +#include "code\__DEFINES\~doppler_defines\speech_channels.dm" #include "code\__DEFINES\~doppler_defines\strippable.dm" #include "code\__DEFINES\~doppler_defines\techweb_nodes.dm" #include "code\__DEFINES\~doppler_defines\traits.dm" @@ -541,7 +546,10 @@ #include "code\__HELPERS\paths\sssp.dm" #include "code\__HELPERS\sorts\helpers.dm" #include "code\__HELPERS\sorts\sort_instance.dm" +#include "code\__HELPERS\~doppler_helpers\chat.dm" #include "code\__HELPERS\~doppler_helpers\global_lists.dm" +#include "code\__HELPERS\~doppler_helpers\logging.dm" +#include "code\__HELPERS\~doppler_helpers\verbs.dm" #include "code\_globalvars\_regexes.dm" #include "code\_globalvars\admin.dm" #include "code\_globalvars\arcade.dm" @@ -588,6 +596,7 @@ #include "code\_globalvars\traits\_traits.dm" #include "code\_globalvars\traits\admin_tooling.dm" #include "code\_globalvars\~doppler_globalvars\bitfields.dm" +#include "code\_globalvars\~doppler_globalvars\configuration.dm" #include "code\_globalvars\~doppler_globalvars\objective.dm" #include "code\_globalvars\~doppler_globalvars\religion.dm" #include "code\_js\byjax.dm" @@ -6430,6 +6439,7 @@ #include "modular_doppler\accessable_storage\accessable_storage.dm" #include "modular_doppler\accessable_storage\item.dm" #include "modular_doppler\accessable_storage\strippable.dm" +#include "modular_doppler\administration\code\preferences.dm" #include "modular_doppler\administration\code\whitelisting.dm" #include "modular_doppler\advanced_reskin\code\advanced_reskin.dm" #include "modular_doppler\automapper\code\area_spawn_entries.dm" @@ -6504,6 +6514,7 @@ #include "modular_doppler\deforest_medical_items\code\medstation_designs\blood.dm" #include "modular_doppler\deforest_medical_items\code\medstation_designs\medical.dm" #include "modular_doppler\emotes\code\emotes.dm" +#include "modular_doppler\emotes\code\hologram.dm" #include "modular_doppler\emotes\code\added_emotes\animal_sounds.dm" #include "modular_doppler\emotes\code\added_emotes\human_things.dm" #include "modular_doppler\emotes\code\added_emotes\robot_sounds.dm" @@ -6800,6 +6811,14 @@ #include "modular_doppler\vending_machines\code\vendor_food.dm" #include "modular_doppler\vending_machines\code\vendor_snacks.dm" #include "modular_doppler\vending_machines\code\vendors.dm" +#include "modular_doppler\verbs\code\communication.dm" +#include "modular_doppler\verbs\code\do_checks.dm" +#include "modular_doppler\verbs\code\do_verbs.dm" +#include "modular_doppler\verbs\code\log_category_game.dm" +#include "modular_doppler\verbs\code\looc.dm" +#include "modular_doppler\verbs\code\preferences.dm" +#include "modular_doppler\verbs\code\say.dm" +#include "modular_doppler\verbs\code\subtle.dm" #include "modular_doppler\wargaming\code\game_kit.dm" #include "modular_doppler\wargaming\code\holograms.dm" #include "modular_doppler\wargaming\code\projectors.dm" diff --git a/tgui/packages/tgui-panel/chat/constants.ts b/tgui/packages/tgui-panel/chat/constants.ts index 57ad525a9a9aa..56378b8bc54b5 100644 --- a/tgui/packages/tgui-panel/chat/constants.ts +++ b/tgui/packages/tgui-panel/chat/constants.ts @@ -53,7 +53,7 @@ export const MESSAGE_TYPES = [ type: MESSAGE_TYPE_LOCALCHAT, name: 'Local', description: 'In-character local messages (say, emote, etc)', - selector: '.say, .emote', + selector: '.say, .emote, .looc', // DOPPLER EDIT ADDITION - LOOC }, { type: MESSAGE_TYPE_RADIO, @@ -86,7 +86,7 @@ export const MESSAGE_TYPES = [ type: MESSAGE_TYPE_OOC, name: 'OOC', description: 'The bluewall of global OOC messages', - selector: '.ooc, .adminooc, .adminobserverooc, .oocplain', + selector: '.ooc, .adminooc, .adminobserverooc, .oocplain, .looc, .rlooc', // DOPPLER EDIT ADDITION - LOOC AND RLOOC }, { type: MESSAGE_TYPE_ADMINPM, diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss index 25f4eabd45d86..d6e2ef8fc692b 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-dark.scss @@ -1188,3 +1188,40 @@ $border-width-px: $border-width * 1px; background-color: darken(map.get($alert-stripe-colors, $color-name), 5); } } + +/* DOPPLER EDIT ADDITION START - DARK MODE CLASSES */ + +.looc { + color: #d8b555; +} + +.rlooc { + color: #b09448; +} + +.pink { + color: #ff00ff; + font-weight: bold; +} + +.brown { + color: #3d2009; + font-weight: bold; +} + +.cyan { + color: #0ea1e6; + font-weight: bold; +} + +.orange { + color: #b8761a; + font-weight: bold; +} + +.yellow { + color: #c7b72c; + font-weight: bold; +} + +// DOPPLER EDIT ADDITION END diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss index b9caf24ddd81f..d0ae460667606 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss @@ -1212,3 +1212,41 @@ $border-width-px: $border-width * 1px; ); } } + +/* DOPPLER EDIT ADDITION START - LIGHT MODE CLASSES */ + +.looc { + color: #6699cc; + font-weight: bold; +} + +.rlooc { + color: #507294; + font-weight: bold; +} + +.pink { + color: #ff00ff; + font-weight: bold; +} + +.brown { + color: #3d2009; + font-weight: bold; +} + +.cyan { + color: #0ea1e6; + font-weight: bold; +} + +.orange { + color: #b8761a; + font-weight: bold; +} + +.yellow { + color: #c7b72c; + font-weight: bold; +} +// DOPPLER EDIT ADDITION END diff --git a/tgui/packages/tgui-say/ChannelIterator.test.ts b/tgui/packages/tgui-say/ChannelIterator.test.ts index 15e9812e702ec..93891ce5fc57a 100644 --- a/tgui/packages/tgui-say/ChannelIterator.test.ts +++ b/tgui/packages/tgui-say/ChannelIterator.test.ts @@ -11,6 +11,11 @@ describe('ChannelIterator', () => { expect(channelIterator.current()).toBe('Say'); expect(channelIterator.next()).toBe('Radio'); expect(channelIterator.next()).toBe('Me'); + // DOPPLER EDIT ADDITION START + expect(channelIterator.next()).toBe('Whis'); + expect(channelIterator.next()).toBe('LOOC'); + expect(channelIterator.next()).toBe('Do'); + // DOPPLER EDIT ADDITION END expect(channelIterator.next()).toBe('OOC'); expect(channelIterator.next()).toBe('Say'); // Admin is blacklisted so it should be skipped }); diff --git a/tgui/packages/tgui-say/ChannelIterator.ts b/tgui/packages/tgui-say/ChannelIterator.ts index 136806927e95e..b30c36bacd8d9 100644 --- a/tgui/packages/tgui-say/ChannelIterator.ts +++ b/tgui/packages/tgui-say/ChannelIterator.ts @@ -1,4 +1,14 @@ -export type Channel = 'Say' | 'Radio' | 'Me' | 'OOC' | 'Admin'; +export type Channel = + | 'Say' + | 'Radio' + | 'Me' + // DOPPLER EDIT ADDITION START + | 'Whis' + | 'LOOC' + | 'Do' + // DOPPLER EDIT ADDITION END + | 'OOC' + | 'Admin'; /** * ### ChannelIterator @@ -8,7 +18,18 @@ export type Channel = 'Say' | 'Radio' | 'Me' | 'OOC' | 'Admin'; */ export class ChannelIterator { private index: number = 0; - private readonly channels: Channel[] = ['Say', 'Radio', 'Me', 'OOC', 'Admin']; + private readonly channels: Channel[] = [ + 'Say', + 'Radio', + 'Me', + // DOPPLER EDIT ADDITION + 'Whis', + 'LOOC', + 'Do', + // DOPPLER EDIT ADDITION + 'OOC', + 'Admin', + ]; private readonly blacklist: Channel[] = ['Admin']; private readonly quiet: Channel[] = ['OOC', 'Admin']; diff --git a/tgui/packages/tgui-say/styles/colors.scss b/tgui/packages/tgui-say/styles/colors.scss index a6b492247187b..aa53224b732ec 100644 --- a/tgui/packages/tgui-say/styles/colors.scss +++ b/tgui/packages/tgui-say/styles/colors.scss @@ -26,6 +26,11 @@ $_channel_map: ( 'Supp': #b88646, 'Svc': #6ca729, 'Synd': #8f4a4b, + // NOVA EDIT ADDITION START + 'Whis': #7c7fd9, + 'LOOC': #ffceb6, + 'Do': #59da7e, + // NOVA EDIT ADDITION END ); $channel_keys: map.keys($_channel_map) !default; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dopplershift_preferences/looc.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dopplershift_preferences/looc.tsx new file mode 100644 index 0000000000000..1c9c5eb3f436e --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dopplershift_preferences/looc.tsx @@ -0,0 +1,17 @@ +import { CheckboxInput, FeatureToggle } from '../base'; + +export const looc_admin_pref: FeatureToggle = { + name: 'See admin LOOC', + category: 'ADMIN', + description: + 'Toggles whether you want to see LOOC anywhere as an admin or not.', + component: CheckboxInput, +}; + +export const enable_looc_runechat: FeatureToggle = { + name: 'Enable LOOC runechat', + category: 'RUNECHAT', + description: + "If TRUE, LOOC will appear above the speaker's head as well as in the chat.", + component: CheckboxInput, +};