From b8cf0b332e78b7918416c44e38ec59fe15a004db Mon Sep 17 00:00:00 2001 From: Zonespace <41448081+Zonespace27@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:58:57 -0700 Subject: [PATCH] Adds a Lorecaster Management Panel (#21379) * new lorecaster junk * corrections * Update StoryManager.tsx --- code/modules/admin/admin_verbs.dm | 1 + .../modules/lorecaster/code/archive_viewer.dm | 29 ++- .../modules/lorecaster/code/story_manager.dm | 172 ++++++++++++++++++ tgstation.dme | 1 + .../packages/tgui/interfaces/StoryManager.tsx | 148 +++++++++++++++ 5 files changed, 333 insertions(+), 18 deletions(-) create mode 100644 modular_skyrat/modules/lorecaster/code/story_manager.dm create mode 100644 tgui/packages/tgui/interfaces/StoryManager.tsx diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 5c5828532d1..3f175927f60 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -104,6 +104,7 @@ GLOBAL_PROTECT(admin_verbs_admin) /client/proc/admin_open_event_spawners_menu, /*EVENTS - SKYRAT EDIT ADDITION*/ /client/proc/request_help, /*SKYRAT EDIT ADDITION*/ /client/proc/view_opfors, /*OPFOR - SKYRAT EDIT ADDITION*/ + /client/proc/lorecaster_story_manager, /* SKYRAT EDIT ADDITION */ ) GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/ban_panel, /client/proc/stickybanpanel)) GLOBAL_PROTECT(admin_verbs_ban) diff --git a/modular_skyrat/modules/lorecaster/code/archive_viewer.dm b/modular_skyrat/modules/lorecaster/code/archive_viewer.dm index 1594444c843..2eaa398531b 100644 --- a/modular_skyrat/modules/lorecaster/code/archive_viewer.dm +++ b/modular_skyrat/modules/lorecaster/code/archive_viewer.dm @@ -27,17 +27,16 @@ return data /datum/computer_file/program/news_archive/proc/generate_stories() + RETURN_TYPE(/list) if(!fexists(ARCHIVE_FILE)) return var/list/compiled_stories = list() var/list/uncompiled_stories = json_load(ARCHIVE_FILE) - var/list/day_to_story = list() + var/list/date_list = list() for(var/story in uncompiled_stories) - - var/generated_num = (text2num(uncompiled_stories[story]["year"]) * 365) + (text2num(uncompiled_stories[story]["month"]) * 30) + text2num(uncompiled_stories[story]["day"]) - day_to_story["[generated_num]"] = story + date_list += (text2num(uncompiled_stories[story]["year"]) * 365) + (text2num(uncompiled_stories[story]["month"]) * 30) + text2num(uncompiled_stories[story]["day"]) // the TGUI needs _all_ of these to work if(!("title" in uncompiled_stories[story])) @@ -47,23 +46,17 @@ if(!("year" in uncompiled_stories[story])) uncompiled_stories[story]["year"] = "[CURRENT_STATION_YEAR]" if(!("month" in uncompiled_stories[story])) - uncompiled_stories[story]["month"] = "[time2text(world.timeofday, "MM")]]" + uncompiled_stories[story]["month"] = "[time2text(world.timeofday, "MM")]" if(!("day" in uncompiled_stories[story])) - uncompiled_stories[story]["day"] = "[time2text(world.timeofday, "DD")]]" + uncompiled_stories[story]["day"] = "[time2text(world.timeofday, "DD")]" - // Sorting my beloathed - var/list/just_numbers = list() - for(var/timestamp in day_to_story) - just_numbers += text2num(timestamp) + sortTim(date_list, cmp=/proc/cmp_numeric_dsc) - sortTim(just_numbers) - - for(var/num in just_numbers) - for(var/date in day_to_story) - if(text2num(date) != num) - continue - compiled_stories += list(uncompiled_stories[day_to_story[date]]) - day_to_story -= date + for(var/date in date_list) + for(var/story in uncompiled_stories) + if((text2num(uncompiled_stories[story]["year"]) * 365) + (text2num(uncompiled_stories[story]["month"]) * 30) + text2num(uncompiled_stories[story]["day"]) == date) + compiled_stories += list(uncompiled_stories[story]) + uncompiled_stories -= story return compiled_stories diff --git a/modular_skyrat/modules/lorecaster/code/story_manager.dm b/modular_skyrat/modules/lorecaster/code/story_manager.dm new file mode 100644 index 00000000000..3b60915bb69 --- /dev/null +++ b/modular_skyrat/modules/lorecaster/code/story_manager.dm @@ -0,0 +1,172 @@ +/client/proc/lorecaster_story_manager() + set category = "Admin.Events" + set name = "Lorecaster Stories" + + if(!check_rights(R_ADMIN)) + return + + var/datum/story_manager_interface/ui = new(usr) + ui.ui_interact(usr) + + +/datum/story_manager_interface + /// A static list of archived stories, generated on New() + var/static/list/archived_stories = list() + /// A static list of current stories, generated on New() + var/static/list/current_stories = list() + + +/datum/story_manager_interface/New() + . = ..() + if(!length(archived_stories)) + archived_stories = generate_stories(ARCHIVE_FILE) + + if(!length(current_stories)) + current_stories = generate_stories(NEWS_FILE) + + +/// Return a list of generated stories in a dict from a passed in file location +/datum/story_manager_interface/proc/generate_stories(file, return_id_dict = FALSE) + RETURN_TYPE(/list) + if(!fexists(file)) + return + + var/list/compiled_stories = list() + var/list/uncompiled_stories = json_load(file) + var/list/date_list = list() + + for(var/story in uncompiled_stories) + date_list += (text2num(uncompiled_stories[story]["year"]) * 365) + (text2num(uncompiled_stories[story]["month"]) * 30) + text2num(uncompiled_stories[story]["day"]) + + // the TGUI needs _all_ of these to work + if(!("title" in uncompiled_stories[story])) + uncompiled_stories[story]["title"] = "Nanotrasen News Broadcast" + if(!("text" in uncompiled_stories[story])) + uncompiled_stories[story]["text"] = "Someone forgot to fill out the article!" + if(!("year" in uncompiled_stories[story])) + uncompiled_stories[story]["year"] = "[CURRENT_STATION_YEAR]" + if(!("month" in uncompiled_stories[story])) + uncompiled_stories[story]["month"] = "[time2text(world.timeofday, "MM")]" + if(!("day" in uncompiled_stories[story])) + uncompiled_stories[story]["day"] = "[time2text(world.timeofday, "DD")]" + if(!("id" in uncompiled_stories[story])) + uncompiled_stories[story]["id"] = story + + sortTim(date_list, cmp=/proc/cmp_numeric_dsc) + + for(var/date in date_list) + for(var/story in uncompiled_stories) + if((text2num(uncompiled_stories[story]["year"]) * 365) + (text2num(uncompiled_stories[story]["month"]) * 30) + text2num(uncompiled_stories[story]["day"]) == date) + if(return_id_dict) + compiled_stories[uncompiled_stories[story]["id"]] = uncompiled_stories[story] + else + compiled_stories += list(uncompiled_stories[story]) + uncompiled_stories -= story + + return compiled_stories + + +/datum/story_manager_interface/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "StoryManager") + ui.open() + + +/datum/story_manager_interface/ui_state(mob/user) + return GLOB.admin_state + + +/datum/story_manager_interface/ui_static_data(mob/user) + var/list/data = list() + + data["archived_stories"] = archived_stories + data["current_stories"] = current_stories + data["current_date"] = "[time2text(world.timeofday, "MM")]/[time2text(world.timeofday, "DD")]/[CURRENT_STATION_YEAR]" + + return data + + +/datum/story_manager_interface/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + if(!check_rights(R_ADMIN)) + return + + switch(action) + if("publish_article") + var/title = params["title"] || "" + var/text = params["text"] || "" + var/id = params["id"] || "" + + if(!id) + return + + id = lowertext(id) + id = replacetext(id, @"\W", "_") + + if(id in current_stories) + return + + if(id in archived_stories) // Even if we're only publishing this, it'll cause issues down the line, so let's block it anyway + return + + var/list/current_story_copy = generate_stories(NEWS_FILE, TRUE) + current_story_copy[id] = list( + "title" = title, + "text" = text, + "year" = "[CURRENT_STATION_YEAR]", + "month" = "[time2text(world.timeofday, "MM")]", + "day" = "[time2text(world.timeofday, "DD")]", + "id" = id, + ) + + rustg_file_write(json_encode(current_story_copy), NEWS_FILE) + log_admin("[usr.ckey] has published a lorecaster article with id [id].") + current_stories = generate_stories(NEWS_FILE) + ui.send_full_update() + + if("archive_article") + var/id = params["id"] + if(!id) + return + + if(!(id in generate_stories(NEWS_FILE, TRUE))) + return + + var/list/current_story_copy = generate_stories(NEWS_FILE, TRUE) + var/list/archive_story_copy = generate_stories(ARCHIVE_FILE, TRUE) + + archive_story_copy[id] = current_story_copy[id] + current_story_copy -= id + + rustg_file_write(json_encode(current_story_copy), NEWS_FILE) + rustg_file_write(json_encode(archive_story_copy), ARCHIVE_FILE) + log_admin("[usr.ckey] has archived a lorecaster article with id [id].") + current_stories = generate_stories(NEWS_FILE) + archived_stories = generate_stories(ARCHIVE_FILE) + ui.send_full_update() + + if("circulate_article") + var/id = params["id"] + if(!id) + return + + if(!(id in generate_stories(ARCHIVE_FILE, TRUE))) + return + + var/list/current_story_copy = generate_stories(NEWS_FILE, TRUE) + var/list/archive_story_copy = generate_stories(ARCHIVE_FILE, TRUE) + + current_story_copy[id] = archive_story_copy[id] + archive_story_copy -= id + + rustg_file_write(json_encode(current_story_copy), NEWS_FILE) + rustg_file_write(json_encode(archive_story_copy), ARCHIVE_FILE) + log_admin("[usr.ckey] has re-circulated an archived lorecaster article with id [id].") + current_stories = generate_stories(NEWS_FILE) + archived_stories = generate_stories(ARCHIVE_FILE) + ui.send_full_update() + diff --git a/tgstation.dme b/tgstation.dme index dd972b91803..bc84f7e7f23 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6451,6 +6451,7 @@ #include "modular_skyrat\modules\loadouts\loadout_ui\loadout_outfit_helpers.dm" #include "modular_skyrat\modules\lorecaster\code\archive_viewer.dm" #include "modular_skyrat\modules\lorecaster\code\config.dm" +#include "modular_skyrat\modules\lorecaster\code\story_manager.dm" #include "modular_skyrat\modules\lorecaster\code\subsystem.dm" #include "modular_skyrat\modules\manufacturer_examine\code\gun_company_additions.dm" #include "modular_skyrat\modules\manufacturer_examine\code\manufacturer_component.dm" diff --git a/tgui/packages/tgui/interfaces/StoryManager.tsx b/tgui/packages/tgui/interfaces/StoryManager.tsx new file mode 100644 index 00000000000..7b334e70f32 --- /dev/null +++ b/tgui/packages/tgui/interfaces/StoryManager.tsx @@ -0,0 +1,148 @@ +import { useBackend, useLocalState } from '../backend'; +import { Collapsible, Section, TextArea, LabeledList, Button } from '../components'; +import { Window } from '../layouts'; + +type StoryManagerData = { + current_stories: Story[]; + archived_stories: Story[]; + current_date: string; +}; + +type Story = { + title: string; + text: string; + id: string; + year: string; + month: string; + day: string; +}; + +export const StoryManager = (props, context) => { + const { data, act } = useBackend(context); + const { current_stories, archived_stories, current_date } = data; + + const [title, setTitle] = useLocalState(context, 'title', ''); + const [text, setText] = useLocalState(context, 'text', ''); + const [id, setID] = useLocalState(context, 'id', ''); + + return ( + + +
+ Lorecaster story manager +
+ Anything published here will not appear until the next round! +
+ + Do not mess with this unless you know what you're doing. + +
+
+ + +