mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-06-23 15:14:43 +01:00
fd06311361
## About The Pull Request This PR converts the native text/list input that pops up when the Spawn verb is used into a TGUI panel with a dynamic search function. It now displays atom names, as well if they are abstract (and probably shouldn't be spawned). You can still input a typepath after the spawn verb in the tab bar which will open the menu with said path already in the input box. If only one typepath matches the input, it will be spawned immediately without opening the panel. <img width="400" height="500" alt="Qs0t8xkGj7" src="https://github.com/user-attachments/assets/d54a57d5-fc22-4f59-af18-45b4fab0b256" /> It features RegEx support which activates when the input starts with ``re:``, as well as toggles for searching in atom names and fancy typepath display. They can be toggled via buttons, or Alt+R/N/F for regex/names/fancy paths respectively. Invalid regex-es will highlight the search bar red. The list itself can be navigated using arrow keys, enter/double click will spawn the atom, and escape will close the menu. <img width="400" height="500" alt="xgK2vCd1ck" src="https://github.com/user-attachments/assets/e621c6ba-ad6b-4a30-922f-eb863797c65a" /> <img width="400" height="500" alt="2DeOPBRqoC" src="https://github.com/user-attachments/assets/18fbba32-17d7-4351-bbc2-bc8e66eb24ae" /> Old functionality of spawning multiple objects by leaving a colon + number after the typepath has been preserved. Using ``*`` and``!`` to signify final path/end of a path respectively also still works when regex mode isn't active. ## Why It's Good For The Game Spawn isn't a critical tool, and using TGUI allows it to have dynamic search and shifts searching from serverside to clientside, making it significantly more responsive. Because we don't need to build a fancy list of atom types, using it the first time won't cause a lag spike on weaker machines anymore, which should make debugging locally a bit less annoying. ## Changelog 🆑 admin: Converted the Spawn verb into a TGUI input, featuring for dynamic search and RegEx support /🆑
180 lines
6.2 KiB
Plaintext
180 lines
6.2 KiB
Plaintext
////////////////////////////////
|
|
/proc/message_admins(msg)
|
|
msg = "<span class=\"admin\"><span class=\"prefix\">ADMIN LOG:</span> <span class=\"message\">[msg]</span></span>"
|
|
to_chat(GLOB.admins,
|
|
type = MESSAGE_TYPE_ADMINLOG,
|
|
html = msg,
|
|
confidential = TRUE)
|
|
|
|
/proc/relay_msg_admins(msg)
|
|
msg = "<span class=\"admin\"><span class=\"prefix\">RELAY:</span> <span class=\"message\">[msg]</span></span>"
|
|
to_chat(GLOB.admins,
|
|
type = MESSAGE_TYPE_ADMINLOG,
|
|
html = msg,
|
|
confidential = TRUE)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////Panels
|
|
|
|
/datum/admins/proc/Game()
|
|
if(!check_rights(0))
|
|
return
|
|
|
|
var/dat
|
|
dat += "<a href='byond://?src=[REF(src)];[HrefToken()];gamemode_panel=1'>Dynamic Panel</a><BR>"
|
|
dat += "<hr/>"
|
|
|
|
dat += "<a href='byond://?src=[REF(src)];[HrefToken()];spawn_panel=1'>Spawn Panel</a><br>"
|
|
|
|
if(marked_datum && istype(marked_datum, /atom))
|
|
dat += "<a href='byond://?src=[REF(src)];[HrefToken()];dupe_marked_datum=1'>Duplicate Marked Datum</a><br>"
|
|
|
|
var/datum/browser/browser = new(usr, "admin2", "Game Panel", 240, 280)
|
|
browser.set_content(dat)
|
|
browser.open()
|
|
return
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////ADMIN HELPER PROCS
|
|
|
|
ADMIN_VERB(spawn_atom, R_SPAWN, "Spawn", "Spawn an atom.", ADMIN_CATEGORY_DEBUG, object as text|null)
|
|
var/static/list/atom_types
|
|
if (isnull(atom_types))
|
|
atom_types = subtypesof(/atom)
|
|
|
|
var/chosen_path = null
|
|
var/list/preparsed = null
|
|
if (object)
|
|
preparsed = splittext(object, ":")
|
|
var/list/matches = filter_fancy_list(atom_types, preparsed[1])
|
|
if (length(matches) == 1)
|
|
chosen_path = matches[1]
|
|
|
|
if(!chosen_path)
|
|
var/datum/spawn_menu/menu = user.holder.spawn_menu
|
|
if (!menu)
|
|
menu = new()
|
|
user.holder.spawn_menu = menu
|
|
menu.init_value = object
|
|
menu.ui_interact(user.mob)
|
|
BLACKBOX_LOG_ADMIN_VERB("Spawn Atom")
|
|
return TRUE
|
|
|
|
var/amount = 1
|
|
if (length(preparsed) > 1)
|
|
amount = clamp(text2num(preparsed[2]), 1, ADMIN_SPAWN_CAP)
|
|
|
|
var/turf/target_turf = get_turf(user.mob)
|
|
if (ispath(chosen_path, /turf))
|
|
target_turf.ChangeTurf(chosen_path)
|
|
else
|
|
for (var/i in 1 to amount)
|
|
var/atom/spawned = new chosen_path(target_turf)
|
|
spawned.flags_1 |= ADMIN_SPAWNED_1
|
|
|
|
log_admin("[key_name(user.mob)] spawned [amount] x [chosen_path] at [AREACOORD(user.mob)]")
|
|
BLACKBOX_LOG_ADMIN_VERB("Spawn Atom")
|
|
return TRUE
|
|
|
|
ADMIN_VERB(spawn_atom_pod, R_SPAWN, "PodSpawn", "Spawn an atom via supply drop.", ADMIN_CATEGORY_DEBUG, object as text)
|
|
var/chosen = pick_closest_path(object)
|
|
if(!chosen)
|
|
return
|
|
var/turf/target_turf = get_turf(user.mob)
|
|
|
|
if(ispath(chosen, /turf))
|
|
target_turf.ChangeTurf(chosen)
|
|
else
|
|
var/obj/structure/closet/supplypod/pod = podspawn(list(
|
|
"target" = target_turf,
|
|
"path" = /obj/structure/closet/supplypod/centcompod,
|
|
))
|
|
//we need to set the admin spawn flag for the spawned items so we do it outside of the podspawn proc
|
|
var/atom/A = new chosen(pod)
|
|
A.flags_1 |= ADMIN_SPAWNED_1
|
|
|
|
log_admin("[key_name(user)] pod-spawned [chosen] at [AREACOORD(user.mob)]")
|
|
BLACKBOX_LOG_ADMIN_VERB("Podspawn Atom")
|
|
|
|
ADMIN_VERB(spawn_cargo, R_SPAWN, "Spawn Cargo", "Spawn a cargo crate.", ADMIN_CATEGORY_DEBUG, object as text)
|
|
var/chosen = pick_closest_path(object, make_types_fancy(subtypesof(/datum/supply_pack)))
|
|
if(!chosen)
|
|
return
|
|
var/datum/supply_pack/S = new chosen
|
|
S.admin_spawned = TRUE
|
|
S.generate(get_turf(user.mob))
|
|
|
|
log_admin("[key_name(user)] spawned cargo pack [chosen] at [AREACOORD(user.mob)]")
|
|
BLACKBOX_LOG_ADMIN_VERB("Spawn Cargo")
|
|
|
|
ADMIN_VERB(create_or_modify_area, R_DEBUG, "Create Or Modify Area", "Create of modify an area. wow.", ADMIN_CATEGORY_DEBUG)
|
|
create_area(user.mob)
|
|
|
|
//Kicks all the clients currently in the lobby. The second parameter (kick_only_afk) determins if an is_afk() check is ran, or if all clients are kicked
|
|
//defaults to kicking everyone (afk + non afk clients in the lobby)
|
|
//returns a list of ckeys of the kicked clients
|
|
/proc/kick_clients_in_lobby(message, kick_only_afk = 0)
|
|
var/list/kicked_client_names = list()
|
|
for(var/client/C in GLOB.clients)
|
|
if(isnewplayer(C.mob))
|
|
if(kick_only_afk && !C.is_afk()) //Ignore clients who are not afk
|
|
continue
|
|
if(message)
|
|
to_chat(C, message, confidential = TRUE)
|
|
kicked_client_names.Add("[C.key]")
|
|
qdel(C)
|
|
return kicked_client_names
|
|
|
|
//returns TRUE to let the dragdrop code know we are trapping this event
|
|
//returns FALSE if we don't plan to trap the event
|
|
/datum/admins/proc/cmd_ghost_drag(mob/dead/observer/frommob, mob/tomob)
|
|
|
|
//this is the exact two check rights checks required to edit a ckey with vv.
|
|
if (!check_rights(R_VAREDIT,0) || !check_rights(R_SPAWN|R_DEBUG,0))
|
|
return FALSE
|
|
|
|
if (!frommob.ckey)
|
|
return FALSE
|
|
|
|
var/question = ""
|
|
if (tomob.ckey)
|
|
question = "This mob already has a user ([tomob.key]) in control of it! "
|
|
question += "Are you sure you want to place [frommob.name]([frommob.key]) in control of [tomob.name]?"
|
|
|
|
var/ask = tgui_alert(usr, question, "Place ghost in control of mob?", list("Yes", "No"))
|
|
if (ask != "Yes")
|
|
return TRUE
|
|
|
|
if (!frommob || !tomob) //make sure the mobs don't go away while we waited for a response
|
|
return TRUE
|
|
|
|
// Disassociates observer mind from the body mind
|
|
if(tomob.client)
|
|
tomob.ghostize(FALSE)
|
|
else
|
|
for(var/mob/dead/observer/ghost in GLOB.dead_mob_list)
|
|
if(tomob.mind == ghost.mind)
|
|
ghost.mind = null
|
|
|
|
message_admins(span_adminnotice("[key_name_admin(usr)] has put [frommob.key] in control of [tomob.name]."))
|
|
log_admin("[key_name(usr)] stuffed [frommob.key] into [tomob.name].")
|
|
BLACKBOX_LOG_ADMIN_VERB("Ghost Drag Control")
|
|
|
|
tomob.PossessByPlayer(frommob.key)
|
|
tomob.client?.init_verbs()
|
|
qdel(frommob)
|
|
|
|
return TRUE
|
|
|
|
/// Sends a message to adminchat when anyone with a holder logs in or logs out.
|
|
/// Is dependent on admin preferences and configuration settings, which means that this proc can fire without sending a message.
|
|
/client/proc/adminGreet(logout = FALSE)
|
|
if(!SSticker.HasRoundStarted())
|
|
return
|
|
|
|
if(logout && CONFIG_GET(flag/announce_admin_logout))
|
|
message_admins("Admin logout: [key_name(src)]")
|
|
return
|
|
|
|
if(!logout && CONFIG_GET(flag/announce_admin_login) && (prefs.toggles & ANNOUNCE_LOGIN))
|
|
message_admins("Admin login: [key_name(src)]")
|
|
return
|