mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-29 15:08:02 +01:00
Merge remote-tracking branch 'upstream/master' into wires-tgui
This commit is contained in:
@@ -152,12 +152,7 @@
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/unpowered)
|
||||
"az" = (
|
||||
/obj/item/spellbook/oneuse/charge{
|
||||
desc = "For the technology-hating wizard.";
|
||||
spell = /obj/effect/proc_holder/spell/targeted/emplosion/disable_tech;
|
||||
spellname = "Disable Technology";
|
||||
used = 1
|
||||
},
|
||||
/obj/item/spellbook/oneuse/emp/used,
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/unpowered)
|
||||
"aA" = (
|
||||
|
||||
@@ -4,3 +4,8 @@
|
||||
#define SAY_LOG "Say"
|
||||
#define EMOTE_LOG "Emote"
|
||||
#define MISC_LOG "Misc"
|
||||
#define DEADCHAT_LOG "Deadchat"
|
||||
#define OOC_LOG "OOC"
|
||||
#define LOOC_LOG "LOOC"
|
||||
|
||||
#define ALL_LOGS list(ATTACK_LOG, DEFENSE_LOG, CONVERSION_LOG, SAY_LOG, EMOTE_LOG, DEADCHAT_LOG, OOC_LOG, LOOC_LOG, MISC_LOG)
|
||||
|
||||
+2
-60
@@ -425,66 +425,8 @@
|
||||
if(pressure <= LAVALAND_EQUIPMENT_EFFECT_PRESSURE)
|
||||
. = TRUE
|
||||
|
||||
proc/pollCandidates(Question, be_special_type, antag_age_check = FALSE, poll_time = 300, ignore_respawnability = FALSE, min_hours = 0, flashwindow = TRUE, check_antaghud = TRUE)
|
||||
var/roletext = be_special_type ? get_roletext(be_special_type) : null
|
||||
var/list/mob/dead/observer/candidates = list()
|
||||
var/time_passed = world.time
|
||||
if(!Question)
|
||||
Question = "Would you like to be a special role?"
|
||||
|
||||
for(var/mob/dead/observer/G in (ignore_respawnability ? GLOB.player_list : GLOB.respawnable_list))
|
||||
if(!G.key || !G.client)
|
||||
continue
|
||||
if(be_special_type)
|
||||
if(!(be_special_type in G.client.prefs.be_special))
|
||||
continue
|
||||
if(antag_age_check)
|
||||
if(!player_old_enough_antag(G.client, be_special_type))
|
||||
continue
|
||||
if(roletext)
|
||||
if(jobban_isbanned(G, roletext) || jobban_isbanned(G, "Syndicate"))
|
||||
continue
|
||||
if(config.use_exp_restrictions && min_hours)
|
||||
if(G.client.get_exp_type_num(EXP_TYPE_LIVING) < min_hours * 60)
|
||||
continue
|
||||
if(check_antaghud && cannotPossess(G))
|
||||
continue
|
||||
spawn(0)
|
||||
G << 'sound/misc/notice2.ogg'//Alerting them to their consideration
|
||||
if(flashwindow)
|
||||
window_flash(G.client)
|
||||
var/ans = alert(G,Question,"Please answer in [poll_time/10] seconds!","No","Yes","Not This Round")
|
||||
if(!G?.client)
|
||||
return
|
||||
switch(ans)
|
||||
if("Yes")
|
||||
to_chat(G, "<span class='notice'>Choice registered: Yes.</span>")
|
||||
if((world.time-time_passed)>poll_time)//If more than 30 game seconds passed.
|
||||
to_chat(G, "<span class='danger'>Sorry, you were too late for the consideration!</span>")
|
||||
G << 'sound/machines/buzz-sigh.ogg'
|
||||
return
|
||||
candidates += G
|
||||
if("No")
|
||||
to_chat(G, "<span class='danger'>Choice registered: No.</span>")
|
||||
return
|
||||
if("Not This Round")
|
||||
to_chat(G, "<span class='danger'>Choice registered: No.</span>")
|
||||
to_chat(G, "<span class='notice'>You will no longer receive notifications for the role '[roletext]' for the rest of the round.</span>")
|
||||
G.client.prefs.be_special -= be_special_type
|
||||
return
|
||||
else
|
||||
return
|
||||
sleep(poll_time)
|
||||
|
||||
//Check all our candidates, to make sure they didn't log off during the 30 second wait period.
|
||||
for(var/mob/dead/observer/G in candidates)
|
||||
if(!G.key || !G.client)
|
||||
candidates.Remove(G)
|
||||
|
||||
return candidates
|
||||
|
||||
/proc/pollCandidatesWithVeto(adminclient, adminusr, max_slots, Question, be_special_type, antag_age_check = 0, poll_time = 300, ignore_respawnability = 0, min_hours = 0, flashwindow = TRUE, check_antaghud = TRUE)
|
||||
var/list/willing_ghosts = pollCandidates(Question, be_special_type, antag_age_check, poll_time, ignore_respawnability, min_hours, flashwindow, check_antaghud)
|
||||
/proc/pollCandidatesWithVeto(adminclient, adminusr, max_slots, Question, be_special_type, antag_age_check = FALSE, poll_time = 300, ignore_respawnability = FALSE, min_hours = FALSE, flashwindow = TRUE, check_antaghud = TRUE, source)
|
||||
var/list/willing_ghosts = SSghost_spawns.poll_candidates(Question, be_special_type, antag_age_check, poll_time, ignore_respawnability, min_hours, flashwindow, check_antaghud, source)
|
||||
var/list/selected_ghosts = list()
|
||||
if(!willing_ghosts.len)
|
||||
return selected_ghosts
|
||||
|
||||
@@ -693,6 +693,9 @@ proc/dd_sortedObjectList(list/incoming)
|
||||
// Lazying Episode 3
|
||||
#define LAZYSET(L, K, V) LAZYINITLIST(L); L[K] = V;
|
||||
|
||||
/// Returns whether a numerical index is within a given list's bounds. Faster than isnull(LAZYACCESS(L, I)).
|
||||
#define ISINDEXSAFE(L, I) (I >= 1 && I <= length(L))
|
||||
|
||||
//same, but returns nothing and acts on list in place
|
||||
/proc/shuffle_inplace(list/L)
|
||||
if(!L)
|
||||
|
||||
@@ -1919,16 +1919,6 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
|
||||
return pois
|
||||
|
||||
/*
|
||||
* Returns all player mobs in an assoc list with ckey as key and the mob as value
|
||||
*/
|
||||
/proc/get_assoc_mob_list_by_ckey()
|
||||
var/list/mob/mobs = list()
|
||||
for(var/i in GLOB.player_list)
|
||||
var/mob/M = i
|
||||
mobs[M.ckey] = M
|
||||
return mobs
|
||||
|
||||
/proc/flash_color(mob_or_client, flash_color="#960000", flash_time=20)
|
||||
var/client/C
|
||||
if(istype(mob_or_client, /mob))
|
||||
|
||||
@@ -34,4 +34,6 @@ GLOBAL_PROTECT(IClog)
|
||||
GLOBAL_LIST_EMPTY(OOClog)
|
||||
GLOBAL_PROTECT(OOClog)
|
||||
|
||||
GLOBAL_DATUM_INIT(logging, /datum/logging, new /datum/logging())
|
||||
|
||||
GLOBAL_LIST_INIT(investigate_log_subjects, list("notes", "watchlist", "hrefs"))
|
||||
|
||||
+83
-20
@@ -3,7 +3,7 @@
|
||||
//PUBLIC - call these wherever you want
|
||||
|
||||
|
||||
/mob/proc/throw_alert(category, type, severity, obj/new_master, override = FALSE)
|
||||
/mob/proc/throw_alert(category, type, severity, obj/new_master, override = FALSE, timeout_override, no_anim)
|
||||
|
||||
/*
|
||||
Proc to create or update an alert. Returns the alert if the alert is new or updated, 0 if it was thrown already
|
||||
@@ -59,14 +59,16 @@
|
||||
LAZYSET(alerts, category, alert) // This also creates the list if it doesn't exist
|
||||
if(client && hud_used)
|
||||
hud_used.reorganize_alerts()
|
||||
alert.transform = matrix(32, 6, MATRIX_TRANSLATE)
|
||||
animate(alert, transform = matrix(), time = 2.5, easing = CUBIC_EASING)
|
||||
|
||||
if(alert.timeout)
|
||||
spawn(alert.timeout)
|
||||
if(alert.timeout && alerts[category] == alert && world.time >= alert.timeout)
|
||||
clear_alert(category)
|
||||
alert.timeout = world.time + alert.timeout - world.tick_lag
|
||||
if(!no_anim)
|
||||
alert.transform = matrix(32, 6, MATRIX_TRANSLATE)
|
||||
animate(alert, transform = matrix(), time = 2.5, easing = CUBIC_EASING)
|
||||
|
||||
var/timeout = timeout_override || alert.timeout
|
||||
if(timeout)
|
||||
addtimer(CALLBACK(alert, /obj/screen/alert/.proc/do_timeout, src, category), timeout)
|
||||
alert.timeout = world.time + timeout - world.tick_lag
|
||||
|
||||
return alert
|
||||
|
||||
// Proc to clear an existing alert.
|
||||
@@ -94,7 +96,6 @@
|
||||
var/alerttooltipstyle = ""
|
||||
var/override_alerts = FALSE //If it is overriding other alerts of the same type
|
||||
|
||||
|
||||
/obj/screen/alert/MouseEntered(location,control,params)
|
||||
openToolTip(usr, src, params, title = name, content = desc, theme = alerttooltipstyle)
|
||||
|
||||
@@ -102,6 +103,12 @@
|
||||
/obj/screen/alert/MouseExited()
|
||||
closeToolTip(usr)
|
||||
|
||||
/obj/screen/alert/proc/do_timeout(mob/M, category)
|
||||
if(!M || !M.alerts)
|
||||
return
|
||||
|
||||
if(timeout && M.alerts[category] == src && world.time >= timeout)
|
||||
M.clear_alert(category)
|
||||
|
||||
//Gas alerts
|
||||
/obj/screen/alert/not_enough_oxy
|
||||
@@ -507,6 +514,34 @@ so as to remain in compliance with the most up-to-date laws."
|
||||
timeout = 300
|
||||
var/atom/target = null
|
||||
var/action = NOTIFY_JUMP
|
||||
var/show_time_left = FALSE // If true you need to call START_PROCESSING manually
|
||||
var/image/time_left_overlay // The last image showing the time left
|
||||
var/datum/candidate_poll/poll // If set, on Click() it'll register the player as a candidate
|
||||
|
||||
/obj/screen/alert/notify_action/process()
|
||||
if(show_time_left)
|
||||
var/timeleft = timeout - world.time
|
||||
if(timeleft <= 0)
|
||||
return PROCESS_KILL
|
||||
|
||||
if(time_left_overlay)
|
||||
overlays -= time_left_overlay
|
||||
|
||||
var/obj/O = new
|
||||
O.maptext = "<span style='font-family: \"Small Fonts\"; font-weight: bold; font-size: 32px; color: [(timeleft <= 10 SECONDS) ? "red" : "white"];'>[CEILING(timeleft / 10, 1)]</span>"
|
||||
O.maptext_width = O.maptext_height = 128
|
||||
var/matrix/M = new
|
||||
M.Translate(4, 16)
|
||||
O.transform = M
|
||||
|
||||
var/image/I = image(O)
|
||||
I.layer = FLOAT_LAYER
|
||||
I.plane = FLOAT_PLANE + 1
|
||||
overlays += I
|
||||
|
||||
time_left_overlay = I
|
||||
qdel(O)
|
||||
..()
|
||||
|
||||
/obj/screen/alert/notify_action/Destroy()
|
||||
target = null
|
||||
@@ -515,20 +550,48 @@ so as to remain in compliance with the most up-to-date laws."
|
||||
/obj/screen/alert/notify_action/Click()
|
||||
if(!usr || !usr.client)
|
||||
return
|
||||
if(!target)
|
||||
return
|
||||
var/mob/dead/observer/G = usr
|
||||
if(!istype(G))
|
||||
return
|
||||
switch(action)
|
||||
if(NOTIFY_ATTACK)
|
||||
target.attack_ghost(G)
|
||||
if(NOTIFY_JUMP)
|
||||
var/turf/T = get_turf(target)
|
||||
if(T && isturf(T))
|
||||
G.loc = T
|
||||
if(NOTIFY_FOLLOW)
|
||||
G.ManualFollow(target)
|
||||
|
||||
if(poll)
|
||||
if(poll.sign_up(G))
|
||||
// Add a small overlay to indicate we've signed up
|
||||
display_signed_up()
|
||||
else if(target)
|
||||
switch(action)
|
||||
if(NOTIFY_ATTACK)
|
||||
target.attack_ghost(G)
|
||||
if(NOTIFY_JUMP)
|
||||
var/turf/T = get_turf(target)
|
||||
if(T && isturf(T))
|
||||
G.loc = T
|
||||
if(NOTIFY_FOLLOW)
|
||||
G.ManualFollow(target)
|
||||
|
||||
/obj/screen/alert/notify_action/proc/display_signed_up()
|
||||
var/image/I = image('icons/mob/screen_gen.dmi', icon_state = "selector")
|
||||
I.layer = FLOAT_LAYER
|
||||
I.plane = FLOAT_PLANE + 2
|
||||
overlays += I
|
||||
|
||||
/obj/screen/alert/notify_action/proc/display_stacks(stacks = 1)
|
||||
if(stacks <= 1)
|
||||
return
|
||||
|
||||
var/obj/O = new
|
||||
O.maptext = "<span style='font-family: \"Small Fonts\"; font-size: 32px; color: yellow;'>[stacks]x</span>"
|
||||
O.maptext_width = O.maptext_height = 128
|
||||
var/matrix/M = new
|
||||
M.Translate(4, 2)
|
||||
O.transform = M
|
||||
|
||||
var/image/I = image(O)
|
||||
I.layer = FLOAT_LAYER
|
||||
I.plane = FLOAT_PLANE + 1
|
||||
overlays += I
|
||||
|
||||
qdel(O)
|
||||
|
||||
/obj/screen/alert/notify_soulstone
|
||||
name = "Soul Stone"
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
SUBSYSTEM_DEF(ghost_spawns)
|
||||
name = "Ghost Spawns"
|
||||
init_order = INIT_ORDER_EVENTS
|
||||
flags = SS_BACKGROUND
|
||||
wait = 1 SECONDS
|
||||
runlevels = RUNLEVEL_GAME
|
||||
offline_implications = "Ghosts will no longer be able to respawn as event mobs (Blob, etc..). Shuttle call recommended."
|
||||
|
||||
/// List of polls currently ongoing, to be checked on next fire()
|
||||
var/list/datum/candidate_poll/currently_polling
|
||||
/// Whether there are active polls or not
|
||||
var/polls_active = FALSE
|
||||
/// Number of polls performed since the start
|
||||
var/total_polls = 0
|
||||
/// The poll that's closest to finishing
|
||||
var/datum/candidate_poll/next_poll_to_finish
|
||||
|
||||
/datum/controller/subsystem/ghost_spawns/fire()
|
||||
if(!polls_active)
|
||||
return
|
||||
if(!currently_polling) // if polls_active is TRUE then this shouldn't happen, but still..
|
||||
currently_polling = list()
|
||||
|
||||
for(var/poll in currently_polling)
|
||||
var/datum/candidate_poll/P = poll
|
||||
if(P.time_left() <= 0)
|
||||
polling_finished(P)
|
||||
|
||||
/**
|
||||
* Polls for candidates with a question and a preview of the role
|
||||
*
|
||||
* This proc replaces /proc/pollCandidates.
|
||||
* Should NEVER be used in a proc that has waitfor set to FALSE/0 (due to #define UNTIL)
|
||||
* Arguments:
|
||||
* * question - The question to ask to potential candidates
|
||||
* * role - The role to poll for. Should be a ROLE_x enum. If set, potential candidates who aren't eligible will be ignored
|
||||
* * antag_age_check - Whether to filter out potential candidates who don't have an old enough account
|
||||
* * poll_time - How long to poll for in deciseconds
|
||||
* * ignore_respawnability - Whether to ignore the player's respawnability
|
||||
* * min_hours - The amount of hours needed for a potential candidate to be eligible
|
||||
* * flash_window - Whether the poll should flash a potential candidate's game window
|
||||
* * check_antaghud - Whether to filter out potential candidates who enabled AntagHUD
|
||||
* * source - The atom, atom prototype, icon or mutable appearance to display as an icon in the alert
|
||||
*/
|
||||
/datum/controller/subsystem/ghost_spawns/proc/poll_candidates(question = "Would you like to play a special role?", role, antag_age_check = FALSE, poll_time = 30 SECONDS, ignore_respawnability = FALSE, min_hours = 0, flash_window = TRUE, check_antaghud = TRUE, source)
|
||||
log_debug("Polling candidates [role ? "for [get_roletext(role)]" : "\"[question]\""] for [poll_time / 10] seconds")
|
||||
|
||||
// Start firing
|
||||
polls_active = TRUE
|
||||
total_polls++
|
||||
|
||||
var/datum/candidate_poll/P = new(role, question, poll_time)
|
||||
LAZYADD(currently_polling, P)
|
||||
|
||||
// We're the poll closest to completion
|
||||
if(!next_poll_to_finish || poll_time < next_poll_to_finish.time_left())
|
||||
next_poll_to_finish = P
|
||||
|
||||
var/category = "[P.hash]_notify_action"
|
||||
|
||||
for(var/mob/dead/observer/M in (ignore_respawnability ? GLOB.player_list : GLOB.respawnable_list))
|
||||
if(!is_eligible(M))
|
||||
continue
|
||||
|
||||
SEND_SOUND(M, 'sound/misc/notice2.ogg')
|
||||
if(flash_window)
|
||||
window_flash(M.client)
|
||||
|
||||
// If we somehow send two polls for the same mob type, but with a duration on the second one shorter than the time left on the first one,
|
||||
// we need to keep the first one's timeout rather than use the shorter one
|
||||
var/obj/screen/alert/notify_action/current_alert = LAZYACCESS(M.alerts, category)
|
||||
var/alert_time = poll_time
|
||||
var/alert_poll = P
|
||||
if(current_alert && current_alert.timeout > (world.time + poll_time - world.tick_lag))
|
||||
alert_time = current_alert.timeout - world.time + world.tick_lag
|
||||
alert_poll = current_alert.poll
|
||||
|
||||
// Send them an on-screen alert
|
||||
var/obj/screen/alert/notify_action/A = M.throw_alert(category, /obj/screen/alert/notify_action, timeout_override = alert_time, no_anim = TRUE)
|
||||
if(!A)
|
||||
continue
|
||||
|
||||
A.icon = ui_style2icon(M.client?.prefs.UI_style)
|
||||
A.name = "Looking for candidates"
|
||||
A.desc = "[question]\n\n(expires in [poll_time / 10] seconds)"
|
||||
A.show_time_left = TRUE
|
||||
A.poll = alert_poll
|
||||
|
||||
// Sign up inheritance and stacking
|
||||
var/inherited_sign_up = FALSE
|
||||
var/num_stack = 1
|
||||
for(var/existing_poll in currently_polling)
|
||||
var/datum/candidate_poll/P2 = existing_poll
|
||||
if(P != P2 && P.hash == P2.hash)
|
||||
// If there's already a poll for an identical mob type ongoing and the client is signed up for it, sign them up for this one
|
||||
if(!inherited_sign_up && (M in P2.signed_up) && P.sign_up(M, TRUE))
|
||||
A.display_signed_up()
|
||||
inherited_sign_up = TRUE
|
||||
// This number is used to display the number of polls the alert regroups
|
||||
num_stack++
|
||||
if(num_stack > 1)
|
||||
A.display_stacks(num_stack)
|
||||
|
||||
// Image to display
|
||||
var/image/I
|
||||
if(source)
|
||||
if(!ispath(source))
|
||||
var/atom/S = source
|
||||
var/old_layer = S.layer
|
||||
var/old_plane = S.plane
|
||||
|
||||
S.layer = FLOAT_LAYER
|
||||
S.plane = FLOAT_PLANE
|
||||
A.overlays += S
|
||||
S.layer = old_layer
|
||||
S.plane = old_plane
|
||||
else
|
||||
I = image(source, layer = FLOAT_LAYER, dir = SOUTH)
|
||||
else
|
||||
// Just use a generic image
|
||||
I = image('icons/effects/effects.dmi', icon_state = "static", layer = FLOAT_LAYER, dir = SOUTH)
|
||||
|
||||
if(I)
|
||||
I.layer = FLOAT_LAYER
|
||||
I.plane = FLOAT_PLANE
|
||||
A.overlays += I
|
||||
|
||||
// Start processing it so it updates visually the timer
|
||||
START_PROCESSING(SSprocessing, A)
|
||||
A.process()
|
||||
|
||||
// Sleep until the time is up
|
||||
UNTIL(P.finished)
|
||||
return P.signed_up
|
||||
|
||||
/**
|
||||
* Returns whether an observer is eligible to be an event mob
|
||||
*
|
||||
* Arguments:
|
||||
* * M - The mob to check eligibility
|
||||
* * role - The role to check eligibility for. Checks 1. the client has enabled the role 2. the account's age for this role if antag_age_check is TRUE
|
||||
* * antag_age_check - Whether to check the account's age or not for the given role.
|
||||
* * role_text - The role's clean text. Used for checking job bans to determine eligibility
|
||||
* * min_hours - The amount of minimum hours the client needs before being eligible
|
||||
* * check_antaghud - Whether to consider a client who enabled AntagHUD ineligible or not
|
||||
*/
|
||||
/datum/controller/subsystem/ghost_spawns/proc/is_eligible(mob/M, role, antag_age_check, role_text, min_hours, check_antaghud)
|
||||
. = FALSE
|
||||
if(!M.key || !M.client)
|
||||
return
|
||||
if(role)
|
||||
if(!(role in M.client.prefs.be_special))
|
||||
return
|
||||
if(antag_age_check)
|
||||
if(!player_old_enough_antag(M.client, role))
|
||||
return
|
||||
if(role_text)
|
||||
if(jobban_isbanned(M, role_text) || jobban_isbanned(M, "Syndicate"))
|
||||
return
|
||||
if(config.use_exp_restrictions && min_hours)
|
||||
if(M.client.get_exp_type_num(EXP_TYPE_LIVING) < min_hours * 60)
|
||||
return
|
||||
if(check_antaghud && cannotPossess(M))
|
||||
return
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Called by the subsystem when a poll's timer runs out
|
||||
*
|
||||
* Can be called manually to finish a poll prematurely
|
||||
* Arguments:
|
||||
* * P - The poll to finish
|
||||
*/
|
||||
/datum/controller/subsystem/ghost_spawns/proc/polling_finished(datum/candidate_poll/P)
|
||||
// Trim players who aren't eligible anymore
|
||||
var/len_pre_trim = length(P.signed_up)
|
||||
P.trim_candidates()
|
||||
log_debug("Candidate poll [P.role ? "for [get_roletext(P.role)]" : "\"[P.question]\""] finished. [len_pre_trim] players signed up, [length(P.signed_up)] after trimming")
|
||||
|
||||
P.finished = TRUE
|
||||
currently_polling -= P
|
||||
|
||||
// Determine which is the next poll closest the completion or "disable" firing if there's none
|
||||
if(!length(currently_polling))
|
||||
polls_active = FALSE
|
||||
next_poll_to_finish = null
|
||||
else if(P == next_poll_to_finish)
|
||||
next_poll_to_finish = null
|
||||
for(var/poll in currently_polling)
|
||||
var/datum/candidate_poll/P2 = poll
|
||||
if(!next_poll_to_finish || P2.time_left() < next_poll_to_finish.time_left())
|
||||
next_poll_to_finish = P2
|
||||
|
||||
/datum/controller/subsystem/ghost_spawns/stat_entry(msg)
|
||||
msg += "Active: [length(currently_polling)] | Total: [total_polls]"
|
||||
if(next_poll_to_finish)
|
||||
msg += " | Next: [DisplayTimeText(next_poll_to_finish.time_left())] ([length(next_poll_to_finish.signed_up)] candidates)"
|
||||
..(msg)
|
||||
|
||||
// The datum that describes one instance of candidate polling
|
||||
/datum/candidate_poll
|
||||
var/role // The role the poll is for
|
||||
var/question // The question asked to observers
|
||||
var/duration // The duration of the poll
|
||||
var/list/mob/dead/observer/signed_up // The players who signed up to this poll
|
||||
var/time_started // The world.time at which the poll was created
|
||||
var/finished = FALSE // Whether the polling is finished
|
||||
var/hash // Used to categorize in the alerts system
|
||||
|
||||
/datum/candidate_poll/New(polled_role, polled_question, poll_duration)
|
||||
role = polled_role
|
||||
question = polled_question
|
||||
duration = poll_duration
|
||||
signed_up = list()
|
||||
time_started = world.time
|
||||
hash = copytext(md5("[question]_[role ? role : "0"]"), 1, 7)
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Attempts to sign a (controlled) mob up
|
||||
*
|
||||
* Will fail if the mob is already signed up or the poll's timer ran out.
|
||||
* Does not check for eligibility
|
||||
* Arguments:
|
||||
* * M - The (controlled) mob to sign up
|
||||
* * silent - Whether no messages should appear or not. If not TRUE, signing up to this poll will also sign the mob up for identical polls
|
||||
*/
|
||||
/datum/candidate_poll/proc/sign_up(mob/dead/observer/M, silent = FALSE)
|
||||
. = FALSE
|
||||
if(!istype(M) || !M.key || !M.client)
|
||||
return
|
||||
if(M in signed_up)
|
||||
if(!silent)
|
||||
to_chat(M, "<span class='warning'>You have already signed up for this!</span>")
|
||||
return
|
||||
if(time_left() <= 0)
|
||||
if(!silent)
|
||||
to_chat(M, "<span class='danger'>Sorry, you were too late for the consideration!</span>")
|
||||
SEND_SOUND(M, 'sound/machines/buzz-sigh.ogg')
|
||||
return
|
||||
|
||||
signed_up += M
|
||||
if(!silent)
|
||||
to_chat(M, "<span class='notice'>You have signed up for this role! A candidate will be picked randomly soon..</span>")
|
||||
// Sign them up for any other polls with the same mob type
|
||||
for(var/existing_poll in SSghost_spawns.currently_polling)
|
||||
var/datum/candidate_poll/P = existing_poll
|
||||
if(src != P && hash == P.hash && !(M in P.signed_up))
|
||||
P.sign_up(M, TRUE)
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Deletes any candidates who may have disconnected from the list
|
||||
*/
|
||||
/datum/candidate_poll/proc/trim_candidates()
|
||||
listclearnulls(signed_up)
|
||||
for(var/mob in signed_up)
|
||||
var/mob/M = mob
|
||||
if(!M.key || !M.client)
|
||||
signed_up -= M
|
||||
|
||||
/**
|
||||
* Returns the time left for a poll
|
||||
*/
|
||||
/datum/candidate_poll/proc/time_left()
|
||||
return duration - (world.time - time_started)
|
||||
@@ -27,7 +27,7 @@ SUBSYSTEM_DEF(jobs)
|
||||
/datum/controller/subsystem/jobs/fire()
|
||||
if(!config.sql_enabled || !config.use_exp_tracking)
|
||||
return
|
||||
update_exp(5,0)
|
||||
INVOKE_ASYNC(GLOBAL_PROC, /.proc/update_exp, 5, 0)
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/SetupOccupations(var/list/faction = list("Station"))
|
||||
occupations = list()
|
||||
@@ -644,6 +644,27 @@ SUBSYSTEM_DEF(jobs)
|
||||
oldjobdatum.current_positions--
|
||||
newjobdatum.current_positions++
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/notify_dept_head(jobtitle, antext)
|
||||
// Used to notify the department head of jobtitle X that their employee was brigged, demoted or terminated
|
||||
if(!jobtitle || !antext)
|
||||
return
|
||||
var/datum/job/tgt_job = GetJob(jobtitle)
|
||||
if(!tgt_job)
|
||||
return
|
||||
if(!tgt_job.department_head[1])
|
||||
return
|
||||
var/boss_title = tgt_job.department_head[1]
|
||||
var/obj/item/pda/target_pda
|
||||
for(var/obj/item/pda/check_pda in GLOB.PDAs)
|
||||
if(check_pda.ownrank == boss_title)
|
||||
target_pda = check_pda
|
||||
break
|
||||
if(!target_pda)
|
||||
return
|
||||
var/datum/data/pda/app/messenger/PM = target_pda.find_program(/datum/data/pda/app/messenger)
|
||||
if(PM && PM.can_receive())
|
||||
PM.notify("<b>Automated Notification: </b>\"[antext]\" (Unable to Reply)")
|
||||
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/fetch_transfer_record_html(var/centcom)
|
||||
var/record_html = "<TABLE border=\"1\">"
|
||||
|
||||
@@ -61,7 +61,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
if(GAME_STATE_STARTUP)
|
||||
// This is ran as soon as the MC starts firing, and should only run ONCE, unless startup fails
|
||||
round_start_time = world.time + (config.pregame_timestart * 10)
|
||||
to_chat(world, "<B><FONT color='blue'>Welcome to the pre-game lobby!</FONT></B>")
|
||||
to_chat(world, "<B><span class='darkmblue'>Welcome to the pre-game lobby!</span></B>")
|
||||
to_chat(world, "Please, setup your character and select ready. Game will start in [config.pregame_timestart] seconds")
|
||||
current_state = GAME_STATE_PREGAME
|
||||
fire() // TG says this is a good idea
|
||||
@@ -217,11 +217,11 @@ SUBSYSTEM_DEF(ticker)
|
||||
for(var/obj/effect/landmark/spacepod/random/R in L)
|
||||
qdel(R)
|
||||
|
||||
to_chat(world, "<FONT color='blue'><B>Enjoy the game!</B></FONT>")
|
||||
to_chat(world, "<span class='darkmblue'><B>Enjoy the game!</B></span>")
|
||||
world << sound('sound/AI/welcome.ogg')// Skie
|
||||
|
||||
if(SSholiday.holidays)
|
||||
to_chat(world, "<font color='blue'>and...</font>")
|
||||
to_chat(world, "<span class='darkmblue'>and...</span>")
|
||||
for(var/holidayname in SSholiday.holidays)
|
||||
var/datum/holiday/holiday = SSholiday.holidays[holidayname]
|
||||
to_chat(world, "<h4>[holiday.greet()]</h4>")
|
||||
|
||||
@@ -6,17 +6,23 @@ GLOBAL_REAL(SSmentor_tickets, /datum/controller/subsystem/tickets/mentor_tickets
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets
|
||||
name = "Mentor Tickets"
|
||||
offline_implications = "Mentor tickets will no longer be marked as stale. No immediate action is needed."
|
||||
ticket_system_name = "Mentor Tickets"
|
||||
ticket_name = "Mentor Ticket"
|
||||
span_class = "mentorhelp"
|
||||
other_ticket_name = "Admin"
|
||||
other_ticket_permission = R_ADMIN
|
||||
close_rights = R_MENTOR | R_ADMIN
|
||||
offline_implications = "Mentor tickets will no longer be marked as stale. No immediate action is needed."
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets/message_staff(var/msg)
|
||||
message_mentorTicket(msg)
|
||||
rights_needed = R_MENTOR | R_ADMIN | R_MOD
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets/Initialize()
|
||||
close_messages = list("<font color='red' size='3'><b>- [ticket_name] Closed -</b></font>",
|
||||
"<span class='boldmessage'>Please try to be as descriptive as possible in mentor helps. Mentors do not know the full situation you're in and need more information to give you a helpful response.</span>",
|
||||
"<span class='[span_class]'>Your [ticket_name] has now been closed.</span>")
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets/message_staff(msg)
|
||||
message_mentorTicket(msg)
|
||||
|
||||
/datum/controller/subsystem/tickets/mentor_tickets/create_other_system_ticket(datum/ticket/T)
|
||||
SStickets.newTicket(T.clientName, T.content, T.title)
|
||||
|
||||
@@ -12,18 +12,23 @@
|
||||
|
||||
SUBSYSTEM_DEF(tickets)
|
||||
name = "Admin Tickets"
|
||||
var/span_class = "adminticket"
|
||||
var/ticket_system_name = "Admin Tickets"
|
||||
var/ticket_name = "Admin Ticket"
|
||||
var/close_rights = R_ADMIN
|
||||
var/list/close_messages
|
||||
init_order = INIT_ORDER_TICKETS
|
||||
wait = 300
|
||||
priority = FIRE_PRIORITY_TICKETS
|
||||
offline_implications = "Admin tickets will no longer be marked as stale. No immediate action is needed."
|
||||
|
||||
flags = SS_BACKGROUND
|
||||
|
||||
var/span_class = "adminticket"
|
||||
var/ticket_system_name = "Admin Tickets"
|
||||
var/ticket_name = "Admin Ticket"
|
||||
var/close_rights = R_ADMIN
|
||||
var/rights_needed = R_ADMIN | R_MOD
|
||||
|
||||
/// The name of the other ticket type to convert to
|
||||
var/other_ticket_name = "Mentor"
|
||||
/// Which permission to look for when seeing if there is staff available for the other ticket type
|
||||
var/other_ticket_permission = R_MENTOR
|
||||
var/list/close_messages
|
||||
var/list/allTickets = list() //make it here because someone might ahelp before the system has initialized
|
||||
|
||||
var/ticketCounter = 1
|
||||
@@ -114,9 +119,37 @@ SUBSYSTEM_DEF(tickets)
|
||||
to_chat_safe(returnClient(N), "<span class='[span_class]'>Your [ticket_name] has now been resolved.</span>")
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/tickets/proc/convert_to_other_ticket(ticketId)
|
||||
if(!check_rights(rights_needed))
|
||||
return
|
||||
if(alert("Are you sure to convert this ticket to an '[other_ticket_name]' ticket?",,"Yes","No") != "Yes")
|
||||
return
|
||||
if(!other_ticket_system_staff_check())
|
||||
return
|
||||
var/datum/ticket/T = allTickets[ticketId]
|
||||
convert_ticket(T)
|
||||
|
||||
/datum/controller/subsystem/tickets/proc/other_ticket_system_staff_check()
|
||||
var/list/staff = staff_countup(other_ticket_permission)
|
||||
if(!staff[1])
|
||||
if(alert("No active staff online to answer the ticket. Are you sure you want to convert the ticket?",, "No", "Yes") != "Yes")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/tickets/proc/convert_ticket(datum/ticket/T)
|
||||
T.ticketState = TICKET_CLOSED
|
||||
var/client/C = usr.client
|
||||
to_chat_safe(T.clientName, list("<span class='[span_class]'>[key_name_hidden(C)] has converted your ticket to a [other_ticket_name] ticket.</span>",\
|
||||
"<span class='[span_class]'>Be sure to use the correct type of help next time!</span>"))
|
||||
message_staff("<span class='[span_class]'>[C] has converted ticket number [T.ticketNum] to a [other_ticket_name] ticket.</span>")
|
||||
log_game("[C] has converted ticket number [T.ticketNum] to a [other_ticket_name] ticket.")
|
||||
create_other_system_ticket(T)
|
||||
|
||||
/datum/controller/subsystem/tickets/proc/create_other_system_ticket(datum/ticket/T)
|
||||
SSmentor_tickets.newTicket(T.clientName, T.content, T.title)
|
||||
|
||||
/datum/controller/subsystem/tickets/proc/autoRespond(N)
|
||||
if(!check_rights(R_ADMIN|R_MOD))
|
||||
if(!check_rights(rights_needed))
|
||||
return
|
||||
|
||||
var/datum/ticket/T = allTickets[N]
|
||||
@@ -158,14 +191,17 @@ SUBSYSTEM_DEF(tickets)
|
||||
resolveTicket(N)
|
||||
message_staff("[C] has auto responded to [T.clientName]\'s adminhelp with:<span class='adminticketalt'> [message_key] </span>")
|
||||
log_game("[C] has auto responded to [T.clientName]\'s adminhelp with: [response_phrases[message_key]]")
|
||||
if("Mentorhelp")
|
||||
convert_ticket(T)
|
||||
else
|
||||
var/msg_sound = sound('sound/effects/adminhelp.ogg')
|
||||
SEND_SOUND(returnClient(N), msg_sound)
|
||||
to_chat(returnClient(N), "<span class='[span_class]'>[key_name_hidden(C)] is autoresponding with: <span/> <span class='adminticketalt'>[response_phrases[message_key]]</span>")//for this we want the full value of whatever key this is to tell the player so we do response_phrases[message_key]
|
||||
to_chat_safe(returnClient(N), "<span class='[span_class]'>[key_name_hidden(C)] is autoresponding with: <span/> <span class='adminticketalt'>[response_phrases[message_key]]</span>")//for this we want the full value of whatever key this is to tell the player so we do response_phrases[message_key]
|
||||
message_staff("[C] has auto responded to [T.clientName]\'s adminhelp with:<span class='adminticketalt'> [message_key] </span>") //we want to use the short named keys for this instead of the full sentence which is why we just do message_key
|
||||
T.lastStaffResponse = "Autoresponse: [message_key]"
|
||||
resolveTicket(N)
|
||||
log_game("[C] has auto responded to [T.clientName]\'s adminhelp with: [response_phrases[message_key]]")
|
||||
|
||||
//Set ticket state with key N to closed
|
||||
/datum/controller/subsystem/tickets/proc/closeTicket(N)
|
||||
var/datum/ticket/T = allTickets[N]
|
||||
@@ -353,7 +389,7 @@ UI STUFF
|
||||
dat += "<tr><td>[T.content[i]]</td></tr>"
|
||||
|
||||
dat += "</table><br /><br />"
|
||||
dat += "<a href='?src=[UID()];detailreopen=[T.ticketNum]'>Re-Open</a>[check_rights(R_ADMIN|R_MOD, 0) ? "<a href='?src=[UID()];autorespond=[T.ticketNum]'>Auto</a>": ""]<a href='?src=[UID()];detailresolve=[T.ticketNum]'>Resolve</a><br /><br />"
|
||||
dat += "<a href='?src=[UID()];detailreopen=[T.ticketNum]'>Re-Open</a>[check_rights(rights_needed, 0) ? "<a href='?src=[UID()];autorespond=[T.ticketNum]'>Auto</a>": ""]<a href='?src=[UID()];detailresolve=[T.ticketNum]'>Resolve</a><br /><br />"
|
||||
|
||||
if(!T.staffAssigned)
|
||||
dat += "No staff member assigned to this [ticket_name] - <a href='?src=[UID()];assignstaff=[T.ticketNum]'>Take Ticket</a><br />"
|
||||
@@ -368,6 +404,7 @@ UI STUFF
|
||||
dat += "<br /><br />"
|
||||
|
||||
dat += "<a href='?src=[UID()];detailclose=[T.ticketNum]'>Close Ticket</a>"
|
||||
dat += "<a href='?src=[UID()];convert_ticket=[T.ticketNum]'>Convert Ticket</a>"
|
||||
|
||||
var/datum/browser/popup = new(user, "[ticket_system_name]detail", "[ticket_system_name] #[T.ticketNum]", 1000, 600)
|
||||
popup.set_content(dat)
|
||||
@@ -450,7 +487,6 @@ UI STUFF
|
||||
if(closeTicket(indexNum))
|
||||
showDetailUI(usr, indexNum)
|
||||
|
||||
|
||||
if(href_list["detailreopen"])
|
||||
var/indexNum = text2num(href_list["detailreopen"])
|
||||
if(openTicket(indexNum))
|
||||
@@ -470,6 +506,10 @@ UI STUFF
|
||||
var/indexNum = text2num(href_list["autorespond"])
|
||||
autoRespond(indexNum)
|
||||
|
||||
if(href_list["convert_ticket"])
|
||||
var/indexNum = text2num(href_list["convert_ticket"])
|
||||
convert_to_other_ticket(indexNum)
|
||||
|
||||
if(href_list["resolveall"])
|
||||
if(ticket_system_name == "Mentor Tickets")
|
||||
usr.client.resolveAllMentorTickets()
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
set name = "Restart Controller"
|
||||
set desc = "Restart one of the various periodic loop controllers for the game (be careful!)"
|
||||
|
||||
if(!holder)
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
switch(controller)
|
||||
if("Master")
|
||||
@@ -26,7 +26,8 @@
|
||||
set name = "Debug Controller"
|
||||
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
|
||||
|
||||
if(!holder) return
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
switch(controller)
|
||||
if("failsafe")
|
||||
debug_variables(Failsafe)
|
||||
|
||||
+65
-20
@@ -1,16 +1,23 @@
|
||||
#define ALL_LOGS list(ATTACK_LOG, DEFENSE_LOG, CONVERSION_LOG, SAY_LOG, EMOTE_LOG, MISC_LOG)
|
||||
#define UPDATE_CKEY_MOB(__ckey) var/mob/result = selected_ckeys_mobs[__ckey];\
|
||||
if(!result || result.ckey != __ckey){\
|
||||
result = get_mob_by_ckey(__ckey);\
|
||||
selected_ckeys_mobs[__ckey] = result;\
|
||||
}
|
||||
|
||||
/datum/log_viewer
|
||||
var/time_from = 0
|
||||
var/time_to = 4 HOURS // 4 Hours should be enough. INFINITY would screw the UI up
|
||||
var/list/selected_mobs = list() // The mobs in question
|
||||
var/list/selected_mobs = list() // The mobs in question.
|
||||
var/list/selected_ckeys = list() // The ckeys selected to search for. Will show all mobs the ckey is attached to
|
||||
var/list/mob/selected_ckeys_mobs = list()
|
||||
var/list/selected_log_types = ALL_LOGS // The log types being searched for
|
||||
|
||||
var/list/log_records = list() // Found and sorted records
|
||||
|
||||
/datum/log_viewer/proc/clear_all()
|
||||
selected_mobs.Cut()
|
||||
selected_log_types = ALL_LOGS
|
||||
selected_ckeys.Cut()
|
||||
selected_ckeys_mobs.Cut()
|
||||
time_from = initial(time_from)
|
||||
time_to = initial(time_to)
|
||||
log_records.Cut()
|
||||
@@ -19,13 +26,17 @@
|
||||
/datum/log_viewer/proc/search()
|
||||
log_records.Cut() // Empty the old results
|
||||
var/list/invalid_mobs = list()
|
||||
var/list/ckeys = selected_ckeys.Copy()
|
||||
for(var/i in selected_mobs)
|
||||
var/mob/M = i
|
||||
if(!M || QDELETED(M))
|
||||
if(!M || QDELETED(M) || !M.last_known_ckey)
|
||||
invalid_mobs |= M
|
||||
continue
|
||||
ckeys |= M.last_known_ckey
|
||||
|
||||
for(var/ckey in ckeys)
|
||||
for(var/log_type in selected_log_types)
|
||||
var/list/logs = M.logs[log_type]
|
||||
var/list/logs = GLOB.logging.get_logs_by_type(ckey, log_type)
|
||||
var/len_logs = length(logs)
|
||||
if(len_logs)
|
||||
var/start_index = get_earliest_log_index(logs)
|
||||
@@ -95,13 +106,19 @@
|
||||
if(!mobs?.len)
|
||||
return
|
||||
for(var/i in mobs)
|
||||
var/mob/M = i
|
||||
if(istype(M))
|
||||
selected_mobs |= M
|
||||
add_mob(usr, i, FALSE)
|
||||
|
||||
/datum/log_viewer/proc/add_mob(mob/user, mob/M)
|
||||
/datum/log_viewer/proc/add_ckey(mob/user, ckey)
|
||||
if(!user || !user)
|
||||
return
|
||||
selected_ckeys |= ckey
|
||||
UPDATE_CKEY_MOB(ckey)
|
||||
show_ui(user)
|
||||
|
||||
/datum/log_viewer/proc/add_mob(mob/user, mob/M, show_the_ui = TRUE)
|
||||
if(!M || !user)
|
||||
return
|
||||
|
||||
selected_mobs |= M
|
||||
|
||||
show_ui(user)
|
||||
@@ -112,7 +129,7 @@
|
||||
var/trStyle = "border-top:1px solid; border-bottom:1px solid; padding-top: 5px; padding-bottom: 5px;"
|
||||
var/dat
|
||||
dat += "<head><meta http-equiv='X-UA-Compatible' content='IE=edge'><style>.adminticket{border:2px solid} td{border:1px solid grey;} th{border:1px solid grey;} span{float:left;width:150px;}</style></head>"
|
||||
dat += "<div style='min-height:95px'>"
|
||||
dat += "<div style='min-height:100px'>"
|
||||
dat += "<span>Time Search Range:</span> <a href='?src=[UID()];start_time=1'>[gameTimestamp(wtime = time_from)]</a>"
|
||||
dat += " To: <a href='?src=[UID()];end_time=1'>[gameTimestamp(wtime = time_to)]</a>"
|
||||
dat += "<BR>"
|
||||
@@ -125,19 +142,24 @@
|
||||
continue
|
||||
dat += "<a href='?src=[UID()];remove_mob=\ref[M]'>[get_display_name(M)]</a>"
|
||||
dat += "<a href='?src=[UID()];add_mob=1'>Add Mob</a>"
|
||||
dat += "<a href='?src=[UID()];add_mob_ckey=1'>Add Mob (by ckey)</a>"
|
||||
dat += "<a href='?src=[UID()];clear_mobs=1'>Clear All Mobs</a>"
|
||||
dat += "<BR>"
|
||||
|
||||
dat += "<span>Ckeys being used:</span>"
|
||||
for(var/ckey in selected_ckeys)
|
||||
dat += "<a href='?src=[UID()];remove_ckey=[ckey]'>[get_ckey_name(ckey)]</a>"
|
||||
dat += "<a href='?src=[UID()];add_ckey=1'>Add ckey</a>"
|
||||
dat += "<a href='?src=[UID()];clear_ckeys=1'>Clear All ckeys</a>"
|
||||
dat += "<BR>"
|
||||
|
||||
dat += "<span>Log Types:</span>"
|
||||
for(var/i in all_log_types)
|
||||
var/log_type = i
|
||||
for(var/log_type in all_log_types)
|
||||
var/enabled = (log_type in selected_log_types)
|
||||
var/text
|
||||
var/style
|
||||
if(enabled)
|
||||
text = "<b>[log_type]</b>"
|
||||
style = "background: [get_logtype_color(i)]"
|
||||
style = "background: [get_logtype_color(log_type)]"
|
||||
else
|
||||
text = log_type
|
||||
|
||||
@@ -153,7 +175,7 @@
|
||||
var/tdStyleType = "width:80px; text-align:center;"
|
||||
var/tdStyleWho = "width:400px; text-align:center;"
|
||||
var/tdStyleWhere = "width:150px; text-align:center;"
|
||||
dat += "<div style='overflow-y: auto; max-height:calc(100vh - 145px);'>"
|
||||
dat += "<div style='overflow-y: auto; max-height:calc(100vh - 150px);'>"
|
||||
dat += "<table style='width:100%; border: 1px solid;'>"
|
||||
dat += "<tr style='[trStyleTop]'><th style='[tdStyleTime]'>When</th><th style='[tdStyleType]'>Type</th><th style='[tdStyleWho]'>Who</th><th>What</th><th>Target</th><th style='[tdStyleWhere]'>Where</th></tr>"
|
||||
for(var/i in log_records)
|
||||
@@ -207,15 +229,20 @@
|
||||
selected_mobs.Cut()
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["clear_ckeys"])
|
||||
selected_ckeys.Cut()
|
||||
selected_ckeys_mobs.Cut()
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["add_mob"])
|
||||
var/list/mobs = getpois(TRUE, TRUE)
|
||||
var/datum/async_input/A = input_autocomplete_async(usr, "Please, select a mob: ", mobs)
|
||||
A.on_close(CALLBACK(src, .proc/add_mob, usr))
|
||||
return
|
||||
if(href_list["add_mob_ckey"])
|
||||
var/list/mobs = get_assoc_mob_list_by_ckey()
|
||||
var/datum/async_input/A = input_autocomplete_async(usr, "Please, select a ckey: ", mobs)
|
||||
A.on_close(CALLBACK(src, .proc/add_mob, usr))
|
||||
if(href_list["add_ckey"])
|
||||
var/list/ckeys = GLOB.logging.get_ckeys_logged()
|
||||
var/datum/async_input/A = input_autocomplete_async(usr, "Please, select a ckey: ", ckeys)
|
||||
A.on_close(CALLBACK(src, .proc/add_ckey, usr))
|
||||
return
|
||||
if(href_list["remove_mob"])
|
||||
var/mob/M = locate(href_list["remove_mob"])
|
||||
@@ -223,6 +250,10 @@
|
||||
selected_mobs -= M
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["remove_ckey"])
|
||||
selected_ckeys -= href_list["remove_ckey"]
|
||||
show_ui(usr)
|
||||
return
|
||||
if(href_list["toggle_log_type"])
|
||||
var/log_type = href_list["toggle_log_type"]
|
||||
if(log_type in selected_log_types)
|
||||
@@ -246,6 +277,12 @@
|
||||
return "deepskyblue"
|
||||
if(MISC_LOG)
|
||||
return "gray"
|
||||
if(DEADCHAT_LOG)
|
||||
return "#cc00c6"
|
||||
if(OOC_LOG)
|
||||
return "#002eb8"
|
||||
if(LOOC_LOG)
|
||||
return "#6699CC"
|
||||
return "slategray"
|
||||
|
||||
/datum/log_viewer/proc/get_display_name(mob/M)
|
||||
@@ -254,4 +291,12 @@
|
||||
name = "[name] ([M.real_name])"
|
||||
if(isobserver(M))
|
||||
name = "[name] (DEAD)"
|
||||
return name
|
||||
return "\[[M.last_known_ckey]\] [name]"
|
||||
|
||||
/datum/log_viewer/proc/get_ckey_name(ckey)
|
||||
UPDATE_CKEY_MOB(ckey)
|
||||
var/mob/M = selected_ckeys_mobs[ckey]
|
||||
|
||||
return get_display_name(M)
|
||||
|
||||
#undef UPDATE_CKEY_MOB
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/datum/logging
|
||||
var/list/datum/log_record/logs = list() // Assoc list of assoc lists (ckey, (log_type, list/logs))
|
||||
|
||||
/datum/logging/proc/add_log(ckey, datum/log_record/log)
|
||||
if(!ckey)
|
||||
log_debug("GLOB.logging.add_log called with an invalid ckey")
|
||||
return
|
||||
|
||||
if(!logs[ckey])
|
||||
logs[ckey] = list()
|
||||
|
||||
var/list/log_types_list = logs[ckey]
|
||||
|
||||
if(!log_types_list[log.log_type])
|
||||
log_types_list[log.log_type] = list()
|
||||
|
||||
var/list/datum/log_record/log_records = log_types_list[log.log_type]
|
||||
log_records.Add(log)
|
||||
|
||||
/datum/logging/proc/get_ckeys_logged()
|
||||
var/list/ckeys = list()
|
||||
for(var/ckey in logs)
|
||||
ckeys.Add(ckey)
|
||||
return ckeys
|
||||
|
||||
/* Returns the logs of a given ckey and log_type
|
||||
* If no logs exist it will return an empty list
|
||||
*/
|
||||
/datum/logging/proc/get_logs_by_type(ckey, log_type)
|
||||
if(!ckey)
|
||||
log_debug("GLOB.logging.get_logs_by_type called with an invalid ckey")
|
||||
return
|
||||
if(!log_type || !(log_type in ALL_LOGS))
|
||||
log_debug("GLOB.logging.get_logs_by_type called with an invalid log_type '[log_type]'")
|
||||
return
|
||||
|
||||
var/list/log_types_list = logs[ckey]
|
||||
// Check if logs exist for the ckey
|
||||
if(!length(log_types_list))
|
||||
return list()
|
||||
|
||||
var/list/datum/log_record/log_records = log_types_list[log_type]
|
||||
|
||||
// Check if logs exist for this type
|
||||
if(!log_records)
|
||||
return list()
|
||||
return log_records
|
||||
@@ -100,14 +100,6 @@
|
||||
current.mind = null
|
||||
leave_all_huds() //leave all the huds in the old body, so it won't get huds if somebody else enters it
|
||||
|
||||
for(var/log_type in current.logs) // Copy the old logs
|
||||
var/list/logs = current.logs[log_type]
|
||||
if(new_character.logs[log_type])
|
||||
new_character.logs[log_type] += logs.Copy() // Append the old ones
|
||||
new_character.logs[log_type] = sortTim(new_character.logs[log_type], /proc/compare_log_record) // Sort them on time
|
||||
else
|
||||
new_character.logs[log_type] = logs.Copy() // Just copy them
|
||||
|
||||
SSnanoui.user_transferred(current, new_character)
|
||||
|
||||
if(new_character.mind) //remove any mind currently in our new body's mind variable
|
||||
|
||||
@@ -222,10 +222,10 @@
|
||||
name = "NT Undercover Operative"
|
||||
// Disguised NT special forces, sent to quietly eliminate or keep tabs on people in high positions (e.g: captain)
|
||||
|
||||
uniform = /obj/item/clothing/under/color/black
|
||||
uniform = /obj/item/clothing/under/color/random
|
||||
back = /obj/item/storage/backpack
|
||||
belt = /obj/item/storage/belt/utility/full/multitool
|
||||
gloves = /obj/item/clothing/gloves/combat
|
||||
gloves = /obj/item/clothing/gloves/color/yellow
|
||||
shoes = /obj/item/clothing/shoes/chameleon/noslip
|
||||
l_ear = /obj/item/radio/headset/centcom
|
||||
id = /obj/item/card/id
|
||||
|
||||
@@ -444,6 +444,11 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
|
||||
return
|
||||
|
||||
// Normally, AoE spells will generate an attack log for every turf they loop over, while searching for targets.
|
||||
// With this override, all /aoe_turf type spells will only generate 1 log, saying that the user has cast the spell.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/perform(list/targets, recharge, mob/user, make_attack_logs)
|
||||
add_attack_logs(user, null, "Cast the AoE spell [name]", ATKLOG_ALL)
|
||||
return ..(targets, recharge, user, FALSE)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/proc/los_check(mob/A,mob/B)
|
||||
//Checks for obstacles from A to B
|
||||
|
||||
@@ -13,11 +13,6 @@
|
||||
action_icon_state = "knock"
|
||||
sound = 'sound/magic/knock.ogg'
|
||||
|
||||
// Knock doesn't need to generate an attack log for every turf, set `make_attack_logs` to FALSE and just create a custom one.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/knock/perform(list/targets, recharge, mob/user)
|
||||
add_attack_logs(user, user, "cast the spell [name]", ATKLOG_ALL)
|
||||
return ..(targets, recharge, user, make_attack_logs = FALSE)
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/knock/cast(list/targets, mob/user = usr)
|
||||
for(var/turf/T in targets)
|
||||
for(var/obj/machinery/door/door in T.contents)
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
// List is required to compile the resources into the game when it loads.
|
||||
// Dynamically loading it has bad results with sounds overtaking each other, even with the wait variable.
|
||||
|
||||
GLOBAL_LIST_INIT(vox_sounds, list("," = 'sound/vox_fem/,.ogg',
|
||||
GLOBAL_LIST_INIT(vox_alerts, list(
|
||||
"bizwarn" = 'sound/vox_fem/bizwarn.ogg',
|
||||
"bloop" = 'sound/vox_fem/bloop.ogg',
|
||||
"buzwarn" = 'sound/vox_fem/buzwarn.ogg',
|
||||
"dadeda" = 'sound/vox_fem/dadeda.ogg',
|
||||
"deeoo" = 'sound/vox_fem/deeoo.ogg'
|
||||
))
|
||||
|
||||
GLOBAL_LIST_INIT(vox_sounds, list(
|
||||
"," = 'sound/vox_fem/,.ogg',
|
||||
"." = 'sound/vox_fem/..ogg',
|
||||
"a" = 'sound/vox_fem/a.ogg',
|
||||
"abortions" = 'sound/vox_fem/abortions.ogg',
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
/atom/movable/proc/get_cell()
|
||||
return
|
||||
|
||||
/atom/movable/proc/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
|
||||
/atom/movable/proc/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)
|
||||
if(QDELETED(AM))
|
||||
return FALSE
|
||||
if(!(AM.can_be_pulled(src, state, force)))
|
||||
@@ -87,7 +87,7 @@
|
||||
if(ismob(AM))
|
||||
var/mob/M = AM
|
||||
add_attack_logs(src, M, "passively grabbed", ATKLOG_ALMOSTALL)
|
||||
if(!supress_message)
|
||||
if(show_message)
|
||||
visible_message("<span class='warning'>[src] has grabbed [M] passively!</span>")
|
||||
return TRUE
|
||||
|
||||
@@ -120,12 +120,18 @@
|
||||
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1) //separated from our puller and not in the middle of a diagonal move.
|
||||
pulledby.stop_pulling()
|
||||
|
||||
/atom/movable/proc/can_be_pulled(user, grab_state, force)
|
||||
/atom/movable/proc/can_be_pulled(user, grab_state, force, show_message = FALSE)
|
||||
if(src == user || !isturf(loc))
|
||||
return FALSE
|
||||
if(anchored || throwing)
|
||||
if(anchored || move_resist == INFINITY)
|
||||
if(show_message)
|
||||
to_chat(user, "<span class='warning'>[src] appears to be anchored to the ground!</span>")
|
||||
return FALSE
|
||||
if(throwing)
|
||||
return FALSE
|
||||
if(force < (move_resist * MOVE_FORCE_PULL_RATIO))
|
||||
if(show_message)
|
||||
to_chat(user, "<span class='warning'>[src] is too heavy to pull!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -104,10 +104,18 @@
|
||||
var/mob/C = null
|
||||
var/list/candidates = list()
|
||||
if(!new_overmind)
|
||||
// Create icon
|
||||
var/mutable_appearance/MA = new
|
||||
var/mutable_appearance/MA1 = new(icon, "blob")
|
||||
MA1.color = overmind ? overmind.blob_reagent_datum.color : color
|
||||
MA.overlays += MA1
|
||||
var/mutable_appearance/MA2 = new(icon, "blob_core_overlay")
|
||||
MA.overlays += MA2
|
||||
// sendit
|
||||
if(is_offspring)
|
||||
candidates = pollCandidates("Do you want to play as a blob offspring?", ROLE_BLOB, 1)
|
||||
candidates = SSghost_spawns.poll_candidates("Do you want to play as a blob offspring?", ROLE_BLOB, TRUE, source = MA)
|
||||
else
|
||||
candidates = pollCandidates("Do you want to play as a blob?", ROLE_BLOB, 1)
|
||||
candidates = SSghost_spawns.poll_candidates("Do you want to play as a blob?", ROLE_BLOB, TRUE, source = MA)
|
||||
|
||||
if(length(candidates))
|
||||
C = pick(candidates)
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
blobber.AIStatus = AI_OFF
|
||||
blobber.LoseTarget()
|
||||
spawn()
|
||||
var/list/candidates = pollCandidates("Do you want to play as a blobbernaut?", ROLE_BLOB, 1, 100)
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a blobbernaut?", ROLE_BLOB, TRUE, 10 SECONDS, source = blobber)
|
||||
if(candidates.len)
|
||||
var/mob/C = pick(candidates)
|
||||
if(C)
|
||||
|
||||
@@ -140,6 +140,7 @@
|
||||
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
|
||||
allowed = list(/obj/item/tome,/obj/item/melee/cultblade)
|
||||
var/current_charges = 3
|
||||
var/shield_state = "shield-cult"
|
||||
hoodtype = /obj/item/clothing/head/hooded/cult_hoodie
|
||||
|
||||
/obj/item/clothing/head/hooded/cult_hoodie
|
||||
@@ -164,13 +165,18 @@
|
||||
if(current_charges)
|
||||
owner.visible_message("<span class='danger'>\The [attack_text] is deflected in a burst of blood-red sparks!</span>")
|
||||
current_charges--
|
||||
playsound(loc, "sparks", 100, 1)
|
||||
new /obj/effect/temp_visual/cult/sparks(get_turf(owner))
|
||||
if(!current_charges)
|
||||
owner.visible_message("<span class='danger'>The runed shield around [owner] suddenly disappears!</span>")
|
||||
shield_state = "broken"
|
||||
owner.update_inv_wear_suit()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/special_overlays()
|
||||
return mutable_appearance('icons/effects/cult_effects.dmi', shield_state, MOB_LAYER + 0.01)
|
||||
|
||||
/obj/item/clothing/suit/hooded/cultrobes/berserker
|
||||
name = "flagellant's robes"
|
||||
desc = "Blood-soaked robes infused with dark magic; allows the user to move at inhuman speeds, but at the cost of increased damage."
|
||||
|
||||
@@ -424,9 +424,9 @@ proc/display_roundstart_logout_report()
|
||||
return nukecode
|
||||
|
||||
/datum/game_mode/proc/replace_jobbanned_player(mob/living/M, role_type)
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as a [role_type]?", role_type, 0, 100)
|
||||
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Do you want to play as a [role_type]?", role_type, FALSE, 10 SECONDS)
|
||||
var/mob/dead/observer/theghost = null
|
||||
if(candidates.len)
|
||||
if(length(candidates))
|
||||
theghost = pick(candidates)
|
||||
to_chat(M, "<span class='userdanger'>Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!</span>")
|
||||
message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(M)]) to replace a jobbanned player.")
|
||||
|
||||
@@ -246,7 +246,7 @@
|
||||
src.verbs -= /mob/living/proc/guardian_reset
|
||||
for(var/mob/living/simple_animal/hostile/guardian/G in GLOB.mob_list)
|
||||
if(G.summoner == src)
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as [G.real_name]?", ROLE_GUARDIAN, 0, 100)
|
||||
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Do you want to play as [G.real_name]?", ROLE_GUARDIAN, FALSE, 10 SECONDS, source = G)
|
||||
var/mob/dead/observer/new_stand = null
|
||||
if(candidates.len)
|
||||
new_stand = pick(candidates)
|
||||
@@ -312,7 +312,7 @@
|
||||
used = FALSE
|
||||
return
|
||||
to_chat(user, "[use_message]")
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as the [mob_name] of [user.real_name]?", ROLE_GUARDIAN, 0, 100)
|
||||
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Do you want to play as the [mob_name] of [user.real_name]?", ROLE_GUARDIAN, FALSE, 10 SECONDS, source = /mob/living/simple_animal/hostile/guardian)
|
||||
var/mob/dead/observer/theghost = null
|
||||
|
||||
if(candidates.len)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/obj/item/projectile/guardian
|
||||
name = "crystal spray"
|
||||
icon_state = "guardian"
|
||||
damage = 5
|
||||
damage = 25
|
||||
damage_type = BRUTE
|
||||
armour_penetration = 100
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
melee_damage_upper = 10
|
||||
damage_transfer = 0.9
|
||||
projectiletype = /obj/item/projectile/guardian
|
||||
ranged_cooldown_time = 1 //fast!
|
||||
ranged_cooldown_time = 5 //fast!
|
||||
projectilesound = 'sound/effects/hit_on_shattered_glass.ogg'
|
||||
ranged = 1
|
||||
range = 13
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
/datum/event/spawn_morph/proc/get_morph()
|
||||
spawn()
|
||||
var/list/candidates = pollCandidates("Do you want to play as a morph?", ROLE_MORPH, 1)
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a morph?", ROLE_MORPH, TRUE, source = /mob/living/simple_animal/hostile/morph)
|
||||
if(!candidates.len)
|
||||
key_of_morph = null
|
||||
return kill()
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
giveObjectivesandGoals()
|
||||
giveSpells()
|
||||
else
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as a revenant?", poll_time = 15 SECONDS)
|
||||
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Do you want to play as a revenant?", poll_time = 15 SECONDS, source = /mob/living/simple_animal/revenant)
|
||||
var/mob/dead/observer/theghost = null
|
||||
if(candidates.len)
|
||||
theghost = pick(candidates)
|
||||
@@ -397,7 +397,7 @@
|
||||
spawn()
|
||||
if(!key_of_revenant)
|
||||
message_admins("The new revenant's old client either could not be found or is in a new, living mob - grabbing a random candidate instead...")
|
||||
var/list/candidates = pollCandidates("Do you want to play as a revenant?", ROLE_REVENANT, 1)
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a revenant?", ROLE_REVENANT, TRUE, source = /mob/living/simple_animal/revenant)
|
||||
if(!candidates.len)
|
||||
qdel(R)
|
||||
message_admins("No candidates were found for the new revenant. Oh well!")
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
return
|
||||
|
||||
spawn()
|
||||
var/list/candidates = pollCandidates("Do you want to play as a revenant?", ROLE_REVENANT, 1)
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a revenant?", ROLE_REVENANT, TRUE, source = /mob/living/simple_animal/revenant)
|
||||
if(!candidates.len)
|
||||
key_of_revenant = null
|
||||
return kill()
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
/mob/living/simple_animal/slaughter/cult/New()
|
||||
..()
|
||||
spawn(5)
|
||||
var/list/demon_candidates = pollCandidates("Do you want to play as a slaughter demon?", ROLE_DEMON, 1, 100)
|
||||
var/list/demon_candidates = SSghost_spawns.poll_candidates("Do you want to play as a slaughter demon?", ROLE_DEMON, TRUE, 10 SECONDS, source = /mob/living/simple_animal/slaughter/cult)
|
||||
if(!demon_candidates.len)
|
||||
visible_message("<span class='warning'>[src] disappears in a flash of red light!</span>")
|
||||
qdel(src)
|
||||
|
||||
@@ -74,7 +74,7 @@ Made by Xhuis
|
||||
required_enemies = 2
|
||||
recommended_enemies = 2
|
||||
restricted_jobs = list("AI", "Cyborg")
|
||||
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Blueshield", "Nanotrasen Representative", "Security Pod Pilot", "Magistrate", "Brig Physician", "Internal Affairs Agent", "Nanotrasen Navy Officer", "Special Operations Officer", "Syndicate Officer")
|
||||
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Head of Personnel", "Captain", "Blueshield", "Nanotrasen Representative", "Security Pod Pilot", "Magistrate", "Brig Physician", "Internal Affairs Agent", "Nanotrasen Navy Officer", "Special Operations Officer", "Syndicate Officer")
|
||||
|
||||
/datum/game_mode/shadowling/announce()
|
||||
to_chat(world, "<b>The current game mode is - Shadowling!</b>")
|
||||
|
||||
@@ -50,7 +50,8 @@
|
||||
to_chat(H, "You already used this contract!")
|
||||
return
|
||||
used = 1
|
||||
var/list/candidates = pollCandidates("Do you want to play as the wizard apprentice of [H.real_name]?", ROLE_WIZARD, 1)
|
||||
var/mutable_appearance/source = new('icons/obj/cardboard_cutout.dmi', "cutout_wizard")
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as the wizard apprentice of [H.real_name]?", ROLE_WIZARD, TRUE, source = source)
|
||||
if(candidates.len)
|
||||
var/mob/C = pick(candidates)
|
||||
new /obj/effect/particle_effect/smoke(H.loc)
|
||||
@@ -307,7 +308,8 @@ GLOBAL_LIST_EMPTY(multiverse)
|
||||
if(M.assigned == assigned)
|
||||
M.cooldown = cooldown
|
||||
|
||||
var/list/candidates = pollCandidates("Do you want to play as the wizard apprentice of [user.real_name]?", ROLE_WIZARD, 1, 100)
|
||||
var/mutable_appearance/source = new('icons/obj/cardboard_cutout.dmi', "cutout_wizard")
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as the wizard apprentice of [user.real_name]?", ROLE_WIZARD, TRUE, 10 SECONDS, source = source)
|
||||
if(candidates.len)
|
||||
var/mob/C = pick(candidates)
|
||||
spawn_copy(C.client, get_turf(user.loc), user)
|
||||
|
||||
@@ -118,7 +118,8 @@
|
||||
return FALSE
|
||||
making_mage = TRUE
|
||||
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as a raging Space Wizard?", ROLE_WIZARD, TRUE, poll_time = 20 SECONDS)
|
||||
var/mutable_appearance/source = new('icons/obj/cardboard_cutout.dmi', "cutout_wizard")
|
||||
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Do you want to play as a raging Space Wizard?", ROLE_WIZARD, TRUE, poll_time = 20 SECONDS, source = source)
|
||||
var/mob/dead/observer/harry = null
|
||||
message_admins("SWF is still pissed, sending another wizard - [max_mages - mages_made] left.")
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@
|
||||
break
|
||||
|
||||
if(!chosen_ghost) //Failing that, we grab a ghost
|
||||
var/list/consenting_candidates = pollCandidates("Would you like to play as a Shade?", ROLE_CULTIST, FALSE, poll_time = 100)
|
||||
var/list/consenting_candidates = SSghost_spawns.poll_candidates("Would you like to play as a Shade?", ROLE_CULTIST, FALSE, poll_time = 10 SECONDS, source = /mob/living/simple_animal/shade)
|
||||
if(consenting_candidates.len)
|
||||
chosen_ghost = pick(consenting_candidates)
|
||||
if(!T)
|
||||
|
||||
+10
-12
@@ -224,19 +224,17 @@ GLOBAL_LIST_INIT(role_playtime_requirements, list(
|
||||
else
|
||||
return "none"
|
||||
|
||||
/proc/update_exp(var/mins, var/ann = 0)
|
||||
if(!establish_db_connection())
|
||||
return -1
|
||||
spawn(0)
|
||||
for(var/client/L in GLOB.clients)
|
||||
if(L.inactivity >= (10 MINUTES))
|
||||
continue
|
||||
spawn(0)
|
||||
L.update_exp_client(mins, ann)
|
||||
sleep(10)
|
||||
/proc/update_exp(mins = 0, ann = 0)
|
||||
if(!GLOB.dbcon.IsConnected())
|
||||
return
|
||||
for(var/client/L in GLOB.clients)
|
||||
if(L.inactivity >= (10 MINUTES))
|
||||
continue
|
||||
L.update_exp_client(mins, ann)
|
||||
CHECK_TICK
|
||||
|
||||
/client/proc/update_exp_client(var/minutes, var/announce_changes = 0)
|
||||
if(!src ||!ckey)
|
||||
/client/proc/update_exp_client(minutes = 0, announce_changes = 0)
|
||||
if(!src || !ckey || !GLOB.dbcon.IsConnected())
|
||||
return
|
||||
var/DBQuery/exp_read = GLOB.dbcon.NewQuery("SELECT exp FROM [format_table_name("player")] WHERE ckey='[ckey]'")
|
||||
if(!exp_read.Execute())
|
||||
|
||||
@@ -390,7 +390,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
if(!job_in_department(SSjobs.GetJob(t1)))
|
||||
return 0
|
||||
if(t1 == "Custom")
|
||||
var/temp_t = sanitize(copytext(input("Enter a custom job assignment.","Assignment"),1,MAX_MESSAGE_LEN))
|
||||
var/temp_t = sanitize(reject_bad_name(copytext(input("Enter a custom job assignment.", "Assignment"), 1, MAX_MESSAGE_LEN), TRUE))
|
||||
//let custom jobs function as an impromptu alt title, mainly for sechuds
|
||||
if(temp_t && modify)
|
||||
SSjobs.log_job_transfer(modify.registered_name, modify.getRankAndAssignment(), temp_t, scan.registered_name)
|
||||
@@ -419,7 +419,8 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
message_admins("[key_name_admin(usr)] has reassigned \"[modify.registered_name]\" from \"[jobnamedata]\" to \"[t1]\".")
|
||||
|
||||
SSjobs.log_job_transfer(modify.registered_name, jobnamedata, t1, scan.registered_name)
|
||||
SSjobs.slot_job_transfer(modify.rank, t1)
|
||||
if(modify.owner_uid)
|
||||
SSjobs.slot_job_transfer(modify.rank, t1)
|
||||
|
||||
var/mob/living/carbon/human/H = modify.getPlayer()
|
||||
if(istype(H))
|
||||
@@ -436,7 +437,7 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
if(is_authenticated(usr) && !target_dept)
|
||||
var/t2 = modify
|
||||
if((modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(loc, /turf)))
|
||||
var/temp_name = reject_bad_name(href_list["reg"])
|
||||
var/temp_name = reject_bad_name(href_list["reg"], TRUE)
|
||||
if(temp_name)
|
||||
modify.registered_name = temp_name
|
||||
else
|
||||
@@ -465,6 +466,8 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
if(is_authenticated(usr) && !target_dept)
|
||||
var/delcount = SSjobs.delete_log_records(scan.registered_name, TRUE)
|
||||
if(delcount)
|
||||
message_admins("[key_name_admin(usr)] has wiped all ID computer logs.")
|
||||
usr.create_log(MISC_LOG, "wiped all ID computer logs.")
|
||||
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
@@ -504,9 +507,16 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
if("terminate")
|
||||
if(is_authenticated(usr) && !target_dept)
|
||||
var/jobnamedata = modify.getRankAndAssignment()
|
||||
log_game("[key_name(usr)] has terminated the employment of \"[modify.registered_name]\" the \"[jobnamedata]\".")
|
||||
message_admins("[key_name_admin(usr)] has terminated the employment of \"[modify.registered_name]\" the \"[jobnamedata]\".")
|
||||
var/reason = sanitize(copytext(input("Enter legal reason for termination. Enter nothing to cancel.", "Employment Termination"), 1, MAX_MESSAGE_LEN))
|
||||
if(!reason || !is_authenticated(usr) || !modify)
|
||||
return FALSE
|
||||
var/m_ckey = modify.getPlayerCkey()
|
||||
var/m_ckey_text = m_ckey ? "([m_ckey])" : "(no ckey)"
|
||||
log_game("[key_name(usr)] has terminated the employment of \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\" for: \"[reason]\".")
|
||||
message_admins("[key_name_admin(usr)] has terminated the employment of \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\" for: \"[reason]\".")
|
||||
usr.create_log(MISC_LOG, "terminated the employment of \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\"")
|
||||
SSjobs.log_job_transfer(modify.registered_name, jobnamedata, "Terminated", scan.registered_name)
|
||||
SSjobs.notify_dept_head(modify.rank, "[scan.registered_name] has terminated the employment of \"[modify.registered_name]\" the \"[jobnamedata]\" for \"[reason]\".")
|
||||
modify.assignment = "Terminated"
|
||||
modify.access = list()
|
||||
|
||||
@@ -518,16 +528,20 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
|
||||
if(!job_in_department(SSjobs.GetJob(modify.rank), FALSE))
|
||||
visible_message("<span class='notice'>[src]: Heads may only demote members of their own department.</span>")
|
||||
return 0
|
||||
|
||||
var/reason = sanitize(copytext(input("Enter legal reason for demotion. Enter nothing to cancel.","Legal Demotion"),1,MAX_MESSAGE_LEN))
|
||||
if(!reason || !is_authenticated(usr) || !modify)
|
||||
return 0
|
||||
var/list/access = list()
|
||||
var/datum/job/jobdatum = new /datum/job/civilian
|
||||
access = jobdatum.get_access()
|
||||
|
||||
var/jobnamedata = modify.getRankAndAssignment()
|
||||
log_game("[key_name(usr)] has demoted \"[modify.registered_name]\" the \"[jobnamedata]\" to \"Civilian (Demoted)\".")
|
||||
message_admins("[key_name_admin(usr)] has demoted \"[modify.registered_name]\" the \"[jobnamedata]\" to \"Civilian (Demoted)\".")
|
||||
var/m_ckey = modify.getPlayerCkey()
|
||||
var/m_ckey_text = m_ckey ? "([m_ckey])" : "(no ckey)"
|
||||
log_game("[key_name(usr)] has demoted \"[modify.registered_name]\" the \"[jobnamedata]\" [m_ckey_text] to \"Civilian (Demoted)\" for: \"[reason]\".")
|
||||
message_admins("[key_name_admin(usr)] has demoted \"[modify.registered_name]\" the \"[jobnamedata]\" [m_ckey_text] to \"Civilian (Demoted)\" for: \"[reason]\".")
|
||||
usr.create_log(MISC_LOG, "demoted \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\"")
|
||||
SSjobs.log_job_transfer(modify.registered_name, jobnamedata, "Demoted", scan.registered_name)
|
||||
|
||||
SSjobs.notify_dept_head(modify.rank, "[scan.registered_name] has demoted \"[modify.registered_name]\" the \"[jobnamedata]\" for \"[reason]\".")
|
||||
modify.access = access
|
||||
modify.rank = "Civilian"
|
||||
modify.assignment = "Demoted"
|
||||
|
||||
@@ -86,8 +86,8 @@
|
||||
Arresting Officer: [usr.name].[R ? "" : " Detainee record not found, manual record update required."]"
|
||||
Radio.autosay(announcetext, name, "Security", list(z))
|
||||
|
||||
if(prisoner_trank != "unknown")
|
||||
notify_dept_head(prisoner_trank, announcetext)
|
||||
if(prisoner_trank != "unknown" && prisoner_trank != "Civilian")
|
||||
SSjobs.notify_dept_head(prisoner_trank, announcetext)
|
||||
|
||||
if(R)
|
||||
prisoner = R
|
||||
@@ -104,31 +104,6 @@
|
||||
update_all_mob_security_hud()
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/door_timer/proc/notify_dept_head(jobtitle, antext)
|
||||
if(!jobtitle || !antext)
|
||||
return
|
||||
if(jobtitle == "Civilian")
|
||||
// Don't notify the HoP about greytiding civilians
|
||||
return
|
||||
var/datum/job/brigged_job = SSjobs.GetJob(jobtitle)
|
||||
if(!brigged_job)
|
||||
return
|
||||
if(!brigged_job.department_head[1])
|
||||
return
|
||||
var/boss_title = brigged_job.department_head[1]
|
||||
|
||||
var/obj/item/pda/target_pda
|
||||
for(var/obj/item/pda/check_pda in GLOB.PDAs)
|
||||
if(check_pda.ownrank == boss_title)
|
||||
target_pda = check_pda
|
||||
if(!target_pda)
|
||||
return
|
||||
var/datum/data/pda/app/messenger/PM = target_pda.find_program(/datum/data/pda/app/messenger)
|
||||
if(PM && PM.can_receive())
|
||||
PM.notify("<b>Message from Brig Timer (Automated), </b>\"[antext]\" (Unable to Reply)")
|
||||
|
||||
|
||||
/obj/machinery/door_timer/Initialize()
|
||||
..()
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
#define RECHARGER_POWER_USAGE_GUN 250
|
||||
#define RECHARGER_POWER_USAGE_MISC 200
|
||||
|
||||
/obj/machinery/recharger
|
||||
name = "recharger"
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "recharger0"
|
||||
desc = "A charging dock for energy based weaponry."
|
||||
anchored = 1
|
||||
anchored = TRUE
|
||||
use_power = IDLE_POWER_USE
|
||||
idle_power_usage = 4
|
||||
active_power_usage = 200
|
||||
pass_flags = PASSTABLE
|
||||
var/obj/item/charging = null
|
||||
var/using_power = FALSE
|
||||
|
||||
var/list/allowed_devices = list(/obj/item/gun/energy, /obj/item/melee/baton, /obj/item/modular_computer, /obj/item/rcs, /obj/item/bodyanalyzer)
|
||||
var/icon_state_off = "rechargeroff"
|
||||
var/icon_state_charged = "recharger2"
|
||||
@@ -17,6 +19,9 @@
|
||||
var/icon_state_idle = "recharger0"
|
||||
var/recharge_coeff = 1
|
||||
|
||||
var/obj/item/charging = null // The item that is being charged
|
||||
var/using_power = FALSE // Whether the recharger is actually transferring power or not, used for icon
|
||||
|
||||
/obj/machinery/recharger/New()
|
||||
..()
|
||||
component_parts = list()
|
||||
@@ -34,32 +39,32 @@
|
||||
if(allowed)
|
||||
if(anchored)
|
||||
if(charging)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
//Checks to make sure he's not in space doing it, and that the area got proper power.
|
||||
var/area/a = get_area(src)
|
||||
if(!isarea(a) || a.power_equip == 0)
|
||||
if(!isarea(a) || !a.power_equip)
|
||||
to_chat(user, "<span class='notice'>[src] blinks red as you try to insert [G].</span>")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(istype(G, /obj/item/gun/energy))
|
||||
var/obj/item/gun/energy/E = G
|
||||
if(!E.can_charge)
|
||||
to_chat(user, "<span class='notice'>Your gun has no external power connector.</span>")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(!user.drop_item())
|
||||
return 1
|
||||
return TRUE
|
||||
G.forceMove(src)
|
||||
charging = G
|
||||
use_power = ACTIVE_POWER_USE
|
||||
using_power = check_cell_needs_recharging(get_cell_from(G))
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[src] isn't connected to anything!</span>")
|
||||
return 1
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/machinery/recharger/crowbar_act(mob/user, obj/item/I)
|
||||
if(panel_open && !charging && default_deconstruction_crowbar(user, I))
|
||||
return TRUE
|
||||
@@ -106,57 +111,15 @@
|
||||
if(stat & (NOPOWER|BROKEN) || !anchored)
|
||||
return
|
||||
|
||||
using_power = FALSE
|
||||
if(charging)
|
||||
if(istype(charging, /obj/item/gun/energy))
|
||||
var/obj/item/gun/energy/E = charging
|
||||
if(E.cell.charge < E.cell.maxcharge)
|
||||
E.cell.give(E.cell.chargerate * recharge_coeff)
|
||||
E.on_recharge()
|
||||
use_power(250)
|
||||
using_power = TRUE
|
||||
|
||||
|
||||
if(istype(charging, /obj/item/melee/baton))
|
||||
var/obj/item/melee/baton/B = charging
|
||||
if(B.cell)
|
||||
if(B.cell.give(B.cell.chargerate))
|
||||
use_power(200)
|
||||
using_power = TRUE
|
||||
|
||||
if(istype(charging, /obj/item/modular_computer))
|
||||
var/obj/item/modular_computer/C = charging
|
||||
var/obj/item/computer_hardware/battery/battery_module = C.all_components[MC_CELL]
|
||||
if(battery_module)
|
||||
var/obj/item/computer_hardware/battery/B = battery_module
|
||||
if(B.battery)
|
||||
if(B.battery.charge < B.battery.maxcharge)
|
||||
B.battery.give(B.battery.chargerate)
|
||||
use_power(200)
|
||||
using_power = TRUE
|
||||
|
||||
if(istype(charging, /obj/item/rcs))
|
||||
var/obj/item/rcs/R = charging
|
||||
if(R.rcell)
|
||||
if(R.rcell.give(R.rcell.chargerate))
|
||||
use_power(200)
|
||||
using_power = TRUE
|
||||
|
||||
if(istype(charging, /obj/item/bodyanalyzer))
|
||||
var/obj/item/bodyanalyzer/B = charging
|
||||
if(B.cell)
|
||||
if(B.cell.give(B.cell.chargerate))
|
||||
use_power(200)
|
||||
using_power = TRUE
|
||||
|
||||
update_icon(using_power)
|
||||
using_power = try_recharging_if_possible()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/recharger/emp_act(severity)
|
||||
if(stat & (NOPOWER|BROKEN) || !anchored)
|
||||
..(severity)
|
||||
return
|
||||
|
||||
if(istype(charging, /obj/item/gun/energy))
|
||||
if(istype(charging, /obj/item/gun/energy))
|
||||
var/obj/item/gun/energy/E = charging
|
||||
if(E.cell)
|
||||
E.cell.emp_act(severity)
|
||||
@@ -167,7 +130,11 @@
|
||||
B.cell.charge = 0
|
||||
..(severity)
|
||||
|
||||
/obj/machinery/recharger/update_icon(using_power = FALSE) //we have an update_icon() in addition to the stuff in process to make it feel a tiny bit snappier.
|
||||
/obj/machinery/recharger/power_change()
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/recharger/update_icon() //we have an update_icon() in addition to the stuff in process to make it feel a tiny bit snappier.
|
||||
if(stat & (NOPOWER|BROKEN) || !anchored)
|
||||
icon_state = icon_state_off
|
||||
return
|
||||
@@ -179,6 +146,55 @@
|
||||
return
|
||||
icon_state = icon_state_idle
|
||||
|
||||
/obj/machinery/recharger/proc/get_cell_from(obj/item/I)
|
||||
if(istype(I, /obj/item/gun/energy))
|
||||
var/obj/item/gun/energy/E = I
|
||||
return E.cell
|
||||
|
||||
if(istype(I, /obj/item/melee/baton))
|
||||
var/obj/item/melee/baton/B = I
|
||||
return B.cell
|
||||
|
||||
if(istype(I, /obj/item/modular_computer))
|
||||
var/obj/item/modular_computer/C = I
|
||||
var/obj/item/computer_hardware/battery/B = C.all_components[MC_CELL]
|
||||
if(B)
|
||||
return B.battery
|
||||
|
||||
if(istype(I, /obj/item/rcs))
|
||||
var/obj/item/rcs/R = I
|
||||
return R.rcell
|
||||
|
||||
if(istype(I, /obj/item/bodyanalyzer))
|
||||
var/obj/item/bodyanalyzer/B = I
|
||||
return B.cell
|
||||
|
||||
return null
|
||||
|
||||
/obj/machinery/recharger/proc/check_cell_needs_recharging(obj/item/stock_parts/cell/C)
|
||||
if(!C || C.charge >= C.maxcharge)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/recharger/proc/recharge_cell(obj/item/stock_parts/cell/C, power_usage)
|
||||
C.give(C.chargerate * recharge_coeff)
|
||||
use_power(power_usage)
|
||||
|
||||
/obj/machinery/recharger/proc/try_recharging_if_possible()
|
||||
var/obj/item/stock_parts/cell/C = get_cell_from(charging)
|
||||
if(!check_cell_needs_recharging(C))
|
||||
return FALSE
|
||||
|
||||
if(istype(charging, /obj/item/gun/energy))
|
||||
recharge_cell(C, RECHARGER_POWER_USAGE_GUN)
|
||||
|
||||
var/obj/item/gun/energy/E = charging
|
||||
E.on_recharge()
|
||||
else
|
||||
recharge_cell(C, RECHARGER_POWER_USAGE_MISC)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/recharger/examine(mob/user)
|
||||
. = ..()
|
||||
if(charging && (!in_range(user, src) && !issilicon(user) && !isobserver(user)))
|
||||
@@ -204,3 +220,6 @@
|
||||
icon_state_idle = "wrecharger0"
|
||||
icon_state_charging = "wrecharger1"
|
||||
icon_state_charged = "wrecharger2"
|
||||
|
||||
#undef RECHARGER_POWER_USAGE_GUN
|
||||
#undef RECHARGER_POWER_USAGE_MISC
|
||||
|
||||
@@ -404,7 +404,7 @@
|
||||
cashmoney.use(currently_vending.price)
|
||||
|
||||
// Vending machines have no idea who paid with cash
|
||||
credit_purchase("(cash)")
|
||||
GLOB.vendor_account.credit(currently_vending.price, "Sale of [currently_vending.name]", name, "(cash)")
|
||||
return 1
|
||||
|
||||
/**
|
||||
@@ -444,26 +444,12 @@
|
||||
return 0
|
||||
else
|
||||
// Okay to move the money at this point
|
||||
var/paid = customer_account.charge(currently_vending.price, GLOB.vendor_account,
|
||||
customer_account.charge(currently_vending.price, GLOB.vendor_account,
|
||||
"Purchase of [currently_vending.name]", name, GLOB.vendor_account.owner_name,
|
||||
"Sale of [currently_vending.name]", customer_account.owner_name)
|
||||
|
||||
if(paid)
|
||||
// Give the vendor the money. We use the account owner name, which means
|
||||
// that purchases made with stolen/borrowed card will look like the card
|
||||
// owner made them
|
||||
credit_purchase(customer_account.owner_name)
|
||||
return paid
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Add money for current purchase to the vendor account.
|
||||
*
|
||||
* Called after the money has already been taken from the customer.
|
||||
*/
|
||||
/obj/machinery/vending/proc/credit_purchase(var/target as text)
|
||||
GLOB.vendor_account.money += currently_vending.price
|
||||
GLOB.vendor_account.credit(currently_vending.price, "Sale of [currently_vending.name]",
|
||||
name, target)
|
||||
|
||||
/obj/machinery/vending/attack_ai(mob/user)
|
||||
return attack_hand(user)
|
||||
@@ -1481,6 +1467,7 @@
|
||||
/obj/item/clothing/under/victsuit/redblk = 1,
|
||||
/obj/item/clothing/under/victsuit/red = 1,
|
||||
/obj/item/clothing/suit/tailcoat = 1,
|
||||
/obj/item/clothing/under/tourist_suit = 1,
|
||||
/obj/item/clothing/suit/draculacoat = 1,
|
||||
/obj/item/clothing/head/zepelli = 1,
|
||||
/obj/item/clothing/under/redhawaiianshirt = 1,
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
icon_state = "eggs"
|
||||
var/amount_grown = 0
|
||||
var/player_spiders = 0
|
||||
var/list/faction = list()
|
||||
var/list/faction = list("spiders")
|
||||
|
||||
/obj/structure/spider/eggcluster/New()
|
||||
..()
|
||||
@@ -90,7 +90,7 @@
|
||||
var/obj/machinery/atmospherics/unary/vent_pump/entry_vent
|
||||
var/travelling_in_vent = 0
|
||||
var/player_spiders = 0
|
||||
var/list/faction = list()
|
||||
var/list/faction = list("spiders")
|
||||
var/selecting_player = 0
|
||||
|
||||
/obj/structure/spider/spiderling/New()
|
||||
@@ -180,7 +180,7 @@
|
||||
if(player_spiders && !selecting_player)
|
||||
selecting_player = 1
|
||||
spawn()
|
||||
var/list/candidates = pollCandidates("Do you want to play as a spider?", ROLE_GSPIDER, 1)
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a giant spider?", ROLE_GSPIDER, TRUE, source = S)
|
||||
|
||||
if(candidates.len)
|
||||
var/mob/C = pick(candidates)
|
||||
|
||||
@@ -2,6 +2,8 @@ GLOBAL_DATUM_INIT(fire_overlay, /image, image("icon" = 'icons/goonstation/effect
|
||||
/obj/item
|
||||
name = "item"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
|
||||
move_resist = null // Set in the Initialise depending on the item size. Unless it's overriden by a specific item
|
||||
var/discrete = 0 // used in item_attack.dm to make an item not show an attack message to viewers
|
||||
var/image/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite
|
||||
var/blood_overlay_color = null
|
||||
@@ -113,6 +115,23 @@ GLOBAL_DATUM_INIT(fire_overlay, /image, image("icon" = 'icons/goonstation/effect
|
||||
hitsound = 'sound/items/welder.ogg'
|
||||
if(damtype == "brute")
|
||||
hitsound = "swing_hit"
|
||||
if(!move_resist)
|
||||
determine_move_resist()
|
||||
|
||||
/obj/item/proc/determine_move_resist()
|
||||
switch(w_class)
|
||||
if(WEIGHT_CLASS_TINY)
|
||||
move_resist = MOVE_FORCE_EXTREMELY_WEAK
|
||||
if(WEIGHT_CLASS_SMALL)
|
||||
move_resist = MOVE_FORCE_VERY_WEAK
|
||||
if(WEIGHT_CLASS_NORMAL)
|
||||
move_resist = MOVE_FORCE_WEAK
|
||||
if(WEIGHT_CLASS_BULKY)
|
||||
move_resist = MOVE_FORCE_NORMAL
|
||||
if(WEIGHT_CLASS_HUGE)
|
||||
move_resist = MOVE_FORCE_NORMAL
|
||||
if(WEIGHT_CLASS_GIGANTIC)
|
||||
move_resist = MOVE_FORCE_NORMAL
|
||||
|
||||
/obj/item/Destroy()
|
||||
flags &= ~DROPDEL //prevent reqdels
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
if(CanUse(U))
|
||||
if(!Use(U))
|
||||
return
|
||||
to_chat(U, "<span class='notice'>You replace [target.fitting] with [src].</span>")
|
||||
to_chat(U, "<span class='notice'>You replace the light [target.fitting] with [src].</span>")
|
||||
|
||||
if(target.status != LIGHT_EMPTY)
|
||||
AddShards(1, U)
|
||||
|
||||
@@ -344,56 +344,56 @@
|
||||
|
||||
/obj/item/toy/prize/ripley
|
||||
name = "toy ripley"
|
||||
desc = "Mini-Mecha action figure! Collect them all! 1/11."
|
||||
desc = "Mini-Mecha action figure! Collect them all! 1/11. This one is a ripley, a mining and engineering mecha."
|
||||
|
||||
/obj/item/toy/prize/fireripley
|
||||
name = "toy firefighting ripley"
|
||||
desc = "Mini-Mecha action figure! Collect them all! 2/11."
|
||||
desc = "Mini-Mecha action figure! Collect them all! 2/11. This one is a firefighter ripley, a fireproof mining and engineering mecha."
|
||||
icon_state = "fireripleytoy"
|
||||
|
||||
/obj/item/toy/prize/deathripley
|
||||
name = "toy deathsquad ripley"
|
||||
desc = "Mini-Mecha action figure! Collect them all! 3/11."
|
||||
desc = "Mini-Mecha action figure! Collect them all! 3/11. This one is the black ripley used by the hero of DeathSquad, that TV drama about loose-cannon ERT officers!"
|
||||
icon_state = "deathripleytoy"
|
||||
|
||||
/obj/item/toy/prize/gygax
|
||||
name = "toy gygax"
|
||||
desc = "Mini-Mecha action figure! Collect them all! 4/11."
|
||||
desc = "Mini-Mecha action figure! Collect them all! 4/11. This one is the speedy gygax combat mecha. Zoom zoom, pew pew!"
|
||||
icon_state = "gygaxtoy"
|
||||
|
||||
/obj/item/toy/prize/durand
|
||||
name = "toy durand"
|
||||
desc = "Mini-Mecha action figure! Collect them all! 5/11."
|
||||
desc = "Mini-Mecha action figure! Collect them all! 5/11. This one is the heavy durand combat mecha. Stomp stomp!"
|
||||
icon_state = "durandprize"
|
||||
|
||||
/obj/item/toy/prize/honk
|
||||
name = "toy H.O.N.K."
|
||||
desc = "Mini-Mecha action figure! Collect them all! 6/11."
|
||||
desc = "Mini-Mecha action figure! Collect them all! 6/11. This one is the infamous H.O.N.K mech!"
|
||||
icon_state = "honkprize"
|
||||
|
||||
/obj/item/toy/prize/marauder
|
||||
name = "toy marauder"
|
||||
desc = "Mini-Mecha action figure! Collect them all! 7/11."
|
||||
desc = "Mini-Mecha action figure! Collect them all! 7/11. This one is the powerful marauder combat mecha! Run for cover!"
|
||||
icon_state = "marauderprize"
|
||||
|
||||
/obj/item/toy/prize/seraph
|
||||
name = "toy seraph"
|
||||
desc = "Mini-Mecha action figure! Collect them all! 8/11."
|
||||
desc = "Mini-Mecha action figure! Collect them all! 8/11. This one is the powerful seraph combat mecha! Someone's in trouble!"
|
||||
icon_state = "seraphprize"
|
||||
|
||||
/obj/item/toy/prize/mauler
|
||||
name = "toy mauler"
|
||||
desc = "Mini-Mecha action figure! Collect them all! 9/11."
|
||||
desc = "Mini-Mecha action figure! Collect them all! 9/11. This one is the deadly mauler combat mecha! Look out!"
|
||||
icon_state = "maulerprize"
|
||||
|
||||
/obj/item/toy/prize/odysseus
|
||||
name = "toy odysseus"
|
||||
desc = "Mini-Mecha action figure! Collect them all! 10/11."
|
||||
desc = "Mini-Mecha action figure! Collect them all! 10/11. This one is the spindly, syringe-firing odysseus medical mecha."
|
||||
icon_state = "odysseusprize"
|
||||
|
||||
/obj/item/toy/prize/phazon
|
||||
name = "toy phazon"
|
||||
desc = "Mini-Mecha action figure! Collect them all! 11/11."
|
||||
desc = "Mini-Mecha action figure! Collect them all! 11/11. This one is the mysterious Phazon combat mecha! Nobody's safe!"
|
||||
icon_state = "phazonprize"
|
||||
|
||||
|
||||
@@ -1591,182 +1591,217 @@ obj/item/toy/cards/deck/syndicate/black
|
||||
|
||||
/obj/item/toy/figure/cmo
|
||||
name = "Chief Medical Officer action figure"
|
||||
desc = "The ever-suffering CMO, from Space Life's SS12 figurine collection."
|
||||
icon_state = "cmo"
|
||||
toysay = "Suit sensors!"
|
||||
|
||||
/obj/item/toy/figure/assistant
|
||||
name = "Assistant action figure"
|
||||
desc = "The faceless, hairless scourge of the station, from Space Life's SS12 figurine collection."
|
||||
icon_state = "assistant"
|
||||
toysay = "Grey tide station wide!"
|
||||
|
||||
/obj/item/toy/figure/atmos
|
||||
name = "Atmospheric Technician action figure"
|
||||
desc = "The faithful atmospheric technician, from Space Life's SS12 figurine collection."
|
||||
icon_state = "atmos"
|
||||
toysay = "Glory to Atmosia!"
|
||||
|
||||
/obj/item/toy/figure/bartender
|
||||
name = "Bartender action figure"
|
||||
desc = "The suave bartender, from Space Life's SS12 figurine collection."
|
||||
icon_state = "bartender"
|
||||
toysay = "Wheres my monkey?"
|
||||
|
||||
/obj/item/toy/figure/borg
|
||||
name = "Cyborg action figure"
|
||||
desc = "The iron-willed cyborg, from Space Life's SS12 figurine collection."
|
||||
icon_state = "borg"
|
||||
toysay = "I. LIVE. AGAIN."
|
||||
|
||||
/obj/item/toy/figure/botanist
|
||||
name = "Botanist action figure"
|
||||
desc = "The drug-addicted botanist, from Space Life's SS12 figurine collection."
|
||||
icon_state = "botanist"
|
||||
toysay = "Dude, I see colors..."
|
||||
|
||||
/obj/item/toy/figure/captain
|
||||
name = "Captain action figure"
|
||||
desc = "The inept captain, from Space Life's SS12 figurine collection."
|
||||
icon_state = "captain"
|
||||
toysay = "Crew, the Nuke Disk is safely up my ass."
|
||||
|
||||
/obj/item/toy/figure/cargotech
|
||||
name = "Cargo Technician action figure"
|
||||
desc = "The hard-working cargo tech, from Space Life's SS12 figurine collection."
|
||||
icon_state = "cargotech"
|
||||
toysay = "For Cargonia!"
|
||||
|
||||
/obj/item/toy/figure/ce
|
||||
name = "Chief Engineer action figure"
|
||||
desc = "The expert Chief Engineer, from Space Life's SS12 figurine collection."
|
||||
icon_state = "ce"
|
||||
toysay = "Wire the solars!"
|
||||
|
||||
/obj/item/toy/figure/chaplain
|
||||
name = "Chaplain action figure"
|
||||
desc = "The obsessed Chaplain, from Space Life's SS12 figurine collection."
|
||||
icon_state = "chaplain"
|
||||
toysay = "Gods make me a killing machine please!"
|
||||
|
||||
/obj/item/toy/figure/chef
|
||||
name = "Chef action figure"
|
||||
desc = "The cannibalistic chef, from Space Life's SS12 figurine collection."
|
||||
icon_state = "chef"
|
||||
toysay = "I swear it's not human meat."
|
||||
|
||||
/obj/item/toy/figure/chemist
|
||||
name = "Chemist action figure"
|
||||
desc = "The legally dubious Chemist, from Space Life's SS12 figurine collection."
|
||||
icon_state = "chemist"
|
||||
toysay = "Get your pills!"
|
||||
|
||||
/obj/item/toy/figure/clown
|
||||
name = "Clown action figure"
|
||||
desc = "The mischevious Clown, from Space Life's SS12 figurine collection."
|
||||
icon_state = "clown"
|
||||
toysay = "Honk!"
|
||||
|
||||
/obj/item/toy/figure/ian
|
||||
name = "Ian action figure"
|
||||
desc = "The adorable corgi, from Space Life's SS12 figurine collection."
|
||||
icon_state = "ian"
|
||||
toysay = "Arf!"
|
||||
|
||||
/obj/item/toy/figure/detective
|
||||
name = "Detective action figure"
|
||||
desc = "The clever detective, from Space Life's SS12 figurine collection."
|
||||
icon_state = "detective"
|
||||
toysay = "This airlock has grey jumpsuit and insulated glove fibers on it."
|
||||
|
||||
/obj/item/toy/figure/dsquad
|
||||
name = "Death Squad Officer action figure"
|
||||
desc = "It's a member of the DeathSquad, a TV drama where loose-cannon ERT officers face up against the threats of the galaxy! It's from Space Life's special edition SS12 figurine collection."
|
||||
icon_state = "dsquad"
|
||||
toysay = "Eliminate all threats!"
|
||||
|
||||
/obj/item/toy/figure/engineer
|
||||
name = "Engineer action figure"
|
||||
desc = "The frantic engineer, from Space Life's SS12 figurine collection."
|
||||
icon_state = "engineer"
|
||||
toysay = "Oh god, the singularity is loose!"
|
||||
|
||||
/obj/item/toy/figure/geneticist
|
||||
name = "Geneticist action figure"
|
||||
desc = "The balding geneticist, from Space Life's SS12 figurine collection."
|
||||
icon_state = "geneticist"
|
||||
toysay = "I'm not qualified for this job."
|
||||
|
||||
/obj/item/toy/figure/hop
|
||||
name = "Head of Personnel action figure"
|
||||
desc = "The officious Head of Personnel, from Space Life's SS12 figurine collection."
|
||||
icon_state = "hop"
|
||||
toysay = "Giving out all access!"
|
||||
toysay = "Papers, please!"
|
||||
|
||||
/obj/item/toy/figure/hos
|
||||
name = "Head of Security action figure"
|
||||
desc = "The bloodlust-filled Head of Security, from Space Life's SS12 figurine collection."
|
||||
icon_state = "hos"
|
||||
toysay = "I'm here to win, anything else is secondary."
|
||||
toysay = "Space law? What?"
|
||||
|
||||
/obj/item/toy/figure/qm
|
||||
name = "Quartermaster action figure"
|
||||
desc = "The nationalistic Quartermaster, from Space Life's SS12 figurine collection."
|
||||
icon_state = "qm"
|
||||
toysay = "Hail Cargonia!"
|
||||
|
||||
/obj/item/toy/figure/janitor
|
||||
name = "Janitor action figure"
|
||||
desc = "The water-using Janitor, from Space Life's SS12 figurine collection."
|
||||
icon_state = "janitor"
|
||||
toysay = "Look at the signs, you idiot."
|
||||
|
||||
/obj/item/toy/figure/lawyer
|
||||
name = "Internal Affairs Agent action figure"
|
||||
desc = "The unappreciated Internal Affairs Agent, from Space Life's SS12 figurine collection."
|
||||
icon_state = "lawyer"
|
||||
toysay = "Standard Operating Procedure says they're guilty! Hacking is proof they're an Enemy of the Corporation!"
|
||||
|
||||
/obj/item/toy/figure/librarian
|
||||
name = "Librarian action figure"
|
||||
desc = "The quiet Librarian, from Space Life's SS12 figurine collection."
|
||||
icon_state = "librarian"
|
||||
toysay = "One day while..."
|
||||
|
||||
/obj/item/toy/figure/md
|
||||
name = "Medical Doctor action figure"
|
||||
desc = "The stressed-out doctor, from Space Life's SS12 figurine collection."
|
||||
icon_state = "md"
|
||||
toysay = "The patient is already dead!"
|
||||
|
||||
/obj/item/toy/figure/mime
|
||||
name = "Mime action figure"
|
||||
desc = "A \"Space Life\" brand Mime action figure."
|
||||
desc = "... from Space Life's SS12 figurine collection."
|
||||
icon_state = "mime"
|
||||
toysay = "..."
|
||||
|
||||
/obj/item/toy/figure/miner
|
||||
name = "Shaft Miner action figure"
|
||||
desc = "The gun-toting Shaft Miner, from Space Life's SS12 figurine collection."
|
||||
icon_state = "miner"
|
||||
toysay = "Oh god it's eating my intestines!"
|
||||
|
||||
/obj/item/toy/figure/ninja
|
||||
name = "Ninja action figure"
|
||||
desc = "It's the mysterious ninja! It's from Space Life's special edition SS12 figurine collection."
|
||||
icon_state = "ninja"
|
||||
toysay = "Oh god! Stop shooting, I'm friendly!"
|
||||
|
||||
/obj/item/toy/figure/wizard
|
||||
name = "Wizard action figure"
|
||||
desc = "It's the deadly, spell-slinging wizard! It's from Space Life's special edition SS12 figurine collection."
|
||||
icon_state = "wizard"
|
||||
toysay = "Ei Nath!"
|
||||
|
||||
/obj/item/toy/figure/rd
|
||||
name = "Research Director action figure"
|
||||
desc = "The ambitious RD, from Space Life's SS12 figurine collection."
|
||||
icon_state = "rd"
|
||||
toysay = "Blowing all of the borgs!"
|
||||
|
||||
/obj/item/toy/figure/roboticist
|
||||
name = "Roboticist action figure"
|
||||
desc = "The skillful Roboticist, from Space Life's SS12 figurine collection."
|
||||
icon_state = "roboticist"
|
||||
toysay = "He asked to be borged!"
|
||||
|
||||
/obj/item/toy/figure/scientist
|
||||
name = "Scientist action figure"
|
||||
desc = "The mad Scientist, from Space Life's SS12 figurine collection."
|
||||
icon_state = "scientist"
|
||||
toysay = "Someone else must have made those bombs!"
|
||||
|
||||
/obj/item/toy/figure/syndie
|
||||
name = "Nuclear Operative action figure"
|
||||
desc = "It's the red-suited Nuclear Operative! It's from Space Life's special edition SS12 figurine collection."
|
||||
icon_state = "syndie"
|
||||
toysay = "Get that fucking disk!"
|
||||
|
||||
/obj/item/toy/figure/secofficer
|
||||
name = "Security Officer action figure"
|
||||
desc = "The power-tripping Security Officer, from Space Life's SS12 figurine collection."
|
||||
icon_state = "secofficer"
|
||||
toysay = "I am the law!"
|
||||
|
||||
/obj/item/toy/figure/virologist
|
||||
name = "Virologist action figure"
|
||||
desc = "The pandemic-starting Virologist, from Space Life's SS12 figurine collection."
|
||||
icon_state = "virologist"
|
||||
toysay = "The cure is potassium!"
|
||||
toysay = "It's not my virus!"
|
||||
|
||||
/obj/item/toy/figure/warden
|
||||
name = "Warden action figure"
|
||||
desc = "The amnesiac Warden, from Space Life's SS12 figurine collection."
|
||||
icon_state = "warden"
|
||||
toysay = "Execute him for breaking in!"
|
||||
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/// Delay in deci-seconds between two non-lethal attacks
|
||||
#define BATON_STUN_COOLDOWN 4 SECONDS
|
||||
/// Force of the telescopic baton when deployed
|
||||
#define BATON_TELESCOPIC_FORCE_DEPLOYED 10
|
||||
|
||||
/**
|
||||
* # Police Baton
|
||||
*
|
||||
* Knocks down the hit mob when not on harm intent and when [/obj/item/melee/classic_baton/on] is TRUE
|
||||
*
|
||||
* A non-lethal attack has a cooldown to avoid spamming
|
||||
*/
|
||||
/obj/item/melee/classic_baton
|
||||
name = "police baton"
|
||||
desc = "A wooden truncheon for beating criminal scum."
|
||||
icon_state = "baton"
|
||||
item_state = "classic_baton"
|
||||
slot_flags = SLOT_BELT
|
||||
force = 12 //9 hit crit
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
/// Whether the baton is on cooldown
|
||||
var/on_cooldown = FALSE
|
||||
/// Whether the baton is toggled on (to allow attacking)
|
||||
var/on = TRUE
|
||||
|
||||
/obj/item/melee/classic_baton/attack(mob/living/target, mob/living/user)
|
||||
if(!on)
|
||||
return ..()
|
||||
|
||||
add_fingerprint(user)
|
||||
if((CLUMSY in user.mutations) && prob(50))
|
||||
user.visible_message("<span class='danger'>[user] accidentally clubs [user.p_them()]self with [src]!</span>", \
|
||||
"<span class='userdanger'>You accidentally club yourself with [src]!</span>")
|
||||
user.Weaken(force * 3)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.apply_damage(force * 2, BRUTE, "head")
|
||||
else
|
||||
user.take_organ_damage(force * 2)
|
||||
return
|
||||
|
||||
if(user.a_intent == INTENT_HARM || isrobot(target)) // Lethal attack or it's a borg (can't knock them down!)
|
||||
return ..()
|
||||
else if(!on_cooldown) // Non-lethal attack - knock them down
|
||||
// Check for shield/countering
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
|
||||
return
|
||||
if(check_martial_counter(H, user))
|
||||
return
|
||||
// Visuals and sound
|
||||
user.do_attack_animation(target)
|
||||
playsound(target, 'sound/effects/woodhit.ogg', 75, TRUE, -1)
|
||||
add_attack_logs(user, target, "Stunned with [src]")
|
||||
target.visible_message("<span class='danger'>[user] has knocked down [target] with \the [src]!</span>", \
|
||||
"<span class='userdanger'>[user] has knocked down [target] with \the [src]!</span>")
|
||||
// Hit 'em
|
||||
target.LAssailant = iscarbon(user) ? user : null
|
||||
target.Weaken(3)
|
||||
on_cooldown = TRUE
|
||||
addtimer(CALLBACK(src, .proc/cooldown_finished), BATON_STUN_COOLDOWN)
|
||||
|
||||
/**
|
||||
* Called some time after a non-lethal attack
|
||||
*/
|
||||
/obj/item/melee/classic_baton/proc/cooldown_finished()
|
||||
on_cooldown = FALSE
|
||||
|
||||
/**
|
||||
* # Fancy Cane
|
||||
*/
|
||||
/obj/item/melee/classic_baton/ntcane
|
||||
name = "fancy cane"
|
||||
desc = "A cane with special engraving on it. It seems well suited for fending off assailants..."
|
||||
icon_state = "cane_nt"
|
||||
item_state = "cane_nt"
|
||||
needs_permit = FALSE
|
||||
|
||||
/obj/item/melee/classic_baton/ntcane/is_crutch()
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* # Telescopic Baton
|
||||
*/
|
||||
/obj/item/melee/classic_baton/telescopic
|
||||
name = "telescopic baton"
|
||||
desc = "A compact yet robust personal defense weapon. Can be concealed when folded."
|
||||
icon_state = "telebaton_0"
|
||||
item_state = null
|
||||
slot_flags = SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
needs_permit = FALSE
|
||||
force = 0
|
||||
on = FALSE
|
||||
/// Attack verbs when concealed (created on Initialize)
|
||||
var/static/list/attack_verb_off
|
||||
/// Attack verbs when extended (created on Initialize)
|
||||
var/static/list/attack_verb_on
|
||||
|
||||
/obj/item/melee/classic_baton/telescopic/Initialize(mapload)
|
||||
. = ..()
|
||||
if(!attack_verb_off)
|
||||
attack_verb_off = list("hit", "poked")
|
||||
attack_verb_on = list("smacked", "struck", "cracked", "beaten")
|
||||
attack_verb = on ? attack_verb_on : attack_verb_off
|
||||
|
||||
/obj/item/melee/classic_baton/telescopic/attack_self(mob/user)
|
||||
on = !on
|
||||
icon_state = "telebaton_[on]"
|
||||
if(on)
|
||||
to_chat(user, "<span class='warning'>You extend the baton.</span>")
|
||||
item_state = "nullrod"
|
||||
w_class = WEIGHT_CLASS_BULKY //doesnt fit in backpack when its on for balance
|
||||
force = BATON_TELESCOPIC_FORCE_DEPLOYED //stunbaton damage
|
||||
attack_verb = attack_verb_on
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You collapse the baton.</span>")
|
||||
item_state = null //no sprite for concealment even when in hand
|
||||
slot_flags = SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
force = 0 //not so robust now
|
||||
attack_verb = attack_verb_off
|
||||
// Update mob hand visuals
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.update_inv_l_hand()
|
||||
H.update_inv_r_hand()
|
||||
playsound(loc, 'sound/weapons/batonextend.ogg', 50, TRUE)
|
||||
add_fingerprint(user)
|
||||
|
||||
#undef BATON_STUN_COOLDOWN
|
||||
#undef BATON_TELESCOPIC_FORCE_DEPLOYED
|
||||
@@ -212,6 +212,11 @@
|
||||
return M
|
||||
owner_ckey = null
|
||||
|
||||
/obj/item/card/id/proc/getPlayerCkey()
|
||||
var/mob/living/carbon/human/H = getPlayer()
|
||||
if(istype(H))
|
||||
return H.ckey
|
||||
|
||||
/obj/item/card/id/proc/is_untrackable()
|
||||
return untrackable
|
||||
|
||||
|
||||
@@ -55,16 +55,15 @@
|
||||
|
||||
/obj/item/lipstick/random/Initialize(mapload)
|
||||
. = ..()
|
||||
var/lscolor = pick(lipstick_colors) // A random color is picked from the var defined initially in a new var.
|
||||
colour = lipstick_colors[lscolor] // The color of the lipstick is pulled from the new variable (right hand side, HTML & Hex RGB)
|
||||
name = "[lscolor] lipstick" // The new variable is also used to match the name to the color of the lipstick. Kudos to Desolate & Lemon
|
||||
colour = pick(lipstick_colors)
|
||||
name = "[colour] lipstick"
|
||||
|
||||
/obj/item/lipstick/attack_self(mob/user)
|
||||
cut_overlays()
|
||||
to_chat(user, "<span class='notice'>You twist \the [src] [open ? "closed" : "open"].</span>")
|
||||
open = !open
|
||||
if(open)
|
||||
var/image/colored = mutable_appearance('icons/obj/items.dmi', "lipstick_uncap_color")
|
||||
var/mutable_appearance/colored = mutable_appearance('icons/obj/items.dmi', "lipstick_uncap_color")
|
||||
colored.color = lipstick_colors[colour]
|
||||
icon_state = "lipstick_uncap"
|
||||
add_overlay(colored)
|
||||
|
||||
@@ -5,39 +5,51 @@
|
||||
origin_tech = "materials=2;combat=3"
|
||||
light_power = 10
|
||||
light_color = LIGHT_COLOR_WHITE
|
||||
var/light_time = 2
|
||||
var/range = 7
|
||||
|
||||
var/light_time = 0.2 SECONDS // The duration the area is illuminated
|
||||
var/range = 7 // The range in tiles of the flashbang
|
||||
|
||||
/obj/item/grenade/flashbang/prime()
|
||||
update_mob()
|
||||
var/flashbang_turf = get_turf(src)
|
||||
if(!flashbang_turf)
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
if(T)
|
||||
// VFX and SFX
|
||||
do_sparks(rand(5, 9), FALSE, src)
|
||||
playsound(T, 'sound/effects/bang.ogg', 100, TRUE)
|
||||
new /obj/effect/dummy/lighting_obj(T, light_color, range + 2, light_power, light_time)
|
||||
|
||||
set_light(7)
|
||||
|
||||
do_sparks(rand(5, 9), FALSE, src)
|
||||
playsound(flashbang_turf, 'sound/effects/bang.ogg', 25, 1)
|
||||
bang(flashbang_turf, src, range)
|
||||
|
||||
for(var/obj/structure/blob/B in hear(8, flashbang_turf)) //Blob damage here
|
||||
var/damage = round(30 / (get_dist(B, get_turf(src)) + 1))
|
||||
B.take_damage(damage, BURN, "melee", 0)
|
||||
|
||||
spawn(light_time)
|
||||
qdel(src)
|
||||
// Stunning & damaging mechanic
|
||||
bang(T, src, range)
|
||||
qdel(src)
|
||||
|
||||
/**
|
||||
* Creates a flashing effect that blinds and deafens mobs within range
|
||||
*
|
||||
* Also damages blobs
|
||||
* Arguments:
|
||||
* * T - The turf to flash
|
||||
* * A - The flashing atom
|
||||
* * range - The range in tiles of the flash
|
||||
* * flash - Whether to flash (blind)
|
||||
* * bang - Whether to bang (deafen)
|
||||
*/
|
||||
/proc/bang(turf/T, atom/A, range = 7, flash = TRUE, bang = TRUE)
|
||||
// Blob damage
|
||||
for(var/obj/structure/blob/B in hear(range + 1, T))
|
||||
var/damage = round(30 / (get_dist(B, T) + 1))
|
||||
B.take_damage(damage, BURN, "melee", FALSE)
|
||||
|
||||
// Flashing mechanic
|
||||
var/source_turf = get_turf(A)
|
||||
for(var/mob/living/M in hearers(range, T))
|
||||
if(M.stat == DEAD)
|
||||
continue
|
||||
M.show_message("<span class='warning'>BANG</span>", 2)
|
||||
|
||||
//Checking for protections
|
||||
var/ear_safety = M.check_ear_prot()
|
||||
var/distance = max(1, get_dist(get_turf(A), get_turf(M)))
|
||||
var/distance = max(1, get_dist(source_turf, get_turf(M)))
|
||||
var/stun_amount = max(10 / distance, 3)
|
||||
|
||||
//Flash
|
||||
// Flash
|
||||
if(flash)
|
||||
if(M.weakeyes)
|
||||
M.visible_message("<span class='disarm'><b>[M]</b> screams and collapses!</span>")
|
||||
@@ -49,21 +61,20 @@
|
||||
var/mob/living/carbon/human/H = M
|
||||
var/obj/item/organ/internal/eyes/E = H.get_int_organ(/obj/item/organ/internal/eyes)
|
||||
if(E)
|
||||
E.receive_damage(8, 1)
|
||||
|
||||
E.receive_damage(8, TRUE)
|
||||
if(M.flash_eyes(affect_silicon = TRUE))
|
||||
M.Stun(max(10 / distance, 3))
|
||||
M.Weaken(max(10 / distance, 3))
|
||||
M.Stun(stun_amount)
|
||||
M.Weaken(stun_amount)
|
||||
|
||||
|
||||
//Bang
|
||||
// Bang
|
||||
var/ear_safety = M.check_ear_prot()
|
||||
if(bang)
|
||||
if(!distance || A.loc == M || A.loc == M.loc) //Holding on person or being exactly where lies is significantly more dangerous and voids protection
|
||||
if(!distance || A.loc == M || A.loc == M.loc) // Holding on person or being exactly where lies is significantly more dangerous and voids protection
|
||||
M.Stun(10)
|
||||
M.Weaken(10)
|
||||
if(!ear_safety)
|
||||
M.Stun(max(10 / distance, 3))
|
||||
M.Weaken(max(10 / distance, 3))
|
||||
M.Stun(stun_amount)
|
||||
M.Weaken(stun_amount)
|
||||
M.AdjustEarDamage(rand(0, 5), 15)
|
||||
if(iscarbon(M))
|
||||
var/mob/living/carbon/C = M
|
||||
@@ -74,6 +85,5 @@
|
||||
if(prob(ears.ear_damage - 5))
|
||||
to_chat(M, "<span class='warning'>You can't hear anything!</span>")
|
||||
M.BecomeDeaf()
|
||||
else
|
||||
if(ears.ear_damage >= 5)
|
||||
to_chat(M, "<span class='warning'>Your ears start to ring!</span>")
|
||||
else if(ears.ear_damage >= 5)
|
||||
to_chat(M, "<span class='warning'>Your ears start to ring!</span>")
|
||||
|
||||
@@ -255,7 +255,7 @@
|
||||
|
||||
possessed = TRUE
|
||||
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as the spirit of [user.real_name]'s blade?", ROLE_PAI, 0, 100)
|
||||
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Do you want to play as the spirit of [user.real_name]'s blade?", ROLE_PAI, FALSE, 10 SECONDS, source = src)
|
||||
var/mob/dead/observer/theghost = null
|
||||
|
||||
if(candidates.len)
|
||||
|
||||
@@ -204,8 +204,10 @@
|
||||
/obj/item/flashlight/pen,
|
||||
/obj/item/seeds,
|
||||
/obj/item/wirecutters,
|
||||
/obj/item/wrench,
|
||||
)
|
||||
/obj/item/wrench,
|
||||
/obj/item/reagent_containers/spray/weedspray,
|
||||
/obj/item/reagent_containers/spray/pestspray
|
||||
)
|
||||
|
||||
/obj/item/storage/belt/security
|
||||
name = "security belt"
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/* Weapons
|
||||
* Contains:
|
||||
* Banhammer
|
||||
* Classic Baton
|
||||
*/
|
||||
|
||||
/*
|
||||
* Banhammer
|
||||
*/
|
||||
/obj/item/banhammer/attack(mob/M, mob/user)
|
||||
to_chat(M, "<font color='red'><b> You have been banned FOR NO REISIN by [user]<b></font>")
|
||||
to_chat(user, "<font color='red'> You have <b>BANNED</b> [M]</font>")
|
||||
playsound(loc, 'sound/effects/adminhelp.ogg', 15) //keep it at 15% volume so people don't jump out of their skin too much
|
||||
|
||||
/*
|
||||
* Classic Baton
|
||||
*/
|
||||
|
||||
/obj/item/melee/classic_baton
|
||||
name = "police baton"
|
||||
desc = "A wooden truncheon for beating criminal scum."
|
||||
icon_state = "baton"
|
||||
item_state = "classic_baton"
|
||||
slot_flags = SLOT_BELT
|
||||
force = 12 //9 hit crit
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
var/cooldown = 0
|
||||
var/on = 1
|
||||
|
||||
/obj/item/melee/classic_baton/attack(mob/target as mob, mob/living/user as mob)
|
||||
if(on)
|
||||
add_fingerprint(user)
|
||||
if((CLUMSY in user.mutations) && prob(50))
|
||||
to_chat(user, "<span class ='danger'>You club yourself over the head.</span>")
|
||||
user.Weaken(3 * force)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.apply_damage(2*force, BRUTE, "head")
|
||||
else
|
||||
user.take_organ_damage(2*force)
|
||||
return
|
||||
if(isrobot(target))
|
||||
..()
|
||||
return
|
||||
if(!isliving(target))
|
||||
return
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
if(!..()) return
|
||||
if(!isrobot(target)) return
|
||||
else
|
||||
if(cooldown <= 0)
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
|
||||
return
|
||||
if(check_martial_counter(H, user))
|
||||
return
|
||||
playsound(get_turf(src), 'sound/effects/woodhit.ogg', 75, 1, -1)
|
||||
target.Weaken(3)
|
||||
add_attack_logs(user, target, "Stunned with [src]")
|
||||
add_fingerprint(user)
|
||||
target.visible_message("<span class ='danger'>[user] has knocked down [target] with \the [src]!</span>", \
|
||||
"<span class ='userdanger'>[user] has knocked down [target] with \the [src]!</span>")
|
||||
if(!iscarbon(user))
|
||||
target.LAssailant = null
|
||||
else
|
||||
target.LAssailant = user
|
||||
cooldown = 1
|
||||
spawn(40)
|
||||
cooldown = 0
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/melee/classic_baton/ntcane
|
||||
name = "fancy cane"
|
||||
desc = "A cane with special engraving on it. It seems well suited for fending off assailants..."
|
||||
icon_state = "cane_nt"
|
||||
item_state = "cane_nt"
|
||||
needs_permit = 0
|
||||
|
||||
/obj/item/melee/classic_baton/ntcane/is_crutch()
|
||||
return 1
|
||||
|
||||
//Telescopic baton
|
||||
/obj/item/melee/classic_baton/telescopic
|
||||
name = "telescopic baton"
|
||||
desc = "A compact yet robust personal defense weapon. Can be concealed when folded."
|
||||
icon_state = "telebaton_0"
|
||||
item_state = null
|
||||
slot_flags = SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
needs_permit = 0
|
||||
force = 0
|
||||
on = 0
|
||||
|
||||
/obj/item/melee/classic_baton/telescopic/attack_self(mob/user as mob)
|
||||
on = !on
|
||||
if(on)
|
||||
to_chat(user, "<span class ='warning'>You extend the baton.</span>")
|
||||
icon_state = "telebaton_1"
|
||||
item_state = "nullrod"
|
||||
w_class = WEIGHT_CLASS_BULKY //doesnt fit in backpack when its on for balance
|
||||
force = 10 //stunbaton damage
|
||||
attack_verb = list("smacked", "struck", "cracked", "beaten")
|
||||
else
|
||||
to_chat(user, "<span class ='notice'>You collapse the baton.</span>")
|
||||
icon_state = "telebaton_0"
|
||||
item_state = null //no sprite for concealment even when in hand
|
||||
slot_flags = SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
force = 0 //not so robust now
|
||||
attack_verb = list("hit", "poked")
|
||||
if(istype(user,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.update_inv_l_hand()
|
||||
H.update_inv_r_hand()
|
||||
playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1)
|
||||
add_fingerprint(user)
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* # Banhammer
|
||||
*/
|
||||
/obj/item/banhammer
|
||||
desc = "A banhammer"
|
||||
name = "banhammer"
|
||||
@@ -13,11 +16,15 @@
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 70)
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
|
||||
/obj/item/banhammer/suicide_act(mob/user)
|
||||
to_chat(viewers(user), "<span class='suicide'>[user] is hitting [user.p_them()]self with the [src.name]! It looks like [user.p_theyre()] trying to ban [user.p_them()]self from life.</span>")
|
||||
return BRUTELOSS|FIRELOSS|TOXLOSS|OXYLOSS
|
||||
|
||||
/obj/item/banhammer/attack(mob/M, mob/user)
|
||||
to_chat(M, "<font color='red'><b> You have been banned FOR NO REISIN by [user]<b></font>")
|
||||
to_chat(user, "<font color='red'> You have <b>BANNED</b> [M]</font>")
|
||||
playsound(loc, 'sound/effects/adminhelp.ogg', 15) //keep it at 15% volume so people don't jump out of their skin too much
|
||||
|
||||
/obj/item/sord
|
||||
name = "\improper SORD"
|
||||
desc = "This thing is so unspeakably shitty you are having a hard time even holding it."
|
||||
|
||||
@@ -25,9 +25,13 @@
|
||||
..()
|
||||
spawn(1)
|
||||
if(!opened) // if closed, any item at the crate's loc is put in the contents
|
||||
var/itemcount = 0
|
||||
for(var/obj/item/I in loc)
|
||||
if(I.density || I.anchored || I == src) continue
|
||||
I.forceMove(src)
|
||||
// Ensure the storage cap is respected
|
||||
if(++itemcount >= storage_capacity)
|
||||
break
|
||||
|
||||
// Fix for #383 - C4 deleting fridges with corpses
|
||||
/obj/structure/closet/Destroy()
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
return
|
||||
if(!in_range(src, user))
|
||||
return
|
||||
if(!iscarbon(usr))
|
||||
if(!iscarbon(usr) && !isrobot(usr))
|
||||
return
|
||||
playsound(loc, 'sound/machines/click.ogg', 15, TRUE, -3)
|
||||
opened = !opened
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
|
||||
GLOBAL_VAR_INIT(normal_ooc_colour, "#275FC5")
|
||||
GLOBAL_VAR_INIT(member_ooc_colour, "#035417")
|
||||
GLOBAL_VAR_INIT(mentor_ooc_colour, "#0099cc")
|
||||
GLOBAL_VAR_INIT(mentor_ooc_colour, "#00B0EB")
|
||||
GLOBAL_VAR_INIT(moderator_ooc_colour, "#184880")
|
||||
GLOBAL_VAR_INIT(admin_ooc_colour, "#b82e00")
|
||||
|
||||
@@ -53,6 +53,7 @@ GLOBAL_VAR_INIT(admin_ooc_colour, "#b82e00")
|
||||
return
|
||||
|
||||
log_ooc(msg, src)
|
||||
mob.create_log(OOC_LOG, msg)
|
||||
|
||||
var/display_colour = GLOB.normal_ooc_colour
|
||||
if(holder && !holder.fakekey)
|
||||
@@ -205,7 +206,7 @@ GLOBAL_VAR_INIT(admin_ooc_colour, "#b82e00")
|
||||
return
|
||||
|
||||
log_looc(msg, src)
|
||||
|
||||
mob.create_log(LOOC_LOG, msg)
|
||||
var/mob/source = mob.get_looc_source()
|
||||
var/list/heard = get_mobs_in_view(7, source)
|
||||
|
||||
|
||||
@@ -299,7 +299,8 @@ datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null)
|
||||
|
||||
datum/admins/proc/DB_ban_unban_by_id(var/id)
|
||||
|
||||
if(!check_rights(R_BAN)) return
|
||||
if(!check_rights(R_BAN))
|
||||
return
|
||||
|
||||
var/sql = "SELECT ckey FROM [format_table_name("ban")] WHERE id = [id]"
|
||||
|
||||
@@ -343,9 +344,9 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
|
||||
/client/proc/DB_ban_panel()
|
||||
set category = "Admin"
|
||||
set name = "Banning Panel"
|
||||
set desc = "Edit admin permissions"
|
||||
set desc = "DB Ban Panel"
|
||||
|
||||
if(!holder)
|
||||
if(!check_rights(R_BAN))
|
||||
return
|
||||
|
||||
holder.DB_ban_panel()
|
||||
@@ -356,7 +357,8 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
|
||||
if(!usr.client)
|
||||
return
|
||||
|
||||
if(!check_rights(R_BAN)) return
|
||||
if(!check_rights(R_BAN))
|
||||
return
|
||||
|
||||
establish_db_connection()
|
||||
if(!GLOB.dbcon.IsConnected())
|
||||
|
||||
+14
-23
@@ -69,7 +69,10 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
body += "<body>Options panel for <b>[M]</b>"
|
||||
if(M.client)
|
||||
body += " played by <b>[M.client]</b> "
|
||||
body += "\[<A href='?_src_=holder;editrights=rank;ckey=[M.ckey]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\] "
|
||||
if(check_rights(R_PERMISSIONS, 0))
|
||||
body += "\[<A href='?_src_=holder;editrights=rank;ckey=[M.ckey]'>[M.client.holder ? M.client.holder.rank : "Player"]</A>\] "
|
||||
else
|
||||
body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\] "
|
||||
body += "\[<A href='?_src_=holder;getplaytimewindow=[M.UID()]'>" + M.client.get_exp_type(EXP_TYPE_CREW) + " as [EXP_TYPE_CREW]</a>\]"
|
||||
|
||||
if(isnewplayer(M))
|
||||
@@ -110,17 +113,18 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
else
|
||||
body += "<A href='?_src_=holder;watchadd=[M.ckey]'>Add to Watchlist</A> "
|
||||
|
||||
if(M.client)
|
||||
body += "| <A href='?_src_=holder;sendtoprison=[M.UID()]'>Prison</A> | "
|
||||
body += "\ <A href='?_src_=holder;sendbacktolobby=[M.UID()]'>Send back to Lobby</A> | "
|
||||
body += "\ <A href='?_src_=holder;eraseflavortext=[M.UID()]'>Erase Flavor Text</A> | "
|
||||
body += "\ <A href='?_src_=holder;userandomname=[M.UID()]'>Use Random Name</A> | "
|
||||
var/muted = M.client.prefs.muted
|
||||
body += {"<br><b>Mute: </b>
|
||||
\[<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_IC]'><font color='[(muted & MUTE_IC)?"red":"blue"]'>IC</font></a> |
|
||||
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_OOC]'><font color='[(muted & MUTE_OOC)?"red":"blue"]'>OOC</font></a> |
|
||||
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_PRAY]'><font color='[(muted & MUTE_PRAY)?"red":"blue"]'>PRAY</font></a> |
|
||||
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_ADMINHELP]'><font color='[(muted & MUTE_ADMINHELP)?"red":"blue"]'>ADMINHELP</font></a> |
|
||||
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_DEADCHAT]'><font color='[(muted & MUTE_DEADCHAT)?"red":"blue"]'>DEADCHAT</font></a>\]
|
||||
(<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_ALL]'><font color='[(muted & MUTE_ALL)?"red":"blue"]'>toggle all</font></a>)
|
||||
\[<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_IC]'><font color='[(muted & MUTE_IC)?"red":"#6685f5"]'>IC</font></a> |
|
||||
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_OOC]'><font color='[(muted & MUTE_OOC)?"red":"#6685f5"]'>OOC</font></a> |
|
||||
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_PRAY]'><font color='[(muted & MUTE_PRAY)?"red":"#6685f5"]'>PRAY</font></a> |
|
||||
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_ADMINHELP]'><font color='[(muted & MUTE_ADMINHELP)?"red":"#6685f5"]'>ADMINHELP</font></a> |
|
||||
<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_DEADCHAT]'><font color='[(muted & MUTE_DEADCHAT)?"red":"#6685f5"]'>DEADCHAT</font></a>\]
|
||||
(<A href='?_src_=holder;mute=[M.UID()];mute_type=[MUTE_ALL]'><font color='[(muted & MUTE_ALL)?"red":"#6685f5"]'>toggle all</font></a>)
|
||||
"}
|
||||
|
||||
var/jumptoeye = ""
|
||||
@@ -281,7 +285,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
/datum/admins/proc/vpn_whitelist()
|
||||
set category = "Admin"
|
||||
set name = "VPN Ckey Whitelist"
|
||||
if(!check_rights(R_ADMIN))
|
||||
if(!check_rights(R_BAN))
|
||||
return
|
||||
var/key = stripped_input(usr, "Enter ckey to add/remove, or leave blank to cancel:", "VPN Whitelist add/remove", max_length=32)
|
||||
if(key)
|
||||
@@ -700,7 +704,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
var/msg = ""
|
||||
if(SSticker.current_state == GAME_STATE_STARTUP)
|
||||
msg = " (The server is still setting up, but the round will be started as soon as possible.)"
|
||||
message_admins("<font color='blue'>[usr.key] has started the game.[msg]</font>")
|
||||
message_admins("<span class='darkmblue'>[usr.key] has started the game.[msg]</span>")
|
||||
feedback_add_details("admin_verb","SN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return 1
|
||||
else
|
||||
@@ -761,19 +765,6 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
world.update_status()
|
||||
feedback_add_details("admin_verb","TR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/toggle_aliens()
|
||||
set category = "Event"
|
||||
set desc="Toggle alien mobs"
|
||||
set name="Toggle Aliens"
|
||||
|
||||
if(!check_rights(R_EVENT))
|
||||
return
|
||||
|
||||
GLOB.aliens_allowed = !GLOB.aliens_allowed
|
||||
log_admin("[key_name(usr)] toggled aliens to [GLOB.aliens_allowed].")
|
||||
message_admins("[key_name_admin(usr)] toggled aliens [GLOB.aliens_allowed ? "on" : "off"].")
|
||||
feedback_add_details("admin_verb","TA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/datum/admins/proc/delay()
|
||||
set category = "Server"
|
||||
set desc="Delay the game start/end"
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
/client/proc/investigate_show( subject in GLOB.investigate_log_subjects )
|
||||
set name = "Investigate"
|
||||
set category = "Admin"
|
||||
if(!holder) return
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
switch(subject)
|
||||
if("notes")
|
||||
show_note()
|
||||
|
||||
@@ -10,11 +10,8 @@ GLOBAL_LIST_INIT(admin_verbs_default, list(
|
||||
GLOBAL_LIST_INIT(admin_verbs_admin, list(
|
||||
/client/proc/check_antagonists, /*shows all antags*/
|
||||
/datum/admins/proc/show_player_panel,
|
||||
/client/proc/player_panel, /*shows an interface for all players, with links to various panels (old style)*/
|
||||
/client/proc/player_panel_new, /*shows an interface for all players, with links to various panels*/
|
||||
/client/proc/invisimin, /*allows our mob to go invisible/visible*/
|
||||
/datum/admins/proc/toggleenter, /*toggles whether people can join the current game*/
|
||||
/datum/admins/proc/toggleguests, /*toggles whether guests can join the current game*/
|
||||
/datum/admins/proc/announce, /*priority announce something to all clients.*/
|
||||
/client/proc/colorooc, /*allows us to set a custom colour for everything we say in ooc*/
|
||||
/client/proc/resetcolorooc, /*allows us to set a reset our ooc color*/
|
||||
@@ -23,7 +20,6 @@ GLOBAL_LIST_INIT(admin_verbs_admin, list(
|
||||
/client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/
|
||||
/client/proc/cmd_admin_pm_panel, /*admin-pm list*/
|
||||
/client/proc/cmd_admin_pm_by_key_panel, /*admin-pm list by key*/
|
||||
/client/proc/cmd_admin_subtle_message, /*send an message to somebody as a 'voice in their head'*/
|
||||
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
|
||||
/client/proc/cmd_admin_check_contents, /*displays the contents of an instance*/
|
||||
/client/proc/cmd_admin_open_logging_view,
|
||||
@@ -55,36 +51,30 @@ GLOBAL_LIST_INIT(admin_verbs_admin, list(
|
||||
/datum/admins/proc/PlayerNotes,
|
||||
/client/proc/cmd_mentor_say,
|
||||
/datum/admins/proc/show_player_notes,
|
||||
/datum/admins/proc/vpn_whitelist,
|
||||
/client/proc/free_slot, /*frees slot for chosen job*/
|
||||
/client/proc/toggleattacklogs,
|
||||
/client/proc/toggleadminlogs,
|
||||
/client/proc/toggledebuglogs,
|
||||
/client/proc/update_mob_sprite,
|
||||
/client/proc/toggledrones,
|
||||
/client/proc/man_up,
|
||||
/client/proc/global_man_up,
|
||||
/client/proc/delbook,
|
||||
/client/proc/view_flagged_books,
|
||||
/client/proc/view_asays,
|
||||
/client/proc/empty_ai_core_toggle_latejoin,
|
||||
/client/proc/aooc,
|
||||
/client/proc/freeze,
|
||||
/client/proc/alt_check,
|
||||
/client/proc/secrets,
|
||||
/client/proc/change_human_appearance_admin, /* Allows an admin to change the basic appearance of human-based mobs */
|
||||
/client/proc/change_human_appearance_self, /* Allows the human-based mob itself to change its basic appearance */
|
||||
/client/proc/debug_variables,
|
||||
/client/proc/reset_all_tcs, /*resets all telecomms scripts*/
|
||||
/client/proc/toggle_mentor_chat,
|
||||
/client/proc/toggle_advanced_interaction, /*toggle admin ability to interact with not only machines, but also atoms such as buttons and doors*/
|
||||
/client/proc/list_ssds_afks,
|
||||
/client/proc/cmd_admin_headset_message,
|
||||
/client/proc/spawn_floor_cluwne
|
||||
/client/proc/list_ssds_afks
|
||||
))
|
||||
GLOBAL_LIST_INIT(admin_verbs_ban, list(
|
||||
/client/proc/unban_panel,
|
||||
/client/proc/jobbans,
|
||||
/client/proc/stickybanpanel
|
||||
/client/proc/ban_panel,
|
||||
/client/proc/stickybanpanel,
|
||||
/datum/admins/proc/vpn_whitelist
|
||||
))
|
||||
GLOBAL_LIST_INIT(admin_verbs_sounds, list(
|
||||
/client/proc/play_local_sound,
|
||||
@@ -100,7 +90,6 @@ GLOBAL_LIST_INIT(admin_verbs_event, list(
|
||||
/client/proc/drop_bomb,
|
||||
/client/proc/cinematic,
|
||||
/client/proc/one_click_antag,
|
||||
/datum/admins/proc/toggle_aliens,
|
||||
/client/proc/cmd_admin_add_freeform_ai_law,
|
||||
/client/proc/cmd_admin_add_random_ai_law,
|
||||
/client/proc/make_sound,
|
||||
@@ -110,6 +99,7 @@ GLOBAL_LIST_INIT(admin_verbs_event, list(
|
||||
/client/proc/show_tip,
|
||||
/client/proc/cmd_admin_change_custom_event,
|
||||
/datum/admins/proc/access_news_network, /*allows access of newscasters*/
|
||||
/client/proc/cmd_admin_subtle_message, /*send an message to somebody as a 'voice in their head'*/
|
||||
/client/proc/cmd_admin_direct_narrate, /*send text directly to a player with no padding. Useful for narratives and fluff-text*/
|
||||
/client/proc/cmd_admin_world_narrate, /*sends text to all players with no padding*/
|
||||
/client/proc/response_team, // Response Teams admin verb
|
||||
@@ -117,7 +107,10 @@ GLOBAL_LIST_INIT(admin_verbs_event, list(
|
||||
/client/proc/fax_panel,
|
||||
/client/proc/event_manager_panel,
|
||||
/client/proc/modify_goals,
|
||||
/client/proc/outfit_manager
|
||||
/client/proc/outfit_manager,
|
||||
/client/proc/cmd_admin_headset_message,
|
||||
/client/proc/change_human_appearance_admin, /* Allows an admin to change the basic appearance of human-based mobs */
|
||||
/client/proc/change_human_appearance_self /* Allows the human-based mob itself to change its basic appearance */
|
||||
))
|
||||
|
||||
GLOBAL_LIST_INIT(admin_verbs_spawn, list(
|
||||
@@ -126,24 +119,27 @@ GLOBAL_LIST_INIT(admin_verbs_spawn, list(
|
||||
/client/proc/admin_deserialize
|
||||
))
|
||||
GLOBAL_LIST_INIT(admin_verbs_server, list(
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/Set_Holiday,
|
||||
/datum/admins/proc/startnow,
|
||||
/datum/admins/proc/restart,
|
||||
/datum/admins/proc/delay,
|
||||
/datum/admins/proc/toggleaban,
|
||||
/datum/admins/proc/toggleenter, /*toggles whether people can join the current game*/
|
||||
/datum/admins/proc/toggleguests, /*toggles whether guests can join the current game*/
|
||||
/client/proc/toggle_log_hrefs,
|
||||
/client/proc/everyone_random,
|
||||
/datum/admins/proc/toggleAI,
|
||||
/client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/
|
||||
/client/proc/cmd_debug_del_all,
|
||||
/client/proc/cmd_debug_del_sing,
|
||||
/datum/admins/proc/toggle_aliens,
|
||||
/client/proc/delbook,
|
||||
/client/proc/view_flagged_books,
|
||||
/client/proc/view_asays,
|
||||
/client/proc/toggle_antagHUD_use,
|
||||
/client/proc/toggle_antagHUD_restrictions,
|
||||
/client/proc/set_ooc,
|
||||
/client/proc/reset_ooc
|
||||
/client/proc/reset_ooc,
|
||||
/client/proc/toggledrones
|
||||
))
|
||||
GLOBAL_LIST_INIT(admin_verbs_debug, list(
|
||||
/client/proc/cmd_admin_list_open_jobs,
|
||||
@@ -152,9 +148,7 @@ GLOBAL_LIST_INIT(admin_verbs_debug, list(
|
||||
/client/proc/debug_controller,
|
||||
/client/proc/cmd_debug_mob_lists,
|
||||
/client/proc/cmd_admin_delete,
|
||||
/client/proc/cmd_debug_del_all,
|
||||
/client/proc/cmd_debug_del_sing,
|
||||
/client/proc/reload_admins,
|
||||
/client/proc/restart_controller,
|
||||
/client/proc/enable_debug_verbs,
|
||||
/client/proc/toggledebuglogs,
|
||||
@@ -197,7 +191,7 @@ GLOBAL_LIST_INIT(admin_verbs_mod, list(
|
||||
/client/proc/player_panel_new,
|
||||
/client/proc/dsay,
|
||||
/datum/admins/proc/show_player_panel,
|
||||
/client/proc/jobbans,
|
||||
/client/proc/ban_panel,
|
||||
/client/proc/debug_variables /*allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify*/
|
||||
))
|
||||
GLOBAL_LIST_INIT(admin_verbs_mentor, list(
|
||||
@@ -367,19 +361,8 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
to_chat(mob, "<span class='notice'>Invisimin on. You are now as invisible as a ghost.</span>")
|
||||
mob.remove_from_all_data_huds()
|
||||
|
||||
/client/proc/player_panel()
|
||||
set name = "Player Panel"
|
||||
set category = "Admin"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
holder.player_panel_old()
|
||||
feedback_add_details("admin_verb","PP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
/client/proc/player_panel_new()
|
||||
set name = "Player Panel New"
|
||||
set name = "Player Panel"
|
||||
set category = "Admin"
|
||||
|
||||
if(!check_rights(R_ADMIN|R_MOD))
|
||||
@@ -401,22 +384,8 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
feedback_add_details("admin_verb","CHA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
/client/proc/jobbans()
|
||||
set name = "Display Job bans"
|
||||
set category = "Admin"
|
||||
|
||||
if(!check_rights(R_ADMIN|R_MOD))
|
||||
return
|
||||
|
||||
if(config.ban_legacy_system)
|
||||
holder.Jobbans()
|
||||
else
|
||||
holder.DB_ban_panel()
|
||||
feedback_add_details("admin_verb","VJB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
/client/proc/unban_panel()
|
||||
set name = "Unban Panel"
|
||||
/client/proc/ban_panel()
|
||||
set name = "Ban Panel"
|
||||
set category = "Admin"
|
||||
|
||||
if(!check_rights(R_BAN))
|
||||
@@ -809,7 +778,7 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
set desc = "Allows you to change the mob appearance"
|
||||
set category = null
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
if(!check_rights(R_EVENT))
|
||||
return
|
||||
|
||||
if(!istype(H))
|
||||
@@ -835,7 +804,7 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
set desc = "Allows the mob to change its appearance"
|
||||
set category = null
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
if(!check_rights(R_EVENT))
|
||||
return
|
||||
|
||||
if(!istype(H))
|
||||
@@ -980,8 +949,8 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
else
|
||||
to_chat(usr, "You now won't get debug log messages")
|
||||
|
||||
/client/proc/man_up(mob/T as mob in GLOB.mob_list)
|
||||
set category = "Admin"
|
||||
/client/proc/man_up(mob/T as mob in GLOB.player_list)
|
||||
set category = null
|
||||
set name = "Man Up"
|
||||
set desc = "Tells mob to man up and deal with it."
|
||||
|
||||
|
||||
@@ -42,20 +42,6 @@ GLOBAL_DATUM_INIT(jobban_regex, /regex, regex("(\[\\S]+) - (\[^#]+\[^# ])(?: ##
|
||||
else
|
||||
return 0
|
||||
|
||||
/*
|
||||
DEBUG
|
||||
/mob/verb/list_all_jobbans()
|
||||
set name = "list all jobbans"
|
||||
|
||||
for(var/s in jobban_keylist)
|
||||
to_chat(world, s)
|
||||
|
||||
/mob/verb/reload_jobbans()
|
||||
set name = "reload jobbans"
|
||||
|
||||
jobban_loadbanfile()
|
||||
*/
|
||||
|
||||
/proc/jobban_loadbanfile()
|
||||
if(config.ban_legacy_system)
|
||||
var/savefile/S=new("data/job_full.ban")
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/proc/machine_upgrade(obj/machinery/M in world)
|
||||
set name = "Tweak Component Ratings"
|
||||
set category = "Debug"
|
||||
set category = null
|
||||
|
||||
if(!check_rights(R_DEBUG))
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
|
||||
if(!istype(M))
|
||||
to_chat(usr, "<span class='danger'>This can only be used on subtypes of /obj/machinery.</span>")
|
||||
return
|
||||
|
||||
|
||||
var/new_rating = input("Enter new rating:","Num") as num
|
||||
if(!isnull(new_rating) && M.component_parts)
|
||||
for(var/obj/item/stock_parts/P in M.component_parts)
|
||||
P.rating = new_rating
|
||||
M.RefreshParts()
|
||||
|
||||
|
||||
message_admins("[key_name_admin(usr)] has set the component rating of [M] to [new_rating]")
|
||||
log_admin("[key_name(usr)] has set the component rating of [M] to [new_rating]")
|
||||
|
||||
|
||||
@@ -332,65 +332,6 @@
|
||||
|
||||
usr << browse(dat, "window=players;size=600x480")
|
||||
|
||||
//The old one
|
||||
/datum/admins/proc/player_panel_old()
|
||||
if(!usr.client.holder)
|
||||
return
|
||||
var/dat = "<html><head><title>Player Menu</title></head>"
|
||||
dat += "<body><table border=1 cellspacing=5><B><tr><th>Name</th><th>Real Name</th><th>Assigned Job</th><th>Key</th><th>Options</th><th>PM</th><th>Traitor?</th></tr></B>"
|
||||
//add <th>IP:</th> to this if wanting to add back in IP checking
|
||||
//add <td>(IP: [M.lastKnownIP])</td> if you want to know their ip to the lists below
|
||||
var/list/mobs = sortmobs()
|
||||
|
||||
for(var/mob/M in mobs)
|
||||
if(!M.ckey) continue
|
||||
|
||||
dat += "<tr><td>[M.name]</td>"
|
||||
if(isAI(M))
|
||||
dat += "<td>AI</td>"
|
||||
else if(isrobot(M))
|
||||
dat += "<td>Cyborg</td>"
|
||||
else if(issmall(M))
|
||||
dat += "<td>Monkey</td>"
|
||||
else if(ishuman(M))
|
||||
dat += "<td>[M.real_name]</td>"
|
||||
else if(istype(M, /mob/living/silicon/pai))
|
||||
dat += "<td>pAI</td>"
|
||||
else if(isnewplayer(M))
|
||||
dat += "<td>New Player</td>"
|
||||
else if(isobserver(M))
|
||||
dat += "<td>Ghost</td>"
|
||||
else if(isalien(M))
|
||||
dat += "<td>Alien</td>"
|
||||
else
|
||||
dat += "<td>Unknown</td>"
|
||||
|
||||
|
||||
if(istype(M,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.mind && H.mind.assigned_role)
|
||||
dat += "<td>[H.mind.assigned_role]</td>"
|
||||
else
|
||||
dat += "<td>NA</td>"
|
||||
|
||||
|
||||
dat += {"<td>[(M.client ? "[M.client]" : "No client")]</td>
|
||||
<td align=center><A HREF='?src=[UID()];adminplayeropts=[M.UID()]'>X</A></td>
|
||||
<td align=center><A href='?src=[usr.UID()];priv_msg=[M.client ? M.client.UID() : null]'>PM</A></td>
|
||||
"}
|
||||
switch(is_special_character(M))
|
||||
if(0)
|
||||
dat += {"<td align=center><A HREF='?src=[UID()];traitor=[M.UID()]'>Traitor?</A></td>"}
|
||||
if(1)
|
||||
dat += {"<td align=center><A HREF='?src=[UID()];traitor=[M.UID()]'><font color=red>Traitor?</font></A></td>"}
|
||||
if(2)
|
||||
dat += {"<td align=center><A HREF='?src=[UID()];traitor=[M.UID()]'><font color=red><b>Traitor?</b></font></A></td>"}
|
||||
|
||||
dat += "</table></body></html>"
|
||||
|
||||
usr << browse(dat, "window=players;size=640x480")
|
||||
|
||||
|
||||
|
||||
/datum/admins/proc/check_antagonists_line(mob/M, caption = "", close = 1)
|
||||
var/logout_status
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
set name = "Open Admin Ticket Interface"
|
||||
set category = "Admin"
|
||||
|
||||
if(!holder || !check_rights(R_ADMIN))
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
SStickets.showUI(usr)
|
||||
@@ -14,7 +14,7 @@
|
||||
set name = "Resolve All Open Admin Tickets"
|
||||
set category = null
|
||||
|
||||
if(!holder || !check_rights(R_ADMIN))
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(alert("Are you sure you want to resolve ALL open admin tickets?","Resolve all open admin tickets?","Yes","No") != "Yes")
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
set name = "Open Mentor Ticket Interface"
|
||||
set category = "Admin"
|
||||
|
||||
if(!holder || !check_rights(R_MENTOR|R_ADMIN))
|
||||
if(!check_rights(R_MENTOR|R_ADMIN))
|
||||
return
|
||||
|
||||
SSmentor_tickets.showUI(usr)
|
||||
@@ -14,7 +14,7 @@
|
||||
set name = "Resolve All Open Mentor Tickets"
|
||||
set category = null
|
||||
|
||||
if(!holder || !check_rights(R_ADMIN))
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(alert("Are you sure you want to resolve ALL open mentor tickets?","Resolve all open mentor tickets?","Yes","No") != "Yes")
|
||||
|
||||
+264
-135
File diff suppressed because it is too large
Load Diff
@@ -80,7 +80,7 @@ GLOBAL_LIST_INIT(adminhelp_ignored_words, list("unknown","the","a","an","of","mo
|
||||
mobs_found += found
|
||||
if(!ai_found && isAI(found))
|
||||
ai_found = 1
|
||||
msg += "<b><font color='black'>[original_word] </font></b> "
|
||||
msg += "<b><span class='adminnotice'>[original_word] </span></b> "
|
||||
continue
|
||||
msg += "[original_word] "
|
||||
|
||||
@@ -125,22 +125,28 @@ GLOBAL_LIST_INIT(adminhelp_ignored_words, list("unknown","the","a","an","of","mo
|
||||
ticketNum = T.ticketNum // ticketNum is the number of their ticket.
|
||||
T.addResponse(src, msg)
|
||||
|
||||
msg = "[span][selected_type]: </span><span class='boldnotice'>[key_name(src, TRUE, selected_type)] ([ADMIN_QUE(mob,"?")]) ([ADMIN_PP(mob,"PP")]) ([ADMIN_VV(mob,"VV")]) ([ADMIN_TP(mob,"TP")]) ([ADMIN_SM(mob,"SM")]) ([admin_jump_link(mob)]) (<A HREF='?_src_=holder;[isMhelp ? "openmentorticket" : "openadminticket"]=[ticketNum]'>TICKET</A>) [ai_found ? "(<A HREF='?_src_=holder;adminchecklaws=[mob.UID()]'>CL</A>)" : ""] (<A HREF='?_src_=holder;take_question=[ticketNum][isMhelp ? ";is_mhelp=1" : ""]'>TAKE</A>) (<A HREF='?_src_=holder;resolve=[ticketNum][isMhelp ? ";is_mhelp=1" : ""]'>RESOLVE</A>) [isMhelp ? "" : "<A HREF='?_src_=holder;autorespond=[ticketNum]'>(AUTO)</A>"] :</span> [span][msg]</span>"
|
||||
var/finalised_msg = "[span][selected_type]: </span><span class='boldnotice'>[key_name(src, TRUE, selected_type)] "
|
||||
finalised_msg += "([ADMIN_QUE(mob,"?")]) ([ADMIN_PP(mob,"PP")]) ([ADMIN_VV(mob,"VV")]) ([ADMIN_TP(mob,"TP")]) ([ADMIN_SM(mob,"SM")]) "
|
||||
finalised_msg += "([admin_jump_link(mob)]) (<A HREF='?_src_=holder;[isMhelp ? "openmentorticket" : "openadminticket"]=[ticketNum]'>TICKET</A>) "
|
||||
finalised_msg += "[ai_found ? "(<A HREF='?_src_=holder;adminchecklaws=[mob.UID()]'>CL</A>)" : ""] (<A HREF='?_src_=holder;take_question=[ticketNum][isMhelp ? ";is_mhelp=1" : ""]'>TAKE</A>) "
|
||||
finalised_msg += "(<A HREF='?_src_=holder;resolve=[ticketNum][isMhelp ? ";is_mhelp=1" : ""]'>RESOLVE</A>) [isMhelp ? "" : "<A HREF='?_src_=holder;autorespond=[ticketNum]'>(AUTO)</A>"] "
|
||||
finalised_msg += "<a href='?_src_=holder;convert_ticket=[ticketNum][isMhelp ? ";is_mhelp=1" : ""]'>(CONVERT)</a> :</span> [span][msg]</span>"
|
||||
|
||||
if(isMhelp)
|
||||
//Open a new adminticket and inform the user.
|
||||
SSmentor_tickets.newTicket(src, prunedmsg, msg)
|
||||
SSmentor_tickets.newTicket(src, prunedmsg, finalised_msg)
|
||||
for(var/client/X in mentorholders + modholders + adminholders)
|
||||
if(X.prefs.sound & SOUND_MENTORHELP)
|
||||
X << 'sound/effects/adminhelp.ogg'
|
||||
to_chat(X, msg)
|
||||
SEND_SOUND(X, 'sound/effects/adminhelp.ogg')
|
||||
to_chat(X, finalised_msg)
|
||||
else //Ahelp
|
||||
//Open a new adminticket and inform the user.
|
||||
SStickets.newTicket(src, prunedmsg, msg)
|
||||
SStickets.newTicket(src, prunedmsg, finalised_msg)
|
||||
for(var/client/X in modholders + adminholders)
|
||||
if(X.prefs.sound & SOUND_ADMINHELP)
|
||||
X << 'sound/effects/adminhelp.ogg'
|
||||
SEND_SOUND(X, 'sound/effects/adminhelp.ogg')
|
||||
window_flash(X)
|
||||
to_chat(X, msg)
|
||||
to_chat(X, finalised_msg)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
feedback_add_details("admin_verb","JK") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/Getmob(var/mob/M in GLOB.mob_list)
|
||||
set category = "Admin"
|
||||
set category = null
|
||||
set name = "Get Mob"
|
||||
set desc = "Mob to teleport"
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
feedback_add_details("admin_verb","GM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/Getkey()
|
||||
set category = "Admin"
|
||||
set category = null
|
||||
set name = "Get Key"
|
||||
set desc = "Key to teleport"
|
||||
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
/client/proc/cmd_admin_pm_context(mob/M as mob in GLOB.mob_list)
|
||||
set category = null
|
||||
set name = "Admin PM Mob"
|
||||
if(!holder)
|
||||
to_chat(src, "<span class='danger'>Error: Admin-PM-Context: Only administrators may use this command.</span>")
|
||||
if(!check_rights(R_ADMIN|R_MENTOR))
|
||||
return
|
||||
if(!ismob(M) || !M.client)
|
||||
return
|
||||
if( !ismob(M) || !M.client ) return
|
||||
cmd_admin_pm(M.client,null)
|
||||
feedback_add_details("admin_verb","APMM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
//shows a list of clients we could send PMs to, then forwards our choice to cmd_admin_pm
|
||||
/client/proc/cmd_admin_pm_panel()
|
||||
set category = "Admin"
|
||||
set name = "Admin PM Name"
|
||||
if(!holder)
|
||||
to_chat(src, "<span class='danger'>Error: Admin-PM-Panel: Only administrators may use this command.</span>")
|
||||
if(!check_rights(R_ADMIN|R_MENTOR))
|
||||
return
|
||||
var/list/client/targets[0]
|
||||
for(var/client/T)
|
||||
@@ -36,8 +36,7 @@
|
||||
/client/proc/cmd_admin_pm_by_key_panel()
|
||||
set category = "Admin"
|
||||
set name = "Admin PM Key"
|
||||
if(!holder)
|
||||
to_chat(src, "<span class='danger'>Error: Admin-PM-Panel: Only administrators may use this command.</span>")
|
||||
if(!check_rights(R_ADMIN|R_MENTOR))
|
||||
return
|
||||
var/list/client/targets[0]
|
||||
for(var/client/T)
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
msg = sanitize(copytext(msg, 1, MAX_MESSAGE_LEN))
|
||||
if(!msg) return
|
||||
|
||||
var/datum/asays/asay = new(usr.ckey, usr.client.holder.rank, msg, world.timeofday)
|
||||
GLOB.asays += asay
|
||||
log_adminsay(msg, src)
|
||||
|
||||
if(check_rights(R_ADMIN,0))
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
/client/proc/alt_check()
|
||||
set category = "Admin"
|
||||
set name = "Alt Account Checker"
|
||||
|
||||
var/dat = {"<B>Just to be sure you should try to also look up computer IDs/IPs on the server logs for a second opinion.</B>
|
||||
<br>Additionally make an attempt to introduce new players to the server
|
||||
<HR>"}
|
||||
|
||||
if(GLOB.dbcon.IsConnected())
|
||||
for(var/client/C in GLOB.clients)
|
||||
dat += "<p>[C.ckey] (Player Age: <font color = 'red'>[C.player_age]</font>) - <b>[C.computer_id]</b> / <b>[C.address]</b><br>"
|
||||
if(C.related_accounts_cid.len)
|
||||
dat += "--Accounts associated with CID: "
|
||||
dat += "<b>[jointext(C.related_accounts_cid, " - ")]</b><br>"
|
||||
if(C.related_accounts_ip.len)
|
||||
dat += "--Accounts associated with IP: "
|
||||
dat += "<b>[jointext(C.related_accounts_ip, " - ")]</b> "
|
||||
usr << browse(dat, "window=alt_panel;size=640x480")
|
||||
return
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
GLOBAL_LIST_EMPTY(asays)
|
||||
|
||||
/datum/asays
|
||||
var/ckey
|
||||
var/rank
|
||||
var/message
|
||||
var/time
|
||||
|
||||
/datum/asays/New(ckey = "", rank = "", message = "", time = 0)
|
||||
src.ckey = ckey
|
||||
src.rank = rank
|
||||
src.message = message
|
||||
src.time = time
|
||||
|
||||
/client/proc/view_asays()
|
||||
set name = "Asays"
|
||||
set desc = "View Asays from the current round."
|
||||
set category = "Admin"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
var/list/output = list({"
|
||||
<style>
|
||||
td, th
|
||||
{
|
||||
border: 1px solid #425c6e;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
thead
|
||||
{
|
||||
color: #517087;
|
||||
font-weight: bold;
|
||||
table-layout: fixed;
|
||||
}
|
||||
</style>
|
||||
<a href='byond://?src=[holder.UID()];asays=1'>Refresh</a>
|
||||
<table style='width: 100%; border-collapse: collapse; table-layout: auto; margin-top: 3px;'>
|
||||
"})
|
||||
|
||||
// Header & body start
|
||||
output += {"
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%">Time</th>
|
||||
<th width="10%">Ckey</th>
|
||||
<th width="85%">Message</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
"}
|
||||
|
||||
for(var/datum/asays/A in GLOB.asays)
|
||||
var/timestr = time2text(A.time, "hh:mm:ss")
|
||||
output += {"
|
||||
<tr>
|
||||
<td width="5%">[timestr]</td>
|
||||
<td width="10%"><b>[A.ckey] ([A.rank])</b></td>
|
||||
<td width="85%">[A.message]</td>
|
||||
</tr>
|
||||
"}
|
||||
|
||||
output += {"
|
||||
</tbody>
|
||||
</table>"}
|
||||
|
||||
var/datum/browser/popup = new(src, "asays", "<div align='center'>Current Round Asays</div>", 1200, 825)
|
||||
popup.set_content(output.Join())
|
||||
popup.open(0)
|
||||
@@ -3,8 +3,7 @@
|
||||
set category = "Event"
|
||||
set name = "Change Custom Event"
|
||||
|
||||
if(!holder)
|
||||
to_chat(src, "Only administrators may use this command.")
|
||||
if(!check_rights(R_EVENT))
|
||||
return
|
||||
|
||||
var/input = input(usr, "Enter the description of the custom event. Be descriptive. To cancel the event, make this blank or hit cancel.", "Custom Event", GLOB.custom_event_msg) as message|null
|
||||
|
||||
@@ -168,7 +168,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
#endif
|
||||
|
||||
/client/proc/callproc_datum(var/A as null|area|mob|obj|turf)
|
||||
set category = "Debug"
|
||||
set category = null
|
||||
set name = "Atom ProcCall"
|
||||
|
||||
if(!check_rights(R_PROCCALL))
|
||||
@@ -418,25 +418,6 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
|
||||
else
|
||||
alert("Invalid mob")
|
||||
|
||||
//TODO: merge the vievars version into this or something maybe mayhaps
|
||||
/client/proc/cmd_debug_del_all()
|
||||
set category = "Debug"
|
||||
set name = "Del-All"
|
||||
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
// to prevent REALLY stupid deletions
|
||||
var/blocked = list(/mob/living, /mob/living/carbon, /mob/living/carbon/human, /mob/dead, /mob/dead/observer, /mob/living/silicon, /mob/living/silicon/robot, /mob/living/silicon/ai)
|
||||
var/hsbitem = input(usr, "Choose an object to delete.", "Delete:") as null|anything in subtypesof(/obj) + subtypesof(/mob) - blocked
|
||||
if(hsbitem)
|
||||
for(var/atom/O in world)
|
||||
if(istype(O, hsbitem))
|
||||
qdel(O)
|
||||
log_admin("[key_name(src)] has deleted all instances of [hsbitem].")
|
||||
message_admins("[key_name_admin(src)] has deleted all instances of [hsbitem].", 0)
|
||||
feedback_add_details("admin_verb","DELA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_debug_del_sing()
|
||||
set category = "Debug"
|
||||
set name = "Del Singulo / Tesla"
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
|
||||
/client/proc/reload_admins()
|
||||
set name = "Reload Admins"
|
||||
set category = "Debug"
|
||||
set category = "Server"
|
||||
|
||||
if(!check_rights(R_SERVER))
|
||||
return
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
if(alert("Do you want these characters automatically classified as antagonists?",,"Yes","No")=="Yes")
|
||||
is_syndicate = 1
|
||||
|
||||
var/datum/outfit/O = outfit_list[dresscode]
|
||||
var/list/players_to_spawn = list()
|
||||
if(pick_manually)
|
||||
var/list/possible_ghosts = list()
|
||||
@@ -52,14 +53,12 @@
|
||||
players_to_spawn += candidate
|
||||
else
|
||||
to_chat(src, "Polling candidates...")
|
||||
players_to_spawn = pollCandidates("Do you want to play as an event character?")
|
||||
players_to_spawn = SSghost_spawns.poll_candidates("Do you want to play as \a [O.name]?")
|
||||
|
||||
if(!players_to_spawn.len)
|
||||
to_chat(src, "Nobody volunteered.")
|
||||
return 0
|
||||
|
||||
var/datum/outfit/O = outfit_list[dresscode]
|
||||
|
||||
var/players_spawned = 0
|
||||
for(var/mob/thisplayer in players_to_spawn)
|
||||
var/mob/living/carbon/human/H = new /mob/living/carbon/human(T)
|
||||
|
||||
@@ -55,7 +55,8 @@ GLOBAL_VAR_INIT(sent_syndicate_infiltration_team, 0)
|
||||
infiltrators += candidate
|
||||
else
|
||||
to_chat(src, "Polling candidates...")
|
||||
infiltrators = pollCandidates("Do you want to play as a SYNDICATE INFILTRATOR?", ROLE_TRAITOR, 1)
|
||||
var/mutable_appearance/ma = new('icons/mob/simple_human.dmi', "syndicate")
|
||||
infiltrators = SSghost_spawns.poll_candidates("Do you want to play as a SYNDICATE INFILTRATOR?", ROLE_TRAITOR, TRUE, source = ma)
|
||||
|
||||
if(!infiltrators.len)
|
||||
to_chat(src, "Nobody volunteered.")
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
set category = "Debug"
|
||||
set name = "Map template - Place"
|
||||
|
||||
if(!holder)
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
var/datum/map_template/template
|
||||
|
||||
var/map = input(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in GLOB.map_templates
|
||||
@@ -36,6 +37,9 @@
|
||||
set category = "Debug"
|
||||
set name = "Map Template - Upload"
|
||||
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
var/map = input(usr, "Choose a Map Template to upload to template storage","Upload Map Template") as null|file
|
||||
if(!map)
|
||||
return
|
||||
|
||||
@@ -137,7 +137,8 @@ client/proc/one_click_antag()
|
||||
var/confirm = alert("Are you sure?", "Confirm creation", "Yes", "No")
|
||||
if(confirm != "Yes")
|
||||
return 0
|
||||
var/list/candidates = pollCandidates("Do you wish to be considered for the position of a Wizard Foundation 'diplomat'?", "wizard")
|
||||
var/mutable_appearance/ma = new('icons/mob/simple_human.dmi', "wizard")
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you wish to be considered for the position of a Wizard Foundation 'diplomat'?", "wizard", source = ma)
|
||||
|
||||
log_admin("[key_name(owner)] tried making a Wizard with One-Click-Antag")
|
||||
message_admins("[key_name_admin(owner)] tried making a Wizard with One-Click-Antag")
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
set name = "Possess Obj"
|
||||
set category = null
|
||||
|
||||
if(!check_rights(R_POSSESS))
|
||||
return
|
||||
|
||||
if(istype(O,/obj/singularity))
|
||||
if(config.forbid_singulo_possession)
|
||||
to_chat(usr, "It is forbidden to possess singularities.")
|
||||
@@ -35,6 +38,9 @@
|
||||
set category = null
|
||||
//usr.loc = get_turf(usr)
|
||||
|
||||
if(!check_rights(R_POSSESS))
|
||||
return
|
||||
|
||||
if(usr.control_object && usr.name_archive) //if you have a name archived and if you are actually relassing an object
|
||||
usr.real_name = usr.name_archive
|
||||
usr.name = usr.real_name
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
if(!ismob(M))
|
||||
return
|
||||
|
||||
if(!check_rights(R_SERVER|R_EVENT))
|
||||
if(!check_rights(R_EVENT))
|
||||
return
|
||||
|
||||
var/msg = clean_input("Message:", text("Subtle PM to [M.key]"))
|
||||
@@ -123,7 +123,7 @@
|
||||
feedback_add_details("admin_verb","GLN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_direct_narrate(var/mob/M) // Targetted narrate -- TLE
|
||||
set category = "Event"
|
||||
set category = null
|
||||
set name = "Direct Narrate"
|
||||
|
||||
if(!check_rights(R_SERVER|R_EVENT))
|
||||
@@ -158,7 +158,7 @@
|
||||
/client/proc/admin_headset_message(mob/M in GLOB.mob_list, sender = null)
|
||||
var/mob/living/carbon/human/H = M
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
if(!check_rights(R_EVENT))
|
||||
return
|
||||
|
||||
if(!istype(H))
|
||||
@@ -572,7 +572,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
feedback_add_details("admin_verb","IONC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/cmd_admin_rejuvenate(mob/living/M as mob in GLOB.mob_list)
|
||||
set category = "Event"
|
||||
set category = null
|
||||
set name = "Rejuvenate"
|
||||
|
||||
if(!check_rights(R_REJUVINATE))
|
||||
@@ -638,7 +638,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
|
||||
|
||||
/client/proc/cmd_admin_delete(atom/A as obj|mob|turf in view())
|
||||
set category = "Admin"
|
||||
set category = null
|
||||
set name = "Delete"
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -1078,12 +1078,12 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
message_admins("Admin [key_name_admin(usr)] has disabled ERT calling.", 1)
|
||||
|
||||
/client/proc/show_tip()
|
||||
set category = "Admin"
|
||||
set category = "Event"
|
||||
set name = "Show Custom Tip"
|
||||
set desc = "Sends a tip (that you specify) to all players. After all \
|
||||
you're the experienced player here."
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
if(!check_rights(R_EVENT))
|
||||
return
|
||||
|
||||
var/input = input(usr, "Please specify your tip that you want to send to the players.", "Tip", "") as message|null
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/client/proc/spawn_floor_cluwne()
|
||||
set category = "Event"
|
||||
set name = "Unleash Floor Cluwne"
|
||||
set desc = "Pick a specific target or just let it select randomly and spawn the floor cluwne mob on the station. Be warned: spawning more than one may cause issues!"
|
||||
var/mob/living/carbon/human/target
|
||||
|
||||
if(!check_rights(R_EVENT))
|
||||
return
|
||||
|
||||
var/confirm = alert("Are you sure you want to release a floor cluwne and kill a lot of people?", "Confirm Massacre", "Yes", "No")
|
||||
if(confirm == "Yes")
|
||||
|
||||
var/turf/T = get_turf(usr)
|
||||
var/list/potential_targets = list()
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(!istype(H))
|
||||
continue
|
||||
if(H.mind.assigned_role == "Cluwne")
|
||||
continue
|
||||
potential_targets += H
|
||||
if(!potential_targets.len) //You're probably the only player on this damn station, spawn it yourself
|
||||
to_chat(src, "<span class='notice'>No valid targets!</span>")
|
||||
return
|
||||
target = input("Any specific target in mind? Please note only live, non cluwned, human targets are valid.", "Target", target) as null|anything in potential_targets
|
||||
var/mob/living/simple_animal/hostile/floor_cluwne/FC = new /mob/living/simple_animal/hostile/floor_cluwne(T)
|
||||
if(target)
|
||||
FC.Acquire_Victim(target)
|
||||
log_admin("[key_name(usr)] spawned floor cluwne[target ? ", initially targetting [target]": null].")
|
||||
message_admins("[key_name(usr)] spawned floor cluwne[target ? ", initially targetting [target]": null].")
|
||||
@@ -37,7 +37,8 @@ GLOBAL_VAR_INIT(sent_strike_team, 0)
|
||||
break
|
||||
|
||||
// Find ghosts willing to be DS
|
||||
var/list/commando_ghosts = pollCandidatesWithVeto(src, usr, COMMANDOS_POSSIBLE, "Join the DeathSquad?",, 21, 600, 1, GLOB.role_playtime_requirements[ROLE_DEATHSQUAD], TRUE, FALSE)
|
||||
var/mutable_appearance/source = new('icons/obj/cardboard_cutout.dmi', "cutout_deathsquad")
|
||||
var/list/commando_ghosts = pollCandidatesWithVeto(src, usr, COMMANDOS_POSSIBLE, "Join the DeathSquad?",, 21, 60 SECONDS, TRUE, GLOB.role_playtime_requirements[ROLE_DEATHSQUAD], TRUE, FALSE, source = source)
|
||||
if(!commando_ghosts.len)
|
||||
to_chat(usr, "<span class='userdanger'>Nobody volunteered to join the DeathSquad.</span>")
|
||||
return
|
||||
|
||||
@@ -45,7 +45,7 @@ GLOBAL_VAR_INIT(sent_syndicate_strike_team, 0)
|
||||
break
|
||||
|
||||
// Find ghosts willing to be SST
|
||||
var/list/commando_ghosts = pollCandidatesWithVeto(src, usr, SYNDICATE_COMMANDOS_POSSIBLE, "Join the Syndicate Strike Team?",, 21, 600, 1, GLOB.role_playtime_requirements[ROLE_DEATHSQUAD], TRUE, FALSE)
|
||||
var/list/commando_ghosts = pollCandidatesWithVeto(src, usr, SYNDICATE_COMMANDOS_POSSIBLE, "Join the Syndicate Strike Team?",, 21, 60 SECONDS, TRUE, GLOB.role_playtime_requirements[ROLE_DEATHSQUAD], TRUE, FALSE)
|
||||
if(!commando_ghosts.len)
|
||||
to_chat(usr, "<span class='userdanger'>Nobody volunteered to join the SST.</span>")
|
||||
return
|
||||
|
||||
@@ -73,7 +73,7 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
/datum/antagonist/proc/replace_banned_player()
|
||||
set waitfor = FALSE
|
||||
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as a [name]?", job_rank, TRUE, 50)
|
||||
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Do you want to play as a [name]?", job_rank, TRUE, 5 SECONDS)
|
||||
if(LAZYLEN(candidates))
|
||||
var/mob/dead/observer/C = pick(candidates)
|
||||
to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
|
||||
|
||||
@@ -46,7 +46,8 @@
|
||||
checking = TRUE
|
||||
|
||||
to_chat(user, "<span class='notice'>You activate [src] and wait for confirmation.</span>")
|
||||
var/list/nuke_candidates = pollCandidates("Do you want to play as a [rolename]?", ROLE_OPERATIVE, TRUE, 150)
|
||||
var/mutable_appearance/ma = new('icons/mob/simple_human.dmi', "syndicate_space_sword")
|
||||
var/list/nuke_candidates = SSghost_spawns.poll_candidates("Do you want to play as a [rolename]?", ROLE_OPERATIVE, TRUE, 15 SECONDS, source = ma)
|
||||
if(LAZYLEN(nuke_candidates))
|
||||
checking = FALSE
|
||||
if(QDELETED(src) || !check_usability(user))
|
||||
@@ -180,7 +181,7 @@
|
||||
var/type = "slaughter"
|
||||
if(demon_type == /mob/living/simple_animal/slaughter/laughter)
|
||||
type = "laughter"
|
||||
var/list/candidates = pollCandidates("Do you want to play as a [type] demon summoned by [user.real_name]?", ROLE_DEMON, 1, 100)
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a [type] demon summoned by [user.real_name]?", ROLE_DEMON, TRUE, 10 SECONDS, source = demon_type)
|
||||
|
||||
if(candidates.len > 0)
|
||||
var/mob/C = pick(candidates)
|
||||
@@ -252,7 +253,7 @@
|
||||
used = TRUE
|
||||
to_chat(user, "<span class='notice'>You break the seal on the bottle, calling upon the dire sludge to awaken...</span>")
|
||||
|
||||
var/list/candidates = pollCandidates("Do you want to play as a magical morph awakened by [user.real_name]?", ROLE_MORPH, 1, 100)
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a magical morph awakened by [user.real_name]?", ROLE_MORPH, 1, 10 SECONDS, source = morph_type)
|
||||
|
||||
if(candidates.len > 0)
|
||||
var/mob/C = pick(candidates)
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
servant_mind.objectives += O
|
||||
servant_mind.transfer_to(H)
|
||||
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as the servant of [user.real_name]?", ROLE_WIZARD, poll_time = 300)
|
||||
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Do you want to play as the servant of [user.real_name]?", ROLE_WIZARD, poll_time = 30 SECONDS, source = H)
|
||||
if(LAZYLEN(candidates))
|
||||
var/mob/dead/observer/C = pick(candidates)
|
||||
message_admins("[ADMIN_LOOKUPFLW(C)] was spawned as Dice Servant")
|
||||
|
||||
@@ -4,10 +4,18 @@
|
||||
name = "Mission Briefing"
|
||||
info = "To the Magnificent Z.A.P.<BR>A small mining base has been created within our territory by wandless scum. Send them a message from the wizard federation they will not forget. I know your kind is rather fragile, but a group of lightly armed miners should not pose any threat to you at all. Just be warned they have a security cyborg for self defence, you might want to tune your spells to that threat. I look forward to hearing of your success.<BR>Grand Magus Abra the Wonderous"
|
||||
|
||||
/obj/item/spellbook/oneuse/emp
|
||||
spell = /obj/effect/proc_holder/spell/targeted/emplosion/disable_tech
|
||||
spellname = "Disable Technology"
|
||||
icon_state = "bookcharge" //it's a lightning bolt, seems appropriate enough
|
||||
desc = "For the tech-hating wizard on the go."
|
||||
|
||||
/obj/item/spellbook/oneuse/emp/used
|
||||
used = TRUE //spawns used
|
||||
|
||||
/obj/effect/spawner/lootdrop/wizardcrash
|
||||
loot = list(
|
||||
/obj/item/guardiancreator = 1, //jackpot.
|
||||
/obj/item/guardiancreator = 1, //jackpot.
|
||||
/obj/item/spellbook/oneuse/knock = 1, //tresspassing charges incoming
|
||||
/obj/item/gun/magic/wand/resurrection = 1, //medbay's best friend
|
||||
/obj/item/spellbook/oneuse/charge = 20, //and now for less useful stuff to dilute the good loot chances
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
set name = "Show/Hide RadioChatter"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggle seeing radiochatter from radios and speakers"
|
||||
if(!holder) return
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
prefs.toggles ^= CHAT_RADIO
|
||||
prefs.save_preferences(src)
|
||||
to_chat(usr, "You will [(prefs.toggles & CHAT_RADIO) ? "now" : "no longer"] see radio chatter from radios or speakers")
|
||||
@@ -49,7 +50,8 @@
|
||||
set name = "Hear/Silence Admin Bwoinks"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggle hearing a notification when admin PMs are recieved"
|
||||
if(!holder) return
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
prefs.sound ^= SOUND_ADMINHELP
|
||||
prefs.save_preferences(src)
|
||||
to_chat(usr, "You will [(prefs.sound & SOUND_ADMINHELP) ? "now" : "no longer"] hear a sound when adminhelps arrive.")
|
||||
@@ -59,7 +61,7 @@
|
||||
set name = "Hear/Silence Mentorhelp Bwoinks"
|
||||
set category = "Preferences"
|
||||
set desc = "Toggle hearing a notification when mentorhelps are recieved"
|
||||
if(!holder)
|
||||
if(!check_rights(R_ADMIN|R_MENTOR))
|
||||
return
|
||||
prefs.sound ^= SOUND_MENTORHELP
|
||||
prefs.save_preferences(src)
|
||||
@@ -296,7 +298,7 @@
|
||||
to_chat(src, "As a ghost, you will now [(prefs.toggles & CHAT_GHOSTPDA) ? "see all PDA messages" : "no longer see PDA messages"].")
|
||||
prefs.save_preferences(src)
|
||||
feedback_add_details("admin_verb","TGP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
|
||||
/client/verb/silence_current_midi()
|
||||
set name = "Silence Current Midi"
|
||||
set category = "Preferences"
|
||||
|
||||
@@ -838,3 +838,10 @@
|
||||
icon_state = "cuban_suit"
|
||||
item_state = "cuban_suit"
|
||||
item_color = "cuban_suit"
|
||||
|
||||
/obj/item/clothing/under/tourist_suit
|
||||
name = "tourist outfit"
|
||||
desc = "A light blue shirt with brown shorts. Feels oddly spooky."
|
||||
icon_state = "tourist"
|
||||
icon_state = "tourist"
|
||||
item_color = "tourist"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
makeAbductorTeam()
|
||||
|
||||
/datum/event/abductor/proc/makeAbductorTeam()
|
||||
var/list/mob/dead/observer/candidates = pollCandidates("Do you wish to be considered for an Abductor Team?", ROLE_ABDUCTOR, 1)
|
||||
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Do you wish to be considered for an Abductor Team?", ROLE_ABDUCTOR, TRUE)
|
||||
|
||||
if(candidates.len >= 2)
|
||||
//Oh god why we can't have static functions
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
vents += temp_vent
|
||||
|
||||
spawn()
|
||||
var/list/candidates = pollCandidates("Do you want to play as an alien?", ROLE_ALIEN, 1)
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as an alien?", ROLE_ALIEN, TRUE, source = /mob/living/carbon/alien/larva)
|
||||
|
||||
while(spawncount > 0 && vents.len && candidates.len)
|
||||
var/obj/vent = pick_n_take(vents)
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
if(!T)
|
||||
return kill()
|
||||
|
||||
var/list/candidates = pollCandidates("Do you want to play as a blob infested mouse?", ROLE_BLOB, 1)
|
||||
if(!candidates.len)
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a blob infested mouse?", ROLE_BLOB, TRUE, source = /mob/living/simple_animal/mouse/blobinfected)
|
||||
if(!length(candidates))
|
||||
return kill()
|
||||
|
||||
var/list/vents = list()
|
||||
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in GLOB.all_vent_pumps)
|
||||
if(is_station_level(temp_vent.loc.z) && !temp_vent.welded)
|
||||
if(temp_vent.parent.other_atmosmch.len > 50)
|
||||
if(length(temp_vent.parent.other_atmosmch) > 50)
|
||||
vents += temp_vent
|
||||
|
||||
var/obj/vent = pick(vents)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
/client/proc/forceEvent(var/type in SSevents.allEvents)
|
||||
set name = "Trigger Event (Debug Only)"
|
||||
set name = "Trigger Event"
|
||||
set category = "Debug"
|
||||
|
||||
if(!holder)
|
||||
if(!check_rights(R_EVENT))
|
||||
return
|
||||
|
||||
if(ispath(type))
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
/datum/event/sentience/start()
|
||||
processing = FALSE //so it won't fire again in next tick
|
||||
|
||||
var/ghostmsg = "Do you want to awaken as a sentient being?"
|
||||
var/list/candidates = pollCandidates(ghostmsg, ROLE_SENTIENT, 1)
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to awaken as a sentient being?", ROLE_SENTIENT, TRUE)
|
||||
var/list/potential = list()
|
||||
var/sentience_type = SENTIENCE_ORGANIC
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
/datum/event/spawn_slaughter/proc/get_slaughter(var/end_if_fail = 0)
|
||||
spawn()
|
||||
var/list/candidates = pollCandidates("Do you want to play as a slaughter demon?", ROLE_DEMON, 1)
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a slaughter demon?", ROLE_DEMON, TRUE, source = /mob/living/simple_animal/slaughter)
|
||||
if(!candidates.len)
|
||||
key_of_slaughter = null
|
||||
return kill()
|
||||
|
||||
@@ -34,7 +34,7 @@ GLOBAL_LIST_INIT(unused_trade_stations, list("sol"))
|
||||
trader_objectives = forge_trader_objectives()
|
||||
|
||||
spawn()
|
||||
var/list/candidates = pollCandidates("Do you want to play as a trader?", ROLE_TRADER, 1)
|
||||
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a Sol Trader?", ROLE_TRADER, TRUE)
|
||||
var/index = 1
|
||||
while(spawn_count > 0 && candidates.len > 0)
|
||||
if(index > spawnlocs.len)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,7 @@
|
||||
set desc = "Permamently deletes a book from the database."
|
||||
set category = "Admin"
|
||||
|
||||
if(!holder)
|
||||
to_chat(src, "Only administrators may use this command.")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
var/isbn = input("ISBN number?", "Delete Book") as num | null
|
||||
@@ -25,8 +24,7 @@
|
||||
set desc = "View books flagged for content."
|
||||
set category = "Admin"
|
||||
|
||||
if(!holder)
|
||||
to_chat(src, "Only administrators may use this command.")
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
holder.view_flagged_books()
|
||||
|
||||
@@ -53,7 +53,6 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
|
||||
if(ismob(body))
|
||||
T = get_turf(body) //Where is the body located?
|
||||
attack_log_old = body.attack_log_old //preserve our attack logs by copying them to our ghost
|
||||
logs = body.logs.Copy()
|
||||
|
||||
var/mutable_appearance/MA = copy_appearance(body)
|
||||
if(body.mind && body.mind.name)
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
. = trim(. + trim(msg))
|
||||
. += "\""
|
||||
|
||||
/mob/proc/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency)
|
||||
/mob/proc/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency, use_voice = TRUE)
|
||||
if(!client)
|
||||
return 0
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
return 0
|
||||
|
||||
var/speaker_name = speaker.name
|
||||
if(ishuman(speaker))
|
||||
if(use_voice && ishuman(speaker))
|
||||
var/mob/living/carbon/human/H = speaker
|
||||
speaker_name = H.GetVoice()
|
||||
|
||||
@@ -99,9 +99,9 @@
|
||||
if(speaker == src)
|
||||
to_chat(src, "<span class='warning'>You cannot hear yourself speak!</span>")
|
||||
else
|
||||
to_chat(src, "<span class='name'>[speaker_name]</span>[speaker.GetAltName()] talks but you cannot hear [speaker.p_them()].")
|
||||
to_chat(src, "<span class='name'>[speaker.name]</span> talks but you cannot hear [speaker.p_them()].")
|
||||
else
|
||||
to_chat(src, "<span class='game say'><span class='name'>[speaker_name]</span>[speaker.GetAltName()] [track][message]</span>")
|
||||
to_chat(src, "<span class='game say'><span class='name'>[speaker_name]</span>[use_voice ? speaker.GetAltName() : ""] [track][message]</span>")
|
||||
if(speech_sound && (get_dist(speaker, src) <= world.view && src.z == speaker.z))
|
||||
var/turf/source = speaker? get_turf(speaker) : get_turf(src)
|
||||
playsound_local(source, speech_sound, sound_vol, 1, sound_frequency)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user