Files
Paradise/code/modules/admin/admin_verbs.dm
RomainzZ e386cfd9bf Lamp Bloom, Exposure and Glare (#24534)
* Light Update

* Not failing tests I hope

* Whitespace Removal

* Tweaking here and there

* Merge Conflict Fix

* Rebuild TGUI Bundle to Fix Merge Conflict

* Settings are now in "Game Preferences" too

* ColorMatrix formatting and removal of unused procs

* A little mistake on matrices

* A little mistake x2 (last I hope)

* Moving Glare under every other effect, tweaking values, playing with blending

* Update TGUI Bundle for Merge Conflict

* Apply suggestions from code reviews

* Fuck it, it just works

* No tabs cool

* Remove unused

* Am I retarded

* We better return

* Whitespace we need

* oh

* New SQL update version

* Missing comma fix and recompiled tgui.bundle

* Updating SQL version in misc_defines and config

* Remove datum in holder

* BloomEdit empty lines removal

* No more unneeded functions calls

* Tgui.bundle rebuild

* SQL Changes

* SQL Version = 56 now

* Documentation and some formatting

* tgui.bundle.js rebuild

* Remove unused layers and variables

* Allow cameras to render backdrops

* Possible runtime issue fix

* Remove "baked" bloom from the lamps

* Revert the "remove". Make it low on alpha channel

* Shuttle rotation light update fix

* We don't need this

* Possible runtime issue fix x2

* tgui.bundle.js update

* tgui.bundle.js update

* tgui.bundle.js update

* Revert config.toml changes

* Revert the revertion of config.toml changes

* Bring that config changes back!

* Entry added

* tgui.bundle.js update

* Prettier possible fix (?)

* Runtime fix (and broken tubes now have light after reinstalling them)

* config update

---------

Co-authored-by: Mikhail Dzianishchyts <mikhail.dzianishchyts@gmail.com>
2024-07-05 21:16:16 +00:00

1231 lines
45 KiB
Plaintext

//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*/
/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/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*/
/datum/admins/proc/PlayerNotes,
/client/proc/cmd_mentor_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/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
))
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
))
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/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
))
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,
// cmd_mentor_say is added/removed by the toggle_mentor_chat verb
))
GLOBAL_LIST_INIT(admin_verbs_proccall, list(
/client/proc/callproc,
/client/proc/callproc_datum,
/client/proc/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?
/client/proc/allow_browser_inspect, // XSS prevention
))
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
))
/client/proc/add_admin_verbs()
if(holder)
// If they have ANYTHING OTHER THAN ONLY VIEW RUNTIMES (65536), then give them the default admin verbs
if(holder.rights != R_VIEWRUNTIMES)
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(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/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
))
add_verb(src, /client/proc/show_verbs)
to_chat(src, "<span class='interface'>Almost all of your adminverbs have been hidden.</span>")
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, "<span class='interface'>All of your adminverbs are now visible.</span>")
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, "<span class='warning'>You aren't allowed to use this!</span>")
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(isAI(mob)) // client.mob, built in byond client var
var/mob/living/silicon/ai/ai = mob
ai.eyeobj.setLoc(old_turf)
else if(isnewplayer(mob))
to_chat(src, "<font color='red'>Error: Aghost: Can't admin-ghost whilst in the lobby. Join or observe first.</font>")
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, "<span class='warning'>You cannot aobserve while in the lobby. Please join or observe first.</span>")
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, "<span class='warning'>You can't observe yourself!</span>")
return
if(isobserver(target))
to_chat(src, "<span class='warning'>[target] is a ghost, and cannot be observed.</span>")
return
if(isnewplayer(target))
to_chat(src, "<span class='warning'>[target] is in the lobby, and cannot be observed.</span>")
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, "<span class='warning'>You cannot aobserve while in the lobby. Please join or observe first.</span>")
return
if(isnewplayer(target))
to_chat(src, "<span class='warning'>[target] is currently in the lobby.</span>")
return
if(isobserver(target))
to_chat(src, "<span class='warning'>You can't observe a ghost.</span>")
return
if(cleanup_admin_observe(mob))
return
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, "<span class='notice'>You have temporarily observed [target], either move or observe again to un-observe.</span>")
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, "<span class='userdanger'>Unable to return you to your body after mentor ghosting. If your body still exists, please contact a coder, and you should probably ahelp.</span>")
/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, "<span class='danger'>Invisimin off. Invisibility reset.</span>")
log_admin("[key_name(mob)] has turned Invisimin OFF")
else
mob.invisibility = INVISIBILITY_OBSERVER
mob.remove_from_all_data_huds()
to_chat(mob, "<span class='notice'>Invisimin on. You are now as invisible as a ghost.</span>")
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/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)
if("Medium Bomb")
explosion(epicenter, 2, 3, 4, 4)
if("Big Bomb")
explosion(epicenter, 3, 5, 7, 5)
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)
log_admin("[key_name(usr)] created an admin explosion at [epicenter.loc]")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] created an admin explosion at [epicenter.loc]</span>")
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("<span class='adminnotice'>[key_name_admin(usr)] gave [key_name(T)] the disease [D].</span>")
/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("<span class='notice'>[key_name_admin(usr)] made [O] at [O.x], [O.y], [O.z] make a sound</span>")
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("<b>[mob.control_object.name]</b> 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, "<span class='interface'>You are now a normal player.</span>")
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,"<span class='boldannounceooc'><big>You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.</big></span>") // 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,"<span class='boldannounceooc'><big>You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.</big></span>") // 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
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, "<b>Stopped logging hrefs</b>")
else
GLOB.configuration.logging.href_logging = TRUE
to_chat(src, "<b>Started logging hrefs</b>")
/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("<span class='notice'><b><font size=4>Man up.<br> Deal with it.</font></b><br>Move on.</span>"))
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("<span class='notice'><b><font size=4>Man up.<br> Deal with it.</font></b><br>Move on.</span>"))
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/alert_type = alert(src, "Do you wish to send an admin alert to [key_name(about_to_be_banned, FALSE)]?", null,"Yes", "No", "Custom Message")
switch(alert_type)
if("Yes")
var/message = "An admin is trying to talk to you!\nCheck your chat window and click their name to respond or you may be banned!"
show_blurb(about_to_be_banned, 15, message, 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)].")
if("Custom Message")
var/message = input(src, "Input your custom admin alert text:", "Message") as text|null
if(!message)
return
message = strip_html(message, 500)
var/message_color = input(src, "Input your message color:", "Color Selector") as color|null
if(!message_color)
return
show_blurb(about_to_be_banned, 15, message, 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 [message].")
message_admins("[key_name(src)] sent an admin alert to [key_name(about_to_be_banned)] with custom message [message].")
/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, "<span class='warning'>You must be an observer to do this!</span>")
return
var/list/interesting_tile = get_random_interesting_tile()
if(!length(interesting_tile))
to_chat(mob, "<span class='notice'>There are no interesting turfs. How interesting!</span>")
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, "<span class='notice'>There are no interesting turfs. How interesting!</span>")
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, "<span class='notice'>Z[key]: <b>[length(zlevel_turf_indexes["[key]"])] Interesting Turfs</b></span>")
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 += "<center><canvas width=\"255px\" height=\"255px\" id=\"atmos\"></canvas></center>"
ui_dat += "<script>e=document.getElementById(\"atmos\");c=e.getContext('2d');c.fillStyle='#ffffff';c.fillRect(0,0,255,255);function s(x,y){var p=c.createImageData(1,1);p.data\[0]=255;p.data\[1]=0;p.data\[2]=0;p.data\[3]=255;c.putImageData(p,(x-1),255-Math.abs(y-1));}</script>"
// 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 += "<script>[turf_markers.Join("")]</script>"
vis.set_content(ui_dat.Join(""))
vis.open(FALSE)