diff --git a/code/datums/keybinding/admin.dm b/code/datums/keybinding/admin.dm
index 80936aa41e76..a5db1f6b51b2 100644
--- a/code/datums/keybinding/admin.dm
+++ b/code/datums/keybinding/admin.dm
@@ -30,14 +30,14 @@
hotkey_keys = list("F6")
name = "player_panel_new"
full_name = "Player Panel New"
- description = "Opens up the new player panel"
+ description = "Opens up the new TGUI player panel"
keybind_signal = COMSIG_KB_ADMIN_PLAYERPANELNEW_DOWN
/datum/keybinding/admin/player_panel_new/down(client/user)
. = ..()
if(.)
return
- user.holder.player_panel_new()
+ user.holder.player_panel_veth()
return TRUE
/datum/keybinding/admin/toggle_buildmode_self
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 877a998ee651..35506e0fa865 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -51,6 +51,9 @@ GLOBAL_PROTECT(admin_verbs_admin)
/datum/verbs/menu/Admin/verb/playerpanel, /* It isn't /datum/admin but it fits no less */
/datum/admins/proc/kick_player_by_ckey, //MONKESTATION ADDITION - kick a player by their ckey
/datum/admins/proc/change_shuttle_events, //allows us to change the shuttle events
+ /datum/admins/proc/player_panel_veth,
+ /datum/admins/proc/vuap_open_context,
+ /datum/admins/proc/vuap_open,
// Client procs
/client/proc/admin_call_shuttle, /*allows us to call the emergency shuttle*/
/client/proc/admin_cancel_shuttle, /*allows us to cancel the emergency shuttle, sending it back to centcom*/
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 88daf9cf16a2..bb387444d705 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -725,7 +725,9 @@
else if(href_list["adminplayeropts"])
var/mob/M = locate(href_list["adminplayeropts"])
- show_player_panel(M)
+ usr.client.VUAP_selected_mob = M
+ usr.client.selectedPlayerCkey = M.ckey
+ usr.client.holder.vuap_open()
else if(href_list["ppbyckey"])
var/target_ckey = href_list["ppbyckey"]
@@ -740,7 +742,9 @@
return
to_chat(usr, span_notice("Jumping to [target_ckey]'s new mob: [target_mob]!"))
- show_player_panel(target_mob)
+ usr.client.VUAP_selected_mob = target_mob
+ usr.client.selectedPlayerCkey = target_mob.ckey
+ usr.client.holder.vuap_open()
else if(href_list["adminopendemo"])
usr.client << link("http://viewer.monkestation.com/?roundid=[GLOB.round_id]&password=[CONFIG_GET(string/replay_password)]#[world.time]") //opens current round at current time
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 7c7b24e72984..29452befa1ff 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1330,7 +1330,9 @@
if(href_list[VV_HK_PLAYER_PANEL])
if(!check_rights(NONE))
return
- usr.client.holder.show_player_panel(src)
+ usr.client.VUAP_selected_mob = src
+ usr.client.selectedPlayerCkey = src.ckey
+ usr.client.holder.vuap_open()
if(href_list[VV_HK_GODMODE])
if(!check_rights(R_ADMIN))
return
diff --git a/code/modules/requests/request_manager.dm b/code/modules/requests/request_manager.dm
index eb16a38fc3bc..b39cb2d9ad72 100644
--- a/code/modules/requests/request_manager.dm
+++ b/code/modules/requests/request_manager.dm
@@ -170,8 +170,9 @@ GLOBAL_DATUM_INIT(requests, /datum/request_manager, new)
switch(action)
if ("pp")
- var/mob/M = request.owner?.mob
- usr.client.holder.show_player_panel(M)
+ usr.client.VUAP_selected_mob = request.owner?.mob
+ usr.client.selectedPlayerCkey = request.owner?.mob.ckey
+ usr.client.holder.vuap_open()
return TRUE
if ("vv")
var/mob/M = request.owner?.mob
diff --git a/code/modules/wiremod/core/admin_panel.dm b/code/modules/wiremod/core/admin_panel.dm
index 1c8dca555741..56cda8fd23b3 100644
--- a/code/modules/wiremod/core/admin_panel.dm
+++ b/code/modules/wiremod/core/admin_panel.dm
@@ -68,7 +68,9 @@
circuit.ui_interact(usr)
if ("open_player_panel")
var/datum/mind/inserter = circuit.inserter_mind?.resolve()
- usr.client?.holder?.show_player_panel(inserter?.current)
+ usr.client.VUAP_selected_mob = inserter?.current
+ usr.client.selectedPlayerCkey = inserter?.current?.ckey
+ usr.client?.holder?.vuap_open()
return TRUE
diff --git a/monkestation/code/modules/veth_misc_items/veth_player_panel/readme.md b/monkestation/code/modules/veth_misc_items/veth_player_panel/readme.md
new file mode 100644
index 000000000000..529172d57820
--- /dev/null
+++ b/monkestation/code/modules/veth_misc_items/veth_player_panel/readme.md
@@ -0,0 +1,29 @@
+## Title:
+
+
+MODULE ID: TGUIPLAYERPANEL
+
+### Description:
+This PR adds a TGUI version of player panel. It should have all of the features of the current player panel, with some additional "most used" buttons on the main player panel. Ideally, if all goes well, I'd like to phase out the older player panel, but this will need extensive testing.
+
+### Master file additions
+
+- N/A
+
+
+### Included files that are not contained in this module:
+
+#NEW tgui/packages/tgui/interfaces/VUAP_personal.tsx
+#NEW tgui/packages/tgui/interfaces/veth_player_panel.tsx
+#CHANGE code/modules/admin/admin_verbs.dm
+
+
+
+
+### Credits:
+
+
+
+Made by Veth
+Special thanks to Fleepy, Pooba & Absolucy for their help.
+
diff --git a/monkestation/code/modules/veth_misc_items/veth_player_panel/veth_player_panel.dm b/monkestation/code/modules/veth_misc_items/veth_player_panel/veth_player_panel.dm
new file mode 100644
index 000000000000..e6084c148d03
--- /dev/null
+++ b/monkestation/code/modules/veth_misc_items/veth_player_panel/veth_player_panel.dm
@@ -0,0 +1,622 @@
+/datum/player_panel_veth/ //required for tgui component
+ var/title = "Veth's Ultimate Player Panel"
+
+/datum/admins/proc/player_panel_veth() //proc for verb in game tab
+
+ set name = "Player Panel Veth"
+ set category = "Admin.Game"
+ set desc = "Updated Player Panel with TGUI. Currently in testing."
+
+ if (!check_rights(NONE))
+ message_admins("[key_name(src)] attempted to use VUAP without sufficient rights.")
+ return
+ var/datum/player_panel_veth/tgui = new(usr)
+ tgui.ui_interact(usr)
+ to_chat(src, span_interface("VUAP has been opened!"), confidential = TRUE)
+ SSblackbox.record_feedback("tally", "admin_verb", 1, "VUAP")
+
+/datum/player_panel_veth/ui_data(mob/user)
+ var/list/players = list()
+ var/mobs = sort_mobs()
+ for (var/mob/mob_data in mobs)
+ if (mob_data.ckey)
+ var/player_previous_names = get_player_details(mob_data)?.played_names?.Join(", ")
+ players += list(list(
+ "name" = mob_data.name || "No Character",
+ "old_name" = player_previous_names || "No Previous Characters",
+ "job" = mob_data.job || "No Job",
+ "ckey" = mob_data.ckey || "No Ckey",
+ "is_antagonist" = is_special_character(mob_data, allow_fake_antags = TRUE),
+ "last_ip" = mob_data.lastKnownIP || "No Last Known IP",
+ "ref" = REF(mob_data)
+ ))
+ return list(
+ "Data" = players
+ )
+
+/datum/player_panel_veth/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ if(..())
+ return
+ if(!check_rights(NONE))
+ return
+ var/mob/selected_mob = get_mob_by_ckey(params["selectedPlayerCkey"]) //gets the mob datum from the ckey in client datum which we've saved. if there's a better way to do this please let me know
+ switch(action) //switch for all the actions from the frontend - all of the Topic() calls check rights & log inside themselves.
+ if("sendPrivateMessage")
+ usr.client.cmd_admin_pm(selected_mob.ckey)
+ SSblackbox.record_feedback("tally", "VUAP", 1, "PM")
+ return
+ if("follow")
+ usr.client.holder.Topic(null, list(
+ "adminplayerobservefollow" = REF(selected_mob),
+ "admin_token" = usr.client.holder.href_token
+ ))
+ to_chat(usr, "Now following [selected_mob.ckey].", confidential = TRUE)
+ return
+ if("smite")
+ usr.client.holder.Topic(null, list(
+ "adminsmite" = REF(selected_mob),
+ "admin_token" = usr.client.holder.href_token
+ ))
+ to_chat(usr, "Smiting [selected_mob.ckey].", confidential = TRUE)
+ if("refresh")
+ ui.send_update()
+ return
+ if("oldPP")
+ usr.client.holder.player_panel_new()
+ SSblackbox.record_feedback("tally", "VUAP", 1, "OldPP")
+ return
+ if("checkPlayers")
+ usr.client.check_players() //logs/rightscheck inside the proc
+ return
+ if("checkAntags")
+ usr.client.check_antagonists() //logs/rightscheck inside the proc
+ return
+ if("faxPanel")
+ usr.client.fax_panel() //logs/rightscheck inside the proc
+ return
+ if("gamePanel")
+ usr.client.game_panel() //logs/rightscheck inside the proc
+ return
+ if("comboHUD")
+ usr.client.toggle_combo_hud() //logs/rightscheck inside the proc
+ return
+ if("adminVOX")
+ usr.client.AdminVOX() //logs/rightscheck inside the proc
+ return
+ if("generateCode")
+ usr.client.generate_code() //logs/rightscheck inside the proc
+ return
+ if("viewOpfors")
+ usr.client.view_opfors() //logs/rightscheck inside the proc
+ return
+ if("openAdditionalPanel") //logs/rightscheck inside the proc
+ usr.client.selectedPlayerCkey = params["selectedPlayerCkey"]
+ usr.client.holder.vuap_open()
+ return
+ if("createCommandReport")
+ usr.client.cmd_admin_create_centcom_report() //logs/rightscheck inside the proc
+ return
+ if("logs")
+ usr.client.holder.Topic(null, list(
+ "individuallog" = REF(selected_mob),
+ "admin_token" = usr.client.holder.href_token
+ ))
+ return
+ if("notes") //i'm pretty sure this checks rights inside the proc but to be safe
+ if(!check_rights(NONE))
+ return
+ browse_messages(target_ckey = selected_mob.ckey)
+ return
+ if("vv") //logs/rightscheck inside the proc
+ usr.client.debug_variables(selected_mob)
+ return
+ if("tp")
+ usr.client.holder.Topic(null, list(
+ "traitor" = REF(selected_mob),
+ "admin_token" = usr.client.holder.href_token
+ ))
+ return
+ if("adminaiinteract") //loggin inside the proc
+ usr.client.toggle_AI_interact()
+
+/datum/player_panel_veth/ui_interact(mob/user, datum/tgui/ui)
+
+ ui = SStgui.try_update_ui(user, src, ui)
+
+ if(!ui)
+ ui = new(user, src, "VethPlayerPanel")
+ ui.set_autoupdate(FALSE)
+ ui.open()
+
+/datum/player_panel_veth/ui_state(mob/user)
+ return GLOB.admin_state
+
+
+/client //this is needed to hold the selected player ckey for moving to and from pp/vuap
+ ///This is used to hold the ckey of the selected player for moving to and from the player panel and vuap
+ var/selectedPlayerCkey = ""
+ ///this is used to hold the mob of the selected player in case the ckey can't be found (this enables pp'ing soulless mobs)
+ var/VUAP_selected_mob = null
+
+/datum/admins/proc/vuap_open_context(mob/r_clicked_mob in GLOB.mob_list) //this is the proc for the right click menu
+ set category = null
+ set name = "Open New Player Panel"
+ if(!check_rights(NONE))
+ return
+ if(!length(r_clicked_mob.ckey) || r_clicked_mob.ckey[1] == "@")
+ var/mob/player = r_clicked_mob
+ var/datum/mind/player_mind = get_mind(player, include_last = TRUE)
+ var/player_mind_ckey = ckey(player_mind.key)
+ usr.client.VUAP_selected_mob = r_clicked_mob
+ usr.client.holder.vuap_open()
+ tgui_alert(usr, "WARNING! This mob has no associated Mind! Most actions will not work. Last ckey to control this mob is [player_mind_ckey].", "No Mind!")
+
+ else
+ usr.client.selectedPlayerCkey = r_clicked_mob.ckey
+ usr.client.holder.vuap_open()
+ SSblackbox.record_feedback("tally", "admin_verb", 1, "VUAP")
+
+/datum/vuap_personal
+
+/*possible bugs that might occur:
+- Atm, if you receive an admin ticket off of something that has changed mob before you hit the PP button, you'll get the old soulless mob. There is a
+warning dialogue box with the ckey of the previous holder of this mob, however.
+if you know how to fix the above and are smarter than me please let me know and I'll give you a kiss
+I've tried to make it as a simple as possible to add new buttons, most of it should be a copy and paste job.area
+
+
+
+Some (poor) explanation of what's going on -
+player_panel_veth is the new tgui version of the player panel, it also includes some most pressed verbs
+I've tried to comment in as much stuff as possible so it can be changed in the future is necessary
+Vuap_personal is the new tgui version of the options panel. It basically does everything the same way the player panel does
+minus some features that the player panel didn't have I guess.
+the client/var/selectedPlayerCkey is used to hold the selected player ckey for moving to and from pp/vuap
+If you want to add info the player panel:
+- add the appropriate info into the backend in ui_data. This gotta be formatted correctly or tgui will scream
+- add the data to the frontend in VethPlayerPanel.tsx, adding a row onto the following table:
+
+ Ckey
+ Char Name
+ Also Known As
+ Job
+ Antagonist
+ Last IP
+ Actions
+
+ {filteredData.map((player) => (
+
+ {player.ckey}
+ {player.name}
+ {player.old_name}
+ {player.job}
+
+ {player.is_antagonist ? (
+ Yes
+ ) : (
+ No
+ )}
+
+ {player.last_ip}
+Same goes for VUAP_personal.tsx, but you gotta add it to the table in there instead :)
+If you want to add a button to the player panel:
+- add the backend instructions for it in /datum/veth_player_panel/ui_act into the action switch (the frontend and backend action names must match, case sensitive)
+- add the button to the frontend. You can basically copy and paste one of the buttons that's in VethPlayerPanel.tsx and add it to a column.
+
+If you want to add a button to the vuap panel:
+- add the backend instructions for it in /datum/vuap_personal/ui_act into the action switch (the frontend and backend action names must match, case sensitive)
+- add the button to the frontend. You can basically copy and paste one of the buttons that's in VUAP_personal.tsx and add it to a section.
+
+Some explanation of the frontend because it's not known by many people:
+