Add a few networks to fax, which send papers to request manager, and staff can answer on them from fax panel. (#71129)

## About The Pull Request

This PR adds the ability to send faxes to a central command or
syndicate, which will be delivered to the admins in request format. And
also, a fax panel for admins has been added, which will allow them to
conveniently send a fax already back (including stamps)

![image](https://user-images.githubusercontent.com/78199449/200159547-4e5f1759-2879-459c-b84f-e6dedd5f1ccb.png)

![image](https://user-images.githubusercontent.com/78199449/200159551-951e235f-e2ac-4f92-a96f-72cba643e634.png)

![image](https://user-images.githubusercontent.com/78199449/200159552-57f3dcf6-5875-4b11-af58-22c0b0fb4ae2.png)

![image](https://user-images.githubusercontent.com/78199449/200159553-57fbf90c-f141-4c12-8879-81a842afe30f.png)


## Why It's Good For The Game

More bureacracy gaming.

## Changelog

🆑 Vishenka0704
add: A way to send faxes to CentCom/Syndicate
admin: New fax panel(with stamps!!!)
/🆑

Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
This commit is contained in:
Yaroslav Nurkov
2022-11-21 07:44:29 +00:00
committed by GitHub
co-authored by Mothblocks
parent aa966ea469
commit ec1115efff
13 changed files with 506 additions and 13 deletions
+2
View File
@@ -68,6 +68,8 @@
#define ADMIN_TAG(datum) "(<A href='?src=[REF(src)];[HrefToken(forceGlobal = TRUE)];tag_datum=[REF(datum)]'>TAG</a>)"
#define ADMIN_LUAVIEW(state) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];lua_state=[REF(state)]'>VIEW STATE</a>)"
#define ADMIN_LUAVIEW_CHUNK(state, log_index) "(<a href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];lua_state=[REF(state)];log_index=[log_index]'>VIEW CODE</a>)"
/// Displays "(SHOW)" in the chat, when clicked it tries to show atom(paper). First you need to set the request_state variable to TRUE for the paper.
#define ADMIN_SHOW_PAPER(atom) "(<A href='?_src_=holder;[HrefToken(forceGlobal = TRUE)];show_paper=[REF(atom)]'>SHOW</a>)"
/atom/proc/Admin_Coordinates_Readable(area_name, admin_jump_ref)
var/turf/T = Safe_COORD_Location()
+145
View File
@@ -0,0 +1,145 @@
/**
* If client have R_ADMIN flag, opens an admin fax panel.
*/
/client/proc/fax_panel()
set category = "Admin.Events"
set name = "Fax Panel"
if(!check_rights(R_ADMIN))
return
var/datum/fax_panel_interface/ui = new(usr)
ui.ui_interact(usr)
/// Admin Fax Panel. Tool for sending fax messages faster.
/datum/fax_panel_interface
/// All faxes in from machinery list()
var/available_faxes = list()
/// List with available stamps
var/stamp_list = list()
/// Paper which admin edit and send.
var/obj/item/paper/fax_paper = new /obj/item/paper(null)
/// Default name of fax. Used when field with fax name not edited.
var/sending_fax_name = "Secret"
/// Default name of paper. paper - bluh-bluh. Used when field with paper name not edited.
var/default_paper_name = "Standart Report"
/datum/fax_panel_interface/New()
//Get all faxes, and save them to our list.
for(var/obj/machinery/fax/fax in GLOB.machines)
available_faxes += WEAKREF(fax)
//Get all stamps
for(var/stamp in subtypesof(/obj/item/stamp))
var/obj/item/stamp/real_stamp = new stamp()
if(!istype(real_stamp, /obj/item/stamp/chameleon) && !istype(real_stamp, /obj/item/stamp/mod))
var/stamp_detail = real_stamp.get_writing_implement_details()
stamp_list += list(list(real_stamp.name, real_stamp.icon_state, stamp_detail["stamp_class"]))
//Give our paper special status, to read everywhere.
fax_paper.request_state = TRUE
/**
* Return fax if name exists
* Arguments:
* * name - Name of fax what we try to find.
*/
/datum/fax_panel_interface/proc/get_fax_by_name(name)
if(!length(available_faxes))
return null
for(var/datum/weakref/weakrefed_fax as anything in available_faxes)
var/obj/machinery/fax/potential_fax = weakrefed_fax.resolve()
if(potential_fax && istype(potential_fax))
if(potential_fax.fax_name == name)
return potential_fax
return null
/datum/fax_panel_interface/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "AdminFax")
ui.open()
/datum/fax_panel_interface/ui_state(mob/user)
return GLOB.admin_state
/datum/fax_panel_interface/ui_static_data(mob/user)
var/list/data = list()
data["faxes"] = list()
data["stamps"] = list()
for(var/stamp in stamp_list)
data["stamps"] += list(stamp[1]) // send only names.
for(var/datum/weakref/weakrefed_fax as anything in available_faxes)
var/obj/machinery/fax/another_fax = weakrefed_fax.resolve()
if(another_fax && istype(another_fax))
data["faxes"] += list(another_fax.fax_name)
return data
/datum/fax_panel_interface/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
if(!check_rights(R_ADMIN))
return
var/obj/machinery/fax/action_fax
if(params["faxName"])
action_fax = get_fax_by_name(params["faxName"])
switch(action)
if("follow")
if(!isobserver(usr))
usr.client?.admin_ghost()
usr.client?.admin_follow(action_fax)
if("preview") // see saved variant
if(!fax_paper)
return
fax_paper.ui_interact(usr)
if("save") // save paper
if(params["paperName"])
default_paper_name = params["paperName"]
if(params["fromWho"])
sending_fax_name = params["fromWho"]
fax_paper.clear_paper()
var/stamp
var/stamp_class
for(var/needed_stamp in stamp_list)
if(needed_stamp[1] == params["stamp"])
stamp = needed_stamp[2]
stamp_class = needed_stamp[3]
break
fax_paper.name = "paper — [default_paper_name]"
fax_paper.add_raw_text(params["rawText"])
if(stamp)
fax_paper.add_stamp(stamp_class, params["stampX"], params["stampY"], params["stampAngle"], stamp)
fax_paper.update_static_data(usr) // OK, it's work, and update UI.
if("send")
//copy
var/obj/item/paper/our_fax = fax_paper.copy(/obj/item/paper)
our_fax.name = fax_paper.name
//send
action_fax.receive(our_fax, sending_fax_name)
message_admins("[key_name_admin(usr)] has send custom fax message to [action_fax.name][ADMIN_FLW(action_fax)][ADMIN_SHOW_PAPER(fax_paper)].")
log_admin("[key_name(usr)] has send custom fax message to [action_fax.name]")
if("createPaper")
var/obj/item/paper/our_paper = fax_paper.copy(/obj/item/paper, usr.loc)
our_paper.name = fax_paper.name
+1
View File
@@ -86,6 +86,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
/client/proc/list_dna,
/client/proc/list_fingerprints,
/client/proc/message_pda, /*send a message to somebody on PDA*/
/client/proc/fax_panel, /*send a paper to fax*/
/datum/admins/proc/trophy_manager,
)
GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/ban_panel, /client/proc/stickybanpanel))
+9
View File
@@ -1738,3 +1738,12 @@
editor.force_view_chunk = log_entry["chunk"]
editor.force_modal = "viewChunk"
editor.ui_interact(usr)
else if(href_list["show_paper"])
if(!check_rights(R_ADMIN))
return
var/obj/item/paper/paper_to_show = locate(href_list["show_paper"])
if(!paper_to_show)
return
paper_to_show.ui_interact(usr)
+29
View File
@@ -44,6 +44,11 @@
/obj/item/holochip,
/obj/item/card
)
/// List with a fake-networks(not a fax actually), for request manager.
var/list/special_networks = list(
list(fax_name = "Central Command", fax_id = "central_command", color = "teal", emag_needed = FALSE),
list(fax_name = "Sabotage Department", fax_id = "syndicate", color = "red", emag_needed = TRUE),
)
/obj/machinery/fax/Initialize(mapload)
. = ..()
@@ -227,6 +232,7 @@
data["syndicate_network"] = (syndicate_network || (obj_flags & EMAGGED))
data["has_paper"] = !!loaded_item_ref?.resolve()
data["fax_history"] = fax_history
data["special_faxes"] = special_networks
return data
/obj/machinery/fax/ui_act(action, list/params)
@@ -245,6 +251,7 @@
playsound(src, 'sound/machines/eject.ogg', 50, FALSE)
update_appearance()
return TRUE
if("send")
var/obj/item/loaded = loaded_item_ref?.resolve()
if (!loaded)
@@ -255,6 +262,27 @@
loaded_item_ref = null
update_appearance()
return TRUE
if("send_special")
var/obj/item/paper/fax_paper = loaded_item_ref?.resolve()
if(!istype(fax_paper))
to_chat(usr, icon2html(src.icon, usr) + span_warning("Fax cannot send all above paper on this protected network, sorry."))
return
fax_paper.request_state = TRUE
fax_paper.loc = null
INVOKE_ASYNC(src, PROC_REF(animate_object_travel), fax_paper, "fax_receive", find_overlay_state(fax_paper, "send"))
playsound(src, 'sound/machines/high_tech_confirm.ogg', 50, vary = FALSE)
history_add("Send", params["name"])
GLOB.requests.fax_request(usr.client, "sent a fax message from [fax_name]/[fax_id] to [params["name"]]", fax_paper)
to_chat(GLOB.admins, span_adminnotice("[icon2html(src.icon, GLOB.admins)]<b><font color=green>FAX REQUEST: </font>[ADMIN_FULLMONTY(usr)]:</b> [span_linkify("sent a fax message from [fax_name]/[fax_id][ADMIN_FLW(src)] to [params["name"]]")] [ADMIN_SHOW_PAPER(fax_paper)]"), confidential = TRUE)
log_fax(fax_paper, params["id"], params["name"])
loaded_item_ref = null
update_appearance()
if("history_clear")
history_clear()
return TRUE
@@ -473,3 +501,4 @@
return CONTEXTUAL_SCREENTIP_SET
return .
+4 -1
View File
@@ -63,6 +63,9 @@
/// state checking on if it should be shown to a viewer.
var/datum/weakref/camera_holder
///If TRUE, staff can read paper everywhere, but usually from requests panel.
var/request_state = FALSE
/obj/item/paper/Initialize(mapload)
. = ..()
pixel_x = base_pixel_x + rand(-9, 9)
@@ -328,7 +331,7 @@
// Are we on fire? Hard to read if so
if(resistance_flags & ON_FIRE)
return UI_CLOSE
if(camera_holder && can_show_to_mob_through_camera(user))
if(camera_holder && can_show_to_mob_through_camera(user) || request_state)
return UI_UPDATE
if(!in_range(user, src) && !isobserver(user))
return UI_CLOSE
+4 -10
View File
@@ -1,12 +1,3 @@
/// Requests from prayers
#define REQUEST_PRAYER "request_prayer"
/// Requests for Centcom
#define REQUEST_CENTCOM "request_centcom"
/// Requests for the Syndicate
#define REQUEST_SYNDICATE "request_syndicate"
/// Requests for the nuke code
#define REQUEST_NUKE "request_nuke"
/**
* # Request
*
@@ -27,10 +18,12 @@
var/owner_name
/// The message associated with the request
var/message
/// Just any information, which you can to send with request. For example paper datum.
var/additional_information
/// When the request was created
var/timestamp
/datum/request/New(client/requestee, type, request)
/datum/request/New(client/requestee, type, request, additional_info)
if (!requestee)
qdel(src)
return
@@ -39,5 +32,6 @@
owner_ckey = owner.ckey
req_type = type
message = request
additional_information = additional_info
timestamp = world.time
owner_name = key_name(requestee, FALSE)
+37 -2
View File
@@ -1,3 +1,14 @@
/// Requests from prayers
#define REQUEST_PRAYER "request_prayer"
/// Requests for Centcom
#define REQUEST_CENTCOM "request_centcom"
/// Requests for the Syndicate
#define REQUEST_SYNDICATE "request_syndicate"
/// Requests for the nuke code
#define REQUEST_NUKE "request_nuke"
/// Requests somebody from fax
#define REQUEST_FAX "request_fax"
GLOBAL_DATUM_INIT(requests, /datum/request_manager, new)
/**
@@ -86,6 +97,16 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new)
/datum/request_manager/proc/nuke_request(client/C, message)
request_for_client(C, REQUEST_NUKE, message)
/**
* Creates a request for fax answer
*
* Arguments:
* * requester - The client who is sending the request
* * message - Paper with text.. some stamps.. and another things.
*/
/datum/request_manager/proc/fax_request(client/requester, message, additional_info)
request_for_client(requester, REQUEST_FAX, message, additional_info)
/**
* Creates a request and registers the request with all necessary internal tracking lists
*
@@ -94,8 +115,8 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new)
* * type - The type of request, see defines
* * message - The message
*/
/datum/request_manager/proc/request_for_client(client/C, type, message)
var/datum/request/request = new(C, type, message)
/datum/request_manager/proc/request_for_client(client/C, type, message, additional_info)
var/datum/request/request = new(C, type, message, additional_info)
if (!requests[C.ckey])
requests[C.ckey] = list()
requests[C.ckey] += request
@@ -193,6 +214,13 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new)
SD.r_code = code
message_admins("[key_name_admin(usr)] has set the self-destruct code to \"[code]\".")
return TRUE
if ("show")
if(request.req_type != REQUEST_FAX)
to_chat(usr, "Request doesn't have a paper to read.", confidential = TRUE)
return TRUE
var/obj/item/paper/request_message = request.additional_information
request_message.ui_interact(usr)
return TRUE
/datum/request_manager/ui_data(mob/user)
. = list(
@@ -207,7 +235,14 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new)
"owner_ckey" = request.owner_ckey,
"owner_name" = request.owner_name,
"message" = request.message,
"additional_info" = request.additional_information,
"timestamp" = request.timestamp,
"timestamp_str" = gameTimestamp(wtime = request.timestamp)
)
.["requests"] += list(data)
#undef REQUEST_PRAYER
#undef REQUEST_CENTCOM
#undef REQUEST_SYNDICATE
#undef REQUEST_NUKE
#undef REQUEST_FAX
+1
View File
@@ -2062,6 +2062,7 @@
#include "code\modules\actionspeed\modifiers\mood.dm"
#include "code\modules\actionspeed\modifiers\status_effects.dm"
#include "code\modules\admin\admin.dm"
#include "code\modules\admin\admin_fax_panel.dm"
#include "code\modules\admin\admin_investigate.dm"
#include "code\modules\admin\admin_pda_message.dm"
#include "code\modules\admin\admin_ranks.dm"
+237
View File
@@ -0,0 +1,237 @@
import { useBackend, useLocalState } from '../backend';
import { Section, Box, Dropdown, Button, Input, TextArea, Divider, NumberInput, Tooltip, Knob } from '../components';
import { Window } from '../layouts';
export const AdminFax = (props, context) => {
return (
<Window title="Admin Fax Panel" width={400} height={675} theme="admin">
<Window.Content>
<FaxMainPanel />
</Window.Content>
</Window>
);
};
export const FaxMainPanel = (props, context) => {
const { act, data } = useBackend(context);
const [fax, setFax] = useLocalState(context, 'fax', '');
const [saved, setSaved] = useLocalState(context, 'saved', false);
const [paperName, setPaperName] = useLocalState(context, 'paperName', '');
const [fromWho, setFromWho] = useLocalState(context, 'fromWho', '');
const [rawText, setRawText] = useLocalState(context, 'rawText', '');
const [stamp, setStamp] = useLocalState(context, 'stampType', '');
const [stampCoordX, setStampCoordX] = useLocalState(
context,
'stampCoordX',
0
);
const [stampCoordY, setStampCoordY] = useLocalState(
context,
'stampCoordY',
0
);
const [stampAngle, setStampAngle] = useLocalState(context, 'stampAngle', 0);
if (stamp && data.stamps[0] !== 'None') {
data.stamps.unshift('None');
}
return (
<div class="faxmenu">
<Section
title="Fax Menu"
buttons={
<Box>
<Button
icon="arrow-up"
disabled={!fax}
onClick={() =>
act('follow', {
faxName: fax,
})
}>
Follow
</Button>
</Box>
}>
<Box fontSize="13px">
<Dropdown
textAlign="center"
selected="Choose fax machine..."
width="100%"
nochevron
nowrap
options={data.faxes}
onSelected={(value) => setFax(value)}
/>
</Box>
</Section>
<Section
title="Paper"
buttons={
<Button
icon="eye"
disabled={!saved}
onClick={() =>
act('preview', {
faxName: fax,
})
}>
Preview
</Button>
}>
<Box fontSize="14px">
<Input
mb="5px"
placeholder="Paper name..."
value={paperName}
width="100%"
onChange={(_, v) => setPaperName(v)}
/>
<Button
icon="n"
mr="7px"
width="49%"
onClick={() => setPaperName('Central Command Report')}>
Central Command
</Button>
<Button
icon="s"
width="49%"
onClick={() => setPaperName('Syndicate Report')}>
Syndicate
</Button>
</Box>
<Divider />
<Box fontSize="14px" mt="5px">
<Tooltip content="What was writen in fax log?">
<Input
mb="5px"
placeholder="From who..."
tooltip="Name what be user in fax history"
value={fromWho}
width="100%"
onChange={(_, v) => setFromWho(v)}
/>
</Tooltip>
<Button
icon="n"
mr="7px"
width="49%"
onClick={() => setFromWho('Central Command')}>
Central Command
</Button>
<Button icon="s" width="49%" onClick={() => setFromWho('Syndicate')}>
Syndicate
</Button>
</Box>
<Divider />
<Box mt="5px">
<TextArea
placeholder="Your message here..."
height="200px"
value={rawText}
onInput={(e, value) => {
setRawText(value);
}}
/>
</Box>
<Divider />
<Box mt="5px">
<Dropdown
width="100%"
options={data.stamps}
selected="Choose stamp(optional)"
onSelected={(v) => {
if (v === 'None') {
setStamp('');
data.stamps.shift();
} else {
setStamp(v);
}
}}
/>
{stamp && (
<Box textAlign="center">
<h4>
X Coordinate:{' '}
<NumberInput
width="45px"
minValue={0}
maxValue={300}
value={stampCoordX}
onChange={(_, v) => setStampCoordX(v)}
/>
</h4>
<h4>
Y Coordinate:{' '}
<NumberInput
width="45px"
minValue={0}
value={stampCoordY}
onChange={(_, v) => setStampCoordY(v)}
/>
</h4>
<Box textAlign="center">
<h4>Rotation Angle</h4>
<Knob
size={1.5}
value={stampAngle}
minValue={0}
maxValue={360}
animated={false}
onChange={(_, v) => setStampAngle(v)}
/>
</Box>
</Box>
)}
</Box>
</Section>
<Section title="Actions">
<Box>
<Button
disabled={!saved || !fax}
icon="paper-plane"
mr="9px"
onClick={() =>
act('send', {
faxName: fax,
})
}>
Send fax
</Button>
<Button
icon="floppy-disk"
mr="9px"
color="green"
onClick={() => {
setSaved(true);
act('save', {
faxName: fax,
paperName: paperName,
rawText: rawText,
stamp: stamp,
stampX: stampCoordX,
stampY: stampCoordY,
stampAngle: stampAngle,
fromWho: fromWho,
});
}}>
Save changes
</Button>
<Button
disabled={!saved}
icon="circle-plus"
onClick={() =>
act('createPaper', {
faxName: fax,
})
}>
Create paper
</Button>
</Box>
</Section>
</div>
);
};
+28
View File
@@ -11,6 +11,7 @@ type FaxData = {
has_paper: string;
syndicate_network: boolean;
fax_history: FaxHistory[];
special_faxes: FaxSpecial[];
};
type FaxInfo = {
@@ -27,6 +28,13 @@ type FaxHistory = {
history_time: string;
};
type FaxSpecial = {
fax_name: string;
fax_id: string;
color: string;
emag_needed: boolean;
};
export const Fax = (props, context) => {
const { act } = useBackend(context);
const { data } = useBackend<FaxData>(context);
@@ -72,6 +80,26 @@ export const Fax = (props, context) => {
<Section title="Send">
{faxes.length !== 0 ? (
<Box mt={0.4}>
{(data.syndicate_network
? data.special_faxes
: data.special_faxes.filter(
(fax: FaxSpecial) => !fax.emag_needed
)
).map((special: FaxSpecial) => (
<Button
key={special.fax_id}
title={special.fax_name}
disabled={!data.has_paper}
color={special.color}
onClick={() =>
act('send_special', {
id: special.fax_id,
name: special.fax_name,
})
}>
{special.fax_name}
</Button>
))}
{faxes.map((fax: FaxInfo) => (
<Button
key={fax.fax_id}
@@ -84,6 +84,7 @@ const displayTypeMap = {
'request_centcom': 'CENTCOM',
'request_syndicate': 'SYNDICATE',
'request_nuke': 'NUKE CODE',
'request_fax': 'FAX',
};
const RequestType = (props) => {
@@ -117,6 +118,9 @@ const RequestControls = (props, context) => {
SETCODE
</Button>
)}
{request.req_type === 'request_fax' && (
<Button onClick={() => act('show', { id: request.id })}>SHOW</Button>
)}
</div>
);
};
@@ -11,6 +11,7 @@ $color-prayer: colors.bg(colors.$purple) !default;
$color-centcom: colors.bg(colors.$yellow) !default;
$color-syndicate: colors.bg(colors.$red) !default;
$color-nuke: colors.bg(colors.$yellow) !default;
$color-fax: colors.bg(colors.$green) !default;
$color-muted: colors.bg(colors.$label) !default;
$color-header: colors.bg(colors.$label) !default;
$background-color: base.$color-bg-section !default;
@@ -39,6 +40,10 @@ $text-color: base.$color-fg !default;
color: $color-nuke;
}
.RequestManager__request_fax {
color: $color-fax;
}
.RequestManager__header {
line-height: 1.375rem;
min-height: 1.375rem;