diff --git a/code/modules/admin/verbs/admin.dm b/code/modules/admin/verbs/admin.dm index 3aaab5bae58fc..86bbd15ff3571 100644 --- a/code/modules/admin/verbs/admin.dm +++ b/code/modules/admin/verbs/admin.dm @@ -42,12 +42,9 @@ ADMIN_VERB(cmd_admin_check_player_exp, R_ADMIN, "Player Playtime", "View player to_chat(user, span_warning("Tracking is disabled in the server configuration file."), confidential = TRUE) return - var/list/msg = list() - msg += "Playtime ReportPlaytime:
" - user << browse(msg.Join(), "window=Player_playtime_check") + // SPLURT EDIT START + new /datum/player_playtime(usr) + // SPLURT EDIT END /client/proc/trigger_centcom_recall() if(!check_rights(R_ADMIN)) diff --git a/modular_zzplurt/code/datums/components/crafting/crafting.dm b/modular_zzplurt/code/datums/components/crafting/crafting.dm new file mode 100644 index 0000000000000..ea99b2e3a3657 --- /dev/null +++ b/modular_zzplurt/code/datums/components/crafting/crafting.dm @@ -0,0 +1,17 @@ +/datum/component/personal_crafting/ui_act(action, params) + . = ..() + if(.) + return + + switch(action) + if("make", "make_mass") + var/datum/crafting_recipe/crafting_recipe = locate(params["recipe"]) in (mode ? GLOB.cooking_recipes : GLOB.crafting_recipes) + + if (istype(crafting_recipe, /datum/crafting_recipe/improv_explosive) || istype(crafting_recipe, /datum/crafting_recipe/molotov) || istype(crafting_recipe, /datum/crafting_recipe/chemical_payload) || istype(crafting_recipe, /datum/crafting_recipe/chemical_payload2)) + var/client/client = usr.client + if (CONFIG_GET(flag/use_exp_tracking) && client && client.get_exp_living(TRUE) < 8 HOURS) // Player with less than 8 hours playtime is making an IED or molotov cocktail. + if(client.next_ied_grief_warning < world.time) + var/turf/T = get_turf(usr) + client.next_ied_grief_warning = world.time + 15 MINUTES // Wait 15 minutes before alerting admins again + message_admins("[span_adminhelp("ANTI-GRIEF:")] New player [ADMIN_LOOKUPFLW(usr)] has crafted an IED or Molotov at [ADMIN_VERBOSEJMP(T)].") + client.crafted_ied = TRUE diff --git a/modular_zzplurt/code/game/objects/items/devices/transfer_valve.dm b/modular_zzplurt/code/game/objects/items/devices/transfer_valve.dm new file mode 100644 index 0000000000000..2bae09b88b051 --- /dev/null +++ b/modular_zzplurt/code/game/objects/items/devices/transfer_valve.dm @@ -0,0 +1,11 @@ +/obj/item/transfer_valve/attack_hand(mob/user, list/modifiers) + . = ..() + + var/client/client = user.client + if (CONFIG_GET(flag/use_exp_tracking) && client && client.get_exp_living(TRUE) < 8 HOURS) // Player with less than 8 hours playtime has touched a bomb valve. + if(client.next_valve_grief_warning < world.time) + var/turf/T = get_turf(src) + client.next_valve_grief_warning = world.time + 15 MINUTES // Wait 15 minutes before alerting admins again + message_admins("[span_adminhelp("ANTI-GRIEF:")] New player [ADMIN_LOOKUPFLW(user)] touched \a [src] at [ADMIN_VERBOSEJMP(T)].") + client.touched_transfer_valve = TRUE + diff --git a/modular_zzplurt/code/modules/admin/playtimes.dm b/modular_zzplurt/code/modules/admin/playtimes.dm new file mode 100644 index 0000000000000..1ef4bb970640b --- /dev/null +++ b/modular_zzplurt/code/modules/admin/playtimes.dm @@ -0,0 +1,123 @@ +/client + var/datum/player_playtime/playtime_menu + var/next_valve_grief_warning = 0 + var/next_chem_grief_warning = 0 + var/next_canister_grief_warning = 0 + var/next_ied_grief_warning = 0 + var/next_circuit_grief_warning = 0 + var/touched_transfer_valve = FALSE + var/used_chem_dispenser = FALSE + var/touched_canister = FALSE + var/crafted_ied = FALSE + var/touched_circuit = FALSE + var/uses_vpn = FALSE + +/datum/player_playtime/New(mob/viewer) + ui_interact(viewer) + +/datum/player_playtime/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PlayerPlaytimes", "Player Playtimes") + ui.open() + +/datum/player_playtime/ui_state(mob/user) + return GLOB.admin_state + +/datum/player_playtime/ui_data(mob/user) + var/list/data = list() + + var/list/clients = list() + for(var/client/C in GLOB.clients) + var/list/client = list() + + client["ckey"] = C.ckey + client["playtime_hours"] = C.get_exp_living() + client["flags"] = check_flags(C) + + var/mob/M = C.mob + client["observer"] = isobserver(M) + client["ingame"] = !isnewplayer(M) + client["name"] = M.real_name + var/nnpa = CONFIG_GET(number/notify_new_player_age) + if(nnpa >= 0) + if(C.account_age >= 0 && (C.account_age < CONFIG_GET(number/notify_new_player_age))) + client["new_account"] = "New BYOND account [C.account_age] day[(C.account_age==1?"":"s")] old, created on [C.account_join_date]" + + clients += list(client) + + clients = sort_list(clients, GLOBAL_PROC_REF(cmp_playtime_asc)) + data["clients"] = clients + return data + +/datum/player_playtime/ui_act(action, params) + if(..()) + return + + switch(action) + if("view_playtime") + var/mob/target = get_mob_by_ckey(params["ckey"]) + usr.client.holder.cmd_show_exp_panel(target.client) + if("admin_pm") + usr.client.cmd_admin_pm(params["ckey"]) + if("player_panel") + var/mob/target = get_mob_by_ckey(params["ckey"]) + SSadmin_verbs.dynamic_invoke_verb(usr.client, /datum/admin_verb/show_player_panel, target) + if("view_variables") + var/mob/target = get_mob_by_ckey(params["ckey"]) + usr.client.debug_variables(target) + if("observe") + if(!isobserver(usr) && !check_rights(R_ADMIN)) + return + + var/mob/target = get_mob_by_key(params["ckey"]) + if(!target) + to_chat(usr, span_notice("Player not found.")) + return + + var/client/C = usr.client + if(!isobserver(usr)) + SSadmin_verbs.dynamic_invoke_verb(usr.client, /datum/admin_verb/admin_ghost) + var/mob/dead/observer/A = C.mob + A.ManualFollow(target) + +/datum/player_playtime/proc/check_flags(client/C) + var/list/flags = list() + + if (C.touched_transfer_valve) + var/list/flag = list() + flag["icon"] = "bomb" + flag["tooltip"] = "This player touched a Transfer Valve." + flags += list(flag) + + if (C.used_chem_dispenser) + var/list/flag = list() + flag["icon"] = "flask" + flag["tooltip"] = "This player used a Chem Dispenser." + flags += list(flag) + + if (C.touched_canister) + var/list/flag = list() + flag["icon"] = "spray-can" + flag["tooltip"] = "This player touched a gas canister." + flags += list(flag) + + if (C.crafted_ied) + var/list/flag = list() + flag["icon"] = "hammer" + flag["tooltip"] = "This player crafted an IED or Molotov." + flags += list(flag) + + if (C.touched_circuit) + var/list/flag = list() + flag["icon"] = "code-branch" + flag["tooltip"] = "This player touched an integrated circuit." + flags += list(flag) + + if(C.uses_vpn) + var/list/flag = list() + flag["icon"] = "wifi" + flag["tooltip"] = "This player is [round(C.ip_intel*100, 0.01)]% likely to be using a Proxy/VPN" + flags += list(flag) + + return flags diff --git a/modular_zzplurt/code/modules/atmospherics/machinery/portable/canister.dm b/modular_zzplurt/code/modules/atmospherics/machinery/portable/canister.dm new file mode 100644 index 0000000000000..569149cb2016a --- /dev/null +++ b/modular_zzplurt/code/modules/atmospherics/machinery/portable/canister.dm @@ -0,0 +1,10 @@ +/obj/machinery/portable_atmospherics/canister/ui_interact(mob/user, datum/tgui/ui) + . = ..() + + var/client/client = user.client + if (CONFIG_GET(flag/use_exp_tracking) && client && client.get_exp_living(TRUE) < 8 HOURS) // Player with less than 8 hours playtime is interacting with this canister. + if(client.next_canister_grief_warning < world.time) + var/turf/T = get_turf(src) + client.next_canister_grief_warning = world.time + 15 MINUTES // Wait 15 minutes before alerting admins again + message_admins("[span_adminhelp("ANTI-GRIEF:")] New player [ADMIN_LOOKUPFLW(user)] has touched \a [src] at [ADMIN_VERBOSEJMP(T)].") + client.touched_canister = TRUE diff --git a/modular_zzplurt/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/modular_zzplurt/code/modules/reagents/chemistry/machinery/chem_dispenser.dm new file mode 100644 index 0000000000000..5b3b50341f596 --- /dev/null +++ b/modular_zzplurt/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -0,0 +1,11 @@ +/obj/machinery/chem_dispenser/ui_interact(mob/user, datum/tgui/ui) + . = ..() + + var/client/client = user.client + if (CONFIG_GET(flag/use_exp_tracking) && client && client.get_exp_living(TRUE) < 8 HOURS) // Player with less than 8 hours playtime is using this machine. + if(client.next_chem_grief_warning < world.time) + if(!istype(src, /obj/machinery/chem_dispenser/drinks) && !istype(src, /obj/machinery/chem_dispenser/mutagen) && !istype(src, /obj/machinery/chem_dispenser/mutagensaltpeter) && !istype(src, /obj/machinery/chem_dispenser/abductor)) // These types aren't used for grief + var/turf/T = get_turf(src) + client.next_chem_grief_warning = world.time + 15 MINUTES // Wait 15 minutes before alerting admins again + message_admins("[span_adminhelp("ANTI-GRIEF:")] New player [ADMIN_LOOKUPFLW(user)] used \a [src] at [ADMIN_VERBOSEJMP(T)].") + client.used_chem_dispenser = TRUE diff --git a/modular_zzplurt/code/modules/wiremod/core/integrated_circuit.dm b/modular_zzplurt/code/modules/wiremod/core/integrated_circuit.dm new file mode 100644 index 0000000000000..9fdefe58240f3 --- /dev/null +++ b/modular_zzplurt/code/modules/wiremod/core/integrated_circuit.dm @@ -0,0 +1,10 @@ +/obj/item/integrated_circuit/ui_interact(mob/user, datum/tgui/ui) + . = ..() + + var/client/client = user.client + if (CONFIG_GET(flag/use_exp_tracking) && client && client.get_exp_living(TRUE) < 8 HOURS) // Player with less than 8 hours playtime is using this machine. + if(client.next_circuit_grief_warning < world.time) + var/turf/T = get_turf(src) + client.next_circuit_grief_warning = world.time + 15 MINUTES // Wait 15 minutes before alerting admins again + message_admins("[span_adminhelp("ANTI-GRIEF:")] New player [ADMIN_LOOKUPFLW(user)] has touched \a [src] at [ADMIN_VERBOSEJMP(T)].") + client.touched_circuit = TRUE diff --git a/tgstation.dme b/tgstation.dme index 57eac54201ee4..001b53f70cbff 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -9104,8 +9104,12 @@ #include "modular_zzplurt\code\_globalvars\mobs.dm" #include "modular_zzplurt\code\controllers\configuration\entries\discord.dm" #include "modular_zzplurt\code\controllers\subsystem\discord.dm" +#include "modular_zzplurt\code\datums\components\crafting\crafting.dm" +#include "modular_zzplurt\code\game\objects\items\devices\transfer_valve.dm" #include "modular_zzplurt\code\modules\admin\player_panel.dm" +#include "modular_zzplurt\code\modules\admin\playtimes.dm" #include "modular_zzplurt\code\modules\admin\transform.dm" +#include "modular_zzplurt\code\modules\atmospherics\machinery\portable\canister.dm" #include "modular_zzplurt\code\modules\client\client_procs.dm" #include "modular_zzplurt\code\modules\client\preferences\player_panel.dm" #include "modular_zzplurt\code\modules\client\verbs\looc.dm" @@ -9117,4 +9121,6 @@ #include "modular_zzplurt\code\modules\mob\dead\new_player\new_player.dm" #include "modular_zzplurt\code\modules\mob\living\living.dm" #include "modular_zzplurt\code\modules\mob\living\living_defines.dm" +#include "modular_zzplurt\code\modules\reagents\chemistry\machinery\chem_dispenser.dm" +#include "modular_zzplurt\code\modules\wiremod\core\integrated_circuit.dm" // END_INCLUDE diff --git a/tgui/packages/tgui/interfaces/PlayerPlaytimes.tsx b/tgui/packages/tgui/interfaces/PlayerPlaytimes.tsx new file mode 100644 index 0000000000000..0db81a27f019f --- /dev/null +++ b/tgui/packages/tgui/interfaces/PlayerPlaytimes.tsx @@ -0,0 +1,156 @@ +import { useBackend } from '../backend'; +import { Box, Button, Icon, Section, Table, Tooltip } from '../components'; +import { Window } from '../layouts'; + +type Data = { + clients: { + ckey: string; + name: string; + observer: boolean; + ingame: boolean; + new_account: string; + playtime_hours: number; + flags: { + icon: string; + tooltip: string; + }[]; + }[]; +}; + +export const PlayerPlaytimes = () => { + const { act, data } = useBackend(); + const { clients } = data; + return ( + + +
+ + + +
+ +
+
+ +
Ckey
+
+ +
Real Name
+
+ +
Flags
+
+ +
Actions
+
+
+ {clients.map((client) => ( + + +
+
+
+ +
+ {!!client.new_account && ( + + + + )}{' '} + {client.ckey} +
+
+ +
+ {!client.ingame ? ( + (At lobby) + ) : ( + !!client.observer && ( + + + + ) + )}{' '} + {client.name} +
+
+ +
+ {client.flags.map((flag) => ( +
+
+ +
+
+
+
+
+ ))} +
+
+
+
+ ); +};