//admin verb groups - They can overlap if you so wish. Only one of each verb will exist in the verbs list regardless GLOBAL_LIST_INIT(admin_verbs_default, list( /client/proc/deadmin_self, /*destroys our own admin datum so we can play as a regular player*/ /client/proc/hide_verbs, /*hides all our adminverbs*/ /client/proc/cmd_mentor_check_new_players, /client/proc/cmd_mentor_check_player_exp /* shows players by playtime */ )) GLOBAL_LIST_INIT(admin_verbs_admin, list( /client/proc/check_antagonists, /*shows all antags*/ /client/proc/check_antagonists2, /*shows all antags*/ /datum/admins/proc/show_player_panel, /client/proc/player_panel_new, /*shows an interface for all players, with links to various panels*/ /client/proc/invisimin, /*allows our mob to go invisible/visible*/ /datum/admins/proc/announce, /*priority announce something to all clients.*/ /client/proc/admin_ghost, /*allows us to ghost/reenter body at will*/ /client/proc/admin_observe, /*allows us to freely observe mobs */ /client/proc/admin_observe_target, /*and gives it to us on right click*/ /client/proc/toggle_view_range, /*changes how far we can see*/ /client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/ /client/proc/cmd_admin_pm_panel, /*admin-pm list*/ /client/proc/cmd_admin_pm_by_key_panel, /*admin-pm list by key*/ /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ /client/proc/cmd_admin_check_contents, /*displays the contents of an instance*/ /client/proc/cmd_admin_open_logging_view, /client/proc/getserverlogs, /*allows us to fetch server logs (diary) for other days*/ /client/proc/get_server_logs_by_round_id, /client/proc/Getmob, /*teleports a mob to our location*/ /client/proc/Getkey, /*teleports a mob with a certain ckey to our location*/ /client/proc/jump_to, /*Opens a menu for jumping to an Area, Mob, Key or Coordinate*/ /client/proc/jumptoturf, /*allows us to jump to a specific turf*/ /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 centcomm*/ /client/proc/admin_deny_shuttle, /*toggles availability of shuttle calling*/ /client/proc/check_ai_laws, /*shows AI and borg laws*/ /client/proc/manage_silicon_laws, /* Allows viewing and editing silicon laws. */ /client/proc/admin_memo, /*admin memo system. show/delete/write. +SERVER needed to delete admin memos of others*/ /client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/ /client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/ /datum/admins/proc/toggleooc, /*toggles ooc on/off for everyone*/ /datum/admins/proc/togglelooc, /*toggles looc on/off for everyone*/ /datum/admins/proc/toggleoocdead, /*toggles ooc on/off for everyone who is dead*/ /datum/admins/proc/toggledsay, /*toggles dsay on/off for everyone*/ /datum/admins/proc/toggleemoji, /*toggles using emoji in ooc for everyone*/ /client/proc/game_panel, /*game panel, allows to change game-mode etc*/ /client/proc/cmd_admin_say, /*admin-only ooc chat*/ /client/proc/cmd_staff_say, /datum/admins/proc/PlayerNotes, /client/proc/cmd_mentor_say, /client/proc/cmd_dev_say, /datum/admins/proc/show_player_notes, /client/proc/free_slot, /*frees slot for chosen job*/ /client/proc/update_mob_sprite, /client/proc/man_up, /client/proc/global_man_up, /client/proc/library_manager, /client/proc/view_asays, /client/proc/view_msays, /client/proc/view_devsays, /client/proc/view_staffsays, /client/proc/empty_ai_core_toggle_latejoin, /client/proc/aooc, /client/proc/freeze, /client/proc/secrets, /client/proc/debug_variables, /client/proc/reset_all_tcs, /*resets all telecomms scripts*/ /client/proc/toggle_mentor_chat, /client/proc/toggle_advanced_interaction, /*toggle admin ability to interact with not only machines, but also atoms such as buttons and doors*/ /client/proc/list_ssds_afks, /client/proc/ccbdb_lookup_ckey, /client/proc/view_instances, /client/proc/start_vote, /client/proc/ping_all_admins, /client/proc/show_watchlist, /client/proc/debugstatpanel, /client/proc/create_rnd_restore_disk )) GLOBAL_LIST_INIT(admin_verbs_ban, list( /client/proc/ban_panel, /datum/admins/proc/vpn_whitelist )) GLOBAL_LIST_INIT(admin_verbs_sounds, list( /client/proc/play_local_sound, /client/proc/play_sound, /client/proc/play_server_sound, /client/proc/play_intercomm_sound, /client/proc/stop_global_admin_sounds, /client/proc/stop_sounds_global, /client/proc/play_sound_tgchat )) GLOBAL_LIST_INIT(admin_verbs_event, list( /client/proc/object_talk, /client/proc/cmd_admin_dress, /client/proc/cmd_admin_gib_self, /client/proc/drop_bomb, /client/proc/one_click_antag, /client/proc/cmd_admin_add_freeform_ai_law, /client/proc/cmd_admin_add_random_ai_law, /client/proc/economy_manager, /client/proc/make_sound, /client/proc/toggle_random_events, /client/proc/toggle_random_events, /client/proc/toggle_ert_calling, /client/proc/show_tip, /client/proc/cmd_admin_change_custom_event, /client/proc/cmd_admin_subtle_message, /*send an message to somebody as a 'voice in their head'*/ /client/proc/cmd_admin_direct_narrate, /*send text directly to a player with no padding. Useful for narratives and fluff-text*/ /client/proc/cmd_admin_world_narrate, /*sends text to all players with no padding*/ /client/proc/response_team, // Response Teams admin verb /client/proc/cmd_admin_create_centcom_report, /client/proc/fax_panel, /client/proc/event_manager_panel, /client/proc/modify_goals, /client/proc/outfit_manager, /client/proc/cmd_admin_headset_message, /client/proc/change_human_appearance_admin, /* Allows an admin to change the basic appearance of human-based mobs */ /client/proc/change_human_appearance_self, /* Allows the human-based mob itself to change its basic appearance */ /datum/admins/proc/station_traits_panel )) GLOBAL_LIST_INIT(admin_verbs_spawn, list( /datum/admins/proc/spawn_atom, /*allows us to spawn instances*/ /client/proc/respawn_character, /client/proc/admin_deserialize, /client/proc/create_crate, /client/proc/json_spawn_menu )) GLOBAL_LIST_INIT(admin_verbs_server, list( /client/proc/reload_admins, /client/proc/Set_Holiday, /datum/admins/proc/startnow, /datum/admins/proc/restart, /datum/admins/proc/end_round, /datum/admins/proc/delay, /datum/admins/proc/toggleaban, /datum/admins/proc/toggleenter, /*toggles whether people can join the current game*/ /datum/admins/proc/toggleguests, /*toggles whether guests can join the current game*/ /client/proc/toggle_log_hrefs, /client/proc/everyone_random, /datum/admins/proc/toggleAI, /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ /client/proc/cmd_debug_del_sing, /client/proc/library_manager, /client/proc/view_asays, /client/proc/toggle_antagHUD_use, /client/proc/toggle_antagHUD_restrictions, /client/proc/set_next_map, /client/proc/manage_queue, /client/proc/add_queue_server_bypass )) GLOBAL_LIST_INIT(admin_verbs_debug, list( /client/proc/cmd_admin_list_open_jobs, /client/proc/cmd_debug_make_powernets, /client/proc/debug_controller, /client/proc/cmd_debug_mob_lists, /client/proc/cmd_admin_delete, /client/proc/cmd_debug_del_sing, /client/proc/restart_controller, /client/proc/enable_debug_verbs, /client/proc/cmd_display_del_log, /client/proc/cmd_display_del_log_simple, /client/proc/check_bomb_impacts, /client/proc/test_movable_UI, /client/proc/test_snap_UI, /proc/machine_upgrade, /client/proc/map_template_load, /client/proc/map_template_upload, /client/proc/map_template_load_lazy, /client/proc/view_runtimes, /client/proc/admin_serialize, /client/proc/uid_log, /client/proc/reestablish_db_connection, /client/proc/ss_breakdown, #ifdef REFERENCE_TRACKING /datum/proc/find_refs, /datum/proc/qdel_then_find_references, /datum/proc/qdel_then_if_fail_find_references, #endif /client/proc/dmapi_debug, /client/proc/dmapi_log, /client/proc/timer_log, /client/proc/debug_timers, /client/proc/force_verb_bypass, /client/proc/show_gc_queues, /client/proc/debug_global_variables, /client/proc/raw_gas_scan, /client/proc/teleport_interesting_turf, /client/proc/visualize_interesting_turfs, /client/proc/profile_code, /client/proc/debug_atom_init, /client/proc/debug_bloom, /client/proc/cmd_mass_screenshot, /client/proc/allow_browser_inspect, )) GLOBAL_LIST_INIT(admin_verbs_possess, list( /proc/possess, /proc/release )) GLOBAL_LIST_INIT(admin_verbs_permissions, list( /client/proc/edit_admin_permissions, /client/proc/big_brother )) GLOBAL_LIST_INIT(admin_verbs_rejuv, list( /client/proc/respawn_character, /client/proc/cmd_admin_rejuvenate )) GLOBAL_LIST_INIT(admin_verbs_mod, list( /client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/ /client/proc/cmd_admin_pm_panel, /*admin-pm list*/ /client/proc/cmd_admin_pm_by_key_panel, /*admin-pm list by key*/ /datum/admins/proc/PlayerNotes, /client/proc/admin_ghost, /*allows us to ghost/reenter body at will*/ /client/proc/cmd_mentor_say, /datum/admins/proc/show_player_notes, /client/proc/player_panel_new, /client/proc/dsay, /datum/admins/proc/show_player_panel, /client/proc/ban_panel, /client/proc/debug_variables, /*allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify*/ /client/proc/admin_observe, /client/proc/admin_observe_target, )) GLOBAL_LIST_INIT(admin_verbs_mentor, list( /client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/ /client/proc/cmd_admin_pm_panel, /*admin-pm list*/ /client/proc/cmd_admin_pm_by_key_panel, /*admin-pm list by key*/ /client/proc/openMentorTicketUI, /client/proc/admin_observe, /* Allow mentors to observe as well, though they face some limitations */ /client/proc/admin_observe_target, /client/proc/cmd_mentor_say, /* mentor say*/ /client/proc/view_msays, /client/proc/cmd_staff_say, /client/proc/view_staffsays // cmd_mentor_say is added/removed by the toggle_mentor_chat verb )) GLOBAL_LIST_INIT(admin_verbs_dev, list( /client/proc/cmd_dev_say, /client/proc/view_devsays, /client/proc/cmd_staff_say, /client/proc/view_staffsays )) GLOBAL_LIST_INIT(admin_verbs_proccall, list( /client/proc/callproc, /client/proc/callproc_datum, /client/proc/SDQL2_query, /client/proc/load_sdql2_query, )) GLOBAL_LIST_INIT(admin_verbs_ticket, list( /client/proc/openAdminTicketUI, /client/proc/openMentorTicketUI, /client/proc/resolveAllAdminTickets, /client/proc/resolveAllMentorTickets )) // In this list are verbs that should ONLY be executed by maintainers, aka people who know how badly this will break the server // If you are adding something here, you MUST justify it GLOBAL_LIST_INIT(admin_verbs_maintainer, list( /client/proc/ticklag, // This adjusts the server tick rate and is VERY easy to hard lockup the server with /client/proc/debugNatureMapGenerator, // This lags like hell, and is very easy to nuke half the server with /client/proc/vv_by_ref, // This allows you to lookup **ANYTHING** in the server memory by spamming refs. Locked for security. /client/proc/cinematic, // This will break everyone's screens in the round. Dont use this for adminbus. /client/proc/throw_runtime, // Do I even need to explain why this is locked? )) GLOBAL_LIST_INIT(view_runtimes_verbs, list( /client/proc/view_runtimes, /client/proc/cmd_display_del_log, /client/proc/cmd_display_del_log_simple, /client/proc/debug_variables, /*allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify*/ /client/proc/ss_breakdown, /client/proc/show_gc_queues, /client/proc/debug_global_variables, /client/proc/debug_timers, /client/proc/timer_log, /client/proc/raw_gas_scan, /client/proc/teleport_interesting_turf, /client/proc/visualize_interesting_turfs, /client/proc/profile_code )) GLOBAL_LIST_INIT(view_logs_verbs, list( /client/proc/getserverlogs, /client/proc/get_server_logs_by_round_id, )) /client/proc/add_admin_verbs() if(holder) // If they have ANYTHING OTHER THAN ONLY VIEW RUNTIMES AND/OR DEV, then give them the default admin verbs if(holder.rights & ~(R_VIEWRUNTIMES|R_DEV_TEAM)) add_verb(src, GLOB.admin_verbs_default) if(holder.rights & R_BUILDMODE) add_verb(src, /client/proc/togglebuildmodeself) if(holder.rights & R_ADMIN) add_verb(src, GLOB.admin_verbs_admin) add_verb(src, GLOB.admin_verbs_ticket) spawn(1) control_freak = 0 if(holder.rights & R_BAN) add_verb(src, GLOB.admin_verbs_ban) if(holder.rights & R_EVENT) add_verb(src, GLOB.admin_verbs_event) if(holder.rights & R_SERVER) add_verb(src, GLOB.admin_verbs_server) if(holder.rights & R_DEBUG) add_verb(src, GLOB.admin_verbs_debug) spawn(1) control_freak = 0 // Setting control_freak to 0 allows you to use the Profiler and other client-side tools if(holder.rights & R_POSSESS) add_verb(src, GLOB.admin_verbs_possess) if(holder.rights & R_PERMISSIONS) add_verb(src, GLOB.admin_verbs_permissions) if(holder.rights & R_STEALTH) add_verb(src, /client/proc/stealth) if(holder.rights & R_REJUVINATE) add_verb(src, GLOB.admin_verbs_rejuv) if(holder.rights & R_SOUNDS) add_verb(src, GLOB.admin_verbs_sounds) if(holder.rights & R_SPAWN) add_verb(src, GLOB.admin_verbs_spawn) if(holder.rights & R_MOD) add_verb(src, GLOB.admin_verbs_mod) if(holder.rights & R_MENTOR) add_verb(src, GLOB.admin_verbs_mentor) if(holder.rights & R_PROCCALL) add_verb(src, GLOB.admin_verbs_proccall) if(holder.rights & R_MAINTAINER) add_verb(src, GLOB.admin_verbs_maintainer) if(holder.rights & R_VIEWRUNTIMES) add_verb(src, GLOB.view_runtimes_verbs) spawn(1) // This setting exposes the profiler for people with R_VIEWRUNTIMES. They must still have it set in cfg/admin.txt control_freak = 0 if(holder.rights & R_DEV_TEAM) add_verb(src, GLOB.admin_verbs_dev) if(holder.rights & R_VIEWLOGS) add_verb(src, GLOB.view_logs_verbs) if(is_connecting_from_localhost()) add_verb(src, /client/proc/export_current_character) /client/proc/hide_verbs() set name = "Adminverbs - Hide All" set category = "Admin" if(!holder) return remove_verb(src, list( /client/proc/togglebuildmodeself, /client/proc/stealth, /client/proc/readmin, /client/proc/cmd_dev_say, /client/proc/export_current_character, GLOB.admin_verbs_default, GLOB.admin_verbs_admin, GLOB.admin_verbs_ban, GLOB.admin_verbs_event, GLOB.admin_verbs_server, GLOB.admin_verbs_debug, GLOB.admin_verbs_possess, GLOB.admin_verbs_permissions, GLOB.admin_verbs_rejuv, GLOB.admin_verbs_sounds, GLOB.admin_verbs_spawn, GLOB.admin_verbs_mod, GLOB.admin_verbs_mentor, GLOB.admin_verbs_proccall, GLOB.admin_verbs_show_debug_verbs, GLOB.admin_verbs_ticket, GLOB.admin_verbs_maintainer, GLOB.admin_verbs_dev )) add_verb(src, /client/proc/show_verbs) to_chat(src, "Almost all of your adminverbs have been hidden.") SSblackbox.record_feedback("tally", "admin_verb", 1, "Hide Admin Verbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return /client/proc/show_verbs() set name = "Adminverbs - Show" set category = "Admin" if(!holder) return remove_verb(src, /client/proc/show_verbs) add_admin_verbs() to_chat(src, "All of your adminverbs are now visible.") SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Admin Verbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/mentor_ghost() var/is_mentor = check_rights(R_MENTOR, FALSE) var/is_full_admin = check_rights(R_ADMIN|R_MOD, FALSE) if(!is_mentor && !is_full_admin) to_chat(src, "You aren't allowed to use this!") return // mentors are allowed only if they have the observe trait, which is given on observe. // they should also not be given this proc. if(!is_full_admin && (is_mentor && !HAS_MIND_TRAIT(mob, TRAIT_MENTOR_OBSERVING) || !is_mentor)) return do_aghost() /client/proc/do_aghost() if(isobserver(mob)) //re-enter var/mob/dead/observer/ghost = mob var/old_turf = get_turf(ghost) ghost.can_reenter_corpse = 1 //just in-case. ghost.reenter_corpse() log_admin("[key_name(usr)] re-entered their body") SSblackbox.record_feedback("tally", "admin_verb", 1, "Aghost") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! if(ishuman(mob)) var/mob/living/carbon/human/H = mob H.regenerate_icons() // workaround for #13269 if(is_ai(mob)) // client.mob, built in byond client var var/mob/living/silicon/ai/ai = mob ai.eyeobj.set_loc(old_turf) else if(isnewplayer(mob)) to_chat(src, "Error: Aghost: Can't admin-ghost whilst in the lobby. Join or observe first.") else //ghostize var/mob/body = mob body.ghostize(1) if(body && !body.key) body.key = "@[key]" //Haaaaaaaack. But the people have spoken. If it breaks; blame adminbus log_admin("[key_name(usr)] has admin-ghosted") // TODO: SStgui.on_transfer() to move windows from old and new SSblackbox.record_feedback("tally", "admin_verb", 1, "Aghost") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/admin_ghost() set category = "Admin" set name = "Aghost" if(!check_rights(R_ADMIN|R_MOD)) return do_aghost() /// Allow an admin to observe someone. /// mentors are allowed to use this verb while living, but with some stipulations: /// if they attempt to do anything that would stop their orbit, they will immediately be returned to their body. /client/proc/admin_observe() set name = "Aobserve" set category = "Admin" if(!check_rights(R_ADMIN|R_MOD|R_MENTOR)) return if(isnewplayer(mob)) to_chat(src, "You cannot aobserve while in the lobby. Please join or observe first.") return var/mob/target target = tgui_input_list(mob, "Select a mob to observe", "Aobserve", GLOB.player_list) if(isnull(target)) return if(target == src) to_chat(src, "You can't observe yourself!") return if(isobserver(target)) to_chat(src, "[target] is a ghost, and cannot be observed.") return if(isnewplayer(target)) to_chat(src, "[target] is in the lobby, and cannot be observed.") return admin_observe_target(target) /client/proc/cleanup_admin_observe(mob/dead/observer/ghost) if(!istype(ghost) || !ghost.mob_observed) return FALSE // un-follow them ghost.cleanup_observe() // if it's a mentor, make sure they go back to their body. if(HAS_TRAIT(mob.mind, TRAIT_MENTOR_OBSERVING)) // handler will handle removing the trait mob.stop_orbit() log_admin("[key_name(src)] has de-activated Aobserve") SSblackbox.record_feedback("tally", "admin_verb", 1, "Aobserve") return TRUE /// targeted form of admin_observe: this should only appear in the right-click menu. /client/proc/admin_observe_target(mob/target as mob in GLOB.mob_list) set name = "\[Admin\] Aobserve" set category = null if(!check_rights(R_ADMIN|R_MOD|R_MENTOR, mob)) return var/full_admin = check_rights(R_ADMIN|R_MOD, FALSE, mob) if(isnewplayer(mob)) to_chat(src, "You cannot aobserve while in the lobby. Please join or observe first.") return if(isnewplayer(target)) to_chat(src, "[target] is currently in the lobby.") return if(isobserver(target)) to_chat(src, "You can't observe a ghost.") return var/mob/dead/observer/observer = mob if(istype(observer) && target == locateUID(observer.mob_observed)) cleanup_admin_observe(mob) return cleanup_admin_observe(mob) if(isnull(target) || target == src) // let the default one find the target if there isn't one admin_observe() return // observers don't need to ghost, so we don't need to worry about adding any traits if(isobserver(mob)) var/mob/dead/observer/ghost = mob SSblackbox.record_feedback("tally", "admin_verb", 1, "Aobserve") ghost.do_observe(target) return log_admin("[key_name(src)] has Aobserved out of their body to follow [target]") do_aghost() var/mob/dead/observer/ghost = mob if(!full_admin) // if they're a me and they're alive, add the MENTOR_OBSERVINGtrait to ensure that they can only go back to their body. // we need to handle this here because when you aghost, your mob gets set to the ghost. Oops! ADD_TRAIT(mob.mind, TRAIT_MENTOR_OBSERVING, MENTOR_OBSERVING) RegisterSignal(ghost, COMSIG_ATOM_ORBITER_STOP, PROC_REF(on_mentor_observe_end), override = TRUE) to_chat(src, "You have temporarily observed [target], either move or observe again to un-observe.") log_admin("[key_name(src)] has mobserved out of their body to follow [target].") else log_admin("[key_name(src)] is aobserving [target].") ghost.do_observe(target) /client/proc/on_mentor_observe_end(atom/movable/us, atom/movable/orbited) SIGNAL_HANDLER // COMSIG_ATOM_ORBITER_STOP if(!isobserver(mob)) log_and_message_admins("A mentor somehow managed to end observing while not being a ghost. Please investigate and notify coders.") return var/mob/dead/observer/ghost = mob // just to be safe ghost.cleanup_observe() REMOVE_TRAIT(mob.mind, TRAIT_MENTOR_OBSERVING, MENTOR_OBSERVING) UnregisterSignal(mob, COMSIG_ATOM_ORBITER_STOP) if(!ghost.reenter_corpse()) // tell everyone since this is kinda nasty. log_debug("Mentor [key_name_mentor(src)] was unable to re-enter their body after mentor observing.") log_and_message_admins("[key_name_mentor(src)] was unable to re-enter their body after mentor observing.") to_chat(src, "Unable to return you to your body after mentor ghosting. If your body still exists, please contact a coder, and you should probably ahelp.") /client/proc/invisimin() set name = "Invisimin" set category = "Admin" set desc = "Toggles ghost-like invisibility (Don't abuse this)" if(!check_rights(R_ADMIN)) return if(!isliving(mob)) return if(mob.invisibility == INVISIBILITY_OBSERVER) mob.invisibility = initial(mob.invisibility) mob.add_to_all_human_data_huds() to_chat(mob, "Invisimin off. Invisibility reset.") log_admin("[key_name(mob)] has turned Invisimin OFF") else mob.invisibility = INVISIBILITY_OBSERVER mob.remove_from_all_data_huds() to_chat(mob, "Invisimin on. You are now as invisible as a ghost.") log_admin("[key_name(mob)] has turned Invisimin ON") SSblackbox.record_feedback("tally", "admin_verb", 1, "Invisimin") /client/proc/player_panel_new() set name = "Player Panel" set category = "Admin" if(!check_rights(R_ADMIN|R_MOD)) return holder.player_panel_new() SSblackbox.record_feedback("tally", "admin_verb", 1, "Player Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return /client/proc/check_antagonists() set name = "Check Antagonists" set category = "Admin" if(!check_rights(R_ADMIN)) return holder.check_antagonists() log_admin("[key_name(usr)] checked antagonists") SSblackbox.record_feedback("tally", "admin_verb", 1, "Check Antags") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return /client/proc/check_antagonists2() set name = "TGUI - Antagonists" set category = "Admin" if(!check_rights(R_ADMIN)) return var/datum/ui_module/admin = get_admin_ui_module(/datum/ui_module/admin/antagonist_menu) admin.ui_interact(usr) log_admin("[key_name(usr)] checked antagonists") SSblackbox.record_feedback("tally", "admin_verb", 1, "Check Antags2") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return /client/proc/ban_panel() set name = "Ban Panel" set category = "Admin" if(!check_rights(R_BAN)) return holder.DB_ban_panel() SSblackbox.record_feedback("tally", "admin_verb", 1, "Ban Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return /client/proc/game_panel() set name = "Game Panel" set category = "Admin" if(!check_rights(R_ADMIN)) return holder.Game() SSblackbox.record_feedback("tally", "admin_verb", 1, "Game Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return /client/proc/secrets() set name = "Secrets" set category = "Admin" if(!check_rights(R_ADMIN)) return holder.Secrets() SSblackbox.record_feedback("tally", "admin_verb", 1, "Secrets") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return /client/proc/getStealthKey() return GLOB.stealthminID[ckey] /client/proc/createStealthKey() var/num = (rand(0,1000)) var/i = 0 while(i == 0) i = 1 for(var/P in GLOB.stealthminID) if(num == GLOB.stealthminID[P]) num++ i = 0 GLOB.stealthminID["[ckey]"] = "@[num2text(num)]" /client/proc/stealth() set category = "Admin" set name = "Stealth Mode" if(!check_rights(R_ADMIN)) return if(holder) holder.big_brother = 0 if(holder.fakekey) holder.fakekey = null else var/new_key = ckeyEx(clean_input("Enter your desired display name.", "Fake Key", key)) if(!new_key) return if(length(new_key) >= 26) new_key = copytext(new_key, 1, 26) holder.fakekey = new_key createStealthKey() log_admin("[key_name(usr)] has turned stealth mode [holder.fakekey ? "ON" : "OFF"]") message_admins("[key_name_admin(usr)] has turned stealth mode [holder.fakekey ? "ON" : "OFF"]", 1) SSblackbox.record_feedback("tally", "admin_verb", 1, "Stealth Mode") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/big_brother() set category = "Admin" set name = "Big Brother Mode" if(!check_rights(R_PERMISSIONS)) return if(holder) if(holder.fakekey) holder.fakekey = null holder.big_brother = 0 else var/new_key = ckeyEx(clean_input("Enter your desired display name. Unlike normal stealth mode, this will not appear in Who at all, except for other heads.", "Fake Key", key)) if(!new_key) return if(length(new_key) >= 26) new_key = copytext(new_key, 1, 26) holder.fakekey = new_key holder.big_brother = 1 if(isobserver(mob)) mob.invisibility = 90 mob.see_invisible = 90 createStealthKey() log_admin("[key_name(usr)] has turned BB mode [holder.fakekey ? "ON" : "OFF"]", TRUE) SSblackbox.record_feedback("tally", "admin_verb", 1, "Big Brother Mode") /client/proc/drop_bomb() // Some admin dickery that can probably be done better -- TLE set category = "Event" set name = "Drop Bomb" set desc = "Cause an explosion of varying strength at your location." if(!check_rights(R_EVENT)) return var/turf/epicenter = mob.loc var/list/choices = list("Small Bomb", "Medium Bomb", "Big Bomb", "Custom Bomb") var/choice = tgui_input_list(src, "What size explosion would you like to produce?", "Drop Bomb", choices) switch(choice) if(null) return 0 if("Small Bomb") explosion(epicenter, 1, 2, 3, 3, cause = "[ckey]: Drop Bomb command") if("Medium Bomb") explosion(epicenter, 2, 3, 4, 4, cause = "[ckey]: Drop Bomb command") if("Big Bomb") explosion(epicenter, 3, 5, 7, 5, cause = "[ckey]: Drop Bomb command") if("Custom Bomb") var/devastation_range = tgui_input_number(src, "Devastation range (in tiles):", "Custom Bomb", max_value = 255) if(isnull(devastation_range)) return var/heavy_impact_range = tgui_input_number(src, "Heavy impact range (in tiles):", "Custom Bomb", max_value = 255) if(isnull(heavy_impact_range)) return var/light_impact_range = tgui_input_number(src, "Light impact range (in tiles):", "Custom Bomb", max_value = 255) if(isnull(light_impact_range)) return var/flash_range = tgui_input_number(src, "Flash range (in tiles):", "Custom Bomb", max_value = 255) if(isnull(flash_range)) return explosion(epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, 1, 1, cause = "[ckey]: Drop Bomb command") log_admin("[key_name(usr)] created an admin explosion at [epicenter.loc]") message_admins("[key_name_admin(usr)] created an admin explosion at [epicenter.loc]") SSblackbox.record_feedback("tally", "admin_verb", 1, "Drop Bomb") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/give_spell(mob/T as mob in GLOB.mob_list) // -- Urist set category = "Event" set name = "Give Spell" set desc = "Gives a spell to a mob." if(!check_rights(R_EVENT)) return var/list/spell_list = list() var/type_length = length("/datum/spell") + 2 for(var/A in GLOB.spells) spell_list[copytext("[A]", type_length)] = A var/datum/spell/S = input("Choose the spell to give to that guy", "ABRAKADABRA") as null|anything in spell_list if(!S) return S = spell_list[S] if(T.mind) T.mind.AddSpell(new S) else T.AddSpell(new S) SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Spell") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! log_admin("[key_name(usr)] gave [key_name(T)] the spell [S].") message_admins("[key_name_admin(usr)] gave [key_name(T)] the spell [S].", 1) /client/proc/give_disease(mob/T in GLOB.mob_list) set category = "Event" set name = "Give Disease" set desc = "Gives a Disease to a mob." var/datum/disease/D = input("Choose the disease to give to that guy", "ACHOO") as null|anything in GLOB.diseases if(!D) return T.ForceContractDisease(new D) SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Disease") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! log_admin("[key_name(usr)] gave [key_name(T)] the disease [D].") message_admins("[key_name_admin(usr)] gave [key_name(T)] the disease [D].") /client/proc/make_sound(obj/O in view()) // -- TLE set name = "\[Admin\] Make Sound" set desc = "Display a message to everyone who can hear the target" if(!check_rights(R_EVENT)) return if(O) var/message = clean_input("What do you want the message to be?", "Make Sound") if(!message) return for(var/mob/V in hearers(O)) V.show_message(admin_pencode_to_html(message), 2) log_admin("[key_name(usr)] made [O] at [O.x], [O.y], [O.z] make a sound") message_admins("[key_name_admin(usr)] made [O] at [O.x], [O.y], [O.z] make a sound") SSblackbox.record_feedback("tally", "admin_verb", 1, "Make Sound") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/togglebuildmodeself() set name = "Toggle Build Mode Self" set category = "Event" if(!check_rights(R_EVENT)) return if(src.mob) togglebuildmode(src.mob) SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle Build Mode") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/object_talk(msg as text) // -- TLE set name = "oSay" set desc = "Display a message to everyone who can hear the target" if(!check_rights(R_EVENT)) return if(mob.control_object) if(!msg) return for(var/mob/V in hearers(mob.control_object)) V.show_message("[mob.control_object.name] says: \"" + msg + "\"", 2) log_admin("[key_name(usr)] used oSay on [mob.control_object]: [msg]") message_admins("[key_name_admin(usr)] used oSay on [mob.control_object]: [msg]") SSblackbox.record_feedback("tally", "admin_verb", 1, "oSay") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/deadmin_self() set name = "De-admin self" set category = "Admin" if(!check_rights(R_ADMIN|R_MENTOR)) return log_admin("[key_name(usr)] deadmined themself.") message_admins("[key_name_admin(usr)] deadmined themself.") if(check_rights(R_ADMIN, FALSE)) GLOB.de_admins += ckey else GLOB.de_mentors += ckey deadmin() add_verb(src, /client/proc/readmin) update_active_keybindings() to_chat(src, "You are now a normal player.") SSblackbox.record_feedback("tally", "admin_verb", 1, "De-admin") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/readmin() set name = "Re-admin self" set category = "Admin" set desc = "Regain your admin powers." var/datum/admins/D = GLOB.admin_datums[ckey] var/rank = null if(!GLOB.configuration.admin.use_database_admins) for(var/iterator_key in GLOB.configuration.admin.ckey_rank_map) var/_ckey = ckey(iterator_key) // Snip out formatting if(ckey != _ckey) continue rank = GLOB.configuration.admin.ckey_rank_map[iterator_key] break else if(!SSdbcore.IsConnected()) to_chat(src, "Warning, MYSQL database is not connected.") return var/datum/db_query/rank_read = SSdbcore.NewQuery( "SELECT admin_rank FROM admin WHERE ckey=:ckey", list("ckey" = ckey) ) if(!rank_read.warn_execute()) qdel(rank_read) return FALSE while(rank_read.NextRow()) rank = ckeyEx(rank_read.item[1]) qdel(rank_read) if(!D) D = try_localhost_autoadmin() if(!D) if(!GLOB.configuration.admin.use_database_admins) if(GLOB.admin_ranks[rank] == null) error("Error while re-adminning [src], admin rank ([rank]) does not exist.") to_chat(src, "Error while re-adminning, admin rank ([rank]) does not exist.") return // Do a little check here if(GLOB.configuration.system.is_production && (GLOB.admin_ranks[rank] & R_ADMIN) && prefs._2fa_status == _2FA_DISABLED) // If they are an admin and their 2FA is disabled to_chat(src,"You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.") // Very fucking obvious return D = new(rank, GLOB.admin_ranks[rank], ckey) else if(!SSdbcore.IsConnected()) to_chat(src, "Warning, MYSQL database is not connected.") return var/datum/db_query/admin_read = SSdbcore.NewQuery( "SELECT ckey, admin_rank, flags FROM admin WHERE ckey=:ckey", list("ckey" = ckey) ) if(!admin_read.warn_execute()) qdel(admin_read) return FALSE while(admin_read.NextRow()) var/admin_ckey = admin_read.item[1] var/admin_rank = admin_read.item[2] var/flags = admin_read.item[3] if(!admin_ckey) to_chat(src, "Error while re-adminning, ckey [admin_ckey] was not found in the admin database.") qdel(admin_read) return if(admin_rank == "Removed") //This person was de-adminned. They are only in the admin list for archive purposes. to_chat(src, "Error while re-adminning, ckey [admin_ckey] is not an admin.") qdel(admin_read) return if(istext(flags)) flags = text2num(flags) var/client/check_client = GLOB.directory[ckey] // Do a little check here if(GLOB.configuration.system.is_production && (flags & R_ADMIN) && check_client.prefs._2fa_status == _2FA_DISABLED) // If they are an admin and their 2FA is disabled to_chat(src,"You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.") // Very fucking obvious qdel(admin_read) return D = new(admin_rank, flags, ckey) qdel(admin_read) var/client/C = GLOB.directory[ckey] D.associate(C) update_active_keybindings() message_admins("[key_name_admin(usr)] re-adminned themselves.") log_admin("[key_name(usr)] re-adminned themselves.") GLOB.de_admins -= ckey GLOB.de_mentors -= ckey if(istype(mob, /mob/dead/observer)) var/mob/dead/observer/O = mob O.update_admin_actions() SSblackbox.record_feedback("tally", "admin_verb", 1, "Re-admin") return else to_chat(src, "You are already an admin.") remove_verb(src, /client/proc/readmin) GLOB.de_admins -= ckey GLOB.de_mentors -= ckey return /client/proc/toggle_log_hrefs() set name = "Toggle href logging" set category = "Server" if(!check_rights(R_SERVER)) return // Why would we ever turn this off? if(GLOB.configuration.logging.href_logging) GLOB.configuration.logging.href_logging = FALSE to_chat(src, "Stopped logging hrefs") else GLOB.configuration.logging.href_logging = TRUE to_chat(src, "Started logging hrefs") /client/proc/check_ai_laws() set name = "Check AI Laws" set category = "Admin" if(!check_rights(R_ADMIN)) return holder.output_ai_laws() /client/proc/manage_silicon_laws() set name = "Manage Silicon Laws" set category = "Admin" if(!check_rights(R_ADMIN)) return var/mob/living/silicon/S = input("Select silicon.", "Manage Silicon Laws") as null|anything in GLOB.silicon_mob_list if(!S) return var/datum/ui_module/law_manager/L = new(S) L.ui_interact(usr) log_and_message_admins("has opened [S]'s law manager.") SSblackbox.record_feedback("tally", "admin_verb", 1, "Manage Silicon Laws") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/change_human_appearance_admin(mob/living/carbon/human/H in GLOB.mob_list) set name = "\[Admin\] C.M.A. - Admin" set desc = "Allows you to change the mob appearance" if(!check_rights(R_EVENT)) return if(!istype(H)) if(isbrain(H)) var/mob/living/brain/B = H if(istype(B.container, /obj/item/mmi/robotic_brain/positronic)) var/obj/item/mmi/robotic_brain/positronic/C = B.container var/obj/item/organ/internal/brain/mmi_holder/posibrain/P = C.loc if(ishuman(P.owner)) H = P.owner else return else return if(holder) log_and_message_admins("is altering the appearance of [H].") H.change_appearance(APPEARANCE_ALL, usr, usr, check_species_whitelist = 0) SSblackbox.record_feedback("tally", "admin_verb", 1, "CMA - Admin") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/change_human_appearance_self(mob/living/carbon/human/H in GLOB.mob_list) set name = "\[Admin\] C.M.A. - Self" set desc = "Allows the mob to change its appearance" if(!check_rights(R_EVENT)) return if(!istype(H)) if(isbrain(H)) var/mob/living/brain/B = H if(istype(B.container, /obj/item/mmi/robotic_brain/positronic)) var/obj/item/mmi/robotic_brain/positronic/C = B.container var/obj/item/organ/internal/brain/mmi_holder/posibrain/P = C.loc if(ishuman(P.owner)) H = P.owner else return else return if(!H.client) to_chat(usr, "Only mobs with clients can alter their own appearance.") return switch(alert("Do you wish for [H] to be allowed to select non-whitelisted races?","Alter Mob Appearance","Yes","No","Cancel")) if("Yes") log_and_message_admins("has allowed [H] to change [H.p_their()] appearance, without whitelisting of races.") H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 0) if("No") log_and_message_admins("has allowed [H] to change [H.p_their()] appearance, with whitelisting of races.") H.change_appearance(APPEARANCE_ALL, H.loc, check_species_whitelist = 1) SSblackbox.record_feedback("tally", "admin_verb", 1, "CMA - Self") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/free_slot() set name = "Free Job Slot" set category = "Admin" if(!check_rights(R_ADMIN)) return var/list/jobs = list() for(var/datum/job/J in SSjobs.occupations) if(J.current_positions >= J.total_positions && J.total_positions != -1) jobs += J.title if(!length(jobs)) to_chat(usr, "There are no fully staffed jobs.") return var/job = input("Please select job slot to free", "Free Job Slot") as null|anything in jobs if(job) SSjobs.FreeRole(job, force = TRUE) log_admin("[key_name(usr)] has freed a job slot for [job].") message_admins("[key_name_admin(usr)] has freed a job slot for [job].") /client/proc/man_up(mob/T as mob in GLOB.player_list) set name = "\[Admin\] Man Up" set desc = "Tells mob to man up and deal with it." if(!check_rights(R_ADMIN)) return to_chat(T, chat_box_notice_thick("Man up.
Deal with it.

Move on.
")) SEND_SOUND(T, sound('sound/voice/manup1.ogg')) log_admin("[key_name(usr)] told [key_name(T)] to man up and deal with it.") message_admins("[key_name_admin(usr)] told [key_name(T)] to man up and deal with it.") /client/proc/global_man_up() set category = "Admin" set name = "Man Up Global" set desc = "Tells everyone to man up and deal with it." if(!check_rights(R_ADMIN)) return var/confirm = alert("Are you sure you want to send the global message?", "Confirm Man Up Global", "Yes", "No") if(confirm == "Yes") var/manned_up_sound = sound('sound/voice/manup1.ogg') for(var/sissy in GLOB.player_list) to_chat(sissy, chat_box_notice_thick("Man up.
Deal with it.

Move on.
")) SEND_SOUND(sissy, manned_up_sound) log_admin("[key_name(usr)] told everyone to man up and deal with it.") message_admins("[key_name_admin(usr)] told everyone to man up and deal with it.") /client/proc/toggle_advanced_interaction() set name = "Toggle Advanced Admin Interaction" set category = "Admin" set desc = "Allows you to interact with atoms such as buttons and doors, on top of regular machinery interaction." if(!check_rights(R_ADMIN)) return advanced_admin_interaction = !advanced_admin_interaction log_admin("[key_name(usr)] has [advanced_admin_interaction ? "activated" : "deactivated"] their advanced admin interaction.") message_admins("[key_name_admin(usr)] has [advanced_admin_interaction ? "activated" : "deactivated"] their advanced admin interaction.") /client/proc/show_watchlist() set name = "Show Watchlist" set category = "Admin" if(!check_rights(R_ADMIN)) return watchlist_show() /client/proc/cmd_admin_alert_message(mob/about_to_be_banned) set name = "Send Alert Message" set category = "Admin" if(!ismob(about_to_be_banned)) return if(!check_rights(R_ADMIN)) return var/default_text = "An admin is trying to talk to you!\nCheck your chat window and click their name to respond or you may be banned!" var/new_text = tgui_input_text(src, "Input your message, or use the default.", "Admin Message - Text Selector", default_text, 500, TRUE) if(!new_text) return if(default_text == new_text) show_blurb(about_to_be_banned, 15, new_text, null, "center", "center", COLOR_RED, null, null, 1) log_admin("[key_name(src)] sent a default admin alert to [key_name(about_to_be_banned)].") message_admins("[key_name(src)] sent a default admin alert to [key_name(about_to_be_banned)].") return new_text = strip_html(new_text, 500) var/message_color = tgui_input_color(src, "Input your message color:", "Admin Message - Color Selector", COLOR_RED) if(isnull(message_color)) return show_blurb(about_to_be_banned, 15, new_text, null, "center", "center", message_color, null, null, 1) log_admin("[key_name(src)] sent an admin alert to [key_name(about_to_be_banned)] with custom message \"[new_text]\".") message_admins("[key_name(src)] sent an admin alert to [key_name(about_to_be_banned)] with custom message \"[new_text]\".") /client/proc/debugstatpanel() set name = "Debug Stat Panel" set category = "Debug" src.stat_panel.send_message("create_debug") /client/proc/profile_code() set name = "Profile Code" set category = "Debug" winset(usr, null, "command=.profile") /client/proc/export_current_character() set name = "Export Character DMI/JSON" set category = "Admin" if(ishuman(mob)) var/mob/living/carbon/human/H = mob H.export_dmi_json() /client/proc/raw_gas_scan() set name = "Raw Gas Scan" set category = "Debug" set desc = "Scans your current tile, including LINDA data not normally displayed." if(!check_rights(R_DEBUG | R_VIEWRUNTIMES)) return atmos_scan(mob, get_turf(mob), silent = TRUE, milla_turf_details = TRUE) /client/proc/teleport_interesting_turf() set name = "Interesting Turf" set category = "Debug" set desc = "Teleports you to a random Interesting Turf from MILLA" if(!check_rights(R_DEBUG | R_VIEWRUNTIMES)) return if(!isobserver(mob)) to_chat(mob, "You must be an observer to do this!") return var/list/interesting_tile = get_random_interesting_tile() if(!length(interesting_tile)) to_chat(mob, "There are no interesting turfs. How interesting!") return var/turf/T = interesting_tile[MILLA_INDEX_TURF] var/mob/dead/observer/O = mob admin_forcemove(O, T) O.ManualFollow(T) /client/proc/visualize_interesting_turfs() set name = "Visualize Interesting Turfs" set category = "Debug" set desc = "Shows all the Interesting Turfs from MILLA" if(!check_rights(R_DEBUG | R_VIEWRUNTIMES)) return if(SSair.interesting_tile_count > 500) // This can potentially iterate through a list thats 20k things long. Give ample warning to the user var/confirm = alert(usr, "WARNING: There are [SSair.interesting_tile_count] Interesting Turfs. This process will be lag intensive and should only be used if the atmos controller is screaming bloody murder. Are you sure you with to continue", "WARNING", "I am sure", "Nope") if(confirm != "I am sure") return var/display_turfs_overlay = FALSE var/do_display_turf_overlay = alert(usr, "Would you like to have all interesting turfs have a client side overlay applied as well?", "Optional", "Yep", "Nope") if(do_display_turf_overlay == "Yep") display_turfs_overlay = TRUE message_admins("[key_name_admin(usr)] is visualising interesting atmos turfs. Server may lag.") var/list/zlevel_turf_indexes = list() var/list/coords = get_interesting_atmos_tiles() if(!length(coords)) to_chat(mob, "There are no interesting turfs. How interesting!") return while(length(coords)) var/offset = length(coords) - MILLA_INTERESTING_TILE_SIZE var/turf/T = coords[offset + MILLA_INDEX_TURF] coords.len -= MILLA_INTERESTING_TILE_SIZE // ENSURE YOU USE STRING NUMBERS HERE, THIS IS A DICTIONARY KEY NOT AN INDEX!!! if(!zlevel_turf_indexes["[T.z]"]) zlevel_turf_indexes["[T.z]"] = list() zlevel_turf_indexes["[T.z]"] |= T if(display_turfs_overlay) usr.client.images += image('icons/effects/alphacolors.dmi', T, "red") CHECK_TICK // Sort the keys zlevel_turf_indexes = sortAssoc(zlevel_turf_indexes) for(var/key in zlevel_turf_indexes) to_chat(usr, "Z[key]: [length(zlevel_turf_indexes["[key]"])] Interesting Turfs") var/z_to_view = input(usr, "A list of z-levels their ITs has appeared in chat. Please enter a Z to visualise. Enter 0 to cancel.", "Selection", 0) as num if(!z_to_view) return // Do not combine these var/list/ui_dat = list() var/list/turf_markers = list() var/datum/browser/vis = new(usr, "atvis", "Interesting Turfs (Z[z_to_view])", 300, 315) ui_dat += "
" ui_dat += "" // Now generate the other list for(var/x in zlevel_turf_indexes["[z_to_view]"]) var/turf/T = x turf_markers += "s([T.x],[T.y]);" CHECK_TICK ui_dat += "" vis.set_content(ui_dat.Join("")) vis.open(FALSE) /client/proc/create_rnd_restore_disk() set name = "Create RnD Backup Restore Disk" set category = "Event" // Im putting this in event because the name is long and will offset everything if(!check_rights(R_ADMIN)) return var/list/targets = list() for(var/rnc_uid in SSresearch.backups) var/datum/rnd_backup/B = SSresearch.backups[rnc_uid] targets["[B.last_name] - [B.last_timestamp]"] = rnc_uid var/choice = input(src, "Select a backup to restore", "RnD Backup Restore") as null|anything in targets if(!choice || !(choice in targets)) return var/actual_target = targets[choice] if(!(actual_target in SSresearch.backups)) return var/datum/rnd_backup/B = SSresearch.backups[actual_target] var/confirmation = alert("Are you sure you want to restore this RnD backup? The disk will spawn below your character.", "Are you sure?", "Yes", "No") if(confirmation != "Yes") return B.to_backup_disk(get_turf(usr)) /proc/ghost_follow_uid(mob/user, uid) var/client/client = user.client if(!isobserver(user)) if(!check_rights(R_ADMIN|R_MOD)) // Need to be mod or admin to aghost return user.client.admin_ghost() var/datum/target = locateUID(uid) if(QDELETED(target)) to_chat(user, "This datum has been deleted!") return if(istype(target, /datum/mind)) var/datum/mind/mind = target if(!ismob(mind.current)) to_chat(user, "This can only be used on instances of type /mob") return target = mind.current var/mob/dead/observer/A = client.mob A.ManualFollow(target)