mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-29 16:18:01 +01:00
## About The Pull Request In `modular_zubbers/code/modules/admin/player_panel.dm` there was an overwrite for the `/datum/ui_state/admin_state/can_use_topic(src_object, mob/user)` proc which was hard coded to check if the admin opening a TGUI window had a `R_ADMIN` permission. This is bad, because that permission gives access to like 90% of all permissions available in the admin panel - meaning that you cannot create admins with say, only the permission to spawn stuff using the `R_SPAWN` flag. This PR fixes it by removing the overwrite - as this proc is also present in `code/modules/tgui/states/admin.dm` on line 24, and it does exactly the same thing, except that it checks the TGUI panels required perms, vs only the `R_ADMIN` flag. ## Why It's Good For The Game Fixes most admin windows requiring the `R_ADMIN` flag to open - they will now require the flag set in `required_perms` (which is `R_ADMIN` by default). ## Proof Of Testing <img width="1500" height="391" alt="image" src="https://github.com/user-attachments/assets/26da7eb7-2a94-4a88-86e6-ec61cd1e4e77" /> Spawn panel, requiring the `R_SPAWN` flag, open despite me not having the `R_ADMIN` flag. ## Changelog 🆑 Swan fix: fixes some admin TGUI menus requiring the R_ADMIN flag instead of any other permission flag. /🆑
768 lines
26 KiB
Plaintext
768 lines
26 KiB
Plaintext
GLOBAL_LIST_INIT(mute_bits, list(
|
|
list(name = "IC", bitflag = MUTE_IC),
|
|
list(name = "OOC", bitflag = MUTE_OOC),
|
|
list(name = "LOOC", bitflag = MUTE_LOOC),
|
|
list(name = "Pray", bitflag = MUTE_PRAY),
|
|
list(name = "Ahelp", bitflag = MUTE_ADMINHELP),
|
|
list(name = "Deadchat", bitflag = MUTE_DEADCHAT)
|
|
))
|
|
|
|
GLOBAL_DATUM_INIT(admin_state, /datum/ui_state/admin_state, new)
|
|
|
|
GLOBAL_LIST_INIT(pp_limbs, list(
|
|
"Head" = BODY_ZONE_HEAD,
|
|
"Left leg" = BODY_ZONE_L_LEG,
|
|
"Right leg" = BODY_ZONE_R_LEG,
|
|
"Left arm" = BODY_ZONE_L_ARM,
|
|
"Right arm" = BODY_ZONE_R_ARM
|
|
))
|
|
|
|
/datum/player_panel
|
|
var/mob/target_mob
|
|
var/client/target_client
|
|
var/discord_id_cache
|
|
|
|
/datum/player_panel/New(mob/target)
|
|
. = ..()
|
|
target_mob = target
|
|
|
|
/datum/player_panel/Destroy(force, ...)
|
|
target_mob = null
|
|
target_client = null
|
|
|
|
SStgui.close_uis(src)
|
|
return ..()
|
|
|
|
/datum/player_panel/ui_interact(mob/user, datum/tgui/ui)
|
|
if(!target_mob)
|
|
return
|
|
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if (!ui)
|
|
ui = new(user, src, "PlayerPanel", "[target_mob.real_name] Player Panel")
|
|
ui.open()
|
|
|
|
/datum/player_panel/ui_state(mob/user)
|
|
return GLOB.admin_state
|
|
|
|
/datum/player_panel/ui_data(mob/user)
|
|
. = list()
|
|
|
|
if(!target_mob)
|
|
return .
|
|
|
|
.["mob_name"] = target_mob.real_name
|
|
.["mob_type"] = target_mob.type
|
|
.["admin_mob_type"] = user.client?.mob.type
|
|
.["godmode"] = HAS_TRAIT(target_mob, TRAIT_GODMODE)
|
|
|
|
var/mob/living/living_mob = target_mob
|
|
if (istype(living_mob))
|
|
.["is_frozen"] = living_mob.admin_frozen
|
|
.["is_slept"] = living_mob.admin_sleeping
|
|
.["mob_scale"] = living_mob.current_size
|
|
.["mob_speed"] = living_mob.cached_multiplicative_slowdown
|
|
.["mob_status_flags"] = living_mob.status_flags
|
|
|
|
.["discord_id"] = discord_id_cache
|
|
|
|
if(target_mob.client)
|
|
target_client = target_mob.client
|
|
.["client_ckey"] = target_client.ckey
|
|
.["client_muted"] = target_client.prefs.muted
|
|
.["client_rank"] = target_client.holder ? target_client.holder.ranks : "Player"
|
|
else
|
|
target_client = null
|
|
.["client_ckey"] = null
|
|
|
|
if (target_mob.ckey)
|
|
.["last_ckey"] = get_target_ckey()
|
|
|
|
/datum/player_panel/ui_static_data()
|
|
. = list()
|
|
|
|
if(!target_mob)
|
|
return .
|
|
|
|
.["transformables"] = GLOB.pp_transformables
|
|
.["glob_limbs"] = GLOB.pp_limbs
|
|
.["glob_mute_bits"] = GLOB.mute_bits
|
|
.["current_time"] = time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss")
|
|
|
|
// Status flags
|
|
.["glob_status_flags"] = list(
|
|
"Stun" = CANSTUN,
|
|
"Knockdown" = CANKNOCKDOWN,
|
|
"Unconscious" = CANUNCONSCIOUS,
|
|
"Push" = CANPUSH,
|
|
"Godmode" = "godmode" // Special string for godmode trait
|
|
)
|
|
|
|
// Factions list
|
|
.["glob_factions"] = list(
|
|
"None",
|
|
"neutral",
|
|
"crew",
|
|
"hostile",
|
|
"mining",
|
|
"pirate",
|
|
"spider",
|
|
"syndicate",
|
|
"wizard",
|
|
"Custom"
|
|
)
|
|
|
|
if(target_client)
|
|
var/byond_version = "Unknown"
|
|
if(target_client.byond_version)
|
|
byond_version = "[target_client.byond_version].[target_client.byond_build ? target_client.byond_build : "xxx"]"
|
|
.["data_byond_version"] = byond_version
|
|
.["data_player_join_date"] = target_client.player_join_date
|
|
.["data_account_join_date"] = target_client.account_join_date
|
|
.["data_related_cid"] = target_client.related_accounts_cid
|
|
.["data_related_ip"] = target_client.related_accounts_ip
|
|
/* // Find relevant PR maybe?
|
|
var/datum/player_details/deets = GLOB.player_details[target_client.ckey]
|
|
.["data_old_names"] = deets.get_played_names() || null
|
|
*/
|
|
var/list/player_ranks = list()
|
|
if(SSplayer_ranks.is_donator(target_client, admin_bypass = FALSE))
|
|
player_ranks += "Donator"
|
|
if(SSplayer_ranks.is_mentor(target_client, admin_bypass = FALSE))
|
|
player_ranks += "Mentor"
|
|
if(SSplayer_ranks.is_vetted(target_client, admin_bypass = FALSE))
|
|
player_ranks += "Vetted"
|
|
.["ranks"] = length(player_ranks) ? player_ranks.Join(", ") : null
|
|
|
|
if(CONFIG_GET(flag/use_exp_tracking))
|
|
.["playtimes_enabled"] = TRUE
|
|
.["playtime"] = target_mob.client.get_exp_living()
|
|
else if(target_mob.ckey)
|
|
var/target_ckey = get_target_ckey()
|
|
if(target_ckey)
|
|
var/datum/persistent_client/PC = GLOB.persistent_clients_by_ckey[target_ckey]
|
|
.["data_old_names"] = PC?.get_played_names() || null
|
|
|
|
/datum/player_panel/ui_act(action, params, datum/tgui/ui)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
|
|
if(!target_mob)
|
|
return FALSE
|
|
|
|
var/mob/admin_mob = ui.user
|
|
var/client/admin_client = admin_mob.client
|
|
|
|
if(!check_rights(R_ADMIN))
|
|
return FALSE
|
|
|
|
switch(action)
|
|
// If this mob used to be player controlled but isn't anymore, this action will open the player panel for the mob that player is now controlling.
|
|
if ("open_latest_panel")
|
|
if (target_mob.client || !target_mob.ckey)
|
|
return FALSE
|
|
|
|
var/ckey = get_target_ckey()
|
|
var/mob/latest_mob = get_mob_by_ckey(ckey)
|
|
|
|
if(!latest_mob)
|
|
to_chat(admin_client, span_warning("That ckey is not controlling a mob."))
|
|
return FALSE
|
|
|
|
if(target_mob == latest_mob)
|
|
return FALSE
|
|
|
|
to_chat(admin_client, span_notice("New mob found for player: [target_mob.ckey] ([latest_mob])."))
|
|
SSadmin_verbs.dynamic_invoke_verb(admin_client, /datum/admin_verb/show_player_panel, latest_mob)
|
|
return TRUE
|
|
|
|
/// Edits player Rank
|
|
if ("edit_rank")
|
|
if (!target_mob.client?.ckey)
|
|
return FALSE
|
|
|
|
var/list/context = list()
|
|
|
|
context["key"] = target_mob.client.ckey
|
|
|
|
if (GLOB.admin_datums[target_mob.client.ckey] || GLOB.deadmins[target_mob.client.ckey])
|
|
context["editrights"] = "rank"
|
|
else
|
|
context["editrights"] = "add"
|
|
|
|
admin_client.holder.edit_rights_topic(context)
|
|
return TRUE
|
|
|
|
/// Opens the view variables list
|
|
if ("access_variables")
|
|
admin_client.debug_variables(target_mob)
|
|
return TRUE
|
|
|
|
/// Sees selected player/client playtime
|
|
if ("access_playtimes")
|
|
if (target_mob.client)
|
|
admin_client.holder.cmd_show_exp_panel(target_mob.client)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/// Privately messages player
|
|
if ("private_message")
|
|
SSadmin_verbs.dynamic_invoke_verb(admin_client, /datum/admin_verb/cmd_admin_pm_context, target_mob)
|
|
return TRUE
|
|
|
|
/// Subtly messages selected mob (requires target to have a headset)
|
|
if ("subtle_message")
|
|
var/list/subtle_message_options = list("Voice in head", RADIO_CHANNEL_CENTCOM, RADIO_CHANNEL_SYNDICATE)
|
|
var/sender = tgui_input_list(admin_client, "Choose the method of subtle messaging", "Subtle Message", subtle_message_options)
|
|
if (!sender)
|
|
return FALSE
|
|
|
|
var/msg = input("Contents of the message", text("Subtle PM to [target_mob.key]")) as text
|
|
if (!msg)
|
|
return FALSE
|
|
|
|
if (sender == "Voice in head")
|
|
to_chat(target_mob, "<i>You hear a voice in your head... <b>[msg]</i></b>")
|
|
else
|
|
var/mob/living/carbon/human/selected_mob = target_mob
|
|
|
|
if(!istype(selected_mob))
|
|
to_chat(admin_client, "The person you are trying to contact is not human. Unsent message: [msg]")
|
|
return FALSE
|
|
|
|
if(!istype(selected_mob.ears, /obj/item/radio/headset))
|
|
to_chat(admin_client, "The person you are trying to contact is not wearing a headset. Unsent message: [msg]")
|
|
return FALSE
|
|
|
|
to_chat(selected_mob, "You hear something crackle in your ears for a moment before a voice speaks. \"Please stand by for a message from [sender == RADIO_CHANNEL_SYNDICATE ? "your benefactor" : "Central Command"]. Message as follows[sender == RADIO_CHANNEL_SYNDICATE ? ", agent." : ":"] <span class='bold'>[msg].</span> Message ends.\"")
|
|
|
|
|
|
log_admin("SubtlePM ([sender]): [key_name(admin_client)] -> [key_name(target_mob)] : [msg]")
|
|
msg = span_adminnotice("<b> SubtleMessage ([sender]): [key_name_admin(admin_client)] -> [key_name_admin(target_mob)] :</b> [msg]")
|
|
message_admins(msg)
|
|
admin_ticket_log(target_mob, msg)
|
|
return TRUE
|
|
|
|
/// Forces a name change on selected player
|
|
if ("set_name")
|
|
target_mob.vv_auto_rename(params["name"])
|
|
return TRUE
|
|
|
|
/// Admin heals
|
|
if ("heal")
|
|
SSadmin_verbs.dynamic_invoke_verb(admin_client, /datum/admin_verb/cmd_admin_rejuvenate, target_mob)
|
|
return TRUE
|
|
|
|
/// Forces selected player/client into ghost, disconnecting them from mob.
|
|
if ("ghost")
|
|
if(target_mob.client)
|
|
log_admin("[key_name(admin_client)] ejected [key_name(target_mob)] from their body.")
|
|
message_admins("[key_name_admin(admin_client)] ejected [key_name_admin(target_mob)] from their body.")
|
|
to_chat(target_mob, span_danger("An admin has ejected you from your body."))
|
|
target_mob.ghostize(FALSE)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/// offers control to ghosts for selected mob/body
|
|
if ("offer_control")
|
|
offer_control(target_mob)
|
|
return TRUE
|
|
|
|
/// Steals control from selected client's body
|
|
if ("take_control")
|
|
// Disassociates observer mind from the body mind
|
|
if(target_mob.client)
|
|
target_mob.ghostize(FALSE)
|
|
else
|
|
for(var/mob/dead/observer/ghost in GLOB.dead_mob_list)
|
|
if(target_mob.mind == ghost.mind)
|
|
ghost.mind = null
|
|
|
|
target_mob.ckey = admin_mob.ckey
|
|
qdel(admin_mob)
|
|
|
|
message_admins(span_adminnotice("[key_name_admin(admin_client)] took control of [target_mob]."))
|
|
log_admin("[key_name(admin_client)] took control of [target_mob].")
|
|
addtimer(CALLBACK(target_mob.mob_panel, TYPE_PROC_REF(/datum, ui_interact), target_mob), 0.1 SECONDS)
|
|
return TRUE
|
|
|
|
/// Smites selected Client/Target
|
|
if ("smite")
|
|
SSadmin_verbs.dynamic_invoke_verb(admin_client, /datum/admin_verb/admin_smite, target_mob)
|
|
return TRUE
|
|
|
|
/// Brings selected Client/target
|
|
if ("bring")
|
|
SSadmin_verbs.dynamic_invoke_verb(admin_client, /datum/admin_verb/get_mob, target_mob)
|
|
return TRUE
|
|
|
|
/// Orbits arround selected Target
|
|
if ("orbit")
|
|
if(!isobserver(admin_mob))
|
|
SSadmin_verbs.dynamic_invoke_verb(admin_client, /datum/admin_verb/admin_ghost)
|
|
var/mob/dead/observer/satellite = admin_client.mob
|
|
satellite.ManualFollow(target_mob)
|
|
return TRUE
|
|
|
|
/// Jumps to selected mob
|
|
if ("jump_to")
|
|
SSadmin_verbs.dynamic_invoke_verb(admin_client, /datum/admin_verb/jump_to_mob, target_mob)
|
|
return TRUE
|
|
|
|
/// Forces the selected mob/client to stop moving
|
|
if ("freeze")
|
|
var/mob/living/living_mob = target_mob
|
|
if (istype(living_mob))
|
|
living_mob.toggle_admin_freeze(admin_client)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/// Forces slected mob/client to sleep
|
|
if ("sleep")
|
|
var/mob/living/living_mob = target_mob
|
|
if (istype(living_mob))
|
|
living_mob.toggle_admin_sleep(admin_client)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/// Yeets target client to the lobby (only works on ghosts)
|
|
if ("lobby")
|
|
if(!isobserver(target_mob))
|
|
to_chat(admin_client, span_notice("You can only send ghost players back to the Lobby."))
|
|
return FALSE
|
|
|
|
if(!target_mob.client)
|
|
to_chat(admin_client, span_warning("[target_mob] doesn't seem to have an active client."))
|
|
return FALSE
|
|
|
|
log_admin("[key_name(admin_client)] has sent [key_name(target_mob)] back to the Lobby.")
|
|
message_admins("[key_name(admin_client)] has sent [key_name(target_mob)] back to the Lobby.")
|
|
|
|
var/mob/dead/new_player/new_connected_player = new()
|
|
new_connected_player.ckey = target_mob.ckey
|
|
qdel(target_mob)
|
|
return TRUE
|
|
|
|
/// Selects admin equipmeent via Equipment UI on the selected player/mob
|
|
if ("select_equipment")
|
|
SSadmin_verbs.dynamic_invoke_verb(admin_client, /datum/admin_verb/select_equipment, target_mob)
|
|
return TRUE
|
|
|
|
/// Forces selecteed client to drop all their stuff (SPREAD YOUR SHIT)
|
|
if ("strip")
|
|
for(var/obj/item/begone_items in target_mob)
|
|
target_mob.dropItemToGround(begone_items, TRUE) //The TRUE forces all items to drop, since this is an admin undress.
|
|
return TRUE
|
|
|
|
/// Forces selected client into cryo storage
|
|
if ("cryo")
|
|
target_mob.vv_send_cryo()
|
|
return TRUE
|
|
|
|
/// Forces selected client to say things against their will
|
|
if ("force_say")
|
|
target_mob.say(params["to_say"], forced="admin")
|
|
return TRUE
|
|
|
|
/// Forces selected client to emote against their will
|
|
if ("force_emote")
|
|
if (params["to_emote"])
|
|
QUEUE_OR_CALL_VERB_FOR(VERB_CALLBACK(target_mob, TYPE_PROC_REF(/mob, emote), "me", EMOTE_VISIBLE|EMOTE_AUDIBLE, params["to_emote"], TRUE), SSspeech_controller)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/// Sends the offender to SUPERJAIL known as SPACE PRISON (admin prison)
|
|
if ("prison")
|
|
if(isAI(target_mob))
|
|
to_chat(admin_client, "This cannot be used on instances of type /mob/living/silicon/ai.")
|
|
return FALSE
|
|
|
|
target_mob.forceMove(pick(GLOB.prisonwarp))
|
|
to_chat(target_mob, span_userdanger("You have been sent to Prison!"))
|
|
|
|
log_admin("[key_name(admin_client)] has sent [key_name(target_mob)] to Prison!")
|
|
message_admins("[key_name_admin(admin_client)] has sent [key_name_admin(target_mob)] to Prison!")
|
|
return TRUE
|
|
|
|
/// Boots the offending client from the server
|
|
if ("kick")
|
|
if(!check_if_greater_rights_than(target_client))
|
|
to_chat(admin_client, span_danger("Error: They have more rights than you do."), confidential = TRUE)
|
|
return FALSE
|
|
if(tgui_alert(admin_mob, "Kick [key_name(target_mob)]?", "Confirm", list("Yes", "No")) != "Yes")
|
|
return FALSE
|
|
if(!target_mob)
|
|
to_chat(admin_client, span_danger("Error: [target_mob] no longer exists!"), confidential = TRUE)
|
|
return FALSE
|
|
if(!target_client)
|
|
to_chat(admin_client, span_danger("Error: [target_mob] no longer has a client!"), confidential = TRUE)
|
|
return FALSE
|
|
to_chat(target_mob, span_danger("You have been kicked from the server by [admin_client.holder.fakekey ? "an Administrator" : "[admin_client.key]"]."), confidential = TRUE)
|
|
log_admin("[key_name(admin_client)] kicked [key_name(target_mob)].")
|
|
message_admins(span_adminnotice("[key_name_admin(admin_client)] kicked [key_name_admin(target_mob)]."))
|
|
qdel(target_client)
|
|
return TRUE
|
|
|
|
/// Bans target
|
|
if ("ban")
|
|
var/target_ckey = get_target_ckey()
|
|
var/player_ip = target_mob.client?.address
|
|
var/player_cid = target_mob.client?.computer_id
|
|
if(!target_ckey)
|
|
to_chat(admin_client, span_warning("No ckey found for this mob."))
|
|
return FALSE
|
|
admin_client.holder.ban_panel(target_ckey, player_ip, player_cid)
|
|
return TRUE
|
|
|
|
/// Stickbans target
|
|
if ("sticky_ban")
|
|
var/list/ban_settings = list()
|
|
var/target_ckey = get_target_ckey()
|
|
if(!target_ckey)
|
|
to_chat(admin_client, span_warning("No ckey found for this mob."))
|
|
return FALSE
|
|
ban_settings["ckey"] = target_ckey
|
|
admin_client.holder.stickyban("add", ban_settings)
|
|
return TRUE
|
|
|
|
/// Opens selected target's Notes
|
|
if ("notes")
|
|
var/target_ckey = get_target_ckey()
|
|
if(!target_ckey)
|
|
to_chat(admin_client, span_warning("No ckey found for this mob."))
|
|
return FALSE
|
|
browse_messages(target_ckey = target_ckey)
|
|
return TRUE
|
|
|
|
/// Opens selected target's logs
|
|
if ("logs")
|
|
var/source = target_mob.client ? LOGSRC_CKEY : LOGSRC_MOB
|
|
show_individual_logging_panel(target_mob, source)
|
|
return TRUE
|
|
|
|
/// Just mutes
|
|
if ("mute")
|
|
if(!target_mob.client)
|
|
return FALSE
|
|
|
|
target_mob.client.prefs.muted = text2num(params["mute_flag"])
|
|
log_admin("[key_name(admin_client)] set the mute flags for [key_name(target_mob)] to [target_mob.client.prefs.muted].")
|
|
return TRUE
|
|
|
|
/// MUTES EVERYBODY (NO ONE GETS TALKING STICK!!!)
|
|
if ("mute_all")
|
|
if(!target_mob.client)
|
|
return FALSE
|
|
|
|
for(var/bit in GLOB.mute_bits)
|
|
target_mob.client.prefs.muted |= bit["bitflag"]
|
|
|
|
log_admin("[key_name(admin_client)] mass-muted [key_name(target_mob)].")
|
|
return TRUE
|
|
|
|
/// Unmutes EVERYBODY
|
|
if ("unmute_all")
|
|
if(!target_mob.client)
|
|
return FALSE
|
|
|
|
for(var/bit in GLOB.mute_bits)
|
|
target_mob.client.prefs.muted &= ~bit["bitflag"]
|
|
|
|
log_admin("[key_name(admin_client)] mass-unmuted [key_name(target_mob)].")
|
|
return TRUE
|
|
|
|
/// Showing linked discord_id
|
|
if ("show_discord_id")
|
|
load_discord_id()
|
|
return TRUE
|
|
|
|
/// Looks for related account data to the selected mob
|
|
if ("related_accounts")
|
|
if(target_mob.client)
|
|
var/related_accounts
|
|
if (params["related_thing"] == "CID")
|
|
related_accounts = target_mob.client.related_accounts_cid
|
|
else
|
|
related_accounts = target_mob.client.related_accounts_ip
|
|
|
|
related_accounts = splittext(related_accounts, ", ")
|
|
|
|
var/list/dat = list("Related accounts by [params["related_thing"]]:")
|
|
dat += related_accounts
|
|
admin_client << browse(dat.Join("<br>"), "window=related_[target_mob.client];size=420x300")
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/// Transforms the selected mob
|
|
if ("transform")
|
|
var/choice = params["newType"]
|
|
if (choice == "/mob/living")
|
|
choice = tgui_input_list(admin_client, "What should this mob transform into", "Mob Transform", subtypesof(choice))
|
|
if (!choice)
|
|
return FALSE
|
|
|
|
admin_client.holder.transform_mob(target_mob, admin_mob, choice, params["newTypeName"])
|
|
return TRUE
|
|
|
|
/// Gives targeted mob spells (shadow wizard money gang)
|
|
if ("spell")
|
|
SSadmin_verbs.dynamic_invoke_verb(admin_client, /datum/admin_verb/give_spell, target_mob)
|
|
return TRUE
|
|
|
|
/// Gives targeted mob quirks
|
|
if ("martial_art")
|
|
admin_client.teach_martial_art(target_mob)
|
|
return TRUE
|
|
|
|
/// Sets targeted mob's quirks
|
|
if ("quirk")
|
|
admin_client.toggle_quirk(target_mob)
|
|
return TRUE
|
|
|
|
/// Sets targeted mob's species
|
|
if ("species")
|
|
admin_client.set_species(target_mob)
|
|
return TRUE
|
|
|
|
/// Delimbs targeted mob (SNAAAAAAAAAAKE!!!!)
|
|
if ("limb")
|
|
if(!params["limbs"] || !ishuman(target_mob))
|
|
return FALSE
|
|
|
|
var/mob/living/carbon/human/punished_mob = target_mob
|
|
|
|
for(var/limb in params["limbs"])
|
|
if (!limb)
|
|
continue
|
|
|
|
if (params["delimb_mode"])
|
|
var/obj/item/bodypart/targeted_limb = punished_mob.get_bodypart(limb)
|
|
if (!targeted_limb)
|
|
continue
|
|
targeted_limb.dismember()
|
|
playsound(punished_mob, 'sound/effects/bamf.ogg', 70)
|
|
else
|
|
punished_mob.regenerate_limb(limb)
|
|
return TRUE
|
|
|
|
/// Assigns selected olayer/client's scale
|
|
if ("scale")
|
|
var/mob/living/local_mob_data = target_mob
|
|
if(!isnull(params["new_scale"]) && istype(local_mob_data))
|
|
local_mob_data.vv_edit_var("current_size", params["new_scale"])
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/// Explodes the selected player with assigned power and blasts (for the funny of course!)
|
|
if ("explode")
|
|
var/power = text2num(params["power"])
|
|
var/emp_mode = text2num(params["emp_mode"])
|
|
|
|
|
|
var/turf/target_turf = get_turf(admin_mob)
|
|
message_admins("[ADMIN_LOOKUPFLW(admin_client)] created an admin [emp_mode ? "EMP" : "explosion"] at [ADMIN_VERBOSEJMP(target_turf)].")
|
|
log_admin("[key_name(admin_client)] created an admin [emp_mode ? "EMP" : "explosion"] at [admin_mob.loc].")
|
|
|
|
if (emp_mode)
|
|
empulse(admin_mob, power, power / 2, TRUE)
|
|
else
|
|
explosion(admin_mob, power / 3, power / 2, power, power, ignorecap = TRUE)
|
|
return TRUE
|
|
|
|
/// Narrates typed texxt to the selected client's chatboxx
|
|
if ("narrate")
|
|
var/list/raw_styles = params["classes"]
|
|
|
|
var/styles = ""
|
|
for(var/style in raw_styles)
|
|
styles += "[style]:[raw_styles[style]];"
|
|
|
|
if (params["mode_global"])
|
|
to_chat(world, "<span style='[styles]'>[params["message"]]</span>")
|
|
log_admin("GlobalNarrate: [key_name(admin_client)] : [params["message"]]")
|
|
message_admins(span_adminnotice("[key_name_admin(admin_client)] Sent a global narrate"))
|
|
else
|
|
for(var/mob/individual_mob in view(params["range"], admin_mob))
|
|
to_chat(individual_mob, "<span style='[styles]'>[params["message"]]</span>")
|
|
|
|
log_admin("LocalNarrate: [key_name(admin_client)] at [AREACOORD(admin_mob)]: [params["message"]]")
|
|
message_admins(span_adminnotice("<b> LocalNarrate: [key_name_admin(admin_client)] at [ADMIN_VERBOSEJMP(admin_mob)]:</b> [params["message"]]<BR>"))
|
|
return TRUE
|
|
|
|
/// Opens languages panel for the selected player/client
|
|
if ("languages")
|
|
var/datum/language_holder/selected_character = target_mob.get_language_holder()
|
|
selected_character.open_language_menu(admin_mob)
|
|
return TRUE
|
|
|
|
/// Opens the Traitor Panel for the selected player/client
|
|
if ("traitor_panel")
|
|
SSadmin_verbs.dynamic_invoke_verb(admin_client, /datum/admin_verb/show_traitor_panel, target_mob)
|
|
return TRUE
|
|
|
|
/// Opens the Job Exemption Panel for the selected player/client
|
|
if ("job_exemption_panel")
|
|
show_job_exempt_menu(admin_mob, target_mob.ckey)
|
|
return TRUE
|
|
|
|
/// Opens the selected player/client's skills panel
|
|
if ("skill_panel")
|
|
SSadmin_verbs.dynamic_invoke_verb(admin_client, /datum/admin_verb/show_skill_panel, target_mob)
|
|
return TRUE
|
|
|
|
/// Opens the selected player/client's borg panel
|
|
if ("borg_panel")
|
|
if(!iscyborg(target_mob))
|
|
to_chat(admin_client, span_warning("This can only be used on cyborgs."))
|
|
return FALSE
|
|
SSadmin_verbs.dynamic_invoke_verb(admin_client, /datum/admin_verb/borg_panel, target_mob)
|
|
return TRUE
|
|
|
|
/// Gives targeted mob GOD (its only invulnerability)
|
|
if ("toggle_godmode")
|
|
admin_client.cmd_admin_godmode(target_mob)
|
|
return TRUE
|
|
|
|
/// Forces a commendation to selected client/player
|
|
if ("commend")
|
|
if(!target_mob.ckey)
|
|
to_chat(admin_client, span_warning("This mob either no longer exists or no longer is being controlled by someone!"))
|
|
return FALSE
|
|
|
|
switch(tgui_alert(admin_mob, "Would you like the effects to apply immediately or at the end of the round? Applying them now will make it clear it was an admin commendation.", "<3?", list("Apply now", "Apply at round end", "Cancel")))
|
|
if("Apply now")
|
|
target_mob.receive_heart(admin_mob, instant = TRUE)
|
|
if("Apply at round end")
|
|
target_mob.receive_heart(admin_mob)
|
|
return TRUE
|
|
|
|
/// Plays a selected sound to target client
|
|
if ("play_sound_to")
|
|
var/sound_file = input("", "Select a sound file",) as null|sound
|
|
|
|
if(sound_file && target_mob)
|
|
SSadmin_verbs.dynamic_invoke_verb(admin_client, /datum/admin_verb/play_direct_mob_sound, sound_file, target_mob)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/// Applies selected client's quirks
|
|
if ("apply_client_quirks")
|
|
var/mob/living/carbon/human/specified_humanoid = target_mob
|
|
if(!istype(specified_humanoid))
|
|
to_chat(admin_client, "this can only be used on instances of type /mob/living/carbon/human.", confidential = TRUE)
|
|
return FALSE
|
|
if(!specified_humanoid.client)
|
|
to_chat(admin_client, "[specified_humanoid] has no client!", confidential = TRUE)
|
|
return FALSE
|
|
SSquirks.AssignQuirks(specified_humanoid, specified_humanoid.client)
|
|
log_admin("[key_name(admin_client)] applied client quirks to [key_name(specified_humanoid)].")
|
|
message_admins(span_adminnotice("[key_name_admin(admin_client)] applied client quirks to [key_name_admin(specified_humanoid)]."))
|
|
return TRUE
|
|
|
|
/// Toggles a status flag on the selected mob
|
|
if ("toggle_status_flag")
|
|
var/mob/living/living_mob = target_mob
|
|
if(!istype(living_mob))
|
|
return FALSE
|
|
|
|
var/flag = params["flag"]
|
|
var/enabled = params["enabled"]
|
|
|
|
// Special handling for godmode trait
|
|
if(flag == "godmode")
|
|
admin_client.cmd_admin_godmode(target_mob)
|
|
else
|
|
var/numeric_flag = text2num(flag)
|
|
if(enabled)
|
|
living_mob.status_flags |= numeric_flag
|
|
else
|
|
living_mob.status_flags &= ~numeric_flag
|
|
log_admin("[key_name(admin_client)] [enabled ? "enabled" : "disabled"] status flag [numeric_flag] on [key_name(target_mob)].")
|
|
return TRUE
|
|
|
|
/// Sets the movement speed of the selected mob
|
|
if ("set_speed")
|
|
var/mob/living/living_mob = target_mob
|
|
if(!istype(living_mob))
|
|
return FALSE
|
|
|
|
var/new_speed = text2num(params["speed"])
|
|
if(isnull(new_speed))
|
|
return FALSE
|
|
|
|
// Remove existing admin speed modifier first to get base speed
|
|
living_mob.remove_movespeed_modifier(/datum/movespeed_modifier/admin_varedit)
|
|
// Calculate diff from base speed (after removing amodifier)
|
|
var/diff = new_speed - living_mob.cached_multiplicative_slowdown
|
|
if(diff != 0)
|
|
living_mob.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/admin_varedit, multiplicative_slowdown = diff)
|
|
|
|
log_admin("[key_name(admin_client)] set speed of [key_name(target_mob)] to [new_speed].")
|
|
return TRUE
|
|
|
|
/// Resets the movement speed
|
|
if ("reset_speed")
|
|
var/mob/living/living_mob = target_mob
|
|
if(!istype(living_mob))
|
|
return FALSE
|
|
|
|
living_mob.remove_movespeed_modifier(/datum/movespeed_modifier/admin_varedit)
|
|
log_admin("[key_name(admin_client)] reset speed modifier of [key_name(target_mob)].")
|
|
return TRUE
|
|
|
|
/// Loads the client's preferences onto the selected human mob
|
|
if ("load_preferences")
|
|
var/mob/living/carbon/human/human_mob = target_mob
|
|
if(!istype(human_mob))
|
|
to_chat(admin_client, "This can only be used on humans.", confidential = TRUE)
|
|
return FALSE
|
|
if(!human_mob.client)
|
|
to_chat(admin_client, "[human_mob] has no client!", confidential = TRUE)
|
|
return FALSE
|
|
|
|
human_mob.client.prefs.apply_prefs_to(human_mob)
|
|
log_admin("[key_name(admin_client)] loaded preferences onto [key_name(human_mob)].")
|
|
message_admins(span_adminnotice("[key_name_admin(admin_client)] loaded preferences onto [key_name_admin(human_mob)]."))
|
|
return TRUE
|
|
|
|
/// Gets the target mob's ckey, handling both active clients and stored ckeys
|
|
/datum/player_panel/proc/get_target_ckey()
|
|
if(target_mob.client)
|
|
return target_mob.client.ckey
|
|
if(target_mob.ckey)
|
|
if(copytext(target_mob.ckey, 1, 2) == "@")
|
|
var/result = copytext(target_mob.ckey, 2)
|
|
return result
|
|
else
|
|
return target_mob.ckey
|
|
return null
|
|
|
|
/// Loads the Discord ID for the target mob from the database and caches it
|
|
/datum/player_panel/proc/load_discord_id()
|
|
if(!target_mob)
|
|
return
|
|
|
|
if(!SSdbcore.IsConnected())
|
|
discord_id_cache = "Database not connected"
|
|
return
|
|
|
|
var/target_ckey = get_target_ckey()
|
|
if(!target_ckey)
|
|
discord_id_cache = "No ckey found"
|
|
return
|
|
|
|
var/datum/db_query/discord_query = SSdbcore.NewQuery(
|
|
"SELECT CAST(discord_id AS CHAR) FROM [format_table_name("discord_links")] WHERE ckey = :ckey and valid = '1'",
|
|
list("ckey" = target_ckey)
|
|
)
|
|
if(discord_query.warn_execute())
|
|
if(discord_query.NextRow())
|
|
discord_id_cache = discord_query.item[1]
|
|
else
|
|
discord_id_cache = "Not found"
|
|
else
|
|
discord_id_cache = "Database error"
|
|
qdel(discord_query)
|
|
|