Skip to content

Commit

Permalink
Merge pull request #11 from Crowbar764/tgui-playtimes
Browse files Browse the repository at this point in the history
TGUI: Playtimes Panel
  • Loading branch information
MosleyTheMalO authored Jul 12, 2024
2 parents a73df44 + 65329fe commit c37cf11
Show file tree
Hide file tree
Showing 9 changed files with 347 additions and 6 deletions.
9 changes: 3 additions & 6 deletions code/modules/admin/verbs/admin.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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 += "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Playtime Report</title></head><body>Playtime:<BR><UL>"
for(var/client/client in sort_list(GLOB.clients, GLOBAL_PROC_REF(cmp_playtime_asc)))
msg += "<LI> [ADMIN_PP(client.mob)] [key_name_admin(client)]: <A href='?_src_=holder;[HrefToken()];getplaytimewindow=[REF(client.mob)]'>" + client.get_exp_living() + "</a></LI>"
msg += "</UL></BODY></HTML>"
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))
Expand Down
17 changes: 17 additions & 0 deletions modular_zzplurt/code/datums/components/crafting/crafting.dm
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions modular_zzplurt/code/game/objects/items/devices/transfer_valve.dm
Original file line number Diff line number Diff line change
@@ -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

123 changes: 123 additions & 0 deletions modular_zzplurt/code/modules/admin/playtimes.dm
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions modular_zzplurt/code/modules/wiremod/core/integrated_circuit.dm
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions tgstation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
156 changes: 156 additions & 0 deletions tgui/packages/tgui/interfaces/PlayerPlaytimes.tsx
Original file line number Diff line number Diff line change
@@ -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<Data>();
const { clients } = data;
return (
<Window title="Player Playtimes" width={600} height={700}>
<Window.Content overflow="auto">
<Section>
<Table>
<Table.Row>
<Table.Cell>
<center>
<Icon name="clock" />
</center>
</Table.Cell>
<Table.Cell pb={1}>
<center>Ckey</center>
</Table.Cell>
<Table.Cell>
<center>Real Name</center>
</Table.Cell>
<Table.Cell>
<center>Flags</center>
</Table.Cell>
<Table.Cell>
<center>Actions</center>
</Table.Cell>
</Table.Row>
{clients.map((client) => (
<Table.Row key={client.name} className="Table__row candystripe">
<Table.Cell>
<center>
<Button
content={client.playtime_hours}
color="transparent"
tooltip="View playtime for this player"
tooltipPosition="bottom"
onClick={() =>
act('view_playtime', {
ckey: client.ckey,
})
}
/>
</center>
</Table.Cell>
<Table.Cell>
<center>
{!!client.new_account && (
<Tooltip content={client.new_account}>
<Icon name="sparkles" />
</Tooltip>
)}{' '}
{client.ckey}
</center>
</Table.Cell>
<Table.Cell>
<center>
{!client.ingame ? (
<Box color="cyan">(At lobby)</Box>
) : (
!!client.observer && (
<Tooltip content="This player is observing">
<Icon name="ghost" />
</Tooltip>
)
)}{' '}
{client.name}
</center>
</Table.Cell>
<Table.Cell>
<center>
{client.flags.map((flag) => (
<Button
key={flag.icon}
icon={flag.icon}
color="average"
tooltip={flag.tooltip}
/>
))}
</center>
</Table.Cell>
<Table.Cell>
<center>
<Button
content={<b>PM</b>}
color="transparent"
tooltip="Send a private message to this player"
tooltipPosition="bottom"
onClick={() =>
act('admin_pm', {
ckey: client.ckey,
})
}
/>
<Button
icon="user"
color="transparent"
tooltip="Open player panel"
tooltipPosition="bottom"
onClick={() =>
act('player_panel', {
ckey: client.ckey,
})
}
/>
<Button
icon="terminal"
color="transparent"
tooltip="View Variables"
tooltipPosition="bottom"
onClick={() =>
act('view_variables', {
ckey: client.ckey,
})
}
/>
<Button
icon="ghost"
color="transparent"
tooltip="Admin-follow"
tooltipPosition="bottom"
onClick={() =>
act('observe', {
ckey: client.ckey,
})
}
/>
</center>
</Table.Cell>
<br />
</Table.Row>
))}
</Table>
</Section>
</Window.Content>
</Window>
);
};

0 comments on commit c37cf11

Please sign in to comment.