mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-08-25 21:19:44 +01:00
TG spawn panel port (#19293)
* TG spawn panel port * . * . * click intercept * . * diagonals * . * . * fix path search * reduce that * Fixes ghost click * lol --------- Co-authored-by: Cameron Lennox <killer65311@gmail.com>
This commit is contained in:
co-authored by
Cameron Lennox
parent
c38c0d0698
commit
7c7aa0d237
@@ -130,6 +130,9 @@
|
||||
#define RANK_SOURCE_BACKUP "rank_backup"
|
||||
#define RANK_SOURCE_TEMPORARY "rank_temp"
|
||||
|
||||
//How many things you can spawn at once with spawn verb/create panel
|
||||
#define ADMIN_SPAWN_CAP 100
|
||||
|
||||
// LOG BROWSE TYPES
|
||||
#define BROWSE_ROOT_ALL_LOGS 1
|
||||
#define BROWSE_ROOT_RUNTIME_LOGS 2
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#define COMPONENT_CANCEL_ATTACK_CHAIN (1<<0)
|
||||
///Skips the specific attack step, continuing for the next one to happen.
|
||||
#define COMPONENT_SKIP_ATTACK (1<<1)
|
||||
///from base of atom/attack_ghost(): (mob/dead/observer/ghost)
|
||||
///from base of atom/attack_ghost(): (mob/observer/dead/ghost)
|
||||
#define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost"
|
||||
///from base of atom/attack_hand(): (mob/user, list/modifiers)
|
||||
#define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand"
|
||||
|
||||
@@ -37,6 +37,7 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
|
||||
#define IS_BUSY (1<<8) // Atom has a TASK_TARGET_EXCLUSIVE do_after with it as the target.
|
||||
#define REMOTEVIEW_ON_ENTER (1<<9) // Object starts a remoteview of itself for any mob that enters it with a client. Items will automatically handle their own remoteview, and ignore this.
|
||||
#define WALL_ITEM (1<<10) // Wall mounted objects
|
||||
#define ADMIN_SPAWNED (1<<22) // Admin Spawned
|
||||
#define ATOM_INITIALIZED (1<<23) // Atom has been initialized. Using a flag instead of a variable saves ~25mb total.
|
||||
|
||||
//Flags for items (equipment) - Used in /obj/item/var/item_flags
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
P.Click(params)
|
||||
break
|
||||
|
||||
if(check_click_intercept(params,A))
|
||||
return
|
||||
|
||||
if(stat)
|
||||
return
|
||||
|
||||
|
||||
+17
-2
@@ -43,9 +43,11 @@
|
||||
* mob/RangedAttack(atom,params) - used only ranged, only used for tk and laser eyes but could be changed
|
||||
*/
|
||||
/mob/proc/ClickOn(atom/A, params)
|
||||
if(world.time <= next_click)
|
||||
if(!checkClickCooldown()) return
|
||||
setClickCooldown(1) //1/10 of a second, 10 clicks allowed per second.
|
||||
|
||||
if(check_click_intercept(params,A) || HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
|
||||
return
|
||||
next_click = world.time + 1
|
||||
|
||||
if(client && client.buildmode)
|
||||
build_click(src, client.buildmode, params, A)
|
||||
@@ -372,3 +374,16 @@
|
||||
/// MouseWheelOn
|
||||
/mob/proc/MouseWheelOn(atom/A, delta_x, delta_y, params)
|
||||
SEND_SIGNAL(src, COMSIG_MOUSE_SCROLL_ON, A, delta_x, delta_y, params)
|
||||
|
||||
/mob/proc/check_click_intercept(params,A)
|
||||
//Client level intercept
|
||||
if(client?.click_intercept)
|
||||
if(call(client.click_intercept, "InterceptClickOn")(src, params, A))
|
||||
return TRUE
|
||||
|
||||
//Mob level intercept
|
||||
if(click_intercept)
|
||||
if(call(click_intercept, "InterceptClickOn")(src, params, A))
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
if(!checkClickCooldown())
|
||||
return
|
||||
|
||||
if(check_click_intercept(params,A))
|
||||
return
|
||||
|
||||
setClickCooldown(1)
|
||||
|
||||
if(client.buildmode) // comes after object.Click to allow buildmode gui objects to be clicked
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
/atom/movable/screen/movable/action_button/proc/can_use(mob/user)
|
||||
// if(isobserver(user))
|
||||
// var/mob/dead/observer/dead_mob = user
|
||||
// var/mob/observer/dead/dead_mob = user
|
||||
// if(dead_mob.observetarget) // Observers can only click on action buttons if they're not observing something
|
||||
// return FALSE
|
||||
|
||||
@@ -327,7 +327,7 @@ GLOBAL_LIST_INIT(palette_removed_matrix, list(1.4,0,0,0, 0.7,0.4,0,0, 0.4,0,0.6,
|
||||
|
||||
/atom/movable/screen/button_palette/proc/can_use(mob/user)
|
||||
if(isobserver(user))
|
||||
// var/mob/dead/observer/O = user
|
||||
// var/mob/observer/dead/O = user
|
||||
// return !O.observetarget
|
||||
return TRUE
|
||||
return TRUE
|
||||
@@ -388,7 +388,7 @@ GLOBAL_LIST_INIT(palette_removed_matrix, list(1.4,0,0,0, 0.7,0.4,0,0, 0.4,0,0.6,
|
||||
|
||||
/atom/movable/screen/palette_scroll/proc/can_use(mob/user)
|
||||
if(isobserver(user))
|
||||
// var/mob/dead/observer/O = user
|
||||
// var/mob/observer/dead/O = user
|
||||
// return !O.observetarget
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
@@ -414,7 +414,7 @@ so as to remain in compliance with the most up-to-date laws."
|
||||
// /atom/movable/screen/alert/notify_jump/Click()
|
||||
// if(!usr || !usr.client) return
|
||||
// if(!jump_target) return
|
||||
// var/mob/dead/observer/G = usr
|
||||
// var/mob/observer/dead/G = usr
|
||||
// if(!istype(G)) return
|
||||
// if(attack_not_jump)
|
||||
// jump_target.attack_ghost(G)
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
/* I wish we had this. Not yet, though.
|
||||
/datum/hud/ghost/show_hud(version = 0, mob/viewmob)
|
||||
// don't show this HUD if observing; show the HUD of the observee
|
||||
var/mob/dead/observer/O = mymob
|
||||
var/mob/observer/dead/O = mymob
|
||||
if (istype(O) && O.observetarget)
|
||||
plane_masters_update()
|
||||
return FALSE
|
||||
@@ -208,7 +208,7 @@
|
||||
|
||||
//We should only see observed mob alerts.
|
||||
/datum/hud/ghost/reorganize_alerts(mob/viewmob)
|
||||
var/mob/dead/observer/O = mymob
|
||||
var/mob/observer/dead/O = mymob
|
||||
if (istype(O) && O.observetarget)
|
||||
return
|
||||
. = ..()
|
||||
|
||||
+41
-10
@@ -11,6 +11,8 @@
|
||||
to_chat(src, span_notice("You will no longer examine things you click on."))
|
||||
|
||||
/mob/observer/dead/DblClickOn(var/atom/A, var/params)
|
||||
if(check_click_intercept(params,A))
|
||||
return
|
||||
if(client.buildmode)
|
||||
build_click(src, client.buildmode, params, A)
|
||||
return
|
||||
@@ -28,21 +30,50 @@
|
||||
stop_following()
|
||||
forceMove(get_turf(A))
|
||||
|
||||
/mob/observer/dead/ClickOn(var/atom/A, var/params)
|
||||
if(client.buildmode)
|
||||
/mob/observer/dead/ClickOn(atom/A, params)
|
||||
if(!checkClickCooldown()) return
|
||||
setClickCooldown(1)
|
||||
|
||||
if(check_click_intercept(params,A))
|
||||
return
|
||||
|
||||
if(client && client.buildmode)
|
||||
build_click(src, client.buildmode, params, A)
|
||||
return
|
||||
if(!checkClickCooldown()) return
|
||||
setClickCooldown(4)
|
||||
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["shift"])
|
||||
examinate(A)
|
||||
|
||||
if(LAZYACCESS(modifiers, BUTTON4) || LAZYACCESS(modifiers, BUTTON5))
|
||||
return
|
||||
if(modifiers["alt"]) // alt and alt-gr (rightalt)
|
||||
var/turf/T = get_turf(A)
|
||||
if(T && TurfAdjacent(T))
|
||||
T.click_alt(src)
|
||||
|
||||
if(LAZYACCESS(modifiers, SHIFT_CLICK))
|
||||
if(LAZYACCESS(modifiers, MIDDLE_CLICK))
|
||||
ShiftMiddleClickOn(A)
|
||||
return
|
||||
if(LAZYACCESS(modifiers, CTRL_CLICK))
|
||||
CtrlShiftClickOn(A)
|
||||
return
|
||||
if (LAZYACCESS(modifiers, ALT_CLICK))
|
||||
alt_shift_click_on(A)
|
||||
return
|
||||
ShiftClickOn(A) //Should in most cases call examinate() unless we block things from examining us.
|
||||
return
|
||||
if(LAZYACCESS(modifiers, MIDDLE_CLICK))
|
||||
if(LAZYACCESS(modifiers, CTRL_CLICK))
|
||||
CtrlMiddleClickOn(A)
|
||||
else
|
||||
MiddleClickOn(A, params)
|
||||
return
|
||||
if(LAZYACCESS(modifiers, ALT_CLICK)) // alt and alt-gr (rightalt)
|
||||
if(LAZYACCESS(modifiers, RIGHT_CLICK))
|
||||
AltClickSecondaryOn(A)
|
||||
else
|
||||
AltClickOn(A)
|
||||
return
|
||||
if(LAZYACCESS(modifiers, CTRL_CLICK))
|
||||
CtrlClickOn(A)
|
||||
return
|
||||
|
||||
// You are responsible for checking config.ghost_interaction when you override this function
|
||||
// Not all of them require checking, see below
|
||||
A.attack_ghost(src)
|
||||
|
||||
@@ -125,6 +125,6 @@
|
||||
if(orbiters)
|
||||
for(var/datum/orbit/O as anything in orbiters)
|
||||
if(O.orbiter && isobserver(O.orbiter))
|
||||
var/mob/dead/observer/D = O.orbiter
|
||||
var/mob/observer/dead/D = O.orbiter
|
||||
D.ManualFollow(target)
|
||||
*/
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
if(A)
|
||||
A.forceMove(src) // helo
|
||||
podfall(auto_open)
|
||||
air = new
|
||||
air = new
|
||||
|
||||
/obj/structure/drop_pod/Destroy()
|
||||
. = ..()
|
||||
|
||||
+200
-203
@@ -49,12 +49,12 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_HOLDER, "Show Player Panel", m
|
||||
var/body = "Options panel for " + span_bold("[player]")
|
||||
if(player.client)
|
||||
body += " played by " + span_bold("[player.client]")
|
||||
body += "\[<A href='byond://?_src_=holder;[HrefToken()];editrights=[(GLOB.admin_datums[player.client.ckey] || GLOB.deadmins[player.client.ckey]) ? "rank" : "add"];key=[player.key]'>[player.client.holder ? player.client.holder.rank_names() : "Player"]</A>\]"
|
||||
body += "\[<a href='byond://?_src_=holder;[HrefToken()];editrights=[(GLOB.admin_datums[player.client.ckey] || GLOB.deadmins[player.client.ckey]) ? "rank" : "add"];key=[player.key]'>[player.client.holder ? player.client.holder.rank_names() : "Player"]</a>\]"
|
||||
|
||||
if(isnewplayer(player))
|
||||
body += span_bold("Hasn't Entered Game")
|
||||
else
|
||||
body += " \[<A href='byond://?_src_=holder;[HrefToken()];revive=[REF(player)]'>Heal</A>\] "
|
||||
body += " \[<a href='byond://?_src_=holder;[HrefToken()];revive=[REF(player)]'>Heal</a>\] "
|
||||
|
||||
if(player.client)
|
||||
body += "<br>" + span_bold("First connection:") + "[player.client.player_age] days ago"
|
||||
@@ -63,42 +63,42 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_HOLDER, "Show Player Panel", m
|
||||
|
||||
body += {"
|
||||
<br><br>\[
|
||||
<a href='byond://?_src_=vars;[HrefToken()];Vars=\ref[player]'>VV</a> -
|
||||
<a href='byond://?_src_=holder;[HrefToken()];traitor=\ref[player]'>TP</a> -
|
||||
<a href='byond://??_src_=holder;[HrefToken()];priv_msg=\ref[player]'>PM</a> -
|
||||
<a href='byond://?_src_=holder;[HrefToken()];subtlemessage=\ref[player]'>SM</a> -
|
||||
<a href='byond://?_src_=vars;[HrefToken()];Vars=[REF(player)]'>VV</a> -
|
||||
<a href='byond://?_src_=holder;[HrefToken()];traitor=[REF(player)]'>TP</a> -
|
||||
<a href='byond://??_src_=holder;[HrefToken()];priv_msg=[REF(player)]'>PM</a> -
|
||||
<a href='byond://?_src_=holder;[HrefToken()];subtlemessage=[REF(player)]'>SM</a> -
|
||||
[admin_jump_link(player, src)]\] <br>
|
||||
"} + span_bold("Mob type:") + {"[player.type]<br>
|
||||
"} + span_bold("Inactivity time:") + {" [player.client ? "[player.client.inactivity/600] minutes" : "Logged out"]<br/><br/>
|
||||
<A href='byond://?_src_=holder;[HrefToken()];boot2=\ref[player]'>Kick</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];warn=[player.ckey]'>Warn</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];newban=\ref[player]'>Ban</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];jobban2=\ref[player]'>Jobban</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];notes=show;mob=\ref[player]'>Notes</A>
|
||||
<a href='byond://?_src_=holder;[HrefToken()];boot2=[REF(player)]'>Kick</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];warn=[player.ckey]'>Warn</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];newban=[REF(player)]'>Ban</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];jobban2=[REF(player)]'>Jobban</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];notes=show;mob=[REF(player)]'>Notes</a>
|
||||
"}
|
||||
|
||||
if(player.client)
|
||||
body += "| <A href='byond://?_src_=holder;[HrefToken()];sendtoprison=\ref[player]'>Prison</A> | "
|
||||
body += "\ <A href='byond://?_src_=holder;[HrefToken()];sendbacktolobby=\ref[player]'>Send back to Lobby</A> | "
|
||||
body += "| <a href='byond://?_src_=holder;[HrefToken()];sendtoprison=[REF(player)]'>Prison</a> | "
|
||||
body += "\ <a href='byond://?_src_=holder;[HrefToken()];sendbacktolobby=[REF(player)]'>Send back to Lobby</a> | "
|
||||
var/muted = player.client.prefs.muted
|
||||
body += {"<br>"} + span_bold("Mute: ") + {"
|
||||
\[<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_IC]'>[(muted & MUTE_IC) ? span_red("IC") : span_blue("IC")]</a> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_OOC]'>[(muted & MUTE_OOC) ? span_red("OOC") : span_blue("OOC")]</a> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_LOOC]'>[(muted & MUTE_LOOC) ? span_red("LOOC") : span_blue("LOOC")]</a> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_PRAY]'>[(muted & MUTE_PRAY) ? span_red("PRAY") : span_blue("PRAY")]</a> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_ADMINHELP]'>[(muted & MUTE_ADMINHELP) ? span_red("ADMINHELP") : span_blue("ADMINHELP")]</a> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_DEADCHAT]'>[(muted & MUTE_DEADCHAT) ? span_red("DEADCHAT") : span_blue("DEADCHAT")]</a>\]
|
||||
(<A href='byond://?_src_=holder;[HrefToken()];mute=\ref[player];mute_type=[MUTE_ALL]'>[(muted & MUTE_ALL) ? span_red("toggle all") : span_blue("toggle all")]</a>)
|
||||
\[<a href='byond://?_src_=holder;[HrefToken()];mute=[REF(player)];mute_type=[MUTE_IC]'>[(muted & MUTE_IC) ? span_red("IC") : span_blue("IC")]</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];mute=[REF(player)];mute_type=[MUTE_OOC]'>[(muted & MUTE_OOC) ? span_red("OOC") : span_blue("OOC")]</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];mute=[REF(player)];mute_type=[MUTE_LOOC]'>[(muted & MUTE_LOOC) ? span_red("LOOC") : span_blue("LOOC")]</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];mute=[REF(player)];mute_type=[MUTE_PRAY]'>[(muted & MUTE_PRAY) ? span_red("PRAY") : span_blue("PRAY")]</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];mute=[REF(player)];mute_type=[MUTE_ADMINHELP]'>[(muted & MUTE_ADMINHELP) ? span_red("ADMINHELP") : span_blue("ADMINHELP")]</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];mute=[REF(player)];mute_type=[MUTE_DEADCHAT]'>[(muted & MUTE_DEADCHAT) ? span_red("DEADCHAT") : span_blue("DEADCHAT")]</a>\]
|
||||
(<a href='byond://?_src_=holder;[HrefToken()];mute=[REF(player)];mute_type=[MUTE_ALL]'>[(muted & MUTE_ALL) ? span_red("toggle all") : span_blue("toggle all")]</a>)
|
||||
"}
|
||||
|
||||
body += {"<br><br>
|
||||
<A href='byond://?_src_=holder;[HrefToken()];jumpto=\ref[player]'>"} + span_bold("Jump to") + {"</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];getmob=\ref[player]'>Get</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];sendmob=\ref[player]'>Send To</A>
|
||||
<a href='byond://?_src_=holder;[HrefToken()];jumpto=[REF(player)]'>"} + span_bold("Jump to") + {"</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];getmob=[REF(player)]'>Get</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];sendmob=[REF(player)]'>Send To</a>
|
||||
<br><br>
|
||||
[check_rights(R_ADMIN|R_MOD|R_EVENT,0) ? "<A href='byond://?_src_=holder;[HrefToken()];traitor=\ref[player]'>Traitor panel</A> | " : "" ]
|
||||
<A href='byond://?_src_=holder;[HrefToken()];narrateto=\ref[player]'>Narrate to</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];subtlemessage=\ref[player]'>Subtle message</A>
|
||||
[check_rights(R_ADMIN|R_MOD|R_EVENT,0) ? "<a href='byond://?_src_=holder;[HrefToken()];traitor=[REF(player)]'>Traitor panel</a> | " : "" ]
|
||||
<a href='byond://?_src_=holder;[HrefToken()];narrateto=[REF(player)]'>Narrate to</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];subtlemessage=[REF(player)]'>Subtle message</a>
|
||||
"}
|
||||
|
||||
if (player.client)
|
||||
@@ -111,30 +111,30 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_HOLDER, "Show Player Panel", m
|
||||
if(issmall(player))
|
||||
body += span_bold("Monkeyized") + " | "
|
||||
else
|
||||
body += "<A href='byond://?_src_=holder;[HrefToken()];turn_monkey=\ref[player]'>Monkeyize</A> | "
|
||||
body += "<a href='byond://?_src_=holder;[HrefToken()];turn_monkey=[REF(player)]'>Monkeyize</a> | "
|
||||
|
||||
//Corgi
|
||||
if(iscorgi(player))
|
||||
body += span_bold("Corgized") + " | "
|
||||
else
|
||||
body += "<A href='byond://?_src_=holder;[HrefToken()];corgione=\ref[player]'>Corgize</A> | "
|
||||
body += "<a href='byond://?_src_=holder;[HrefToken()];corgione=[REF(player)]'>Corgize</a> | "
|
||||
|
||||
//AI / Cyborg
|
||||
if(isAI(player))
|
||||
body += span_bold("Is an AI ")
|
||||
else if(ishuman(player))
|
||||
body += {"<A href='byond://?_src_=holder;[HrefToken()];turn_ai=\ref[player]'>Make AI</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];turn_robot=\ref[player]'>Make Robot</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];turn_alien=\ref[player]'>Make Alien</A>
|
||||
body += {"<a href='byond://?_src_=holder;[HrefToken()];turn_ai=[REF(player)]'>Make AI</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];turn_robot=[REF(player)]'>Make Robot</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];turn_alien=[REF(player)]'>Make Alien</a>
|
||||
"}
|
||||
|
||||
//Simple Animals
|
||||
if(isanimal(player))
|
||||
body += "<A href='byond://?_src_=holder;[HrefToken()];makeanimal=\ref[player]'>Re-Animalize</A> | "
|
||||
body += "<a href='byond://?_src_=holder;[HrefToken()];makeanimal=[REF(player)]'>Re-Animalize</a> | "
|
||||
else
|
||||
body += "<A href='byond://?_src_=holder;[HrefToken()];makeanimal=\ref[player]'>Animalize</A> | "
|
||||
body += "<a href='byond://?_src_=holder;[HrefToken()];makeanimal=[REF(player)]'>Animalize</a> | "
|
||||
|
||||
body += "<A href='byond://?_src_=holder;[HrefToken()];respawn=\ref[player.client]'>Respawn</A> | "
|
||||
body += "<a href='byond://?_src_=holder;[HrefToken()];respawn=[REF(player.client)]'>Respawn</a> | "
|
||||
|
||||
// DNA2 - Admin Hax
|
||||
if(player.dna && iscarbon(player))
|
||||
@@ -170,7 +170,7 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_HOLDER, "Show Player Panel", m
|
||||
bname = span_orange(bname)
|
||||
else
|
||||
bname = span_red(bname)
|
||||
body += "<A href='byond://?_src_=holder;[HrefToken()];togmutate=\ref[player];block=[block]' title='[tname]'>[bname]</A><sub>[block]</sub>" // Traitgenes edit - show trait linked names on mouseover
|
||||
body += "<a href='byond://?_src_=holder;[HrefToken()];togmutate=[REF(player)];block=[block]' title='[tname]'>[bname]</a><sub>[block]</sub>" // Traitgenes edit - show trait linked names on mouseover
|
||||
else
|
||||
body += "[block]"
|
||||
body+="</td>"
|
||||
@@ -178,45 +178,45 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_HOLDER, "Show Player Panel", m
|
||||
|
||||
body += {"<br><br>
|
||||
"} + span_bold("Rudimentary transformation:") + span_normal("<br>These transformations only create a new mob type and copy stuff over. They do not take into account MMIs and similar mob-specific things. The buttons in 'Transformations' are preferred, when possible.") + {"<br>
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=observer;mob=\ref[player]'>Observer</A> |
|
||||
\[ Xenos: <A href='byond://?_src_=holder;[HrefToken()];simplemake=larva;mob=\ref[player]'>Larva</A>
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Xenomorph Drone;mob=\ref[player]'>Drone</A>
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Xenomorph Hunter;mob=\ref[player]'>Hunter</A>
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Xenomorph Sentinel;mob=\ref[player]'>Sentinel</A>
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Xenomorph Queen;mob=\ref[player]'>Queen</A> \] |
|
||||
\[ Crew: <A href='byond://?_src_=holder;[HrefToken()];simplemake=human;mob=\ref[player]'>Human</A>
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Unathi;mob=\ref[player]'>Unathi</A>
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Tajaran;mob=\ref[player]'>Tajaran</A>
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Skrell;mob=\ref[player]'>Skrell</A> \] | \[
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=nymph;mob=\ref[player]'>Nymph</A>
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=human;species='Diona';mob=\ref[player]'>Diona</A> \] |
|
||||
\[ slime: <A href='byond://?_src_=holder;[HrefToken()];simplemake=slime;mob=\ref[player]'>Baby</A>,
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=adultslime;mob=\ref[player]'>Adult</A> \]
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=monkey;mob=\ref[player]'>Monkey</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=robot;mob=\ref[player]'>Cyborg</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=cat;mob=\ref[player]'>Cat</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=runtime;mob=\ref[player]'>Runtime</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=corgi;mob=\ref[player]'>Corgi</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=ian;mob=\ref[player]'>Ian</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=crab;mob=\ref[player]'>Crab</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=coffee;mob=\ref[player]'>Coffee</A> |
|
||||
\[ Construct: <A href='byond://?_src_=holder;[HrefToken()];simplemake=constructarmoured;mob=\ref[player]'>Armoured</A> ,
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=constructbuilder;mob=\ref[player]'>Builder</A> ,
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=constructwraith;mob=\ref[player]'>Wraith</A> \]
|
||||
<A href='byond://?_src_=holder;[HrefToken()];simplemake=shade;mob=\ref[player]'>Shade</A>
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=observer;mob=[REF(player)]'>Observer</a> |
|
||||
\[ Xenos: <a href='byond://?_src_=holder;[HrefToken()];simplemake=larva;mob=[REF(player)]'>Larva</a>
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Xenomorph Drone;mob=[REF(player)]'>Drone</a>
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Xenomorph Hunter;mob=[REF(player)]'>Hunter</a>
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Xenomorph Sentinel;mob=[REF(player)]'>Sentinel</a>
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Xenomorph Queen;mob=[REF(player)]'>Queen</a> \] |
|
||||
\[ Crew: <a href='byond://?_src_=holder;[HrefToken()];simplemake=human;mob=[REF(player)]'>Human</a>
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Unathi;mob=[REF(player)]'>Unathi</a>
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Tajaran;mob=[REF(player)]'>Tajaran</a>
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=human;species=Skrell;mob=[REF(player)]'>Skrell</a> \] | \[
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=nymph;mob=[REF(player)]'>Nymph</a>
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=human;species='Diona';mob=[REF(player)]'>Diona</a> \] |
|
||||
\[ slime: <a href='byond://?_src_=holder;[HrefToken()];simplemake=slime;mob=[REF(player)]'>Baby</a>,
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=adultslime;mob=[REF(player)]'>Adult</a> \]
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=monkey;mob=[REF(player)]'>Monkey</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=robot;mob=[REF(player)]'>Cyborg</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=cat;mob=[REF(player)]'>Cat</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=runtime;mob=[REF(player)]'>Runtime</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=corgi;mob=[REF(player)]'>Corgi</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=ian;mob=[REF(player)]'>Ian</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=crab;mob=[REF(player)]'>Crab</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=coffee;mob=[REF(player)]'>Coffee</a> |
|
||||
\[ Construct: <a href='byond://?_src_=holder;[HrefToken()];simplemake=constructarmoured;mob=[REF(player)]'>Armoured</a> ,
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=constructbuilder;mob=[REF(player)]'>Builder</a> ,
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=constructwraith;mob=[REF(player)]'>Wraith</a> \]
|
||||
<a href='byond://?_src_=holder;[HrefToken()];simplemake=shade;mob=[REF(player)]'>Shade</a>
|
||||
<br>
|
||||
"}
|
||||
body += {"<br><br>
|
||||
"} + span_bold("Other actions:") + {"
|
||||
<br>
|
||||
<A href='byond://?_src_=holder;[HrefToken()];forcespeech=\ref[player]'>Forcesay</A>
|
||||
<a href='byond://?_src_=holder;[HrefToken()];forcespeech=[REF(player)]'>Forcesay</a>
|
||||
"}
|
||||
if (player.client)
|
||||
body += {" |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];tdome1=\ref[player]'>Thunderdome 1</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];tdome2=\ref[player]'>Thunderdome 2</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];tdomeadmin=\ref[player]'>Thunderdome Admin</A> |
|
||||
<A href='byond://?_src_=holder;[HrefToken()];tdomeobserve=\ref[player]'>Thunderdome Observer</A> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];tdome1=[REF(player)]'>Thunderdome 1</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];tdome2=[REF(player)]'>Thunderdome 2</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];tdomeadmin=[REF(player)]'>Thunderdome Admin</a> |
|
||||
<a href='byond://?_src_=holder;[HrefToken()];tdomeobserve=[REF(player)]'>Thunderdome Observer</a> |
|
||||
"}
|
||||
// language toggles
|
||||
body += "<br><br>" + span_bold("Languages:") + "<br>"
|
||||
@@ -227,9 +227,9 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_HOLDER, "Show Player Panel", m
|
||||
if(!f) body += " | "
|
||||
else f = 0
|
||||
if(L in player.languages)
|
||||
body += "<a href='byond://?_src_=holder;[HrefToken()];toglang=\ref[player];lang=[html_encode(k)]'>[span_green(k)]</a>"
|
||||
body += "<a href='byond://?_src_=holder;[HrefToken()];toglang=[REF(player)];lang=[html_encode(k)]'>[span_green(k)]</a>"
|
||||
else
|
||||
body += "<a href='byond://?_src_=holder;[HrefToken()];toglang=\ref[player];lang=[html_encode(k)]'>[span_red(k)]</a>"
|
||||
body += "<a href='byond://?_src_=holder;[HrefToken()];toglang=[REF(player)];lang=[html_encode(k)]'>[span_red(k)]</a>"
|
||||
|
||||
body += {"<br>"}
|
||||
|
||||
@@ -279,28 +279,28 @@ ADMIN_VERB(access_news_network, R_ADMIN|R_EVENT, "Access Newscaster Network", "A
|
||||
var/datum/admins/admin_holder = user.holder
|
||||
switch(admin_holder.admincaster_screen)
|
||||
if(0)
|
||||
dat += {"Welcome to the admin newscaster.<BR> Here you can add, edit and censor every newspiece on the network.
|
||||
<BR>Feed channels and stories entered through here will be uneditable and handled as official news by the rest of the units.
|
||||
<BR>Note that this panel allows full freedom over the news network, there are no constrictions except the few basic ones. Don't break things!
|
||||
dat += {"Welcome to the admin newscaster.<br> Here you can add, edit and censor every newspiece on the network.
|
||||
<br>Feed channels and stories entered through here will be uneditable and handled as official news by the rest of the units.
|
||||
<br>Note that this panel allows full freedom over the news network, there are no constrictions except the few basic ones. Don't break things!
|
||||
"}
|
||||
if(GLOB.news_network.wanted_issue)
|
||||
dat+= "<HR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_view_wanted=1'>Read Wanted Issue</A>"
|
||||
dat+= "<HR><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_view_wanted=1'>Read Wanted Issue</a>"
|
||||
|
||||
dat+= {"<HR><BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_create_channel=1'>Create Feed Channel</A>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_view=1'>View Feed Channels</A>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_create_feed_story=1'>Submit new Feed story</A>
|
||||
<BR><BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];mach_close=newscaster_main'>Exit</A>
|
||||
dat+= {"<HR><br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_create_channel=1'>Create Feed Channel</a>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_view=1'>View Feed Channels</a>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_create_feed_story=1'>Submit new Feed story</a>
|
||||
<br><br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];mach_close=newscaster_main'>Exit</a>
|
||||
"}
|
||||
|
||||
var/wanted_already = 0
|
||||
if(GLOB.news_network.wanted_issue)
|
||||
wanted_already = 1
|
||||
|
||||
dat+={"<HR>"} + span_bold("Feed Security functions:") + {"<BR>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_menu_wanted=1'>[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue</A>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_menu_censor_story=1'>Censor Feed Stories</A>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_menu_censor_channel=1'>Mark Feed Channel with [using_map.company_name] D-Notice (disables and locks the channel.</A>
|
||||
<BR><HR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_set_signature=1'>The newscaster recognises you as:<BR>"} + span_green("[admin_holder.admincaster_signature]") + {"</A>
|
||||
dat+={"<HR>"} + span_bold("Feed Security functions:") + {"<br>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_menu_wanted=1'>[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue</a>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_menu_censor_story=1'>Censor Feed Stories</a>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_menu_censor_channel=1'>Mark Feed Channel with [using_map.company_name] D-Notice (disables and locks the channel.</a>
|
||||
<br><HR><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_set_signature=1'>The newscaster recognises you as:<br>"} + span_green("[admin_holder.admincaster_signature]") + {"</a>
|
||||
"}
|
||||
if(1)
|
||||
dat+= "Station Feed Channels<HR>"
|
||||
@@ -309,97 +309,97 @@ ADMIN_VERB(access_news_network, R_ADMIN|R_EVENT, "Access Newscaster Network", "A
|
||||
else
|
||||
for(var/datum/feed_channel/CHANNEL in GLOB.news_network.network_channels)
|
||||
if(CHANNEL.is_admin_channel)
|
||||
dat+=span_bold("<FONT style='BACKGROUND-COLOR: LightGreen'><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_show_channel=\ref[CHANNEL]'>[CHANNEL.channel_name]</A></FONT>") + "<BR>"
|
||||
dat+=span_bold("<FONT style='BACKGROUND-COLOR: LightGreen'><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_show_channel=[REF(CHANNEL)]'>[CHANNEL.channel_name]</a></FONT>") + "<br>"
|
||||
else
|
||||
dat+=span_bold("<A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_show_channel=\ref[CHANNEL]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? (span_red("***")) : null]<BR>")
|
||||
dat+={"<BR><HR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_refresh=1'>Refresh</A>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[0]'>Back</A>
|
||||
dat+=span_bold("<a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_show_channel=[REF(CHANNEL)]'>[CHANNEL.channel_name]</a> [(CHANNEL.censored) ? (span_red("***")) : null]<br>")
|
||||
dat+={"<br><HR><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_refresh=1'>Refresh</a>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[0]'>Back</a>
|
||||
"}
|
||||
|
||||
if(2)
|
||||
dat+={"
|
||||
Creating new Feed Channel...
|
||||
<HR>"} + span_bold("<A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_set_channel_name=1'>Channel Name</A>:") + {" [admin_holder.admincaster_feed_channel.channel_name]<BR>
|
||||
"} + span_bold("<A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_set_signature=1'>Channel Author</A>:") + {" "} + span_green("[admin_holder.admincaster_signature]") + {"<BR>
|
||||
"} + span_bold("<A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_set_channel_lock=1'>Will Accept Public Feeds</A>:") + {" [(admin_holder.admincaster_feed_channel.locked) ? ("NO") : ("YES")]<BR><BR>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_submit_new_channel=1'>Submit</A><BR><BR><A href='byond://?src=\ref[src];[HrefToken()];ac_setScreen=[0]'>Cancel</A><BR>
|
||||
<HR>"} + span_bold("<a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_set_channel_name=1'>Channel Name</a>:") + {" [admin_holder.admincaster_feed_channel.channel_name]<br>
|
||||
"} + span_bold("<a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_set_signature=1'>Channel Author</a>:") + {" "} + span_green("[admin_holder.admincaster_signature]") + {"<br>
|
||||
"} + span_bold("<a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_set_channel_lock=1'>Will Accept Public Feeds</a>:") + {" [(admin_holder.admincaster_feed_channel.locked) ? ("NO") : ("YES")]<br><br>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_submit_new_channel=1'>Submit</a><br><br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[0]'>Cancel</a><br>
|
||||
"}
|
||||
if(3)
|
||||
dat+={"
|
||||
Creating new Feed Message...
|
||||
<HR>"} + span_bold("<A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_set_channel_receiving=1'>Receiving Channel</A>:") + {" [admin_holder.admincaster_feed_channel.channel_name]<BR>
|
||||
"} + span_bold("Message Author:") + {" "} + span_green("[admin_holder.admincaster_signature]") + {"<BR>
|
||||
"} + span_bold("<A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_set_new_message=1'>Message Body</A>:") + {" [admin_holder.admincaster_feed_message.body] <BR>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_submit_new_message=1'>Submit</A><BR><BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[0]'>Cancel</A><BR>
|
||||
<HR>"} + span_bold("<a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_set_channel_receiving=1'>Receiving Channel</a>:") + {" [admin_holder.admincaster_feed_channel.channel_name]<br>
|
||||
"} + span_bold("Message Author:") + {" "} + span_green("[admin_holder.admincaster_signature]") + {"<br>
|
||||
"} + span_bold("<a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_set_new_message=1'>Message Body</a>:") + {" [admin_holder.admincaster_feed_message.body] <br>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_submit_new_message=1'>Submit</a><br><br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[0]'>Cancel</a><br>
|
||||
"}
|
||||
if(4)
|
||||
dat+={"
|
||||
Feed story successfully submitted to [admin_holder.admincaster_feed_channel.channel_name].<BR><BR>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>
|
||||
Feed story successfully submitted to [admin_holder.admincaster_feed_channel.channel_name].<br><br>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[0]'>Return</a><br>
|
||||
"}
|
||||
if(5)
|
||||
dat+={"
|
||||
Feed Channel [admin_holder.admincaster_feed_channel.channel_name] created successfully.<BR><BR>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>
|
||||
Feed Channel [admin_holder.admincaster_feed_channel.channel_name] created successfully.<br><br>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[0]'>Return</a><br>
|
||||
"}
|
||||
if(6)
|
||||
dat+=span_bold(span_maroon("ERROR: Could not submit Feed story to Network.")) + "<HR><BR>"
|
||||
dat+=span_bold(span_maroon("ERROR: Could not submit Feed story to Network.")) + "<HR><br>"
|
||||
if(admin_holder.admincaster_feed_channel.channel_name=="")
|
||||
dat+=span_maroon("Invalid receiving channel name.") + "<BR>"
|
||||
dat+=span_maroon("Invalid receiving channel name.") + "<br>"
|
||||
if(admin_holder.admincaster_feed_message.body == "" || admin_holder.admincaster_feed_message.body == "\[REDACTED\]" || admin_holder.admincaster_feed_message.title == "")
|
||||
dat+=span_maroon("Invalid message body.") + "<BR>"
|
||||
dat+="<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[3]'>Return</A><BR>"
|
||||
dat+=span_maroon("Invalid message body.") + "<br>"
|
||||
dat+="<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[3]'>Return</a><br>"
|
||||
if(7)
|
||||
dat+=span_bold(span_maroon("ERROR: Could not submit Feed Channel to Network.")) + "<HR><BR>"
|
||||
dat+=span_bold(span_maroon("ERROR: Could not submit Feed Channel to Network.")) + "<HR><br>"
|
||||
if(admin_holder.admincaster_feed_channel.channel_name =="" || admin_holder.admincaster_feed_channel.channel_name == "\[REDACTED\]")
|
||||
dat+=span_maroon("Invalid channel name.") + "<BR>"
|
||||
dat+=span_maroon("Invalid channel name.") + "<br>"
|
||||
var/check = 0
|
||||
for(var/datum/feed_channel/FC in GLOB.news_network.network_channels)
|
||||
if(FC.channel_name == admin_holder.admincaster_feed_channel.channel_name)
|
||||
check = 1
|
||||
break
|
||||
if(check)
|
||||
dat+=span_maroon("Channel name already in use.") + "<BR>"
|
||||
dat+="<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[2]'>Return</A><BR>"
|
||||
dat+=span_maroon("Channel name already in use.") + "<br>"
|
||||
dat+="<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[2]'>Return</a><br>"
|
||||
if(9)
|
||||
dat+=span_bold("[admin_holder.admincaster_feed_channel.channel_name]: ") + span_small("\[created by: [span_maroon("[admin_holder.admincaster_feed_channel.author]")]\]") + "<HR>"
|
||||
if(admin_holder.admincaster_feed_channel.censored)
|
||||
dat+={"
|
||||
"} + span_red(span_bold("ATTENTION: ")) + {"This channel has been deemed as threatening to the welfare of the station, and marked with a [using_map.company_name] D-Notice.<BR>
|
||||
No further feed story additions are allowed while the D-Notice is in effect.<BR><BR>
|
||||
"} + span_red(span_bold("ATTENTION: ")) + {"This channel has been deemed as threatening to the welfare of the station, and marked with a [using_map.company_name] D-Notice.<br>
|
||||
No further feed story additions are allowed while the D-Notice is in effect.<br><br>
|
||||
"}
|
||||
else
|
||||
if( isemptylist(admin_holder.admincaster_feed_channel.messages) )
|
||||
dat+=span_italics("No feed messages found in channel...") + "<BR>"
|
||||
dat+=span_italics("No feed messages found in channel...") + "<br>"
|
||||
else
|
||||
var/i = 0
|
||||
for(var/datum/feed_message/MESSAGE in admin_holder.admincaster_feed_channel.messages)
|
||||
i++
|
||||
//dat+="-[MESSAGE.body] <BR>"
|
||||
//dat+="-[MESSAGE.body] <br>"
|
||||
var/pic_data
|
||||
if(MESSAGE.img)
|
||||
user << browse_rsc(MESSAGE.img, "tmp_photo[i].png")
|
||||
pic_data+="<img src='tmp_photo[i].png' width = '180'><BR>"
|
||||
dat+= get_newspaper_content(MESSAGE.title, MESSAGE.body, MESSAGE.author,"#d4cec1", pic_data)
|
||||
dat+="<BR>"
|
||||
dat+=span_small("\[Story by [span_maroon("[MESSAGE.author] - [MESSAGE.time_stamp]")]\]") + "<BR>"
|
||||
dat+="<br>"
|
||||
dat+=span_small("\[Story by [span_maroon("[MESSAGE.author] - [MESSAGE.time_stamp]")]\]") + "<br>"
|
||||
dat+={"
|
||||
<BR><HR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_refresh=1'>Refresh</A>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[1]'>Back</A>
|
||||
<br><HR><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_refresh=1'>Refresh</a>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[1]'>Back</a>
|
||||
"}
|
||||
if(10)
|
||||
dat+={"
|
||||
"} + span_bold("[using_map.company_name] Feed Censorship Tool") + {"<BR>
|
||||
"} + span_small("NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.<BR>") + {"
|
||||
"} + span_bold("[using_map.company_name] Feed Censorship Tool") + {"<br>
|
||||
"} + span_small("NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.<br>") + {"
|
||||
"} + span_small("Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.") + {"
|
||||
<HR>Select Feed channel to get Stories from:<BR>
|
||||
<HR>Select Feed channel to get Stories from:<br>
|
||||
"}
|
||||
if(isemptylist(GLOB.news_network.network_channels))
|
||||
dat+=span_italics("No feed channels found active...") + "<BR>"
|
||||
dat+=span_italics("No feed channels found active...") + "<br>"
|
||||
else
|
||||
for(var/datum/feed_channel/CHANNEL in GLOB.news_network.network_channels)
|
||||
dat+="<A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_pick_censor_channel=\ref[CHANNEL]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? (span_red("***")) : null]<BR>"
|
||||
dat+="<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[0]'>Cancel</A>"
|
||||
dat+="<a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_pick_censor_channel=[REF(CHANNEL)]'>[CHANNEL.channel_name]</a> [(CHANNEL.censored) ? (span_red("***")) : null]<br>"
|
||||
dat+="<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[0]'>Cancel</a>"
|
||||
if(11)
|
||||
dat+={"
|
||||
"} + span_bold("[using_map.company_name] D-Notice Handler") + {"<HR>
|
||||
@@ -408,44 +408,44 @@ ADMIN_VERB(access_news_network, R_ADMIN|R_EVENT, "Access Newscaster Network", "A
|
||||
"} + span_small("stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.") + {"<HR>
|
||||
"}
|
||||
if(isemptylist(GLOB.news_network.network_channels))
|
||||
dat+=span_italics("No feed channels found active...") + "<BR>"
|
||||
dat+=span_italics("No feed channels found active...") + "<br>"
|
||||
else
|
||||
for(var/datum/feed_channel/CHANNEL in GLOB.news_network.network_channels)
|
||||
dat+="<A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_pick_d_notice=\ref[CHANNEL]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? (span_red("***")) : null]<BR>"
|
||||
dat+="<a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_pick_d_notice=[REF(CHANNEL)]'>[CHANNEL.channel_name]</a> [(CHANNEL.censored) ? (span_red("***")) : null]<br>"
|
||||
|
||||
dat+="<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[0]'>Back</A>"
|
||||
dat+="<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[0]'>Back</a>"
|
||||
if(12)
|
||||
dat+={"
|
||||
"} + span_bold("[admin_holder.admincaster_feed_channel.channel_name]: ") + span_small("\[ created by: [span_maroon("[admin_holder.admincaster_feed_channel.author]")] \]") + {"<BR>
|
||||
"} + span_normal("<A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_censor_channel_author=\ref[admin_holder.admincaster_feed_channel]'>[(admin_holder.admincaster_feed_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]</A>") + {"<HR>
|
||||
"} + span_bold("[admin_holder.admincaster_feed_channel.channel_name]: ") + span_small("\[ created by: [span_maroon("[admin_holder.admincaster_feed_channel.author]")] \]") + {"<br>
|
||||
"} + span_normal("<a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_censor_channel_author=[REF(admin_holder.admincaster_feed_channel)]'>[(admin_holder.admincaster_feed_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]</a>") + {"<HR>
|
||||
"}
|
||||
if( isemptylist(admin_holder.admincaster_feed_channel.messages) )
|
||||
dat+=span_italics("No feed messages found in channel...") + "<BR>"
|
||||
dat+=span_italics("No feed messages found in channel...") + "<br>"
|
||||
else
|
||||
for(var/datum/feed_message/MESSAGE in admin_holder.admincaster_feed_channel.messages)
|
||||
dat+={"
|
||||
-[MESSAGE.body] <BR>"} + span_small("\[Story by [span_maroon("[MESSAGE.author]")]\]") + {"<BR>
|
||||
"} + span_normal("<A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_censor_channel_story_body=\ref[MESSAGE]'>[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")]</A> - <A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_censor_channel_story_author=\ref[MESSAGE]'>[(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]</A>") + {"<BR>
|
||||
-[MESSAGE.body] <br>"} + span_small("\[Story by [span_maroon("[MESSAGE.author]")]\]") + {"<br>
|
||||
"} + span_normal("<a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_censor_channel_story_body=[REF(MESSAGE)]'>[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")]</a> - <a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_censor_channel_story_author=[REF(MESSAGE)]'>[(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]</a>") + {"<br>
|
||||
"}
|
||||
dat+="<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[10]'>Back</A>"
|
||||
dat+="<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[10]'>Back</a>"
|
||||
if(13)
|
||||
dat+={"
|
||||
"} + span_bold("[admin_holder.admincaster_feed_channel.channel_name]: ") + span_small("\[ created by: [span_maroon("[admin_holder.admincaster_feed_channel.author]")] \]") + {"<BR>
|
||||
Channel messages listed below. If you deem them dangerous to the station, you can <A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_toggle_d_notice=\ref[admin_holder.admincaster_feed_channel]'>Bestow a D-Notice upon the channel</A>.<HR>
|
||||
"} + span_bold("[admin_holder.admincaster_feed_channel.channel_name]: ") + span_small("\[ created by: [span_maroon("[admin_holder.admincaster_feed_channel.author]")] \]") + {"<br>
|
||||
Channel messages listed below. If you deem them dangerous to the station, you can <a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_toggle_d_notice=[REF(admin_holder.admincaster_feed_channel)]'>Bestow a D-Notice upon the channel</a>.<HR>
|
||||
"}
|
||||
if(admin_holder.admincaster_feed_channel.censored)
|
||||
dat+={"
|
||||
"} + span_red(span_bold("ATTENTION: ")) + {"This channel has been deemed as threatening to the welfare of the station, and marked with a [using_map.company_name] D-Notice.<BR>
|
||||
No further feed story additions are allowed while the D-Notice is in effect.<BR><BR>
|
||||
"} + span_red(span_bold("ATTENTION: ")) + {"This channel has been deemed as threatening to the welfare of the station, and marked with a [using_map.company_name] D-Notice.<br>
|
||||
No further feed story additions are allowed while the D-Notice is in effect.<br><br>
|
||||
"}
|
||||
else
|
||||
if( isemptylist(admin_holder.admincaster_feed_channel.messages) )
|
||||
dat+=span_italics("No feed messages found in channel...") + "<BR>"
|
||||
dat+=span_italics("No feed messages found in channel...") + "<br>"
|
||||
else
|
||||
for(var/datum/feed_message/MESSAGE in admin_holder.admincaster_feed_channel.messages)
|
||||
dat+="-[MESSAGE.body] <BR>" + span_small("\[Story by [span_maroon("[MESSAGE.author]")]\]") + "<BR>"
|
||||
dat+="-[MESSAGE.body] <br>" + span_small("\[Story by [span_maroon("[MESSAGE.author]")]\]") + "<br>"
|
||||
|
||||
dat+="<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[11]'>Back</A>"
|
||||
dat+="<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[11]'>Back</a>"
|
||||
if(14)
|
||||
dat+=span_bold("Wanted Issue Handler:")
|
||||
var/wanted_already = 0
|
||||
@@ -454,54 +454,54 @@ ADMIN_VERB(access_news_network, R_ADMIN|R_EVENT, "Access Newscaster Network", "A
|
||||
wanted_already = 1
|
||||
end_param = 2
|
||||
if(wanted_already)
|
||||
dat+=span_normal(span_italics("<BR>A wanted issue is already in Feed Circulation. You can edit or cancel it below."))
|
||||
dat+=span_normal(span_italics("<br>A wanted issue is already in Feed Circulation. You can edit or cancel it below."))
|
||||
dat+={"
|
||||
<HR>
|
||||
<A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_set_wanted_name=1'>Criminal Name</A>: [admin_holder.admincaster_feed_message.author] <BR>
|
||||
<A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_set_wanted_desc=1'>Description</A>: [admin_holder.admincaster_feed_message.body] <BR>
|
||||
<a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_set_wanted_name=1'>Criminal Name</a>: [admin_holder.admincaster_feed_message.author] <br>
|
||||
<a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_set_wanted_desc=1'>Description</a>: [admin_holder.admincaster_feed_message.body] <br>
|
||||
"}
|
||||
if(wanted_already)
|
||||
dat+=span_bold("Wanted Issue created by:") + span_green(" [GLOB.news_network.wanted_issue.backup_author]") + "<BR>"
|
||||
dat+=span_bold("Wanted Issue created by:") + span_green(" [GLOB.news_network.wanted_issue.backup_author]") + "<br>"
|
||||
else
|
||||
dat+=span_bold("Wanted Issue will be created under prosecutor:") + span_green(" [admin_holder.admincaster_signature]") + "<BR>"
|
||||
dat+="<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_submit_wanted=[end_param]'>[(wanted_already) ? ("Edit Issue") : ("Submit")]</A>"
|
||||
dat+=span_bold("Wanted Issue will be created under prosecutor:") + span_green(" [admin_holder.admincaster_signature]") + "<br>"
|
||||
dat+="<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_submit_wanted=[end_param]'>[(wanted_already) ? ("Edit Issue") : ("Submit")]</a>"
|
||||
if(wanted_already)
|
||||
dat+="<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_cancel_wanted=1'>Take down Issue</A>"
|
||||
dat+="<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[0]'>Cancel</A>"
|
||||
dat+="<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_cancel_wanted=1'>Take down Issue</a>"
|
||||
dat+="<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[0]'>Cancel</a>"
|
||||
if(15)
|
||||
dat+={"
|
||||
"} + span_green("Wanted issue for [admin_holder.admincaster_feed_message.author] is now in Network Circulation.") + {"<BR><BR>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>
|
||||
"} + span_green("Wanted issue for [admin_holder.admincaster_feed_message.author] is now in Network Circulation.") + {"<br><br>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[0]'>Return</a><br>
|
||||
"}
|
||||
if(16)
|
||||
dat+=span_bold(span_maroon("ERROR: Wanted Issue rejected by Network.")) + "<HR><BR>"
|
||||
dat+=span_bold(span_maroon("ERROR: Wanted Issue rejected by Network.")) + "<HR><br>"
|
||||
if(admin_holder.admincaster_feed_message.author =="" || admin_holder.admincaster_feed_message.author == "\[REDACTED\]")
|
||||
dat+=span_maroon("Invalid name for person wanted.") + "<BR>"
|
||||
dat+=span_maroon("Invalid name for person wanted.") + "<br>"
|
||||
if(admin_holder.admincaster_feed_message.body == "" || admin_holder.admincaster_feed_message.body == "\[REDACTED\]")
|
||||
dat+=span_maroon("Invalid description.") + "<BR>"
|
||||
dat+="<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>"
|
||||
dat+=span_maroon("Invalid description.") + "<br>"
|
||||
dat+="<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[0]'>Return</a><br>"
|
||||
if(17)
|
||||
dat+={"
|
||||
"} + span_bold("Wanted Issue successfully deleted from Circulation") + {"<BR>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>
|
||||
"} + span_bold("Wanted Issue successfully deleted from Circulation") + {"<br>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[0]'>Return</a><br>
|
||||
"}
|
||||
if(18)
|
||||
dat+={"
|
||||
"} + span_bold(span_maroon("-- STATIONWIDE WANTED ISSUE --")) + {"<BR>"} + span_normal("\[Submitted by: [span_green("[GLOB.news_network.wanted_issue.backup_author]")]\]") + {"<HR>
|
||||
"} + span_bold("Criminal") + {": [GLOB.news_network.wanted_issue.author]<BR>
|
||||
"} + span_bold("Description") + {": [GLOB.news_network.wanted_issue.body]<BR>
|
||||
"} + span_bold(span_maroon("-- STATIONWIDE WANTED ISSUE --")) + {"<br>"} + span_normal("\[Submitted by: [span_green("[GLOB.news_network.wanted_issue.backup_author]")]\]") + {"<HR>
|
||||
"} + span_bold("Criminal") + {": [GLOB.news_network.wanted_issue.author]<br>
|
||||
"} + span_bold("Description") + {": [GLOB.news_network.wanted_issue.body]<br>
|
||||
"} + span_bold("Photo:") + {":
|
||||
"}
|
||||
if(GLOB.news_network.wanted_issue.img)
|
||||
user << browse_rsc(GLOB.news_network.wanted_issue.img, "tmp_photow.png")
|
||||
dat+="<BR><img src='tmp_photow.png' width = '180'>"
|
||||
dat+="<br><img src='tmp_photow.png' width = '180'>"
|
||||
else
|
||||
dat+="None"
|
||||
dat+="<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[0]'>Back</A><BR>"
|
||||
dat+="<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[0]'>Back</a><br>"
|
||||
if(19)
|
||||
dat+={"
|
||||
"} + span_green("Wanted issue for [admin_holder.admincaster_feed_message.author] successfully edited.") + {"<BR><BR>
|
||||
<BR><A href='byond://?src=\ref[admin_holder];[HrefToken()];ac_setScreen=[0]'>Return</A><BR>
|
||||
"} + span_green("Wanted issue for [admin_holder.admincaster_feed_message.author] successfully edited.") + {"<br><br>
|
||||
<br><a href='byond://?src=[REF(admin_holder)];[HrefToken()];ac_setScreen=[0]'>Return</a><br>
|
||||
"}
|
||||
else
|
||||
dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com"
|
||||
@@ -523,7 +523,7 @@ ADMIN_VERB(access_news_network, R_ADMIN|R_EVENT, "Access Newscaster Network", "A
|
||||
var/r = t
|
||||
if( findtext(r,"##") )
|
||||
r = copytext( r, 1, findtext(r,"##") )//removes the description
|
||||
dat += text("<tr><td>[t] (<A href='byond://?src=\ref[src];[HrefToken()];removejobban=[r]'>unban</A>)</td></tr>")
|
||||
dat += text("<tr><td>[t] (<a href='byond://?src=[REF(src)];[HrefToken()];removejobban=[r]'>unban</a>)</td></tr>")
|
||||
dat += "</table>"
|
||||
|
||||
var/datum/browser/popup = new(owner, "ban", "Job Bans", 400, 400)
|
||||
@@ -536,20 +536,17 @@ ADMIN_VERB(access_news_network, R_ADMIN|R_EVENT, "Access Newscaster Network", "A
|
||||
|
||||
var/dat = {"
|
||||
<center>"} + span_bold("Game Panel") + {"</center><hr>\n
|
||||
<A href='byond://?src=\ref[src];[HrefToken()];c_mode=1'>Change Game Mode</A><br>
|
||||
<a href='byond://?src=[REF(src)];[HrefToken()];c_mode=1'>Change Game Mode</a><br>
|
||||
"}
|
||||
if(GLOB.master_mode == "secret")
|
||||
dat += "<A href='byond://?src=\ref[src];[HrefToken()];f_secret=1'>(Force Secret Mode)</A><br>"
|
||||
dat += "<a href='byond://?src=[REF(src)];[HrefToken()];f_secret=1'>(Force Secret Mode)</a><br>"
|
||||
|
||||
dat += {"
|
||||
<BR>
|
||||
<A href='byond://?src=\ref[src];[HrefToken()];create_object=1'>Create Object</A><br>
|
||||
<A href='byond://?src=\ref[src];[HrefToken()];quick_create_object=1'>Quick Create Object</A><br>
|
||||
<A href='byond://?src=\ref[src];[HrefToken()];create_turf=1'>Create Turf</A><br>
|
||||
<A href='byond://?src=\ref[src];[HrefToken()];create_mob=1'>Create Mob</A><br>
|
||||
<br><A href='byond://?src=\ref[src];[HrefToken()];vsc=airflow'>Edit Airflow Settings</A><br>
|
||||
<A href='byond://?src=\ref[src];[HrefToken()];vsc=phoron'>Edit Phoron Settings</A><br>
|
||||
<A href='byond://?src=\ref[src];[HrefToken()];vsc=default'>Choose a default ZAS setting</A><br>
|
||||
<br>
|
||||
<a href='byond://?src=[REF(src)];[HrefToken()];spawn_panel=1'>Spawn Panel</a><br>
|
||||
<br><a href='byond://?src=[REF(src)];[HrefToken()];vsc=airflow'>Edit Airflow Settings</a><br>
|
||||
<a href='byond://?src=[REF(src)];[HrefToken()];vsc=phoron'>Edit Phoron Settings</a><br>
|
||||
<a href='byond://?src=[REF(src)];[HrefToken()];vsc=default'>Choose a default ZAS setting</a><br>
|
||||
"}
|
||||
|
||||
var/datum/browser/popup = new(owner, "admin2", "Game Panel", 220, 295)
|
||||
@@ -565,19 +562,19 @@ ADMIN_VERB(access_news_network, R_ADMIN|R_EVENT, "Access Newscaster Network", "A
|
||||
for(var/datum/admin_secret_category/category in admin_secrets.categories)
|
||||
if(!category.can_view(usr))
|
||||
continue
|
||||
dat += "<A href='byond://?src=\ref[src];[HrefToken()];admin_secrets_panel=\ref[category]'>[category.name]</A> "
|
||||
dat += "<a href='byond://?src=[REF(src)];[HrefToken()];admin_secrets_panel=[REF(category)]'>[category.name]</a> "
|
||||
dat += "<HR>"
|
||||
|
||||
// If a category is selected, print its description and then options
|
||||
if(istype(active_category) && active_category.can_view(usr))
|
||||
dat += span_bold("[active_category.name]") + "<BR>"
|
||||
dat += span_bold("[active_category.name]") + "<br>"
|
||||
if(active_category.desc)
|
||||
dat += span_italics("[active_category.desc]") + "<BR>"
|
||||
dat += span_italics("[active_category.desc]") + "<br>"
|
||||
for(var/datum/admin_secret_item/item in active_category.items)
|
||||
if(!item.can_view(usr))
|
||||
continue
|
||||
dat += "<A href='byond://?src=\ref[src];[HrefToken()];admin_secrets=\ref[item]'>[item.name()]</A><BR>"
|
||||
dat += "<BR>"
|
||||
dat += "<a href='byond://?src=[REF(src)];[HrefToken()];admin_secrets=[REF(item)]'>[item.name()]</a><br>"
|
||||
dat += "<br>"
|
||||
|
||||
var/datum/browser/popup = new(usr, "secrets", "Secrets", 500, 500)
|
||||
popup.set_content(dat)
|
||||
@@ -1072,66 +1069,66 @@ ADMIN_VERB(show_game_mode, R_ADMIN|R_EVENT, "Show Game Mode", "Show the current
|
||||
tgui_alert_async(user, "Not before roundstart!", "Alert")
|
||||
return
|
||||
|
||||
var/out = span_large(span_bold("Current mode: [SSticker.mode.name] (<a href='byond://?src=\ref[SSticker.mode];[HrefToken()];debug_antag=self'>[SSticker.mode.config_tag]</a>)")) + "<br/>"
|
||||
var/out = span_large(span_bold("Current mode: [SSticker.mode.name] (<a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];debug_antag=self'>[SSticker.mode.config_tag]</a>)")) + "<br/>"
|
||||
out += "<hr>"
|
||||
|
||||
if(SSticker.mode.ert_disabled)
|
||||
out += span_bold("Emergency Response Teams:") + "<a href='byond://?src=\ref[SSticker.mode];[HrefToken()];toggle=ert'>disabled</a>"
|
||||
out += span_bold("Emergency Response Teams:") + "<a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];toggle=ert'>disabled</a>"
|
||||
else
|
||||
out += span_bold("Emergency Response Teams:") + "<a href='byond://?src=\ref[SSticker.mode];[HrefToken()];toggle=ert'>enabled</a>"
|
||||
out += span_bold("Emergency Response Teams:") + "<a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];toggle=ert'>enabled</a>"
|
||||
out += "<br/>"
|
||||
|
||||
if(SSticker.mode.deny_respawn)
|
||||
out += span_bold("Respawning:") + "<a href='byond://?src=\ref[SSticker.mode];[HrefToken()];toggle=respawn'>disallowed</a>"
|
||||
out += span_bold("Respawning:") + "<a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];toggle=respawn'>disallowed</a>"
|
||||
else
|
||||
out += span_bold("Respawning:") + "<a href='byond://?src=\ref[SSticker.mode];[HrefToken()];toggle=respawn'>allowed</a>"
|
||||
out += span_bold("Respawning:") + "<a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];toggle=respawn'>allowed</a>"
|
||||
out += "<br/>"
|
||||
|
||||
out += span_bold("Shuttle delay multiplier:") + " <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];set=shuttle_delay'>[SSticker.mode.shuttle_delay]</a><br/>"
|
||||
out += span_bold("Shuttle delay multiplier:") + " <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];set=shuttle_delay'>[SSticker.mode.shuttle_delay]</a><br/>"
|
||||
|
||||
if(SSticker.mode.auto_recall_shuttle)
|
||||
out += span_bold("Shuttle auto-recall:") + " <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];toggle=shuttle_recall'>enabled</a>"
|
||||
out += span_bold("Shuttle auto-recall:") + " <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];toggle=shuttle_recall'>enabled</a>"
|
||||
else
|
||||
out += span_bold("Shuttle auto-recall:") + " <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];toggle=shuttle_recall'>disabled</a>"
|
||||
out += span_bold("Shuttle auto-recall:") + " <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];toggle=shuttle_recall'>disabled</a>"
|
||||
out += "<br/><br/>"
|
||||
|
||||
if(SSticker.mode.event_delay_mod_moderate)
|
||||
out += span_bold("Moderate event time modifier:") + " <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];set=event_modifier_moderate'>[SSticker.mode.event_delay_mod_moderate]</a><br/>"
|
||||
out += span_bold("Moderate event time modifier:") + " <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];set=event_modifier_moderate'>[SSticker.mode.event_delay_mod_moderate]</a><br/>"
|
||||
else
|
||||
out += span_bold("Moderate event time modifier:") + " <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];set=event_modifier_moderate'>unset</a><br/>"
|
||||
out += span_bold("Moderate event time modifier:") + " <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];set=event_modifier_moderate'>unset</a><br/>"
|
||||
|
||||
if(SSticker.mode.event_delay_mod_major)
|
||||
out += span_bold("Major event time modifier:") + " <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];set=event_modifier_severe'>[SSticker.mode.event_delay_mod_major]</a><br/>"
|
||||
out += span_bold("Major event time modifier:") + " <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];set=event_modifier_severe'>[SSticker.mode.event_delay_mod_major]</a><br/>"
|
||||
else
|
||||
out += span_bold("Major event time modifier:") + " <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];set=event_modifier_severe'>unset</a><br/>"
|
||||
out += span_bold("Major event time modifier:") + " <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];set=event_modifier_severe'>unset</a><br/>"
|
||||
|
||||
out += "<hr>"
|
||||
|
||||
if(SSticker.mode.antag_tags && SSticker.mode.antag_tags.len)
|
||||
out += span_bold("Core antag templates:") + "</br>"
|
||||
for(var/antag_tag in SSticker.mode.antag_tags)
|
||||
out += "<a href='byond://?src=\ref[SSticker.mode];[HrefToken()];debug_antag=[antag_tag]'>[antag_tag]</a>.</br>"
|
||||
out += "<a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];debug_antag=[antag_tag]'>[antag_tag]</a>.</br>"
|
||||
|
||||
if(SSticker.mode.round_autoantag)
|
||||
out += span_bold("Autotraitor <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];toggle=autotraitor'>enabled</a>.")
|
||||
out += span_bold("Autotraitor <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];toggle=autotraitor'>enabled</a>.")
|
||||
if(SSticker.mode.antag_scaling_coeff > 0)
|
||||
out += " (scaling with <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];set=antag_scaling'>[SSticker.mode.antag_scaling_coeff]</a>)"
|
||||
out += " (scaling with <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];set=antag_scaling'>[SSticker.mode.antag_scaling_coeff]</a>)"
|
||||
else
|
||||
out += " (not currently scaling, <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];set=antag_scaling'>set a coefficient</a>)"
|
||||
out += " (not currently scaling, <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];set=antag_scaling'>set a coefficient</a>)"
|
||||
out += "<br/>"
|
||||
else
|
||||
out += span_bold("Autotraitor <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];toggle=autotraitor'>disabled</a>.") + "<br/>"
|
||||
out += span_bold("Autotraitor <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];toggle=autotraitor'>disabled</a>.") + "<br/>"
|
||||
|
||||
out += span_bold("All antag ids:")
|
||||
if(SSticker.mode.antag_templates && SSticker.mode.antag_templates.len)
|
||||
for(var/datum/antagonist/antag in SSticker.mode.antag_templates)
|
||||
antag.update_current_antag_max()
|
||||
out += " <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];debug_antag=[antag.id]'>[antag.id]</a>"
|
||||
out += " <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];debug_antag=[antag.id]'>[antag.id]</a>"
|
||||
out += " ([antag.get_antag_count()]/[antag.cur_max]) "
|
||||
out += " <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];remove_antag_type=[antag.id]'>\[-\]</a><br/>"
|
||||
out += " <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];remove_antag_type=[antag.id]'>\[-\]</a><br/>"
|
||||
else
|
||||
out += " None."
|
||||
out += " <a href='byond://?src=\ref[SSticker.mode];[HrefToken()];add_antag_type=1'>\[+\]</a><br/>"
|
||||
out += " <a href='byond://?src=[REF(SSticker.mode)];[HrefToken()];add_antag_type=1'>\[+\]</a><br/>"
|
||||
|
||||
var/datum/browser/popup = new(user, "edit_mode[user.holder]", "Edit Game Mode")
|
||||
popup.set_content(out)
|
||||
@@ -1188,19 +1185,19 @@ ADMIN_VERB(toggleguests, R_HOST, "Toggle guests", "Guests can't enter.", ADMIN_C
|
||||
return span_bold("[key_name(C, link, name, highlight_special)]")
|
||||
|
||||
if(1) //Private Messages
|
||||
return span_bold("[key_name(C, link, name, highlight_special)](<A href='byond://?_src_=holder;[HrefToken()];adminmoreinfo=\ref[M]'>?</A>)")
|
||||
return span_bold("[key_name(C, link, name, highlight_special)](<a href='byond://?_src_=holder;[HrefToken()];adminmoreinfo=[REF(M)]'>?</a>)")
|
||||
|
||||
if(2) //Admins
|
||||
var/ref_mob = "\ref[M]"
|
||||
return span_bold("[key_name(C, link, name, highlight_special)](<A href='byond://?_src_=holder;[HrefToken()];adminmoreinfo=[ref_mob]'>?</A>) (<A href='byond://?_src_=holder;[HrefToken()];adminplayeropts=[ref_mob]'>PP</A>) (<A href='byond://?_src_=vars;[HrefToken()];Vars=[ref_mob]'>VV</A>) (<A href='byond://?_src_=holder;[HrefToken()];subtlemessage=[ref_mob]'>SM</A>) ([admin_jump_link(M)]) (<A href='byond://?_src_=holder;[HrefToken()];check_antagonist=1'>CA</A>) (<A href='byond://?_src_=holder;[HrefToken()];take_question=\ref[M]'>TAKE</A>)")
|
||||
var/ref_mob = "[REF(M)]"
|
||||
return span_bold("[key_name(C, link, name, highlight_special)](<a href='byond://?_src_=holder;[HrefToken()];adminmoreinfo=[ref_mob]'>?</a>) (<a href='byond://?_src_=holder;[HrefToken()];adminplayeropts=[ref_mob]'>PP</a>) (<a href='byond://?_src_=vars;[HrefToken()];Vars=[ref_mob]'>VV</a>) (<a href='byond://?_src_=holder;[HrefToken()];subtlemessage=[ref_mob]'>SM</a>) ([admin_jump_link(M)]) (<a href='byond://?_src_=holder;[HrefToken()];check_antagonist=1'>CA</a>) (<a href='byond://?_src_=holder;[HrefToken()];take_question=[REF(M)]'>TAKE</a>)")
|
||||
|
||||
if(3) //Devs
|
||||
var/ref_mob = "\ref[M]"
|
||||
return span_bold("[key_name(C, link, name, highlight_special)](<A href='byond://?_src_=vars;[HrefToken()];Vars=[ref_mob]'>VV</A>)([admin_jump_link(M)]) (<A href='byond://?_src_=holder;[HrefToken()];take_question=\ref[M]'>TAKE</A>)")
|
||||
var/ref_mob = "[REF(M)]"
|
||||
return span_bold("[key_name(C, link, name, highlight_special)](<a href='byond://?_src_=vars;[HrefToken()];Vars=[ref_mob]'>VV</a>)([admin_jump_link(M)]) (<a href='byond://?_src_=holder;[HrefToken()];take_question=[REF(M)]'>TAKE</a>)")
|
||||
|
||||
if(4) //Event Managers
|
||||
var/ref_mob = "\ref[M]"
|
||||
return span_bold("[key_name(C, link, name, highlight_special)] (<A href='byond://?_src_=holder;[HrefToken()];adminmoreinfo=\ref[M]'>?</A>) (<A href='byond://?_src_=holder;[HrefToken()];adminplayeropts=[ref_mob]'>PP</A>) (<A href='byond://?_src_=vars;[HrefToken()];Vars=[ref_mob]'>VV</A>) (<A href='byond://?_src_=holder;[HrefToken()];subtlemessage=[ref_mob]'>SM</A>) ([admin_jump_link(M)]) (<A href='byond://?_src_=holder;[HrefToken()];take_question=\ref[M]'>TAKE</A>)")
|
||||
var/ref_mob = "[REF(M)]"
|
||||
return span_bold("[key_name(C, link, name, highlight_special)] (<a href='byond://?_src_=holder;[HrefToken()];adminmoreinfo=[REF(M)]'>?</a>) (<a href='byond://?_src_=holder;[HrefToken()];adminplayeropts=[ref_mob]'>PP</a>) (<a href='byond://?_src_=vars;[HrefToken()];Vars=[ref_mob]'>VV</a>) (<a href='byond://?_src_=holder;[HrefToken()];subtlemessage=[ref_mob]'>SM</a>) ([admin_jump_link(M)]) (<a href='byond://?_src_=holder;[HrefToken()];take_question=[REF(M)]'>TAKE</a>)")
|
||||
|
||||
|
||||
/proc/ishost(whom)
|
||||
@@ -1369,12 +1366,12 @@ ADMIN_VERB(sendFax, R_ADMIN|R_MOD|R_EVENT, "Send Fax", "Sends a fax to this mach
|
||||
log_admin("[key_name(src.owner)] replied to a fax message from [key_name(P.sender)]")
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(check_rights_for(C, (R_ADMIN | R_MOD | R_EVENT)))
|
||||
to_chat(C, span_log_message("[span_prefix("FAX LOG:")][key_name_admin(src.owner)] replied to a fax message from [key_name_admin(P.sender)] (<a href='byond://?_src_=holder;[HrefToken()];AdminFaxView=\ref[rcvdcopy]'>VIEW</a>)"))
|
||||
to_chat(C, span_log_message("[span_prefix("FAX LOG:")][key_name_admin(src.owner)] replied to a fax message from [key_name_admin(P.sender)] (<a href='byond://?_src_=holder;[HrefToken()];AdminFaxView=[REF(rcvdcopy)]'>VIEW</a>)"))
|
||||
else
|
||||
log_admin("[key_name(src.owner)] has sent a fax message to [destination.department]")
|
||||
for(var/client/C in GLOB.admins)
|
||||
if(check_rights_for(C, (R_ADMIN | R_MOD | R_EVENT)))
|
||||
to_chat(C, span_log_message("[span_prefix("FAX LOG:")][key_name_admin(src.owner)] has sent a fax message to [destination.department] (<a href='byond://?_src_=holder;[HrefToken()];AdminFaxView=\ref[rcvdcopy]'>VIEW</a>)"))
|
||||
to_chat(C, span_log_message("[span_prefix("FAX LOG:")][key_name_admin(src.owner)] has sent a fax message to [destination.department] (<a href='byond://?_src_=holder;[HrefToken()];AdminFaxView=[REF(rcvdcopy)]'>VIEW</a>)"))
|
||||
|
||||
var/plaintext_title = P.sender ? "replied to [key_name(P.sender)]'s fax" : "sent a fax message to [destination.department]"
|
||||
var/fax_text = paper_html_to_plaintext(P.info)
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
/var/create_mob_html = null
|
||||
/datum/admins/proc/create_mob(var/mob/user)
|
||||
if (!create_mob_html)
|
||||
var/mobjs = null
|
||||
mobjs = jointext(typesof(/mob), ";")
|
||||
create_mob_html = file2text('html/create_object.html')
|
||||
create_mob_html = replacetext(create_mob_html, "null /* object types */", "\"[mobjs]\"")
|
||||
|
||||
user << browse(create_panel_helper(create_mob_html), "window=create_mob;size=680x600")
|
||||
@@ -1,47 +0,0 @@
|
||||
/datum/admins/proc/create_panel_helper(template)
|
||||
var/final_html = replacetext(template, "/* ref src */", "\ref[src];[HrefToken()]")
|
||||
final_html = replacetext(final_html,"/* hreftokenfield */","[HrefTokenFormField()]")
|
||||
return final_html
|
||||
|
||||
/datum/admins/proc/create_object(var/mob/user)
|
||||
var/static/create_object_html = null
|
||||
if (!create_object_html)
|
||||
var/objectjs = null
|
||||
objectjs = jointext(typesof(/obj), ";")
|
||||
create_object_html = file2text('html/create_object.html')
|
||||
create_object_html = replacetext(create_object_html, "null /* object types */", "\"[objectjs]\"")
|
||||
|
||||
user << browse(create_panel_helper(create_object_html), "window=create_object;size=680x600")
|
||||
|
||||
|
||||
/datum/admins/proc/quick_create_object(var/mob/user)
|
||||
|
||||
var/quick_create_object_html = null
|
||||
var/pathtext = null
|
||||
var/list/choices = list("/obj",
|
||||
"/obj/structure",
|
||||
"/obj/item",
|
||||
"/obj/item/melee",
|
||||
"/obj/item/gun",
|
||||
"/obj/item/reagent_containers",
|
||||
"/obj/item/reagent_containers/food",
|
||||
"/obj/item/clothing",
|
||||
"/obj/item/storage/box/fluff", //VOREStation Edit,
|
||||
"/obj/machinery",
|
||||
"/obj/mecha",
|
||||
"/obj/item/mecha_parts",
|
||||
"/obj/item/mecha_parts/mecha_equipment")
|
||||
|
||||
pathtext = tgui_input_list(usr, "Select the path of the object you wish to create.", "Path", choices, "/obj")
|
||||
|
||||
if(!pathtext)
|
||||
return
|
||||
var path = text2path(pathtext)
|
||||
|
||||
if (!quick_create_object_html)
|
||||
var/objectjs = null
|
||||
objectjs = jointext(typesof(path), ";")
|
||||
quick_create_object_html = file2text('html/create_object.html')
|
||||
quick_create_object_html = replacetext(quick_create_object_html, "null /* object types */", "\"[objectjs]\"")
|
||||
|
||||
user << browse(create_panel_helper(quick_create_object_html), "window=quick_create_object;size=680x600")
|
||||
@@ -1,9 +0,0 @@
|
||||
/var/create_turf_html = null
|
||||
/datum/admins/proc/create_turf(var/mob/user)
|
||||
if (!create_turf_html)
|
||||
var/turfjs = null
|
||||
turfjs = jointext(typesof(/turf), ";")
|
||||
create_turf_html = file2text('html/create_object.html')
|
||||
create_turf_html = replacetext(create_turf_html, "null /* object types */", "\"[turfjs]\"")
|
||||
|
||||
user << browse(create_panel_helper(create_turf_html), "window=create_turf;size=680x600")
|
||||
@@ -32,6 +32,7 @@ GLOBAL_PROTECT(href_token)
|
||||
var/datum/filter_editor/filteriffic
|
||||
var/datum/particle_editor/particle_test
|
||||
var/datum/whitelist_editor/whitelist_editor
|
||||
var/datum/spawnpanel/spawn_panel
|
||||
|
||||
/// A lazylist of tagged datums, for quick reference with the View Tags verb
|
||||
var/list/tagged_datums
|
||||
|
||||
@@ -219,63 +219,14 @@
|
||||
target.module_reset(FALSE)
|
||||
return TRUE
|
||||
if("add_module")
|
||||
var/obj/item/add_item = locate(params["module"])
|
||||
if(!add_item)
|
||||
var/obj/item/selected_item = locate(params["module"])
|
||||
if(!selected_item)
|
||||
return TRUE
|
||||
if(istype(add_item, /obj/item/card/id))
|
||||
if(istype(selected_item, /obj/item/card/id))
|
||||
source.idcard = null
|
||||
source.module.emag.Remove(add_item)
|
||||
source.module.modules.Remove(add_item)
|
||||
source.module.contents.Remove(add_item)
|
||||
if(istype(add_item, /obj/item/card/id))
|
||||
if(target.idcard)
|
||||
qdel(target.idcard)
|
||||
target.idcard = add_item
|
||||
target.module.modules.Add(add_item)
|
||||
target.module.contents.Add(add_item)
|
||||
spawn(0)
|
||||
SEND_SIGNAL(add_item, COMSIG_MOVABLE_ATTEMPTED_MOVE)
|
||||
target.hud_used?.update_robot_modules_display()
|
||||
if(istype(add_item, /obj/item/stack/))
|
||||
var/obj/item/stack/item_with_synth = add_item
|
||||
for(var/synth in item_with_synth.synths)
|
||||
var/found = target.module.synths.Find(synth)
|
||||
if(!found)
|
||||
source.module.synths.Remove(synth)
|
||||
target.module.synths.Add(synth)
|
||||
else
|
||||
item_with_synth.synths = list(target.module.synths[found])
|
||||
return TRUE
|
||||
if(istype(add_item, /obj/item/matter_decompiler/) || istype(add_item, /obj/item/dogborg/sleeper/compactor/decompiler/))
|
||||
var/obj/item/matter_decompiler/item_with_matter = add_item
|
||||
if(item_with_matter.metal)
|
||||
var/found = target.module.synths.Find(item_with_matter.metal)
|
||||
if(!found)
|
||||
source.module.synths.Remove(item_with_matter.metal)
|
||||
target.module.synths.Add(item_with_matter.metal)
|
||||
else
|
||||
item_with_matter.metal = target.module.synths[found]
|
||||
if(item_with_matter.glass)
|
||||
var/found = target.module.synths.Find(item_with_matter.glass)
|
||||
if(!found)
|
||||
source.module.synths.Remove(item_with_matter.glass)
|
||||
target.module.synths.Add(item_with_matter.glass)
|
||||
else
|
||||
item_with_matter.glass = target.module.synths[found]
|
||||
if(item_with_matter.wood)
|
||||
var/found = target.module.synths.Find(item_with_matter.wood)
|
||||
if(!found)
|
||||
source.module.synths.Remove(item_with_matter.wood)
|
||||
target.module.synths.Add(item_with_matter.wood)
|
||||
else
|
||||
item_with_matter.wood = target.module.synths[found]
|
||||
if(item_with_matter.plastic)
|
||||
var/found = target.module.synths.Find(item_with_matter.plastic)
|
||||
if(!found)
|
||||
source.module.synths.Remove(item_with_matter.plastic)
|
||||
target.module.synths.Add(item_with_matter.plastic)
|
||||
else
|
||||
item_with_matter.plastic = target.module.synths[found]
|
||||
source.module.emag -= selected_item
|
||||
source.module.modules -= selected_item
|
||||
target.module.add_item(selected_item, target)
|
||||
return TRUE
|
||||
if("rem_module")
|
||||
var/obj/item/rem_item = locate(params["module"])
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// Open "View Variables" menu for target
|
||||
/mob/observer/dead/CtrlShiftClickOn(atom/target)
|
||||
if(check_rights(R_DEBUG))
|
||||
SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/debug_variables, target)
|
||||
|
||||
// Open "Show Player Panel" menu for target mob
|
||||
/mob/observer/dead/CtrlClickOn(atom/target)
|
||||
if(check_rights(R_ADMIN) && ismob(target))
|
||||
SSadmin_verbs.dynamic_invoke_verb(client, /datum/admin_verb/show_player_panel, target)
|
||||
@@ -0,0 +1,51 @@
|
||||
/datum/asset/json/spawnpanel
|
||||
name = "spawnpanel_atom_data"
|
||||
|
||||
/datum/asset/json/spawnpanel/generate()
|
||||
var/list/data = list()
|
||||
|
||||
var/static/list/mapping_objects = typecacheof(list(
|
||||
/obj/effect/landmark,
|
||||
/obj/effect/spawner,
|
||||
/obj/effect/shuttle_landmark,
|
||||
/obj/effect/floor_decal,
|
||||
/obj/effect/decal,
|
||||
/obj/effect/overlay,
|
||||
/obj/effect/step_trigger,
|
||||
/obj/effect/overmap,
|
||||
/obj/effect/zone_divider,
|
||||
))
|
||||
|
||||
data["atoms"] = list()
|
||||
|
||||
for(var/obj/each_object as anything in typesof(/obj))
|
||||
data["atoms"][each_object] = list(
|
||||
"icon" = /* each_object?.icon_preview ||*/ each_object?.icon || "none",
|
||||
"icon_state" = /* each_object?.icon_state_preview ||*/ each_object?.icon_state || "none",
|
||||
"name" = each_object.name,
|
||||
"description" = each_object.desc,
|
||||
"mapping" = is_type_in_typecache(each_object, mapping_objects),
|
||||
"type" = "Objects"
|
||||
)
|
||||
|
||||
for(var/turf/each_turf as anything in typesof(/turf))
|
||||
data["atoms"][each_turf] = list(
|
||||
"icon" = each_turf?.icon || "noneturf",
|
||||
"icon_state" = each_turf?.icon_state || "noneturf",
|
||||
"name" = each_turf.name,
|
||||
"description" = each_turf.desc,
|
||||
"mapping" = is_type_in_typecache(each_turf, mapping_objects),
|
||||
"type" = "Turfs"
|
||||
)
|
||||
|
||||
for(var/mob/each_mob as anything in typesof(/mob))
|
||||
data["atoms"][each_mob] = list(
|
||||
"icon" = each_mob?.icon || "nonemob",
|
||||
"icon_state" = each_mob?.icon_state || "nonemob",
|
||||
"name" = each_mob.name,
|
||||
"description" = each_mob.desc,
|
||||
"mapping" = is_type_in_typecache(each_mob, mapping_objects),
|
||||
"type" = "Mobs"
|
||||
)
|
||||
|
||||
return data
|
||||
@@ -0,0 +1,161 @@
|
||||
#define WHERE_FLOOR_BELOW_MOB "Current location"
|
||||
#define WHERE_SUPPLY_BELOW_MOB "Current location (droppod)"
|
||||
#define WHERE_MOB_HAND "In own mob's hand"
|
||||
#define WHERE_MARKED_OBJECT "At a marked object"
|
||||
#define WHERE_IN_MARKED_OBJECT "In the marked object"
|
||||
#define WHERE_TARGETED_LOCATION "Targeted location"
|
||||
#define WHERE_TARGETED_LOCATION_POD "Targeted location (droppod)"
|
||||
#define WHERE_TARGETED_MOB_HAND "In targeted mob's hand"
|
||||
|
||||
#define OFFSET_ABSOLUTE "Absolute offset"
|
||||
#define OFFSET_RELATIVE "Relative offset"
|
||||
|
||||
/*
|
||||
Handles spawning an atom. See the call examples for the proper spawn parameters fetching.
|
||||
*/
|
||||
/datum/spawnpanel/proc/spawn_atom(list/spawn_params, mob/user)
|
||||
if(!check_rights_for(user.client, R_SPAWN) || !spawn_params)
|
||||
return
|
||||
|
||||
var/atom/atom_to_spawn = spawn_params["selected_atom"]
|
||||
|
||||
if(!atom_to_spawn || (!ispath(atom_to_spawn, /obj) && !ispath(atom_to_spawn, /turf) && !ispath(atom_to_spawn, /mob)))
|
||||
return
|
||||
|
||||
var/amount = clamp(text2num(spawn_params["atom_amount"]), 1, ADMIN_SPAWN_CAP)
|
||||
|
||||
var/X = offset["X"] || 0
|
||||
var/Y = offset["Y"] || 0
|
||||
var/Z = offset["Z"] || 0
|
||||
|
||||
var/atom_dir = text2num(spawn_params["atom_dir"]) || 1
|
||||
var/atom_name = sanitize(spawn_params["atom_name"])
|
||||
|
||||
var/where_target_type = spawn_params["where_target_type"]
|
||||
var/atom/target = null
|
||||
|
||||
if(where_target_type == WHERE_MOB_HAND || where_target_type == WHERE_TARGETED_MOB_HAND)
|
||||
target = (where_target_type == WHERE_TARGETED_MOB_HAND ? spawn_params["target"] : user)
|
||||
|
||||
if(!target)
|
||||
to_chat(user, span_warning("No target specified."))
|
||||
return
|
||||
|
||||
if(!ismob(target))
|
||||
to_chat(user, span_warning("The targeted atom is not a mob."))
|
||||
return
|
||||
|
||||
if(!iscarbon(target) && !isrobot(target))
|
||||
to_chat(user, span_warning("Can only spawn in hand when the target is a carbon mob or a cyborg."))
|
||||
where_target_type = WHERE_FLOOR_BELOW_MOB
|
||||
|
||||
else if(where_target_type == WHERE_MARKED_OBJECT || where_target_type == WHERE_IN_MARKED_OBJECT)
|
||||
if(!user.client.holder.marked_datum)
|
||||
to_chat(user, span_warning("You don't have any object marked."))
|
||||
return
|
||||
else if(!istype(user.client.holder.marked_datum, /atom))
|
||||
to_chat(user, span_warning("The object you have marked cannot be used as a target. Target must be of type /atom."))
|
||||
return
|
||||
else
|
||||
target = (where_target_type == WHERE_MARKED_OBJECT ? get_turf(user.client.holder.marked_datum) : user.client.holder.marked_datum)
|
||||
|
||||
else if(where_target_type == WHERE_TARGETED_LOCATION || where_target_type == WHERE_TARGETED_LOCATION_POD)
|
||||
target = spawn_params["target"]
|
||||
else
|
||||
switch(spawn_params["offset_type"])
|
||||
if(OFFSET_ABSOLUTE)
|
||||
target = locate(X, Y, Z)
|
||||
|
||||
if(OFFSET_RELATIVE)
|
||||
var/turf/relative_turf
|
||||
var/atom/user_loc = user.loc
|
||||
|
||||
if (user_loc)
|
||||
relative_turf = get_turf(user_loc)
|
||||
|
||||
if (!relative_turf)
|
||||
if(isobserver(user))
|
||||
var/mob/observer/dead/user_observer = user
|
||||
relative_turf = get_turf(user_observer.client?.eye) || get_turf(user_observer)
|
||||
if (!relative_turf)
|
||||
relative_turf = locate(1, 1, 1)
|
||||
|
||||
if (!relative_turf)
|
||||
to_chat(user, span_warning("Could not determine a valid relative location."))
|
||||
return
|
||||
|
||||
target = locate(relative_turf.x + X, relative_turf.y + Y, relative_turf.z + Z)
|
||||
|
||||
if(!target)
|
||||
return
|
||||
|
||||
var/use_droppod = where_target_type == WHERE_SUPPLY_BELOW_MOB || where_target_type == WHERE_TARGETED_LOCATION_POD
|
||||
|
||||
var/obj/structure/drop_pod/polite/pod
|
||||
if(use_droppod)
|
||||
pod = new(target)
|
||||
|
||||
for(var/i in 1 to amount)
|
||||
if(istype(atom_to_spawn, /turf))
|
||||
var/turf/original_turf = target
|
||||
var/turf/created_turf = original_turf.ChangeTurf(atom_to_spawn.type)
|
||||
if(created_turf && atom_name)
|
||||
created_turf.name = atom_name
|
||||
continue
|
||||
|
||||
var/atom/created_atom = new atom_to_spawn(use_droppod ? pod : target)
|
||||
|
||||
if(QDELETED(created_atom))
|
||||
return
|
||||
|
||||
created_atom.flags |= ADMIN_SPAWNED
|
||||
|
||||
if(spawn_params["apply_icon_override"])
|
||||
if(spawn_params["selected_atom_icon"])
|
||||
created_atom.icon = file(spawn_params["selected_atom_icon"])
|
||||
|
||||
if(spawn_params["selected_atom_icon_state"])
|
||||
created_atom.icon_state = spawn_params["selected_atom_icon_state"]
|
||||
|
||||
if(spawn_params["atom_icon_size"])
|
||||
if(ismob(created_atom))
|
||||
var/mob/living/created_mob = created_atom
|
||||
created_mob.size_multiplier = spawn_params["atom_icon_size"] / 100
|
||||
|
||||
if(atom_dir)
|
||||
created_atom.set_dir(atom_dir)
|
||||
|
||||
if(atom_name)
|
||||
created_atom.name = atom_name
|
||||
if(ismob(created_atom))
|
||||
var/mob/created_mob = created_atom
|
||||
created_mob.real_name = atom_name
|
||||
|
||||
if((where_target_type == WHERE_MOB_HAND || where_target_type == WHERE_TARGETED_MOB_HAND) && isliving(target) && isitem(created_atom))
|
||||
var/mob/living/living_target = target
|
||||
var/obj/item/created_item = created_atom
|
||||
living_target.put_in_hands(created_item)
|
||||
|
||||
if(isrobot(living_target))
|
||||
var/mob/living/silicon/robot/target_robot = living_target
|
||||
if(target_robot.module)
|
||||
target_robot.module.add_item(created_item, target_robot)
|
||||
target_robot.activate_module(created_item)
|
||||
|
||||
if(pod)
|
||||
pod.podfall()
|
||||
|
||||
log_admin("[key_name(user)] created [amount == 1 ? "an instance" : "[amount] instances"] of [atom_to_spawn.type]")
|
||||
if(istype(atom_to_spawn, /mob))
|
||||
message_admins("[key_name_admin(user)] created [amount == 1 ? "an instance" : "[amount] instances"] of [atom_to_spawn.type]")
|
||||
|
||||
#undef WHERE_FLOOR_BELOW_MOB
|
||||
#undef WHERE_SUPPLY_BELOW_MOB
|
||||
#undef WHERE_MOB_HAND
|
||||
#undef WHERE_MARKED_OBJECT
|
||||
#undef WHERE_IN_MARKED_OBJECT
|
||||
#undef WHERE_TARGETED_LOCATION
|
||||
#undef WHERE_TARGETED_LOCATION_POD
|
||||
#undef WHERE_TARGETED_MOB_HAND
|
||||
#undef OFFSET_ABSOLUTE
|
||||
#undef OFFSET_RELATIVE
|
||||
@@ -0,0 +1,304 @@
|
||||
#define WHERE_FLOOR_BELOW_MOB "Current location"
|
||||
#define WHERE_SUPPLY_BELOW_MOB "Current location (droppod)"
|
||||
#define WHERE_MOB_HAND "In own mob's hand"
|
||||
#define WHERE_MARKED_OBJECT "At a marked object"
|
||||
#define WHERE_IN_MARKED_OBJECT "In the marked object"
|
||||
#define WHERE_TARGETED_LOCATION "Targeted location"
|
||||
#define WHERE_TARGETED_LOCATION_POD "Targeted location (droppod)"
|
||||
#define WHERE_TARGETED_MOB_HAND "In targeted mob's hand"
|
||||
|
||||
#define PRECISE_MODE_OFF "Off"
|
||||
#define PRECISE_MODE_TARGET "Target"
|
||||
#define PRECISE_MODE_MARK "Mark"
|
||||
#define PRECISE_MODE_COPY "Copy"
|
||||
|
||||
#define OFFSET_ABSOLUTE "Absolute offset"
|
||||
#define OFFSET_RELATIVE "Relative offset"
|
||||
|
||||
/*
|
||||
An instance of a /tg/UI™ Spawn Panel. Stores preferences, spawns things, controls the UI. Unique for each user (their ckey).
|
||||
*/
|
||||
/datum/spawnpanel
|
||||
/// Where and how the atom should be spawned.
|
||||
var/where_target_type = WHERE_FLOOR_BELOW_MOB
|
||||
/// The atom selected from the panel.
|
||||
var/atom/selected_atom = null
|
||||
/// The icon selected for the atom from the panel.
|
||||
var/selected_atom_icon = null
|
||||
/// The icon state selected for the atom from the panel.
|
||||
var/selected_atom_icon_state = null
|
||||
/// Should selected icon/icon state override the initial ones? Added as an edge case to not replace animated GAGS icons.
|
||||
var/apply_icon_override = FALSE
|
||||
/// A list of icon states to display in preview panels.
|
||||
var/list/available_icon_states = null
|
||||
/// Override for the icon size of the spawned mob.
|
||||
var/atom_icon_size = 100
|
||||
/// How many atoms will be spawned at once.
|
||||
var/atom_amount = 1
|
||||
/// Custom atom name (leave `null` for initial).
|
||||
var/atom_name = null
|
||||
/// Custom atom description (leave `null` for initial).
|
||||
var/atom_desc = null
|
||||
/// Custom atom dir (leave `null` for `2`).
|
||||
var/atom_dir = 1
|
||||
/// An associative list of x-y-z offsets.
|
||||
var/offset = list()
|
||||
/// The pivot point for offsetting — relative or absolute.
|
||||
var/offset_type = OFFSET_RELATIVE
|
||||
/// Precise mode toggle. Used for build-mode-like spawning experience and targeting datums.
|
||||
var/precise_mode = PRECISE_MODE_OFF
|
||||
|
||||
/datum/spawnpanel/New()
|
||||
. = ..()
|
||||
offset = list("X" = 0, "Y" = 0, "Z" = 0)
|
||||
|
||||
/datum/spawnpanel/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "SpawnPanel")
|
||||
ui.open()
|
||||
|
||||
/datum/spawnpanel/tgui_close(mob/user)
|
||||
. = ..()
|
||||
if (precise_mode && precise_mode != PRECISE_MODE_OFF)
|
||||
toggle_precise_mode(PRECISE_MODE_OFF, user)
|
||||
|
||||
/datum/spawnpanel/tgui_state(mob/user)
|
||||
return ADMIN_STATE(R_SPAWN)
|
||||
|
||||
/datum/spawnpanel/tgui_act(action, params, datum/tgui/ui)
|
||||
if(..() || !check_rights_for(ui.user.client, R_SPAWN))
|
||||
return FALSE
|
||||
|
||||
switch(action)
|
||||
if("select-new-DMI")
|
||||
var/icon/new_icon = input("Select a new icon file:", "Icon") as null|icon
|
||||
if(new_icon)
|
||||
selected_atom_icon = new_icon
|
||||
available_icon_states = icon_states(selected_atom_icon)
|
||||
if(!(selected_atom_icon_state in available_icon_states))
|
||||
selected_atom_icon_state = available_icon_states[1]
|
||||
return TRUE
|
||||
|
||||
if("set-apply-icon-override")
|
||||
apply_icon_override = !!params["value"]
|
||||
return TRUE
|
||||
|
||||
if("reset-DMI-icon")
|
||||
selected_atom_icon = null
|
||||
selected_atom_icon_state = null
|
||||
if(selected_atom)
|
||||
selected_atom_icon = initial(selected_atom.icon)
|
||||
selected_atom_icon_state = initial(selected_atom.icon_state)
|
||||
available_icon_states = icon_states(selected_atom_icon)
|
||||
else
|
||||
available_icon_states = list()
|
||||
return TRUE
|
||||
|
||||
if("select-new-icon-state")
|
||||
selected_atom_icon_state = params["new_state"]
|
||||
return TRUE
|
||||
|
||||
if("reset-icon-state")
|
||||
selected_atom_icon_state = null
|
||||
if(selected_atom)
|
||||
selected_atom_icon_state = initial(selected_atom.icon_state)
|
||||
return TRUE
|
||||
|
||||
if("set-icon-size")
|
||||
atom_icon_size = params["size"]
|
||||
return TRUE
|
||||
|
||||
if("reset-icon-size")
|
||||
atom_icon_size = 100
|
||||
return TRUE
|
||||
|
||||
if("get-icon-states")
|
||||
available_icon_states = icon_states(selected_atom_icon)
|
||||
return TRUE
|
||||
|
||||
if("selected-atom-changed")
|
||||
var/path = text2path(params["newObj"])
|
||||
if(path)
|
||||
var/atom/temp_atom = path
|
||||
selected_atom_icon = initial(temp_atom.icon)
|
||||
selected_atom_icon_state = initial(temp_atom.icon_state)
|
||||
available_icon_states = icon_states(selected_atom_icon)
|
||||
selected_atom = temp_atom
|
||||
return TRUE
|
||||
|
||||
if("create-atom-action")
|
||||
var/list/spawn_params = list(
|
||||
"selected_atom" = selected_atom,
|
||||
"offset" = params["offset"],
|
||||
"atom_dir" = text2num(params["dir"]) || 1,
|
||||
"atom_amount" = text2num(params["atom_amount"]) || 1,
|
||||
"atom_name" = params["atom_name"],
|
||||
"where_target_type" = params["where_target_type"] || WHERE_FLOOR_BELOW_MOB,
|
||||
"atom_icon_size" = params["atom_icon_size"],
|
||||
"offset_type" = params["offset_type"] || OFFSET_RELATIVE,
|
||||
"apply_icon_override" = apply_icon_override,
|
||||
)
|
||||
|
||||
if(apply_icon_override)
|
||||
spawn_params["selected_atom_icon"] = selected_atom_icon
|
||||
spawn_params["selected_atom_icon_state"] = selected_atom_icon_state
|
||||
|
||||
spawn_atom(spawn_params, ui.user)
|
||||
return TRUE
|
||||
|
||||
if("toggle-precise-mode")
|
||||
var/precise_type = params["newPreciseType"]
|
||||
if(precise_type == PRECISE_MODE_TARGET && params["where_target_type"])
|
||||
where_target_type = params["where_target_type"]
|
||||
toggle_precise_mode(precise_type, ui.user)
|
||||
return TRUE
|
||||
|
||||
if("update-settings")
|
||||
if(params["atom_amount"])
|
||||
atom_amount = text2num(params["atom_amount"])
|
||||
if(params["atom_dir"])
|
||||
atom_dir = text2num(params["atom_dir"])
|
||||
if(params["offset"])
|
||||
var/list/temp_offset = params["offset"]
|
||||
offset["X"] = temp_offset[1]
|
||||
offset["Y"] = temp_offset[2]
|
||||
offset["Z"] = temp_offset[3]
|
||||
if(params["atom_name"])
|
||||
atom_name = params["atom_name"]
|
||||
if(params["where_target_type"])
|
||||
where_target_type = params["where_target_type"]
|
||||
if(params["offset_type"])
|
||||
offset_type = params["offset_type"]
|
||||
if(params["atom_icon_size"])
|
||||
atom_icon_size = text2num(params["atom_icon_size"])
|
||||
if(params["selected_atom_icon"])
|
||||
selected_atom_icon = params["selected_atom_icon"]
|
||||
if(params["selected_atom_icon_state"])
|
||||
selected_atom_icon_state = params["selected_atom_icon_state"]
|
||||
return TRUE
|
||||
|
||||
/datum/spawnpanel/proc/toggle_precise_mode(precise_type, mob/user)
|
||||
precise_mode = precise_type
|
||||
var/client/admin_client = user.client
|
||||
if (!admin_client)
|
||||
return
|
||||
|
||||
/* Unimplemented
|
||||
admin_client.mouse_up_icon = null
|
||||
admin_client.mouse_down_icon = null
|
||||
admin_client.mouse_override_icon = null
|
||||
*/
|
||||
admin_client.click_intercept = null
|
||||
|
||||
if (precise_mode != PRECISE_MODE_OFF)
|
||||
/* Unimplemented
|
||||
admin_client.mouse_up_icon = 'icons/effects/mouse_pointers/supplypod_pickturf.dmi'
|
||||
admin_client.mouse_down_icon = 'icons/effects/mouse_pointers/supplypod_pickturf_down.dmi'
|
||||
admin_client.mouse_override_icon = admin_client.mouse_up_icon
|
||||
admin_client.mouse_pointer_icon = admin_client.mouse_override_icon
|
||||
*/
|
||||
admin_client.click_intercept = src
|
||||
winset(admin_client, "mapwindow.map", "right-click=true")
|
||||
else
|
||||
winset(admin_client, "mapwindow.map", "right-click=false")
|
||||
|
||||
/* Unimplemented
|
||||
var/mob/holder_mob = admin_client.mob
|
||||
holder_mob?.update_mouse_pointer()
|
||||
*/
|
||||
|
||||
/datum/spawnpanel/proc/InterceptClickOn(mob/user, params, atom/target)
|
||||
var/list/modifiers = params2list(params)
|
||||
var/left_click = LAZYACCESS(modifiers, LEFT_CLICK)
|
||||
var/right_click = LAZYACCESS(modifiers, RIGHT_CLICK)
|
||||
|
||||
if(right_click)
|
||||
toggle_precise_mode(PRECISE_MODE_OFF, user)
|
||||
SStgui.update_uis(src)
|
||||
return TRUE
|
||||
|
||||
if(left_click)
|
||||
if(istype(target,/atom/movable/screen))
|
||||
return FALSE
|
||||
|
||||
var/turf/clicked_turf = get_turf(target)
|
||||
if(!clicked_turf)
|
||||
return FALSE
|
||||
|
||||
switch(precise_mode)
|
||||
if(PRECISE_MODE_TARGET)
|
||||
var/list/spawn_params = list(
|
||||
"selected_atom" = selected_atom,
|
||||
"atom_amount" = atom_amount,
|
||||
"offset" = "0,0,0",
|
||||
"atom_dir" = atom_dir,
|
||||
"atom_name" = atom_name,
|
||||
"atom_desc" = atom_desc,
|
||||
"offset_type" = OFFSET_ABSOLUTE,
|
||||
"where_target_type" = where_target_type,
|
||||
"target" = target,
|
||||
"atom_icon_size" = atom_icon_size,
|
||||
"apply_icon_override" = apply_icon_override,
|
||||
)
|
||||
|
||||
if(apply_icon_override)
|
||||
spawn_params["selected_atom_icon"] = selected_atom_icon
|
||||
spawn_params["selected_atom_icon_state"] = selected_atom_icon_state
|
||||
|
||||
if(where_target_type == WHERE_TARGETED_LOCATION || where_target_type == WHERE_TARGETED_LOCATION_POD)
|
||||
spawn_params["X"] = clicked_turf.x
|
||||
spawn_params["Y"] = clicked_turf.y
|
||||
spawn_params["Z"] = clicked_turf.z
|
||||
|
||||
spawn_atom(spawn_params, user)
|
||||
|
||||
if(PRECISE_MODE_MARK)
|
||||
var/client/admin_client = user.client
|
||||
admin_client.mark_datum(target)
|
||||
to_chat(user, span_notice("Marked object: [icon2html(target, user)] [span_bold("[target]")]"))
|
||||
toggle_precise_mode(PRECISE_MODE_OFF, user)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
if(PRECISE_MODE_COPY)
|
||||
to_chat(user, span_notice("Picked object: [icon2html(target, user)] [span_bold("[target]")]"))
|
||||
selected_atom = target
|
||||
toggle_precise_mode(PRECISE_MODE_OFF, user)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/spawnpanel/tgui_data(mob/user)
|
||||
var/data = list()
|
||||
data["icon"] = selected_atom_icon
|
||||
data["iconState"] = selected_atom_icon_state
|
||||
data["iconSize"] = atom_icon_size
|
||||
data["apply_icon_override"] = apply_icon_override
|
||||
var/list/states = list()
|
||||
if(available_icon_states)
|
||||
for(var/state in available_icon_states)
|
||||
states += state
|
||||
data["iconStates"] = states
|
||||
data["precise_mode"] = precise_mode
|
||||
data["selected_object"] = selected_atom ? "[selected_atom.type]" : ""
|
||||
return data
|
||||
|
||||
/datum/spawnpanel/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/json/spawnpanel),
|
||||
)
|
||||
|
||||
#undef WHERE_FLOOR_BELOW_MOB
|
||||
#undef WHERE_SUPPLY_BELOW_MOB
|
||||
#undef WHERE_MOB_HAND
|
||||
#undef WHERE_MARKED_OBJECT
|
||||
#undef WHERE_IN_MARKED_OBJECT
|
||||
#undef WHERE_TARGETED_LOCATION
|
||||
#undef WHERE_TARGETED_LOCATION_POD
|
||||
#undef WHERE_TARGETED_MOB_HAND
|
||||
#undef PRECISE_MODE_OFF
|
||||
#undef PRECISE_MODE_TARGET
|
||||
#undef PRECISE_MODE_MARK
|
||||
#undef PRECISE_MODE_COPY
|
||||
#undef OFFSET_ABSOLUTE
|
||||
#undef OFFSET_RELATIVE
|
||||
+2
-132
@@ -1534,138 +1534,8 @@
|
||||
return
|
||||
SSadmin_verbs.dynamic_invoke_verb(usr.client, /datum/admin_verb/show_traitor_panel, M)
|
||||
|
||||
else if(href_list["create_object"])
|
||||
if(!check_rights(R_SPAWN)) return
|
||||
return create_object(usr)
|
||||
|
||||
else if(href_list["quick_create_object"])
|
||||
if(!check_rights(R_SPAWN)) return
|
||||
return quick_create_object(usr)
|
||||
|
||||
else if(href_list["create_turf"])
|
||||
if(!check_rights(R_SPAWN)) return
|
||||
return create_turf(usr)
|
||||
|
||||
else if(href_list["create_mob"])
|
||||
if(!check_rights(R_SPAWN)) return
|
||||
return create_mob(usr)
|
||||
|
||||
else if(href_list["object_list"]) //this is the laggiest thing ever
|
||||
if(!check_rights(R_SPAWN)) return
|
||||
|
||||
if(!CONFIG_GET(flag/allow_admin_spawning))
|
||||
to_chat(usr, span_filter_adminlog("Spawning of items is not allowed."))
|
||||
return
|
||||
|
||||
var/atom/loc = usr.loc
|
||||
|
||||
var/dirty_paths
|
||||
if (istext(href_list["object_list"]))
|
||||
dirty_paths = list(href_list["object_list"])
|
||||
else if (istype(href_list["object_list"], /list))
|
||||
dirty_paths = href_list["object_list"]
|
||||
|
||||
var/paths = list()
|
||||
var/removed_paths = list()
|
||||
|
||||
for(var/dirty_path in dirty_paths)
|
||||
var/path = text2path(dirty_path)
|
||||
if(!path)
|
||||
removed_paths += dirty_path
|
||||
continue
|
||||
else if(!ispath(path, /obj) && !ispath(path, /turf) && !ispath(path, /mob))
|
||||
removed_paths += dirty_path
|
||||
continue
|
||||
else if(ispath(path, /obj/item/gun/energy/pulse_rifle))
|
||||
if(!check_rights(R_FUN,0))
|
||||
removed_paths += dirty_path
|
||||
continue
|
||||
else if(ispath(path, /obj/item/melee/energy/blade))//Not an item one should be able to spawn./N
|
||||
if(!check_rights(R_FUN,0))
|
||||
removed_paths += dirty_path
|
||||
continue
|
||||
else if(ispath(path, /obj/effect/bhole))
|
||||
if(!check_rights(R_FUN,0))
|
||||
removed_paths += dirty_path
|
||||
continue
|
||||
paths += path
|
||||
|
||||
if(!paths)
|
||||
tgui_alert(usr, "The path list you sent is empty")
|
||||
return
|
||||
if(length(paths) > 5)
|
||||
tgui_alert_async(usr, "Select fewer object types, (max 5)")
|
||||
return
|
||||
else if(length(removed_paths))
|
||||
tgui_alert_async(usr, "Removed:\n" + jointext(removed_paths, "\n"))
|
||||
|
||||
var/list/offset = splittext(href_list["offset"],",")
|
||||
var/number = dd_range(1, 100, text2num(href_list["object_count"]))
|
||||
var/X = offset.len > 0 ? text2num(offset[1]) : 0
|
||||
var/Y = offset.len > 1 ? text2num(offset[2]) : 0
|
||||
var/Z = offset.len > 2 ? text2num(offset[3]) : 0
|
||||
var/tmp_dir = href_list["object_dir"]
|
||||
var/obj_dir = tmp_dir ? text2num(tmp_dir) : 2
|
||||
if(!obj_dir || !(obj_dir in list(1,2,4,8,5,6,9,10)))
|
||||
obj_dir = 2
|
||||
var/obj_name = sanitize(href_list["object_name"])
|
||||
var/where = href_list["object_where"]
|
||||
if (!( where in list("onfloor","inhand","inmarked") ))
|
||||
where = "onfloor"
|
||||
|
||||
if( where == "inhand" )
|
||||
to_chat(usr, span_filter_adminlog("Support for inhand not available yet. Will spawn on floor."))
|
||||
where = "onfloor"
|
||||
|
||||
if ( where == "inhand" ) //Can only give when human or monkey
|
||||
if ( !( ishuman(usr) || issmall(usr) ) )
|
||||
to_chat(usr, span_filter_adminlog("Can only spawn in hand when you're a human or a monkey."))
|
||||
where = "onfloor"
|
||||
else if ( usr.get_active_hand() )
|
||||
to_chat(usr, span_filter_adminlog("Your active hand is full. Spawning on floor."))
|
||||
where = "onfloor"
|
||||
|
||||
if ( where == "inmarked" )
|
||||
if ( !marked_datum )
|
||||
to_chat(usr, span_filter_adminlog("You don't have any object marked. Abandoning spawn."))
|
||||
return
|
||||
else
|
||||
if ( !istype(marked_datum,/atom) )
|
||||
to_chat(usr, span_filter_adminlog("The object you have marked cannot be used as a target. Target must be of type /atom. Abandoning spawn."))
|
||||
return
|
||||
|
||||
var/atom/target //Where the object will be spawned
|
||||
switch ( where )
|
||||
if ( "onfloor" )
|
||||
switch (href_list["offset_type"])
|
||||
if ("absolute")
|
||||
target = locate(0 + X,0 + Y,0 + Z)
|
||||
if ("relative")
|
||||
target = locate(loc.x + X,loc.y + Y,loc.z + Z)
|
||||
if ( "inmarked" )
|
||||
target = marked_datum
|
||||
|
||||
if(target)
|
||||
for (var/path in paths)
|
||||
for (var/i = 0; i < number; i++)
|
||||
if(path in typesof(/turf))
|
||||
var/turf/O = target
|
||||
var/turf/N = O.ChangeTurf(path)
|
||||
if(N)
|
||||
if(obj_name)
|
||||
N.name = obj_name
|
||||
else
|
||||
var/atom/O = new path(target)
|
||||
if(O)
|
||||
O.set_dir(obj_dir)
|
||||
if(obj_name)
|
||||
O.name = obj_name
|
||||
if(istype(O,/mob))
|
||||
var/mob/M = O
|
||||
M.real_name = obj_name
|
||||
|
||||
log_and_message_admins("created [number] [english_list(paths)]")
|
||||
return
|
||||
else if(href_list["spawn_panel"])
|
||||
SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/spawn_panel)
|
||||
|
||||
//else if(href_list["admin_secrets_panel"])
|
||||
//var/datum/admin_secret_category/AC = locate(href_list["admin_secrets_panel"]) in admin_secrets.categories
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
ADMIN_VERB(spawn_panel, R_SPAWN, "Spawn Panel", "Spawn Panel (TGUI).", ADMIN_CATEGORY_GAME)
|
||||
var/datum/spawnpanel/panel = user.holder.spawn_panel
|
||||
if(!panel)
|
||||
panel = new()
|
||||
user.holder.spawn_panel = panel
|
||||
panel.tgui_interact(user.mob)
|
||||
feedback_add_details("admin_verb","SP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
@@ -40,6 +40,8 @@
|
||||
show_verb_panel = FALSE
|
||||
///Contains admin info. Null if client is not an admin.
|
||||
var/datum/admins/holder = null
|
||||
///Needs to implement InterceptClickOn(user,params,atom) proc
|
||||
var/datum/click_intercept = null
|
||||
var/buildmode = 0
|
||||
|
||||
///Contains the last message sent by this client - used to protect against copy-paste spamming.
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
var/max_item_count = 1
|
||||
var/upgraded_capacity = FALSE
|
||||
var/gulpsound = 'sound/vore/gulp.ogg'
|
||||
var/datum/matter_synth/metal = null
|
||||
var/datum/matter_synth/glass = null
|
||||
var/datum/matter_synth/wood = null
|
||||
var/datum/matter_synth/plastic = null
|
||||
var/datum/matter_synth/metal/metal = null
|
||||
var/datum/matter_synth/glass/glass = null
|
||||
var/datum/matter_synth/wood/wood = null
|
||||
var/datum/matter_synth/plastic/plastic = null
|
||||
var/datum/matter_synth/water = null
|
||||
var/digest_brute = 2
|
||||
var/digest_burn = 3
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
icon_state = "decompiler"
|
||||
|
||||
//Metal, glass, wood, plastic.
|
||||
var/datum/matter_synth/metal = null
|
||||
var/datum/matter_synth/glass = null
|
||||
var/datum/matter_synth/wood = null
|
||||
var/datum/matter_synth/plastic = null
|
||||
var/datum/matter_synth/metal/metal = null
|
||||
var/datum/matter_synth/glass/glass = null
|
||||
var/datum/matter_synth/wood/wood = null
|
||||
var/datum/matter_synth/plastic/plastic = null
|
||||
|
||||
/obj/item/matter_decompiler/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
|
||||
return
|
||||
|
||||
@@ -184,6 +184,85 @@
|
||||
CHANNEL_EXPLORATION = 1
|
||||
)
|
||||
|
||||
/obj/item/robot_module/proc/add_item_with_reagents(obj/item/stack/item_with_synth)
|
||||
var/list/item_synths = list()
|
||||
for(var/datum/matter_synth/matter_synth as anything in item_with_synth.synths)
|
||||
var/found = FALSE
|
||||
for(var/datum/matter_synth/synth as anything in synths)
|
||||
if(matter_synth.type == synth.type)
|
||||
item_synths += synth
|
||||
break
|
||||
if(!found)
|
||||
var/datum/matter_synth/new_synth = new matter_synth.type(10000)
|
||||
item_synths += new_synth
|
||||
synths += new_synth
|
||||
item_with_synth.synths = item_synths
|
||||
|
||||
/obj/item/robot_module/proc/add_item(atom/movable/new_item, mob/living/silicon/robot/robot)
|
||||
if(istype(new_item, /obj/item/card/id))
|
||||
if(robot.idcard)
|
||||
modules -= robot.idcard
|
||||
QDEL_NULL(robot.idcard)
|
||||
robot.idcard = new_item
|
||||
modules += new_item
|
||||
new_item.forceMove(src)
|
||||
robot.hud_used?.update_robot_modules_display()
|
||||
|
||||
if(istype(new_item, /obj/item/robotic_multibelt/materials))
|
||||
var/obj/item/robotic_multibelt/materials/mat_belt = new_item
|
||||
for(var/obj/item/stack as anything in mat_belt.cyborg_integrated_tools)
|
||||
add_item_with_reagents(stack)
|
||||
|
||||
if(istype(new_item, /obj/item/stack))
|
||||
add_item_with_reagents(new_item)
|
||||
|
||||
if(istype(new_item, /obj/item/matter_decompiler) || istype(new_item, /obj/item/dogborg/sleeper/compactor/decompiler))
|
||||
var/obj/item/matter_decompiler/item_with_matter = new_item
|
||||
if(item_with_matter.metal)
|
||||
var/found = FALSE
|
||||
for(var/datum/matter_synth/synth as anything in synths)
|
||||
if(item_with_matter.metal.type == synth.type)
|
||||
item_with_matter.metal = synth
|
||||
found = TRUE
|
||||
break
|
||||
if(!found)
|
||||
var/datum/matter_synth/metal = new /datum/matter_synth/metal(40000)
|
||||
item_with_matter.metal = metal
|
||||
LAZYADD(synths, metal)
|
||||
if(item_with_matter.glass)
|
||||
var/found = FALSE
|
||||
for(var/datum/matter_synth/synth as anything in synths)
|
||||
if(item_with_matter.glass.type == synth.type)
|
||||
item_with_matter.glass = synth
|
||||
found = TRUE
|
||||
break
|
||||
if(!found)
|
||||
var/datum/matter_synth/glass = new /datum/matter_synth/glass(40000)
|
||||
item_with_matter.glass = glass
|
||||
LAZYADD(synths, glass)
|
||||
if(item_with_matter.wood)
|
||||
var/found = FALSE
|
||||
for(var/datum/matter_synth/synth as anything in synths)
|
||||
if(item_with_matter.wood.type == synth.type)
|
||||
item_with_matter.wood = synth
|
||||
found = TRUE
|
||||
break
|
||||
if(!found)
|
||||
var/datum/matter_synth/wood = new /datum/matter_synth/wood(40000)
|
||||
item_with_matter.wood = wood
|
||||
LAZYADD(synths, wood)
|
||||
if(item_with_matter.plastic)
|
||||
var/found = FALSE
|
||||
for(var/datum/matter_synth/synth as anything in synths)
|
||||
if(item_with_matter.plastic.type == synth.type)
|
||||
item_with_matter.plastic = synth
|
||||
found = TRUE
|
||||
break
|
||||
if(!found)
|
||||
var/datum/matter_synth/plastic = new /datum/matter_synth/plastic(40000)
|
||||
item_with_matter.plastic = plastic
|
||||
LAZYADD(synths, plastic)
|
||||
|
||||
// Cyborgs (non-drones), default loadout. This will be given to every module.
|
||||
/obj/item/robot_module/robot/create_equipment(var/mob/living/silicon/robot/robot)
|
||||
..()
|
||||
|
||||
@@ -269,6 +269,9 @@
|
||||
///For storing what do_after's someone has, key = string, value = amount of interactions of that type happening.
|
||||
var/list/do_afters
|
||||
|
||||
///Allows a datum to intercept all click calls this mob is the source of
|
||||
var/datum/click_intercept
|
||||
|
||||
var/datum/focus //What receives our keyboard inputs. src by default
|
||||
/// dict of custom stat tabs with data
|
||||
var/list/list/misc_tabs = list()
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Create Object</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-size: 9pt;
|
||||
font-family: Verdana, sans-serif;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: #00f;
|
||||
font-family: Georgia, Arial, sans-serif;
|
||||
}
|
||||
img {
|
||||
border: 0px;
|
||||
}
|
||||
p.lic {
|
||||
font-size: 6pt;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form name="spawner" action="byond://?src=/* ref src */" method="get">
|
||||
<input type="hidden" name="src" value="/* ref src */" />
|
||||
/* hreftokenfield */
|
||||
<input type="hidden" name="action" value="object_list" />
|
||||
|
||||
Type
|
||||
<input
|
||||
type="text"
|
||||
name="filter"
|
||||
value=""
|
||||
onkeypress="submitFirst(event)"
|
||||
style="width: 280px; height: 25"
|
||||
/>
|
||||
<input type="button" value="Search" onclick="updateSearch()" /><br />
|
||||
Offset:
|
||||
<input type="text" name="offset" value="x,y,z" style="width: 250px" />
|
||||
|
||||
A <input type="radio" name="offset_type" value="absolute" /> R
|
||||
<input
|
||||
type="radio"
|
||||
name="offset_type"
|
||||
value="relative"
|
||||
checked="checked"
|
||||
/><br />
|
||||
|
||||
Number:
|
||||
<input type="text" name="object_count" value="1" style="width: 30px" />
|
||||
Dir:
|
||||
<input type="text" name="object_dir" value="2" style="width: 30px" />
|
||||
Name:
|
||||
<input
|
||||
type="text"
|
||||
name="object_name"
|
||||
value=""
|
||||
style="width: 180px"
|
||||
/><br />
|
||||
Where:
|
||||
<select name="object_where" style="width: 320px">
|
||||
<option value="onfloor">On floor below own mob</option>
|
||||
<!-- <option value='inhand'>In own mob's hand</option> -->
|
||||
<option value="inmarked">In marked object</option>
|
||||
</select>
|
||||
<br /><br />
|
||||
Number of matches:
|
||||
<input id="number" value="0" style="width: 180px" /><br />
|
||||
<br /><br />
|
||||
|
||||
<div id="selector_hs">
|
||||
<select name="object_list" id="object_list" multiple size="20"></select>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<input type="submit" value="spawn" />
|
||||
</form>
|
||||
|
||||
<script language="JavaScript">
|
||||
var old_search = "";
|
||||
var object_list = document.spawner.object_list;
|
||||
var object_list_container = document.getElementById("selector_hs");
|
||||
// prettier-ignore
|
||||
var object_paths = (null /* object types */);
|
||||
var objects =
|
||||
object_paths == null ? new Array() : object_paths.split(";");
|
||||
|
||||
document.spawner.filter.focus();
|
||||
populateList(objects);
|
||||
|
||||
function populateList(from_list) {
|
||||
var newOpts = "";
|
||||
var i;
|
||||
for (i in from_list) {
|
||||
newOpts +=
|
||||
'<option value="' +
|
||||
from_list[i] +
|
||||
'">' +
|
||||
from_list[i] +
|
||||
"</option>";
|
||||
}
|
||||
object_list_container.innerHTML =
|
||||
'<select name="object_list" id="object_list" multiple size="20">' +
|
||||
newOpts +
|
||||
"</select>";
|
||||
document.getElementById("number").value = from_list.length;
|
||||
}
|
||||
|
||||
function updateSearch() {
|
||||
if (old_search == document.spawner.filter.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
old_search = document.spawner.filter.value;
|
||||
|
||||
var filtered = new Array();
|
||||
var i;
|
||||
for (i in objects) {
|
||||
if (objects[i].search(old_search) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
filtered.push(objects[i]);
|
||||
}
|
||||
|
||||
populateList(filtered);
|
||||
|
||||
if (object_list.options.length)
|
||||
object_list.options[0].selected = "true";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function submitFirst(event) {
|
||||
if (!object_list.options.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.keyCode == 13 || event.which == 13) {
|
||||
object_list.options[0].selected = "true";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -11,33 +11,17 @@ export function exportChatSettings(): void {
|
||||
const chatPages = store.get(chatPagesRecordAtom);
|
||||
const settings = store.get(storedSettingsAtom);
|
||||
|
||||
const opts: SaveFilePickerOptions = {
|
||||
id: `ss13-chatprefs-${Date.now()}`,
|
||||
suggestedName: `ss13-chatsettings-${new Date().toJSON().slice(0, 10)}.json`,
|
||||
types: [
|
||||
{
|
||||
description: 'SS13 file',
|
||||
accept: { 'application/json': ['.json'] },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const exportObject = { ...settings, chatPages };
|
||||
|
||||
window
|
||||
.showSaveFilePicker(opts)
|
||||
.then((fileHandle) => {
|
||||
fileHandle.createWritable().then((writableHandle) => {
|
||||
writableHandle.write(JSON.stringify(exportObject));
|
||||
writableHandle.close();
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
// Log the error if the error has nothing to do with the user aborting the download
|
||||
if (e.name !== 'AbortError') {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
const blob = new Blob([JSON.stringify(exportObject)], {
|
||||
type: 'application/json',
|
||||
});
|
||||
|
||||
Byond.saveBlob(
|
||||
blob,
|
||||
`ss13-chatsettings-${new Date().toJSON().slice(0, 10)}.json`,
|
||||
'.json',
|
||||
);
|
||||
}
|
||||
|
||||
export function importChatSettings(settings: string | string[]): void {
|
||||
|
||||
@@ -0,0 +1,475 @@
|
||||
import { storage } from 'common/storage';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import {
|
||||
Button,
|
||||
DmIcon,
|
||||
Input,
|
||||
NoticeBox,
|
||||
Section,
|
||||
Stack,
|
||||
VirtualList,
|
||||
} from 'tgui-core/components';
|
||||
import { useFuzzySearch } from 'tgui-core/fuzzysearch';
|
||||
|
||||
import { useBackend } from '../../backend';
|
||||
import { CreateObjectSettings } from './CreateObjectSettings';
|
||||
import { listNames, listTypes } from './constants';
|
||||
import type {
|
||||
AtomData,
|
||||
CreateObjectProps,
|
||||
SpawnPanelPreferences,
|
||||
} from './types';
|
||||
|
||||
type SpawnPanelData = {
|
||||
icon: string;
|
||||
iconState: string;
|
||||
selected_object?: string;
|
||||
copied_type?: string;
|
||||
preferences?: SpawnPanelPreferences;
|
||||
};
|
||||
|
||||
interface SpawnPreferences {
|
||||
hide_icons: boolean;
|
||||
hide_mappings: boolean;
|
||||
sort_by: string;
|
||||
search_text: string;
|
||||
search_by: string;
|
||||
selected_atom?: string;
|
||||
}
|
||||
|
||||
export function CreateObject(props: CreateObjectProps) {
|
||||
const { act, data } = useBackend<SpawnPanelData>();
|
||||
const { setAdvancedSettings, iconSettings, objList = { atoms: {} } } = props;
|
||||
|
||||
const [tooltipIcon, setTooltipIcon] = useState(false);
|
||||
const [selectedObj, setSelectedObj] = useState<string | null>(null);
|
||||
const [searchBy, setSearchBy] = useState(false);
|
||||
const [sortBy, setSortBy] = useState(listTypes.Objects);
|
||||
const [hideMapping, setHideMapping] = useState(false);
|
||||
const [showIcons, setshowIcons] = useState(false);
|
||||
const [showPreview, setshowPreview] = useState(false);
|
||||
|
||||
// flattening the object lists
|
||||
const allObjects = objList.atoms;
|
||||
|
||||
const currentList = objList;
|
||||
const currentType = allObjects[data.copied_type ?? '']?.type || 'Objects';
|
||||
|
||||
const getSearchString = useCallback(
|
||||
(key: string) => {
|
||||
const item = allObjects[key];
|
||||
if (!item) return key;
|
||||
return searchBy ? key : `${key} ${item.name || ''}`;
|
||||
},
|
||||
[searchBy, allObjects],
|
||||
);
|
||||
|
||||
const { query, setQuery, results } = useFuzzySearch({
|
||||
searchArray: Object.keys(allObjects),
|
||||
matchStrategy: 'smart',
|
||||
getSearchString,
|
||||
});
|
||||
|
||||
const filteredResults = results.filter((obj) => {
|
||||
const item = allObjects[obj];
|
||||
if (!item) return false;
|
||||
if (sortBy !== listTypes[item.type]) return false;
|
||||
if (hideMapping && item.mapping) return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (data.selected_object) {
|
||||
setSelectedObj(data.selected_object);
|
||||
if (currentList[data.selected_object]) {
|
||||
props.onIconSettingsChange?.({
|
||||
icon: currentList[data.selected_object].icon,
|
||||
iconState: currentList[data.selected_object].icon_state,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [data.selected_object]);
|
||||
|
||||
useEffect(() => {
|
||||
if (data.copied_type) {
|
||||
setSelectedObj(data.copied_type);
|
||||
setQuery(data.copied_type);
|
||||
|
||||
const copiedAtom: AtomData = objList.atoms[data.copied_type];
|
||||
setSortBy(listTypes[copiedAtom.type]);
|
||||
setSearchBy(true);
|
||||
|
||||
const list = objList.atoms;
|
||||
if (list[data.copied_type]) {
|
||||
props.onIconSettingsChange?.({
|
||||
icon: list[data.copied_type].icon,
|
||||
iconState: list[data.copied_type].icon_state,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [data.copied_type]);
|
||||
|
||||
useEffect(() => {
|
||||
const loadStoredValues = async () => {
|
||||
const storedSearchText = await storage.get('spawnpanel-searchText');
|
||||
const storedSearchBy = await storage.get('spawnpanel-searchBy');
|
||||
const storedSortBy = await storage.get('spawnpanel-sortBy');
|
||||
const storedHideMapping = await storage.get('spawnpanel-hideMapping');
|
||||
const storedShowIcons = await storage.get('spawnpanel-showIcons');
|
||||
const storedShowPreview = await storage.get('spawnpanel-showPreview');
|
||||
const storedSelectedObj = await storage.get('spawnpanel-selectedObj');
|
||||
|
||||
if (storedSearchText) setQuery(storedSearchText);
|
||||
if (storedSearchBy !== undefined) setSearchBy(storedSearchBy);
|
||||
if (storedSortBy) setSortBy(storedSortBy);
|
||||
if (storedHideMapping !== undefined) setHideMapping(storedHideMapping);
|
||||
if (storedShowIcons !== undefined) setshowIcons(storedShowIcons);
|
||||
if (storedShowPreview !== undefined) setshowPreview(storedShowPreview);
|
||||
if (storedSelectedObj && allObjects[storedSelectedObj]) {
|
||||
setSelectedObj(storedSelectedObj);
|
||||
props.onIconSettingsChange?.({
|
||||
icon: allObjects[storedSelectedObj].icon,
|
||||
iconState: allObjects[storedSelectedObj].icon_state,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
loadStoredValues();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedObj(null);
|
||||
}, [currentType]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedObj !== null) {
|
||||
storage.set('spawnpanel-selectedObj', selectedObj);
|
||||
}
|
||||
}, [selectedObj]);
|
||||
|
||||
useEffect(() => {
|
||||
if (data.selected_object) {
|
||||
setSelectedObj(data.selected_object);
|
||||
} else if (data.copied_type) {
|
||||
setSelectedObj(data.copied_type);
|
||||
}
|
||||
}, [data.selected_object, data.copied_type]);
|
||||
|
||||
useEffect(() => {
|
||||
if (data.iconState !== undefined) {
|
||||
props.onIconSettingsChange({
|
||||
iconState: data.iconState,
|
||||
});
|
||||
}
|
||||
}, [data.iconState]);
|
||||
|
||||
const sendUpdatedSettings = (
|
||||
changedSettings: Partial<Record<string, unknown>> = {},
|
||||
) => {
|
||||
act('update-settings', changedSettings);
|
||||
};
|
||||
|
||||
const updateSearchText = (value: string) => {
|
||||
setQuery(value);
|
||||
storage.set('spawnpanel-searchText', value);
|
||||
};
|
||||
|
||||
const updateSearchBy = (value: boolean) => {
|
||||
setSearchBy(value);
|
||||
storage.set('spawnpanel-searchBy', value);
|
||||
};
|
||||
|
||||
const updateSortBy = (value: string) => {
|
||||
setSortBy(value);
|
||||
storage.set('spawnpanel-sortBy', value);
|
||||
};
|
||||
|
||||
const updateHideMapping = (value: boolean) => {
|
||||
setHideMapping(value);
|
||||
storage.set('spawnpanel-hideMapping', value);
|
||||
};
|
||||
|
||||
const updateShowIcons = (value: boolean) => {
|
||||
setshowIcons(value);
|
||||
storage.set('spawnpanel-showIcons', value);
|
||||
};
|
||||
|
||||
const updateShowPreview = (value: boolean) => {
|
||||
setshowPreview(value);
|
||||
storage.set('spawnpanel-showPreview', value);
|
||||
};
|
||||
|
||||
const sendPreferences = (settings: Partial<SpawnPreferences>) => {
|
||||
const parseOffset = (offsetStr: string): number[] => {
|
||||
if (!offsetStr.trim()) return [0, 0, 0];
|
||||
|
||||
const parts = offsetStr.split(',').map((part) => {
|
||||
return parseInt(part.trim(), 10);
|
||||
});
|
||||
|
||||
while (parts.length < 3) {
|
||||
parts.push(0);
|
||||
}
|
||||
|
||||
return parts.slice(0, 3);
|
||||
};
|
||||
|
||||
const prefsToSend = {
|
||||
hide_icons: showIcons,
|
||||
hide_mappings: hideMapping,
|
||||
sort_by:
|
||||
Object.keys(listTypes).find((key) => listTypes[key] === sortBy) ||
|
||||
'Objects',
|
||||
search_text: query,
|
||||
search_by: searchBy ? 'type' : 'name',
|
||||
...settings,
|
||||
};
|
||||
|
||||
act('create-atom-action', prefsToSend);
|
||||
};
|
||||
|
||||
const handleObjectSelect = (obj: string) => {
|
||||
setSelectedObj(obj);
|
||||
act('selected-atom-changed', {
|
||||
newObj: obj,
|
||||
});
|
||||
if (allObjects[obj]) {
|
||||
props.onIconSettingsChange?.({
|
||||
icon: allObjects[obj].icon,
|
||||
iconState: allObjects[obj].icon_state,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleResetIconState = () => {
|
||||
props.onIconSettingsChange({
|
||||
iconState: null,
|
||||
icon: selectedObj ? allObjects[selectedObj]?.icon : null,
|
||||
});
|
||||
act('reset-icon-state');
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack vertical fill>
|
||||
<Stack.Item>
|
||||
<Section>
|
||||
<CreateObjectSettings
|
||||
onCreateObject={sendPreferences}
|
||||
setAdvancedSettings={setAdvancedSettings}
|
||||
iconSettings={iconSettings}
|
||||
/>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
|
||||
{showPreview && selectedObj && allObjects[selectedObj] && (
|
||||
<Stack.Item>
|
||||
<Section style={{ height: '6em' }}>
|
||||
<Stack>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
width="5em"
|
||||
height="4.8em"
|
||||
mb="-3px"
|
||||
color="transparent"
|
||||
ml="1px"
|
||||
style={{ alignContent: 'center' }}
|
||||
>
|
||||
<DmIcon
|
||||
width="4em"
|
||||
mt="2px"
|
||||
icon={
|
||||
iconSettings.icon ||
|
||||
data.icon ||
|
||||
allObjects[selectedObj].icon
|
||||
}
|
||||
icon_state={
|
||||
iconSettings.iconState ||
|
||||
data.iconState ||
|
||||
allObjects[selectedObj].icon_state
|
||||
}
|
||||
/>
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
<Stack.Item
|
||||
grow
|
||||
style={{
|
||||
maxHeight: '4.8em',
|
||||
overflowY: 'auto',
|
||||
}}
|
||||
>
|
||||
<Stack vertical>
|
||||
<Stack.Item bold>{allObjects[selectedObj].name}</Stack.Item>
|
||||
<Stack.Item
|
||||
grow
|
||||
italic
|
||||
style={{ color: 'rgba(200, 200, 200, 0.7)' }}
|
||||
>
|
||||
{allObjects[selectedObj].description || 'no description'}
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
)}
|
||||
|
||||
<Stack.Item>
|
||||
<Section>
|
||||
<Stack vertical>
|
||||
<Stack>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon={sortBy}
|
||||
onClick={() => {
|
||||
const types = Object.values(listTypes);
|
||||
const currentIndex = types.indexOf(sortBy);
|
||||
const nextIndex = (currentIndex + 1) % types.length;
|
||||
updateSortBy(types[nextIndex]);
|
||||
}}
|
||||
tooltip={`Cycle the searching target (objects, mobs, turfs)`}
|
||||
>
|
||||
{
|
||||
listNames[
|
||||
Object.keys(listTypes).find(
|
||||
(key) => listTypes[key] === sortBy,
|
||||
) || 'Objects'
|
||||
]
|
||||
}
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon={searchBy ? 'code' : 'font'}
|
||||
onClick={() => {
|
||||
updateSearchBy(!searchBy);
|
||||
}}
|
||||
tooltip={`Cycle the search method (by name, by type)`}
|
||||
>
|
||||
{searchBy ? 'By type' : 'By name'}
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button.Checkbox
|
||||
onClick={() => {
|
||||
updateHideMapping(!hideMapping);
|
||||
}}
|
||||
color={!hideMapping && 'good'}
|
||||
checked={!hideMapping}
|
||||
tooltip={`Toggle mapping objects visibility`}
|
||||
>
|
||||
Mapping
|
||||
</Button.Checkbox>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button.Checkbox
|
||||
onClick={() => {
|
||||
updateShowIcons(!showIcons);
|
||||
}}
|
||||
color={showIcons && 'good'}
|
||||
checked={showIcons}
|
||||
tooltip={`Toggle preview icons on hovering`}
|
||||
>
|
||||
Icons
|
||||
</Button.Checkbox>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button.Checkbox
|
||||
onClick={() => {
|
||||
updateShowPreview(!showPreview);
|
||||
}}
|
||||
color={showPreview && 'good'}
|
||||
checked={showPreview}
|
||||
tooltip={`Toggle the large object preview panel`}
|
||||
>
|
||||
Preview
|
||||
</Button.Checkbox>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
height="1.7em"
|
||||
color="transparent"
|
||||
icon="close"
|
||||
onClick={() => setQuery('')}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
<Stack.Item grow>
|
||||
<Input
|
||||
placeholder="Search here..."
|
||||
value={query}
|
||||
onChange={(value) => updateSearchText(value)}
|
||||
fluid
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
|
||||
<Stack.Item grow>
|
||||
<Section fill scrollable={filteredResults.length !== 0}>
|
||||
{query === '' ? (
|
||||
<NoticeBox textAlign="center" color="blue" width="100%">
|
||||
Begin typing to search...
|
||||
</NoticeBox>
|
||||
) : !filteredResults.length ? (
|
||||
<NoticeBox textAlign="center" color="blue" width="100%">
|
||||
Nothing found
|
||||
</NoticeBox>
|
||||
) : (
|
||||
<VirtualList>
|
||||
{filteredResults.map((obj, index) => (
|
||||
<Button
|
||||
key={index}
|
||||
color="transparent"
|
||||
tooltip={
|
||||
(showIcons || tooltipIcon) &&
|
||||
allObjects[obj] && (
|
||||
<DmIcon
|
||||
icon={allObjects[obj].icon}
|
||||
icon_state={allObjects[obj].icon_state}
|
||||
/>
|
||||
)
|
||||
}
|
||||
tooltipPosition="top-start"
|
||||
fluid
|
||||
selected={selectedObj === obj}
|
||||
style={{
|
||||
backgroundColor:
|
||||
selectedObj === obj
|
||||
? 'rgba(160, 200, 255, 0.1)'
|
||||
: undefined,
|
||||
color: selectedObj === obj ? '#fff' : undefined,
|
||||
}}
|
||||
onDoubleClick={() => {
|
||||
if (selectedObj) {
|
||||
sendPreferences({ selected_atom: selectedObj });
|
||||
}
|
||||
}}
|
||||
onClick={() => handleObjectSelect(obj)}
|
||||
>
|
||||
{searchBy ? (
|
||||
obj
|
||||
) : (
|
||||
<>
|
||||
{allObjects[obj]?.name}
|
||||
<span
|
||||
className="label label-info"
|
||||
style={{
|
||||
marginLeft: '0.5em',
|
||||
color: 'rgba(200, 200, 200, 0.5)',
|
||||
fontSize: '10px',
|
||||
}}
|
||||
>
|
||||
{obj}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
))}
|
||||
</VirtualList>
|
||||
)}
|
||||
</Section>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
import { useEffect } from 'react';
|
||||
import { Button, Dropdown, Slider, Table } from 'tgui-core/components';
|
||||
|
||||
import { useBackend } from '../../backend';
|
||||
import type { IconSettings } from './index';
|
||||
|
||||
type SpawnPanelData = {
|
||||
icon: string;
|
||||
iconState: string;
|
||||
iconStates: string[];
|
||||
selected_object?: string;
|
||||
apply_icon_override?: boolean;
|
||||
};
|
||||
|
||||
interface CreateObjectAdvancedSettingsProps {
|
||||
iconSettings: IconSettings;
|
||||
onIconSettingsChange: (settings: Partial<IconSettings>) => void;
|
||||
}
|
||||
|
||||
export function CreateObjectAdvancedSettings(
|
||||
props: CreateObjectAdvancedSettingsProps,
|
||||
) {
|
||||
const { act, data } = useBackend<SpawnPanelData>();
|
||||
const { iconSettings, onIconSettingsChange } = props;
|
||||
|
||||
const sendUpdatedSettings = (
|
||||
changedSettings: Partial<Record<string, unknown>> = {},
|
||||
) => {
|
||||
const currentSettings = {
|
||||
selected_atom_icon: data.icon || iconSettings.icon,
|
||||
selected_atom_icon_state: data.iconState || iconSettings.iconState,
|
||||
atom_icon_size: iconSettings.iconSize,
|
||||
...changedSettings,
|
||||
};
|
||||
act('update-settings', currentSettings);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
act('get-icon-states');
|
||||
}, []);
|
||||
|
||||
const iconStateOptions = (
|
||||
Array.isArray(data.iconStates) ? data.iconStates : []
|
||||
).map((state) => ({
|
||||
value: state,
|
||||
displayText: state,
|
||||
}));
|
||||
|
||||
return (
|
||||
<Table>
|
||||
<Table.Row className="candystripe" lineHeight="26px">
|
||||
<Table.Cell pl={1} width="fit-content">
|
||||
Icon:
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Button fluid onClick={() => act('select-new-DMI')}>
|
||||
{data.icon || iconSettings.icon || 'Default'}
|
||||
</Button>
|
||||
</Table.Cell>
|
||||
<Table.Cell pr={1} width="25px">
|
||||
<Button
|
||||
icon="arrow-rotate-right"
|
||||
color="transparent"
|
||||
onClick={() => {
|
||||
act('reset-DMI-icon');
|
||||
sendUpdatedSettings();
|
||||
}}
|
||||
/>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row className="candystripe" lineHeight="26px">
|
||||
<Table.Cell pl={1}>Icon state:</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Dropdown
|
||||
options={iconStateOptions}
|
||||
selected={data.iconState || iconSettings.iconState || 'Default'}
|
||||
displayText={data.iconState || iconSettings.iconState || 'Default'}
|
||||
onSelected={(value) => {
|
||||
act('select-new-icon-state', {
|
||||
new_state: value,
|
||||
current_icon: data.icon || iconSettings.icon,
|
||||
});
|
||||
onIconSettingsChange({ iconState: value });
|
||||
sendUpdatedSettings({ selected_atom_icon_state: value });
|
||||
}}
|
||||
width="100%"
|
||||
/>
|
||||
</Table.Cell>
|
||||
<Table.Cell pr={1}>
|
||||
<Button
|
||||
icon="arrow-rotate-right"
|
||||
color="transparent"
|
||||
onClick={() => {
|
||||
onIconSettingsChange({ iconState: null });
|
||||
act('reset-icon-state');
|
||||
}}
|
||||
/>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row className="candystripe" lineHeight="26px">
|
||||
<Table.Cell pl={1}>Explicitly set icon:</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Button.Checkbox
|
||||
checked={!!iconSettings.applyIcon}
|
||||
onClick={() => {
|
||||
const next = !iconSettings.applyIcon;
|
||||
onIconSettingsChange({ applyIcon: next });
|
||||
act('set-apply-icon-override', { value: next });
|
||||
}}
|
||||
>
|
||||
Enabled
|
||||
</Button.Checkbox>
|
||||
</Table.Cell>
|
||||
<Table.Cell pr={1} />
|
||||
</Table.Row>
|
||||
<Table.Row className="candystripe" lineHeight="26px">
|
||||
<Table.Cell pl={1}>Icon scale:</Table.Cell>
|
||||
<Table.Cell width="auto">
|
||||
<Slider
|
||||
minValue={25}
|
||||
maxValue={500}
|
||||
value={iconSettings.iconSize}
|
||||
step={25}
|
||||
lineHeight={1}
|
||||
stepPixelSize={20}
|
||||
onChange={(e, value) => {
|
||||
onIconSettingsChange({ iconSize: value });
|
||||
sendUpdatedSettings({ atom_icon_size: value });
|
||||
}}
|
||||
/>
|
||||
</Table.Cell>
|
||||
<Table.Cell pr={1}>
|
||||
<Button
|
||||
icon="arrow-rotate-right"
|
||||
color="transparent"
|
||||
onClick={() => {
|
||||
onIconSettingsChange({ iconSize: 100 });
|
||||
act('reset-icon-size');
|
||||
sendUpdatedSettings({ atom_icon_size: 100 });
|
||||
}}
|
||||
/>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,492 @@
|
||||
import { storage } from 'common/storage';
|
||||
import { useEffect, useState } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Dropdown,
|
||||
Icon,
|
||||
Input,
|
||||
NumberInput,
|
||||
Slider,
|
||||
Stack,
|
||||
Table,
|
||||
} from 'tgui-core/components';
|
||||
|
||||
import { useBackend } from '../../backend';
|
||||
import {
|
||||
directionNames,
|
||||
directionRotation,
|
||||
spawnLocationIcons,
|
||||
spawnLocationOptions,
|
||||
} from './constants';
|
||||
import type { IconSettings } from './index';
|
||||
|
||||
export type SpawnPanelData = {
|
||||
icon: string;
|
||||
iconState: string;
|
||||
iconStates: string[];
|
||||
selected_object?: string;
|
||||
precise_mode: string;
|
||||
};
|
||||
|
||||
interface CreateObjectSettingsProps {
|
||||
onCreateObject?: (obj: Record<string, unknown>) => void;
|
||||
setAdvancedSettings: (value: boolean) => void;
|
||||
iconSettings: IconSettings;
|
||||
}
|
||||
|
||||
export function CreateObjectSettings(props: CreateObjectSettingsProps) {
|
||||
const { onCreateObject, setAdvancedSettings, iconSettings } = props;
|
||||
const { act, data } = useBackend<SpawnPanelData>();
|
||||
|
||||
const [amount, setAmount] = useState(1);
|
||||
const [cordsType, setCordsType] = useState(0);
|
||||
const [spawnLocation, setSpawnLocation] = useState('Current location');
|
||||
const [direction, setDirection] = useState(0);
|
||||
const [objectName, setObjectName] = useState('');
|
||||
const [offset, setOffset] = useState('');
|
||||
|
||||
const dirValues = [1, 5, 4, 6, 2, 10, 8, 9];
|
||||
const updateAmount = (value: number) => {
|
||||
setAmount(value);
|
||||
sendUpdatedSettings({ atom_amount: value });
|
||||
};
|
||||
|
||||
const updateCordsType = (value: number) => {
|
||||
setCordsType(value);
|
||||
storage.set('spawnpanel-offset_type', value);
|
||||
sendUpdatedSettings({
|
||||
offset_type: value ? 'Absolute offset' : 'Relative offset',
|
||||
});
|
||||
};
|
||||
|
||||
const updateSpawnLocation = (value: string) => {
|
||||
setSpawnLocation(value);
|
||||
storage.set('spawnpanel-where_target_type', value);
|
||||
sendUpdatedSettings({ where_target_type: value });
|
||||
};
|
||||
|
||||
const updateDirection = (value: number) => {
|
||||
setDirection(value);
|
||||
storage.set('spawnpanel-direction', value);
|
||||
sendUpdatedSettings({ atom_dir: dirValues[value] });
|
||||
};
|
||||
|
||||
const updateObjectName = (value: string) => {
|
||||
setObjectName(value);
|
||||
storage.set('spawnpanel-atom_name', value);
|
||||
sendUpdatedSettings({ atom_name: value });
|
||||
|
||||
if (isPreciseModeActive) {
|
||||
sendUpdatedSettings();
|
||||
}
|
||||
};
|
||||
|
||||
const updateOffset = (value: string) => {
|
||||
setOffset(value);
|
||||
storage.set('spawnpanel-offset', value);
|
||||
|
||||
const parseOffset = (offsetStr: string): number[] => {
|
||||
if (!offsetStr.trim()) return [0, 0, 0];
|
||||
|
||||
const parts = offsetStr.split(',').map((part) => {
|
||||
return parseInt(part.trim(), 10);
|
||||
});
|
||||
|
||||
while (parts.length < 3) {
|
||||
parts.push(0);
|
||||
}
|
||||
|
||||
return parts.slice(0, 3);
|
||||
};
|
||||
|
||||
sendUpdatedSettings({ offset: parseOffset(value) });
|
||||
};
|
||||
|
||||
const sendUpdatedSettings = (
|
||||
changedSettings: Partial<Record<string, unknown>> = {},
|
||||
) => {
|
||||
const parseOffset = (offsetStr: string): number[] => {
|
||||
if (!offsetStr.trim()) return [0, 0, 0];
|
||||
|
||||
const parts = offsetStr.split(',').map((part) => {
|
||||
return parseInt(part.trim(), 10);
|
||||
});
|
||||
|
||||
while (parts.length < 3) {
|
||||
parts.push(0);
|
||||
}
|
||||
|
||||
return parts.slice(0, 3);
|
||||
};
|
||||
|
||||
const currentSettings = {
|
||||
atom_amount: amount,
|
||||
offset_type: cordsType ? 'Absolute offset' : 'Relative offset',
|
||||
where_target_type: spawnLocation,
|
||||
atom_dir: dirValues[direction],
|
||||
offset: parseOffset(offset),
|
||||
atom_name: objectName,
|
||||
atom_icon_size: iconSettings.iconSize,
|
||||
apply_icon_override: iconSettings.applyIcon ?? false,
|
||||
...changedSettings,
|
||||
};
|
||||
act('update-settings', currentSettings);
|
||||
};
|
||||
|
||||
const resetAdvancedSettings = () => {
|
||||
const defaultAmount = 1;
|
||||
const defaultCordsType = 0;
|
||||
const defaultSpawnLocation = 'Current location';
|
||||
const defaultDirection = 0;
|
||||
const defaultObjectName = '';
|
||||
const defaultOffset = '';
|
||||
|
||||
setAmount(defaultAmount);
|
||||
setCordsType(defaultCordsType);
|
||||
setSpawnLocation(defaultSpawnLocation);
|
||||
setDirection(defaultDirection);
|
||||
setObjectName(defaultObjectName);
|
||||
setOffset(defaultOffset);
|
||||
|
||||
storage.set('spawnpanel-atom_amount', defaultAmount);
|
||||
storage.set('spawnpanel-offset_type', defaultCordsType);
|
||||
storage.set('spawnpanel-where_target_type', defaultSpawnLocation);
|
||||
storage.set('spawnpanel-direction', defaultDirection);
|
||||
storage.set('spawnpanel-atom_name', defaultObjectName);
|
||||
storage.set('spawnpanel-offset', defaultOffset);
|
||||
|
||||
sendUpdatedSettings({
|
||||
atom_amount: defaultAmount,
|
||||
offset_type: defaultCordsType ? 'Absolute offset' : 'Relative offset',
|
||||
where_target_type: defaultSpawnLocation,
|
||||
atom_dir: dirValues[defaultDirection],
|
||||
offset: defaultOffset,
|
||||
atom_name: defaultObjectName,
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const loadStoredValues = async () => {
|
||||
const storedCordsType = await storage.get('spawnpanel-offset_type');
|
||||
const storedSpawnLocation = await storage.get(
|
||||
'spawnpanel-where_target_type',
|
||||
);
|
||||
const storedDirection = await storage.get('spawnpanel-direction');
|
||||
const storedObjectName = await storage.get('spawnpanel-atom_name');
|
||||
const storedOffset = await storage.get('spawnpanel-offset');
|
||||
|
||||
if (storedCordsType !== undefined) setCordsType(storedCordsType);
|
||||
if (storedSpawnLocation) setSpawnLocation(storedSpawnLocation);
|
||||
if (storedDirection !== undefined) setDirection(storedDirection);
|
||||
if (storedObjectName !== undefined) setObjectName(storedObjectName);
|
||||
if (storedOffset !== undefined) setOffset(storedOffset);
|
||||
};
|
||||
|
||||
loadStoredValues();
|
||||
}, []);
|
||||
|
||||
const isTargetMode =
|
||||
spawnLocation === 'Targeted location' ||
|
||||
spawnLocation === 'Targeted location (droppod)' ||
|
||||
spawnLocation === "In targeted mob's hand";
|
||||
|
||||
const isPreciseModeActive = data?.precise_mode === 'Target';
|
||||
const isMarkModeActive = data?.precise_mode === 'Mark';
|
||||
const isCopyModeActive = data?.precise_mode === 'Copy';
|
||||
|
||||
const isAnyPreciseModeActive = !(data?.precise_mode === 'Off');
|
||||
|
||||
const disablePreciseMode = () => {
|
||||
if (isPreciseModeActive) {
|
||||
act('toggle-precise-mode', {
|
||||
newPreciseType: 'Off',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleSpawn = () => {
|
||||
const parseOffset = (offsetStr: string): number[] => {
|
||||
if (!offsetStr.trim()) return [0, 0, 0];
|
||||
|
||||
const parts = offsetStr.split(',').map((part) => {
|
||||
return parseInt(part.trim(), 10);
|
||||
});
|
||||
|
||||
while (parts.length < 3) {
|
||||
parts.push(0);
|
||||
}
|
||||
|
||||
return parts.slice(0, 3);
|
||||
};
|
||||
|
||||
const currentSettings = {
|
||||
atom_amount: amount,
|
||||
offset_type: cordsType ? 'Absolute offset' : 'Relative offset',
|
||||
where_target_type: spawnLocation,
|
||||
atom_dir: dirValues[direction],
|
||||
offset: parseOffset(offset),
|
||||
atom_name: objectName,
|
||||
atom_icon_size: iconSettings.iconSize,
|
||||
selected_atom: data.selected_object,
|
||||
apply_icon_override: iconSettings.applyIcon ?? false,
|
||||
};
|
||||
|
||||
act('update-settings', currentSettings);
|
||||
|
||||
if (!isTargetMode) {
|
||||
if (onCreateObject) {
|
||||
onCreateObject(currentSettings);
|
||||
} else {
|
||||
act('create-atom-action', currentSettings);
|
||||
}
|
||||
} else {
|
||||
if (isPreciseModeActive) {
|
||||
act('toggle-precise-mode', { newPreciseType: 'Off' });
|
||||
} else {
|
||||
act('toggle-precise-mode', {
|
||||
newPreciseType: 'Target',
|
||||
where_target_type: spawnLocation,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isTargetMode && isPreciseModeActive) {
|
||||
disablePreciseMode();
|
||||
}
|
||||
}, [spawnLocation]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isPreciseModeActive) {
|
||||
sendUpdatedSettings();
|
||||
}
|
||||
}, [iconSettings.icon, iconSettings.iconState, iconSettings.iconSize]);
|
||||
|
||||
return (
|
||||
<Stack fill vertical>
|
||||
<Stack>
|
||||
<Stack.Item grow>
|
||||
<Table
|
||||
style={{
|
||||
paddingLeft: '5px',
|
||||
}}
|
||||
>
|
||||
<Table.Row className="candystripe" lineHeight="26px">
|
||||
<Table.Cell pl={1}>Amnt.:</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Stack>
|
||||
<Stack.Item>
|
||||
<NumberInput
|
||||
width="45px"
|
||||
minValue={1}
|
||||
maxValue={100}
|
||||
step={1}
|
||||
value={amount}
|
||||
onChange={(value) => updateAmount(value)}
|
||||
disabled={isAnyPreciseModeActive}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>Dir:</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
tooltip={directionNames[dirValues[direction]]}
|
||||
tooltipPosition="top"
|
||||
fontSize="14"
|
||||
onClick={() => {
|
||||
updateDirection((direction + 1) % dirValues.length);
|
||||
}}
|
||||
disabled={isAnyPreciseModeActive}
|
||||
>
|
||||
<Icon
|
||||
name="arrow-up"
|
||||
style={{
|
||||
transform: `rotate(${directionRotation[dirValues[direction]]}deg)`,
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Slider
|
||||
tickWhileDragging
|
||||
minValue={0}
|
||||
maxValue={7}
|
||||
step={1}
|
||||
lineHeight={1}
|
||||
stepPixelSize={25}
|
||||
value={direction}
|
||||
format={(value) => dirValues[value].toString()}
|
||||
onChange={(e, value) => updateDirection(value)}
|
||||
disabled={isAnyPreciseModeActive}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row className="candystripe" lineHeight="26px">
|
||||
<Table.Cell pl={1}>Offset:</Table.Cell>
|
||||
<Table.Cell width="1200px">
|
||||
<Stack>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon={cordsType ? 'a' : 'r'}
|
||||
fontSize="14"
|
||||
onClick={() => {
|
||||
const newCordsType = cordsType ? 0 : 1;
|
||||
updateCordsType(newCordsType);
|
||||
if (isPreciseModeActive) {
|
||||
disablePreciseMode();
|
||||
}
|
||||
}}
|
||||
tooltip={cordsType ? 'Absolute' : 'Relative'}
|
||||
tooltipPosition="top"
|
||||
disabled={
|
||||
isTargetMode ||
|
||||
spawnLocation === 'At a marked object' ||
|
||||
spawnLocation === 'In the marked object' ||
|
||||
isAnyPreciseModeActive
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Input
|
||||
placeholder="x, y, z"
|
||||
value={offset}
|
||||
onChange={(value: string) => updateOffset(value)}
|
||||
width="100%"
|
||||
disabled={
|
||||
isTargetMode ||
|
||||
spawnLocation === 'At a marked object' ||
|
||||
spawnLocation === 'In the marked object' ||
|
||||
isAnyPreciseModeActive
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row className="candystripe" lineHeight="26px">
|
||||
<Table.Cell pl={1} width="80px">
|
||||
Name:
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Input
|
||||
onChange={(value: string) => updateObjectName(value)}
|
||||
value={objectName}
|
||||
width="100%"
|
||||
placeholder="leave empty for initial"
|
||||
disabled={isAnyPreciseModeActive}
|
||||
/>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Stack fill>
|
||||
<Stack.Item>
|
||||
<Stack vertical>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="gear"
|
||||
onClick={() => setAdvancedSettings(true)}
|
||||
style={{
|
||||
height: '22px',
|
||||
width: '22px',
|
||||
lineHeight: '22px',
|
||||
}}
|
||||
tooltip="Advanced settings"
|
||||
tooltipPosition="top"
|
||||
disabled={isAnyPreciseModeActive}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="trash"
|
||||
style={{
|
||||
height: '22px',
|
||||
width: '22px',
|
||||
lineHeight: '22px',
|
||||
}}
|
||||
onClick={() => resetAdvancedSettings()}
|
||||
tooltip="Reset advanced settings"
|
||||
tooltipPosition="top"
|
||||
disabled={isAnyPreciseModeActive}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
style={{
|
||||
height: '22px',
|
||||
width: '22px',
|
||||
lineHeight: '22px',
|
||||
}}
|
||||
icon={
|
||||
spawnLocation === 'At a marked object' ||
|
||||
spawnLocation === 'In the marked object'
|
||||
? 'thumbtack'
|
||||
: 'eye-dropper'
|
||||
}
|
||||
onClick={() => {
|
||||
act('toggle-precise-mode', {
|
||||
newPreciseType:
|
||||
isMarkModeActive || isCopyModeActive
|
||||
? 'Off'
|
||||
: spawnLocation === 'At a marked object' ||
|
||||
spawnLocation === 'In the marked object'
|
||||
? 'Mark'
|
||||
: 'Copy',
|
||||
});
|
||||
}}
|
||||
selected={isMarkModeActive || isCopyModeActive}
|
||||
tooltip={
|
||||
spawnLocation === 'At a marked object' ||
|
||||
spawnLocation === 'In the marked object'
|
||||
? 'Mark atom'
|
||||
: 'Copy atom path'
|
||||
}
|
||||
tooltipPosition="top"
|
||||
disabled={isAnyPreciseModeActive && !isMarkModeActive}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
<Stack.Item grow>
|
||||
<Stack vertical fill>
|
||||
<Stack.Item grow>
|
||||
<Button
|
||||
onClick={handleSpawn}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
textAlign: 'center',
|
||||
fontSize: '20px',
|
||||
alignContent: 'center',
|
||||
}}
|
||||
icon={spawnLocationIcons[spawnLocation]}
|
||||
selected={isTargetMode && isPreciseModeActive}
|
||||
>
|
||||
SPAWN
|
||||
</Button>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Dropdown
|
||||
options={spawnLocationOptions}
|
||||
onSelected={(value) => {
|
||||
if (data?.precise_mode && data.precise_mode !== 'Off') {
|
||||
act('toggle-precise-mode', {
|
||||
newPreciseType: 'Off',
|
||||
});
|
||||
}
|
||||
updateSpawnLocation(value);
|
||||
}}
|
||||
selected={spawnLocation}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
export const spawnLocationOptions = [
|
||||
'Current location',
|
||||
'Current location (droppod)',
|
||||
"In own mob's hand",
|
||||
'At a marked object',
|
||||
'In the marked object',
|
||||
'Targeted location',
|
||||
'Targeted location (droppod)',
|
||||
"In targeted mob's hand",
|
||||
];
|
||||
|
||||
export const listTypes = {
|
||||
Objects: 'cube',
|
||||
Turfs: 'map',
|
||||
Mobs: 'cat',
|
||||
};
|
||||
|
||||
export const listNames = {
|
||||
Objects: 'Search objects',
|
||||
Turfs: 'Search turfs',
|
||||
Mobs: 'Search mobs',
|
||||
};
|
||||
|
||||
export const spawnLocationIcons = {
|
||||
'Current location': 'map-marker',
|
||||
'Current location (droppod)': 'parachute-box',
|
||||
"In own mob's hand": 'hand-holding',
|
||||
'At a marked object': 'floppy-disk',
|
||||
'In the marked object': 'floppy-disk',
|
||||
'Targeted location': 'crosshairs',
|
||||
'Targeted location (droppod)': 'crosshairs',
|
||||
"In targeted mob's hand": 'crosshairs',
|
||||
};
|
||||
|
||||
export const directionRotation = {
|
||||
1: 0,
|
||||
5: 45,
|
||||
4: 90,
|
||||
6: 135,
|
||||
2: 180,
|
||||
10: 225,
|
||||
8: 270,
|
||||
9: 315,
|
||||
};
|
||||
|
||||
export const directionNames = {
|
||||
1: 'NORTH',
|
||||
2: 'SOUTH',
|
||||
4: 'EAST',
|
||||
8: 'WEST',
|
||||
5: 'NORTHEAST',
|
||||
6: 'SOUTHEAST',
|
||||
9: 'NORTHWEST',
|
||||
10: 'SOUTHWEST',
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Button, Modal, Section, Stack } from 'tgui-core/components';
|
||||
import { fetchRetry } from 'tgui-core/http';
|
||||
|
||||
import { resolveAsset } from '../../assets';
|
||||
import { Window } from '../../layouts';
|
||||
import { logger } from '../../logging';
|
||||
import { CreateObject } from './CreateObject';
|
||||
import { CreateObjectAdvancedSettings } from './CreateObjectAdvancedSettings';
|
||||
import type { CreateObjectData } from './types';
|
||||
|
||||
export interface IconSettings {
|
||||
icon: string | null;
|
||||
iconState: string | null;
|
||||
iconSize: number;
|
||||
applyIcon?: boolean;
|
||||
}
|
||||
|
||||
export function SpawnPanel() {
|
||||
const [data, setData] = useState<CreateObjectData | undefined>();
|
||||
const [advancedSettings, setAdvancedSettings] = useState(false);
|
||||
const [iconSettings, setIconSettings] = useState<IconSettings>({
|
||||
icon: null,
|
||||
iconState: null,
|
||||
iconSize: 100,
|
||||
applyIcon: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
fetchRetry(resolveAsset('spawnpanel_atom_data.json'))
|
||||
.then((response) => response.json())
|
||||
.then(setData)
|
||||
.catch((error) => {
|
||||
logger.log(
|
||||
'Failed to fetch spawnpanel_atom_data.json',
|
||||
JSON.stringify(error),
|
||||
);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleIconSettingsChange = (newSettings: Partial<IconSettings>) => {
|
||||
setIconSettings((current) => ({
|
||||
...current,
|
||||
...newSettings,
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<Window height={550} title="Spawn Panel" width={500} theme="admin">
|
||||
<Window.Content>
|
||||
{advancedSettings && (
|
||||
<Modal
|
||||
style={{
|
||||
padding: '6px',
|
||||
width: '30em',
|
||||
marginTop: '-15em',
|
||||
}}
|
||||
>
|
||||
<Section
|
||||
title="Advanced settings"
|
||||
buttons={
|
||||
<Button
|
||||
color="transparent"
|
||||
icon="close"
|
||||
onClick={() => setAdvancedSettings(false)}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<CreateObjectAdvancedSettings
|
||||
iconSettings={iconSettings}
|
||||
onIconSettingsChange={handleIconSettingsChange}
|
||||
/>
|
||||
</Section>
|
||||
</Modal>
|
||||
)}
|
||||
<Stack vertical fill>
|
||||
<Stack.Item grow>
|
||||
{data && (
|
||||
<CreateObject
|
||||
objList={data}
|
||||
setAdvancedSettings={setAdvancedSettings}
|
||||
iconSettings={iconSettings}
|
||||
onIconSettingsChange={handleIconSettingsChange}
|
||||
/>
|
||||
)}
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import type { BooleanLike } from 'tgui-core/react';
|
||||
|
||||
export interface SpawnPreferences {
|
||||
hide_icons: boolean;
|
||||
hide_mappings: boolean;
|
||||
sort_by: string;
|
||||
search_text: string;
|
||||
search_by: string;
|
||||
where_dropdown_value: string;
|
||||
offset_type: string;
|
||||
offset: string;
|
||||
object_count: number;
|
||||
dir: number;
|
||||
object_name: string;
|
||||
}
|
||||
|
||||
export interface SpawnPanelPreferences {
|
||||
hide_icons: boolean;
|
||||
hide_mappings: boolean;
|
||||
sort_by: string;
|
||||
search_text: string;
|
||||
search_by: string;
|
||||
}
|
||||
|
||||
export interface AtomData {
|
||||
icon: string;
|
||||
icon_state: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
mapping: BooleanLike;
|
||||
type: 'Objects' | 'Turfs' | 'Mobs';
|
||||
}
|
||||
|
||||
export interface CreateObjectData {
|
||||
atoms: Record<string, AtomData>;
|
||||
}
|
||||
|
||||
export interface CreateObjectProps {
|
||||
objList: CreateObjectData;
|
||||
setAdvancedSettings: (value: boolean) => void;
|
||||
iconSettings: {
|
||||
icon: string | null;
|
||||
iconState: string | null;
|
||||
iconSize: number;
|
||||
};
|
||||
onIconSettingsChange: (
|
||||
settings: Partial<{
|
||||
icon: string | null;
|
||||
iconState: string | null;
|
||||
iconSize: number;
|
||||
}>,
|
||||
) => void;
|
||||
}
|
||||
+5
-3
@@ -2181,9 +2181,6 @@
|
||||
#include "code\modules\admin\admin_verbs.dm"
|
||||
#include "code\modules\admin\banjob.dm"
|
||||
#include "code\modules\admin\ckey_vr.dm"
|
||||
#include "code\modules\admin\create_mob.dm"
|
||||
#include "code\modules\admin\create_object.dm"
|
||||
#include "code\modules\admin\create_turf.dm"
|
||||
#include "code\modules\admin\fix_player_notes_listing.dm"
|
||||
#include "code\modules\admin\health_scan.dm"
|
||||
#include "code\modules\admin\holder2.dm"
|
||||
@@ -2204,8 +2201,13 @@
|
||||
#include "code\modules\admin\callproc\callproc.dm"
|
||||
#include "code\modules\admin\DB ban\ban_panle_ui.dm"
|
||||
#include "code\modules\admin\DB ban\functions.dm"
|
||||
#include "code\modules\admin\spawn_panel\admin_hotkeys.dm"
|
||||
#include "code\modules\admin\spawn_panel\assets.dm"
|
||||
#include "code\modules\admin\spawn_panel\spawn_handling.dm"
|
||||
#include "code\modules\admin\spawn_panel\spawn_panel.dm"
|
||||
#include "code\modules\admin\verb_datums\_admin_verb_datum.dm"
|
||||
#include "code\modules\admin\verbs\adminfun.dm"
|
||||
#include "code\modules\admin\verbs\admingame.dm"
|
||||
#include "code\modules\admin\verbs\adminjump.dm"
|
||||
#include "code\modules\admin\verbs\adminpm.dm"
|
||||
#include "code\modules\admin\verbs\adminsay.dm"
|
||||
|
||||
Reference in New Issue
Block a user