Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Admin Fax System #70072

Closed
wants to merge 11 commits into from
21 changes: 21 additions & 0 deletions code/_globalvars/lists/faxes.dm
@@ -0,0 +1,21 @@
/**
* This defines the list of faxes managed by the server administrators. They are not physically present in
* the game, but are shown in the fax list as existing.
* Lists:
* * additional_faxes_list - A list of "legal" faxes available with authorization.
* * syndicate_faxes_list - List of faxes available after hacking.
*
* The list consists of the following elements:
* * fax_name - The name displayed in the fax list.
* * button_color - The color of this fax button in the list of all faxes.
*/
GLOBAL_LIST_INIT(additional_faxes_list, list(
list("fax_name" = "Central Command", "button_color" = "#34c924"),
list("fax_name" = "Clown Planet", "button_color" = "#f4c800"),
))

GLOBAL_LIST_INIT(syndicate_faxes_list, list(
list("fax_name" = "Syndicate Coordination Center", "button_color" = "#ff0000"),
list("fax_name" = "Federation of Wizards", "button_color" = "#8b00ff"),
list("fax_name" = "Nar-Sie Church", "button_color" = "#8b0000"),
))
Comment on lines +12 to +21
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this seems nice, I don't think I agree with it being in-game, unless you change the methods to gain these.
My thinking is limiting individual faxes to specific accesses (Centcom is Cap/Lawyer, Clown planet is Clown, Syndicate is Syndie access (the one that Agent IDs have), Nar'Sie could be maybe a culted fax using twisted construction, wizard federation I can't really explain at all).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your criticism. But I still want to defend my approach. First of all, I'm afraid that organizing access for each role would make the system very complicated. Secondly, giving access to certain facsimiles for certain roles will narrow the framework for role-playing. I see no reason to limit the captain to be able to write complaints to Planet of the Clowns, and the clown to write unfunny jokes for the CC. Third, I created the list specifically based on requests from developers of other builds based on TG. They would like to be able to designate their own organizations and factions for their servers. For TG, I entered such organizations for example, and nothing stops them from tweaking or deleting.

3 changes: 2 additions & 1 deletion code/modules/admin/admin_verbs.dm
Expand Up @@ -20,7 +20,8 @@ GLOBAL_PROTECT(admin_verbs_default)
/client/proc/tag_datum_mapview,
/client/proc/debugstatpanel,
/client/proc/fix_air, /*resets air in designated radius to its default atmos composition*/
/client/proc/requests
/client/proc/requests,
/client/proc/fax_manager,
)
GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin())
GLOBAL_PROTECT(admin_verbs_admin)
Expand Down
6 changes: 6 additions & 0 deletions code/modules/admin/verbs/fax_manager.dm
@@ -0,0 +1,6 @@
/client/proc/fax_manager()
set name = "Fax Manager"
set desc = "Open the manager panel to view all requests during the round in progress."
set category = "Admin.Game"
SSblackbox.record_feedback("tally", "admin_verb", 1, "Fax Manager") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
GLOB.fax_manager.ui_interact(usr)
78 changes: 75 additions & 3 deletions code/modules/paperwork/fax.dm
Expand Up @@ -18,6 +18,10 @@
var/seconds_electrified = MACHINE_NOT_ELECTRIFIED
/// If true, the fax machine is jammed and needs cleaning
var/jammed = FALSE
/// Determines the possibility of sending papers to the additional faxes.
var/access_additional_faxes = FALSE
/// Defines a list of accesses whose owners can open a connection with the additional faxes.
var/static/access_additional_faxes_required = list(ACCESS_CAPTAIN)
/// Necessary to hide syndicate faxes from the general list. Doesn't mean he's EMAGGED!
var/syndicate_network = FALSE
/// True if the fax machine should be visible to other fax machines in general.
Expand Down Expand Up @@ -150,6 +154,26 @@
return
return ..()

// Checks if the card has access to switch "legal" faxes of administrators.
/obj/machinery/fax/proc/access_additional_faxes_check(mob/living/user)
if(isAdminGhostAI(user))
return TRUE

var/obj/item/card/id/used_id = user.get_idcard(TRUE)
// We check if it makes sense to check access at all.
if(!access_additional_faxes_required || !used_id.access)
return FALSE

for(var/requested_access in access_additional_faxes_required)
if(requested_access in used_id.access)
return TRUE
return FALSE

// Switches access to the "legal" administrator's fax list. Access to the "illegal" is switched by hacking.
/obj/machinery/fax/proc/access_additional_faxes_toggle()
access_additional_faxes = !access_additional_faxes
say("The channel of communication with CentCom is [access_additional_faxes ? "open" : "close"].")

/**
* Attempts to clean out a jammed machine using a passed item.
* Returns true if successful.
Expand Down Expand Up @@ -204,6 +228,12 @@
ui = new(user, src, "Fax")
ui.open()

/obj/machinery/fax/ui_static_data(mob/user)
var/list/data = list()
data["additional_faxes_list"] = GLOB.additional_faxes_list
data["syndicate_faxes_list"] = GLOB.syndicate_faxes_list
return data

/obj/machinery/fax/ui_data(mob/user)
var/list/data = list()
//Record a list of all existing faxes.
Expand All @@ -223,6 +253,8 @@
data["fax_id"] = fax_id
data["fax_name"] = fax_name
data["visible"] = visible_to_network
data["access_additional_faxes"] = access_additional_faxes
data["сan_switch_access"] = access_additional_faxes_check(user)
// In this case, we don't care if the fax is hacked or in the syndicate's network. The main thing is to check the visibility of other faxes.
data["syndicate_network"] = (syndicate_network || (obj_flags & EMAGGED))
data["has_paper"] = !!loaded_item_ref?.resolve()
Expand All @@ -245,6 +277,8 @@
playsound(src, 'sound/machines/eject.ogg', 50, FALSE)
update_appearance()
return TRUE
if("access_additional_faxes_toggle")
access_additional_faxes_toggle()
if("send")
var/obj/item/loaded = loaded_item_ref?.resolve()
if (!loaded)
Expand All @@ -255,6 +289,17 @@
loaded_item_ref = null
update_appearance()
return TRUE
if("send_to_additional_fax")
var/obj/item/loaded = loaded_item_ref?.resolve()
if (!loaded)
return
if(istype(loaded, /obj/item/paper))
if(send_to_additional_faxes(loaded, usr, params["name"], params["color"]))
loaded_item_ref = null
update_appearance()
return TRUE
else
say("The destination fax blocks the reception of this item.")
if("history_clear")
history_clear()
return TRUE
Expand Down Expand Up @@ -293,12 +338,39 @@
playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
return FALSE
FAX.receive(loaded, fax_name)
history_add("Send", FAX.fax_name)
INVOKE_ASYNC(src, .proc/animate_object_travel, loaded, "fax_receive", find_overlay_state(loaded, "send"))
playsound(src, 'sound/machines/high_tech_confirm.ogg', 50, FALSE)
playback_sending(loaded, FAX.fax_name)
return TRUE
return FALSE

/**
* The procedure for sending a paper to virtual admins fax machine.
*
* This procedure is similar to the send procedure except that it sends the paper to
* a "virtual" fax to a special administrator list.
* Arguments:
* * paper - The paper to be sent.
* * sender - Reference to the sender's substance.
* * receiver_name - The recipient's fax name, which will be displayed in the administrator's list.
* * receiver_color - The color the receiver_name will be colored in.
*/
/obj/machinery/fax/proc/send_to_additional_faxes(obj/item/paper/paper, mob/sender, receiver_name, receiver_color)
GLOB.fax_manager.receive_request(sender, src, receiver_name, paper, receiver_color)
playback_sending(paper, receiver_name)
return TRUE

/**
* The procedure for playing the animation and the sending sound.
*
* Procedure called to add to the history of sending messages, playing the sending animation and sound.
* Arguments:
* * loaded - Sending item to determine the animation..
* * receiver_name - Recipient's name to be added to the message history.
*/
/obj/machinery/fax/proc/playback_sending(obj/item/loaded, receiver_name)
history_add("Send", receiver_name)
INVOKE_ASYNC(src, .proc/animate_object_travel, loaded, "fax_receive", find_overlay_state(loaded, "send"))
playsound(src, 'sound/machines/high_tech_confirm.ogg', 50, FALSE)

/**
* Procedure for accepting papers from another fax machine.
*
Expand Down
149 changes: 149 additions & 0 deletions code/modules/paperwork/fax_manager.dm
@@ -0,0 +1,149 @@
GLOBAL_DATUM_INIT(fax_manager, /datum/fax_manager, new)

/**
* Fax Request Manager
*
* In its functionality it is similar to the usual Request Manager, but respectively for faxes.
* This manager allows you to send faxes on behalf of certain virtual faxes to all existing faxes,
* as well as receive faxes in their name from the players.
*/
/datum/fax_manager
/// A list that contains faxes from players and other related information. You can view the filling of its fields in procedure receive_request.
var/list/requests = list()
twilightwanderer marked this conversation as resolved.
Show resolved Hide resolved

/datum/fax_manager/Destroy(force, ...)
QDEL_LIST(requests)
return ..()

/datum/fax_manager/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
ui = new(user, src, "FaxManager")
ui.open()

/datum/fax_manager/ui_state(mob/user)
return GLOB.admin_state

/datum/fax_manager/ui_static_data(mob/user)
var/list/data = list()
// Record additional faxes on a separate list
data["additional_faxes"] = GLOB.additional_faxes_list + GLOB.syndicate_faxes_list
return data

/datum/fax_manager/ui_data(mob/user)
var/list/data = list()
//Record a list of all existing faxes.
for(var/obj/machinery/fax/FAX in GLOB.machines)
var/list/fax_data = list()
fax_data["fax_name"] = FAX.fax_name
fax_data["fax_id"] = FAX.fax_id
fax_data["syndicate_network"] = FAX.syndicate_network
data["faxes"] += list(fax_data)
for(var/list/REQUEST in requests)
var/list/request = list()
request["id_message"] = REQUEST["id_message"]
request["time"] = REQUEST["time"]
var/mob/sender = REQUEST["sender"]
request["sender_name"] = sender.name
request["sender_fax_id"] = REQUEST["sender_fax_id"]
request["sender_fax_name"] = REQUEST["sender_fax_name"]
request["receiver_fax_name"] = REQUEST["receiver_fax_name"]
data["requests"] += list(request)
return data

/datum/fax_manager/ui_act(action, list/params)
. = ..()
if(.)
return

switch(action)
if("send")
for(var/obj/machinery/fax/FAX in GLOB.machines)
if (FAX.fax_id == params["fax_id"])
var/obj/item/paper/paper = new()
paper.add_raw_text(params["message"])
FAX.receive(paper, params["fax_name"])
return TRUE
if("flw_fax")
for(var/obj/machinery/fax/FAX in GLOB.machines)
if (FAX.fax_id == params["fax_id"])
usr.client.admin_follow(FAX)
return TRUE
if("read_message")
var/list/REQUEST = get_request(params["id_message"])
var/obj/item/paper/request/paper = REQUEST["paper"]
paper.ui_interact(usr)
return TRUE
if("flw")
var/list/REQUEST = get_request(params["id_message"])
usr.client.admin_follow(REQUEST["sender"])
return TRUE
if("pp")
var/list/REQUEST = get_request(params["id_message"])
usr.client.holder.show_player_panel(REQUEST["sender"])
return TRUE
if("vv")
var/list/REQUEST = get_request(params["id_message"])
usr.client.debug_variables(REQUEST["sender"])
return TRUE
if("sm")
var/list/REQUEST = get_request(params["id_message"])
usr.client.cmd_admin_subtle_message(REQUEST["sender"])
return TRUE
if("logs")
var/list/REQUEST = get_request(params["id_message"])
if(!ismob(REQUEST["sender"]))
to_chat(usr, "This can only be used on instances of type /mob.", confidential = TRUE)
return TRUE
show_individual_logging_panel(REQUEST["sender"], null, null)
return TRUE
if("smite")
var/list/REQUEST = get_request(params["id_message"])
if(!check_rights(R_FUN))
to_chat(usr, "Insufficient permissions to smite, you require +FUN", confidential = TRUE)
return TRUE
var/mob/living/carbon/human/H = REQUEST["sender"]
if (!H || !istype(H))
to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human", confidential = TRUE)
return TRUE
usr.client.smite(H)
return TRUE

/datum/fax_manager/proc/get_request(id_message)
for(var/list/REQUEST in requests)
if(REQUEST["id_message"] == id_message)
return REQUEST

/datum/fax_manager/proc/receive_request(mob/sender, obj/machinery/fax/sender_fax, receiver_fax_name, obj/item/paper/paper, receiver_color)
var/list/request = list()
var/obj/item/paper/request/message = new()
request["id_message"] = requests.len
request["time"] = gameTimestamp()
request["sender"] = sender
request["sender_fax_id"] = sender_fax.fax_id
request["sender_fax_name"] = sender_fax.fax_name
request["receiver_fax_name"] = receiver_fax_name
message.copy_properties(paper)
request["paper"] = message
requests += list(request)
var/msg = span_adminnotice("<b><font color=[receiver_color]>[sanitize(receiver_fax_name)] fax</font> received a message from [sanitize(sender_fax.fax_name)][ADMIN_JMP(sender_fax)]/[ADMIN_FULLMONTY(sender)]</b>")
to_chat(GLOB.admins, msg, confidential = TRUE)
for(var/client/admin in GLOB.admins)
if((admin.prefs.chat_toggles & CHAT_PRAYER) && (admin.prefs.toggles & SOUND_PRAYERS))
SEND_SOUND(admin, sound('sound/machines/printer.ogg'))

// A special piece of paper for the administrator that will open the interface no matter what.
/obj/item/paper/request/ui_status()
return UI_INTERACTIVE
JohnFulpWillard marked this conversation as resolved.
Show resolved Hide resolved

// I'm sure there's a better way to transfer it, I just couldn't find it
/obj/item/paper/request/proc/copy_properties(obj/item/paper/paper)
raw_text_inputs = paper.raw_text_inputs
raw_stamp_data = paper.raw_stamp_data
raw_field_input_data = paper.raw_field_input_data
show_written_words = paper.show_written_words
stamp_cache = paper.stamp_cache
contact_poison = paper.contact_poison
contact_poison_volume = paper.contact_poison_volume
default_raw_text = paper.default_raw_text
input_field_count = paper.input_field_count
3 changes: 3 additions & 0 deletions tgstation.dme
Expand Up @@ -403,6 +403,7 @@
#include "code\_globalvars\lists\ambience.dm"
#include "code\_globalvars\lists\client.dm"
#include "code\_globalvars\lists\color.dm"
#include "code\_globalvars\lists\faxes.dm"
#include "code\_globalvars\lists\flavor_misc.dm"
#include "code\_globalvars\lists\keybindings.dm"
#include "code\_globalvars\lists\maintenance_loot.dm"
Expand Down Expand Up @@ -2097,6 +2098,7 @@
#include "code\modules\admin\verbs\debug.dm"
#include "code\modules\admin\verbs\diagnostics.dm"
#include "code\modules\admin\verbs\ert.dm"
#include "code\modules\admin\verbs\fax_manager.dm"
#include "code\modules\admin\verbs\fix_air.dm"
#include "code\modules\admin\verbs\fov.dm"
#include "code\modules\admin\verbs\fps.dm"
Expand Down Expand Up @@ -3912,6 +3914,7 @@
#include "code\modules\paperwork\contract.dm"
#include "code\modules\paperwork\desk_bell.dm"
#include "code\modules\paperwork\fax.dm"
#include "code\modules\paperwork\fax_manager.dm"
#include "code\modules\paperwork\filingcabinet.dm"
#include "code\modules\paperwork\folders.dm"
#include "code\modules\paperwork\folders_premade.dm"
Expand Down