", "\[cell\]")
text = replacetext(text, "", "\[logo\]")
return text
-
-#define string2charlist(string) (splittext(string, regex("(\\x0A|.)")) - splittext(string, ""))
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index d6caa29f670..fc0f7520e0e 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -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))
diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm
index 21af95cab48..ab3bfa85451 100644
--- a/code/_globalvars/lists/objects.dm
+++ b/code/_globalvars/lists/objects.dm
@@ -47,7 +47,10 @@ GLOBAL_LIST_EMPTY(ladders)
GLOBAL_LIST_INIT(active_diseases, list()) //List of Active disease in all mobs; purely for quick referencing.
GLOBAL_LIST_EMPTY(mob_spawners) // All mob_spawn objects
-
+GLOBAL_LIST_EMPTY(alert_consoles) // Station alert consoles, /obj/machinery/computer/station_alert
GLOBAL_LIST_EMPTY(explosive_walls)
GLOBAL_LIST_EMPTY(engine_beacon_list)
+
+/// List of wire colors for each object type of that round. One for airlocks, one for vendors, etc.
+GLOBAL_LIST_EMPTY(wire_color_directory) // This is an associative list with the `holder_type` as the key, and a list of colors as the value.
diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm
index f5f71e65c57..50e70bc62a4 100644
--- a/code/_globalvars/logging.dm
+++ b/code/_globalvars/logging.dm
@@ -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"))
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index fbb04d4c021..b0676eabdc7 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -145,12 +145,10 @@
/mob/living/silicon/ai/MiddleClickOn(var/atom/A)
A.AIMiddleClick(src)
-/*
- The following criminally helpful code is just the previous code cleaned up;
- I have no idea why it was in atoms.dm instead of respective files.
-*/
-/atom/proc/AICtrlShiftClick(var/mob/user) // Examines
+// DEFAULT PROCS TO OVERRIDE
+
+/atom/proc/AICtrlShiftClick(mob/user) // Examines
if(user.client)
user.examinate(src)
return
@@ -158,74 +156,86 @@
/atom/proc/AIAltShiftClick()
return
-/obj/machinery/door/airlock/AIAltShiftClick() // Sets/Unsets Emergency Access Override
- if(density)
- Topic(src, list("src" = UID(), "command"="emergency", "activate" = "1"), 1) // 1 meaning no window (consistency!)
- else
- Topic(src, list("src" = UID(), "command"="emergency", "activate" = "0"), 1)
- return
-
-/atom/proc/AIShiftClick(var/mob/user)
+/atom/proc/AIShiftClick(mob/living/user) // borgs use this too
if(user.client)
user.examinate(src)
return
-/obj/machinery/door/airlock/AIShiftClick() // Opens and closes doors!
- if(density)
- Topic(src, list("src" = UID(), "command"="open", "activate" = "1"), 1) // 1 meaning no window (consistency!)
- else
- Topic(src, list("src" = UID(), "command"="open", "activate" = "0"), 1)
+/atom/proc/AICtrlClick(mob/living/silicon/ai/user)
return
-/atom/proc/AICtrlClick(var/mob/living/silicon/ai/user)
- return
-
-/obj/machinery/door/airlock/AICtrlClick() // Bolts doors
- if(locked)
- Topic(src, list("src" = UID(), "command"="bolts", "activate" = "0"), 1)// 1 meaning no window (consistency!)
- else
- Topic(src, list("src" = UID(), "command"="bolts", "activate" = "1"), 1)
-
-/obj/machinery/power/apc/AICtrlClick() // turns off/on APCs.
- Topic("breaker=1", list("breaker"="1"), 0) // 0 meaning no window (consistency! wait...)
-
-/obj/machinery/turretid/AICtrlClick() //turns off/on Turrets
- Topic(src, list("src" = UID(), "command"="enable", "value"="[!enabled]"), 1) // 1 meaning no window (consistency!)
-
-/atom/proc/AIAltClick(var/atom/A)
+/atom/proc/AIAltClick(atom/A)
AltClick(A)
-/obj/machinery/door/airlock/AIAltClick() // Electrifies doors.
- if(!electrified_until)
- // permanent shock
- Topic(src, list("src" = UID(), "command"="electrify_permanently", "activate" = "1"), 1) // 1 meaning no window (consistency!)
- else
- // disable/6 is not in Topic; disable/5 disables both temporary and permanent shock
- Topic(src, list("src" = UID(), "command"="electrify_permanently", "activate" = "0"), 1)
+/atom/proc/AIMiddleClick(mob/living/user)
return
+/mob/living/silicon/ai/TurfAdjacent(turf/T)
+ return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(T))
+
+
+// APC
+
+/obj/machinery/power/apc/AICtrlClick(mob/living/user) // turns off/on APCs.
+ toggle_breaker(user)
+
+
+// TURRETCONTROL
+
+/obj/machinery/turretid/AICtrlClick(mob/living/silicon/ai/user) //turns off/on Turrets
+ enabled = !enabled
+ updateTurrets()
+
/obj/machinery/turretid/AIAltClick() //toggles lethal on turrets
- Topic(src, list("src" = UID(), "command"="lethal", "value"="[!lethal]"), 1) // 1 meaning no window (consistency!)
+ if(lethal_is_configurable)
+ lethal = !lethal
+ updateTurrets()
-/atom/proc/AIMiddleClick()
- return
+// AIRLOCKS
-/obj/machinery/door/airlock/AIMiddleClick() // Toggles door bolt lights.
- if(!src.lights)
- Topic(src, list("src" = UID(), "command"="lights", "activate" = "1"), 1) // 1 meaning no window (consistency!)
+/obj/machinery/door/airlock/AIAltShiftClick(mob/user) // Sets/Unsets Emergency Access Override
+ emergency = !emergency
+ update_icon()
+
+/obj/machinery/door/airlock/AIShiftClick(mob/user) // Opens and closes doors!
+ if(welded)
+ to_chat(user, "The airlock has been welded shut!")
+ if(locked)
+ locked = !locked
+ if(density)
+ open()
else
- Topic(src, list("src" = UID(), "command"="lights", "activate" = "0"), 1)
- return
+ close()
-/obj/machinery/ai_slipper/AICtrlClick() //Turns liquid dispenser on or off
+/obj/machinery/door/airlock/AICtrlClick(mob/living/silicon/ai/user) // Bolts doors
+ locked = !locked
+ update_icon()
+
+/obj/machinery/door/airlock/AIAltClick(mob/living/silicon/ai/user) // Electrifies doors.
+ if(wires.is_cut(WIRE_ELECTRIFY))
+ to_chat(user, "The electrification wire is cut - Cannot electrify the door.")
+ if(isElectrified())
+ electrify(0) // un-shock
+ else
+ electrify(-1) // permanent shock
+
+
+/obj/machinery/door/airlock/AIMiddleClick(mob/living/user) // Toggles door bolt lights.
+ if(wires.is_cut(WIRE_BOLT_LIGHT))
+ to_chat(user, "The bolt lights wire has been cut - The door bolt lights are permanently disabled.")
+ else if(lights)
+ lights = FALSE
+ to_chat(user, "The door bolt lights have been disabled.")
+ else if(!lights)
+ lights = TRUE
+ to_chat(user, "The door bolt lights have been enabled.")
+ update_icon()
+
+
+// AI-CONTROLLED SLIP GENERATOR IN AI CORE
+
+/obj/machinery/ai_slipper/AICtrlClick(mob/living/silicon/ai/user) //Turns liquid dispenser on or off
ToggleOn()
/obj/machinery/ai_slipper/AIAltClick() //Dispenses liquid if on
Activate()
-
-//
-// Override AdjacentQuick for AltClicking
-//
-
-/mob/living/silicon/ai/TurfAdjacent(var/turf/T)
- return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(T))
diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm
index ada0ce8cd30..856f724f925 100644
--- a/code/_onclick/hud/ai.dm
+++ b/code/_onclick/hud/ai.dm
@@ -64,7 +64,7 @@
/obj/screen/ai/alerts/Click()
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
- AI.subsystem_alarm_monitor()
+ AI.ai_alerts()
/obj/screen/ai/announcement
name = "Make Announcement"
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index a93e65c762b..7b53bce22de 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -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 = "[CEILING(timeleft / 10, 1)]"
+ 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,55 @@ 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/Topic(href, href_list)
+ if(..())
+ return TRUE
+
+ if(href_list["signup"] && isobserver(usr) && poll?.sign_up(usr))
+ display_signed_up()
+
+/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 = "[stacks]x"
+ 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"
diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm
index a291120fb85..67df5eb3013 100644
--- a/code/_onclick/hud/ghost.dm
+++ b/code/_onclick/hud/ghost.dm
@@ -81,6 +81,9 @@
/obj/screen/ghost/respawn_pai/Click()
var/mob/dead/observer/G = usr
+ if(!GLOB.paiController.check_recruit(G))
+ to_chat(G, "You are not eligible to become a pAI.")
+ return
GLOB.paiController.recruitWindow(G)
/datum/hud/ghost
diff --git a/code/_onclick/hud/guardian.dm b/code/_onclick/hud/guardian.dm
index d628124e052..6c9e95f457e 100644
--- a/code/_onclick/hud/guardian.dm
+++ b/code/_onclick/hud/guardian.dm
@@ -13,7 +13,7 @@
using.icon_state = mymob.a_intent
static_inventory += using
action_intent = using
-
+
using = new /obj/screen/guardian/Manifest()
using.screen_loc = ui_rhand
static_inventory += using
@@ -49,8 +49,8 @@
/obj/screen/guardian/Manifest/Click()
if(isguardian(usr))
var/mob/living/simple_animal/hostile/guardian/G = usr
- G.Manifest()
-
+ if(G.loc == G.summoner)
+ G.Manifest()
/obj/screen/guardian/Recall
icon_state = "recall"
diff --git a/code/controllers/subsystem/alarm.dm b/code/controllers/subsystem/alarm.dm
index 289adf6de40..3d91d763be3 100644
--- a/code/controllers/subsystem/alarm.dm
+++ b/code/controllers/subsystem/alarm.dm
@@ -1,31 +1,31 @@
-SUBSYSTEM_DEF(alarms)
- name = "Alarms"
- init_order = INIT_ORDER_ALARMS // 2
- offline_implications = "Alarms (Power, camera, fire, etc) will no longer be checked. No immediate action is needed."
- var/datum/alarm_handler/atmosphere/atmosphere_alarm = new()
- var/datum/alarm_handler/burglar/burglar_alarm = new()
- var/datum/alarm_handler/camera/camera_alarm = new()
- var/datum/alarm_handler/fire/fire_alarm = new()
- var/datum/alarm_handler/motion/motion_alarm = new()
- var/datum/alarm_handler/power/power_alarm = new()
- var/list/datum/alarm/all_handlers
+SUBSYSTEM_DEF(alarm)
+ name = "Alarm"
+ flags = SS_NO_INIT | SS_NO_FIRE
+ var/list/alarms = list("Motion" = list(), "Fire" = list(), "Atmosphere" = list(), "Power" = list(), "Camera" = list(), "Burglar" = list())
-/datum/controller/subsystem/alarms/Initialize(start_timeofday)
- all_handlers = list(SSalarms.atmosphere_alarm, SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.fire_alarm, SSalarms.motion_alarm, SSalarms.power_alarm)
- return ..()
+/datum/controller/subsystem/alarm/proc/triggerAlarm(class, area/A, list/O, obj/alarmsource)
+ var/list/L = alarms[class]
+ for(var/I in L)
+ if(I == A.name)
+ var/list/alarm = L[I]
+ var/list/sources = alarm[3]
+ if(!(alarmsource.UID() in sources))
+ sources += alarmsource.UID()
+ return TRUE
+ L[A.name] = list(get_area_name(A, TRUE), O, list(alarmsource.UID()))
+ SEND_SIGNAL(SSalarm, COMSIG_TRIGGERED_ALARM, class, A, O, alarmsource)
+ return TRUE
-/datum/controller/subsystem/alarms/fire()
- for(var/datum/alarm_handler/AH in all_handlers)
- AH.process()
+/datum/controller/subsystem/alarm/proc/cancelAlarm(class, area/A, obj/origin)
+ var/list/L = alarms[class]
+ var/cleared = FALSE
+ for(var/I in L)
+ if(I == A.name)
+ var/list/alarm = L[I]
+ var/list/srcs = alarm[3]
+ srcs -= origin.UID()
+ if(!length(srcs))
+ cleared = TRUE
+ L -= I
-/datum/controller/subsystem/alarms/proc/active_alarms()
- var/list/all_alarms = new ()
- for(var/datum/alarm_handler/AH in all_handlers)
- var/list/alarms = AH.alarms
- all_alarms += alarms
-
- return all_alarms
-
-/datum/controller/subsystem/alarms/proc/number_of_active_alarms()
- var/list/alarms = active_alarms()
- return alarms.len
+ SEND_SIGNAL(SSalarm, COMSIG_CANCELLED_ALARM, class, A, origin, cleared)
diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm
deleted file mode 100644
index 4eb468a0952..00000000000
--- a/code/controllers/subsystem/chat.dm
+++ /dev/null
@@ -1,67 +0,0 @@
-SUBSYSTEM_DEF(chat)
- name = "Chat"
- flags = SS_TICKER|SS_NO_INIT
- wait = 1
- priority = FIRE_PRIORITY_CHAT
- init_order = INIT_ORDER_CHAT
- offline_implications = "Chat messages will no longer be cleanly queued. No immediate action is needed."
-
- var/list/payload = list()
-
-
-/datum/controller/subsystem/chat/fire()
- for(var/i in payload)
- var/client/C = i
- if(C)
- C << output(payload[C], "browseroutput:output")
- payload -= C
-
- if(MC_TICK_CHECK)
- return
-
-
-/datum/controller/subsystem/chat/proc/queue(target, message, flag)
- if(!target || !message)
- return
-
- if(!istext(message))
- stack_trace("to_chat called with invalid input type")
- return
-
- if(target == world)
- target = GLOB.clients
-
- //Some macros remain in the string even after parsing and fuck up the eventual output
- message = replacetext(message, "\improper", "")
- message = replacetext(message, "\proper", "")
- message += " "
-
-
- //url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
- //Do the double-encoding here to save nanoseconds
- var/twiceEncoded = url_encode(url_encode(message))
-
- if(islist(target))
- for(var/I in target)
- var/client/C = CLIENT_FROM_VAR(I) //Grab us a client if possible
-
- if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
- continue
-
- if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
- C.chatOutput.messageQueue += message
- continue
-
- payload[C] += twiceEncoded
-
- else
- var/client/C = CLIENT_FROM_VAR(target) //Grab us a client if possible
-
- if(!C?.chatOutput || C.chatOutput.broken) //A player who hasn't updated his skin file.
- return
-
- if(!C.chatOutput.loaded) //Client still loading, put their messages in a queue
- C.chatOutput.messageQueue += message
- return
-
- payload[C] += twiceEncoded
diff --git a/code/controllers/subsystem/ghost_spawns.dm b/code/controllers/subsystem/ghost_spawns.dm
new file mode 100644
index 00000000000..ea0aefb88bd
--- /dev/null
+++ b/code/controllers/subsystem/ghost_spawns.dm
@@ -0,0 +1,275 @@
+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, role, antag_age_check, role, min_hours, check_antaghud))
+ 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
+
+ // Chat message
+ var/act_jump = ""
+ if(isatom(source))
+ act_jump = "\[Teleport]"
+ var/act_signup = "\[Sign Up]"
+ to_chat(M, "Now looking for candidates [role ? "to play as \an [get_roletext(role)]" : "\"[question]\""]. [act_jump] [act_signup]")
+
+ // 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, "You have already signed up for this!")
+ return
+ if(time_left() <= 0)
+ if(!silent)
+ to_chat(M, "Sorry, you were too late for the consideration!")
+ SEND_SOUND(M, 'sound/machines/buzz-sigh.ogg')
+ return
+
+ signed_up += M
+ if(!silent)
+ to_chat(M, "You have signed up for this role! A candidate will be picked randomly soon..")
+ // 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)
diff --git a/code/controllers/subsystem/jobs.dm b/code/controllers/subsystem/jobs.dm
index ef89317d0f5..3adfdf3972f 100644
--- a/code/controllers/subsystem/jobs.dm
+++ b/code/controllers/subsystem/jobs.dm
@@ -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("Automated Notification: \"[antext]\" (Unable to Reply)")
+
/datum/controller/subsystem/jobs/proc/fetch_transfer_record_html(var/centcom)
var/record_html = "
"
diff --git a/code/controllers/subsystem/processing/instruments.dm b/code/controllers/subsystem/processing/instruments.dm
new file mode 100644
index 00000000000..3d571d2a13d
--- /dev/null
+++ b/code/controllers/subsystem/processing/instruments.dm
@@ -0,0 +1,86 @@
+PROCESSING_SUBSYSTEM_DEF(instruments)
+ name = "Instruments"
+ init_order = INIT_ORDER_INSTRUMENTS
+ wait = 1
+ flags = SS_TICKER|SS_BACKGROUND|SS_KEEP_TIMING
+ offline_implications = "Instruments will no longer play. No immediate action is needed."
+
+ /// List of all instrument data, associative id = datum
+ var/list/datum/instrument/instrument_data
+ /// List of all song datums.
+ var/list/datum/song/songs
+ /// Max lines in songs
+ var/musician_maxlines = 600
+ /// Max characters per line in songs
+ var/musician_maxlinechars = 300
+ /// Deciseconds between hearchecks. Too high and instruments seem to lag when people are moving around in terms of who can hear it. Too low and the server lags from this.
+ var/musician_hearcheck_mindelay = 5
+ /// Maximum instrument channels total instruments are allowed to use. This is so you don't have instruments deadlocking all sound channels.
+ var/max_instrument_channels = MAX_INSTRUMENT_CHANNELS
+ /// Current number of channels allocated for instruments
+ var/current_instrument_channels = 0
+ /// Single cached list for synthesizer instrument ids, so you don't have to have a new list with every synthesizer.
+ var/list/synthesizer_instrument_ids
+
+/datum/controller/subsystem/processing/instruments/Initialize()
+ initialize_instrument_data()
+ synthesizer_instrument_ids = get_allowed_instrument_ids()
+ return ..()
+
+/**
+ * Initializes all instrument datums
+ */
+/datum/controller/subsystem/processing/instruments/proc/initialize_instrument_data()
+ instrument_data = list()
+ for(var/path in subtypesof(/datum/instrument))
+ var/datum/instrument/I = path
+ if(initial(I.abstract_type) == path)
+ continue
+ I = new path
+ I.Initialize()
+ if(!I.id)
+ qdel(I)
+ continue
+ else
+ instrument_data[I.id] = I
+ CHECK_TICK
+
+/**
+ * Reserves a sound channel for a given instrument datum
+ *
+ * Arguments:
+ * * I - The instrument datum
+ */
+/datum/controller/subsystem/processing/instruments/proc/reserve_instrument_channel(datum/instrument/I)
+ if(current_instrument_channels > max_instrument_channels)
+ return
+ . = SSsounds.reserve_sound_channel(I)
+ if(!isnull(.))
+ current_instrument_channels++
+
+/**
+ * Called when a datum/song is created
+ *
+ * Arguments:
+ * * S - The created datum/song
+ */
+/datum/controller/subsystem/processing/instruments/proc/on_song_new(datum/song/S)
+ LAZYADD(songs, S)
+
+/**
+ * Called when a datum/song is deleted
+ *
+ * Arguments:
+ * * S - The deleted datum/song
+ */
+/datum/controller/subsystem/processing/instruments/proc/on_song_del(datum/song/S)
+ LAZYREMOVE(songs, S)
+
+/**
+ * Returns the instrument datum at the given ID or path
+ *
+ * Arguments:
+ * * id_or_path - The ID or path of the instrument
+ */
+/datum/controller/subsystem/processing/instruments/proc/get_instrument(id_or_path)
+ return instrument_data["[id_or_path]"]
diff --git a/code/controllers/subsystem/shuttles.dm b/code/controllers/subsystem/shuttles.dm
index 247d71d05b8..08fa7709320 100644
--- a/code/controllers/subsystem/shuttles.dm
+++ b/code/controllers/subsystem/shuttles.dm
@@ -14,9 +14,9 @@ SUBSYSTEM_DEF(shuttle)
//emergency shuttle stuff
var/obj/docking_port/mobile/emergency/emergency
var/obj/docking_port/mobile/emergency/backup/backup_shuttle
- var/emergencyCallTime = 6000 //time taken for emergency shuttle to reach the station when called (in deciseconds)
- var/emergencyDockTime = 1800 //time taken for emergency shuttle to leave again once it has docked (in deciseconds)
- var/emergencyEscapeTime = 1200 //time taken for emergency shuttle to reach a safe distance after leaving station (in deciseconds)
+ var/emergencyCallTime = SHUTTLE_CALLTIME //time taken for emergency shuttle to reach the station when called (in deciseconds)
+ var/emergencyDockTime = SHUTTLE_DOCKTIME //time taken for emergency shuttle to leave again once it has docked (in deciseconds)
+ var/emergencyEscapeTime = SHUTTLE_ESCAPETIME //time taken for emergency shuttle to reach a safe distance after leaving station (in deciseconds)
var/emergency_sec_level_time = 0 // time sec level was last raised to red or higher
var/area/emergencyLastCallLoc
var/emergencyNoEscape
diff --git a/code/controllers/subsystem/sounds.dm b/code/controllers/subsystem/sounds.dm
new file mode 100644
index 00000000000..33d97fcfe04
--- /dev/null
+++ b/code/controllers/subsystem/sounds.dm
@@ -0,0 +1,165 @@
+#define DATUMLESS "NO_DATUM"
+
+SUBSYSTEM_DEF(sounds)
+ name = "Sounds"
+ init_order = INIT_ORDER_SOUNDS
+ flags = SS_NO_FIRE
+ offline_implications = "Sounds may not play correctly. Shuttle call recommended."
+
+ var/using_channels_max = CHANNEL_HIGHEST_AVAILABLE // BYOND max channels
+ /// Amount of channels to reserve for random usage rather than reservations being allowed to reserve all channels. Also a nice safeguard for when someone screws up.
+ var/random_channels_min = 50
+ // Hey uh these two needs to be initialized fast because the whole "things get deleted before init" thing.
+ /// Assoc list, "[channel]" = either the datum using it or TRUE for an unsafe-reserved (datumless reservation) channel
+ var/list/using_channels
+ /// Assoc list datum = list(channel1, channel2, ...) for what channels something reserved.
+ var/list/using_channels_by_datum
+ // Special datastructure for fast channel management
+ /// List of all channels as numbers
+ var/list/channel_list
+ /// Associative list of all reserved channels associated to their position. "[channel_number]" = index as number
+ var/list/reserved_channels
+ /// lower iteration position - Incremented and looped to get "random" sound channels for normal sounds. The channel at this index is returned when asking for a random channel.
+ var/channel_random_low
+ /// higher reserve position - decremented and incremented to reserve sound channels, anything above this is reserved. The channel at this index is the highest unreserved channel.
+ var/channel_reserve_high
+
+/datum/controller/subsystem/sounds/Initialize()
+ setup_available_channels()
+ return ..()
+
+/**
+ * Sets up all available sound channels
+ */
+/datum/controller/subsystem/sounds/proc/setup_available_channels()
+ channel_list = list()
+ reserved_channels = list()
+ using_channels = list()
+ using_channels_by_datum = list()
+ for(var/i in 1 to using_channels_max)
+ channel_list += i
+ channel_random_low = 1
+ channel_reserve_high = length(channel_list)
+
+/**
+ * Removes a channel from using list
+ *
+ * Arguments:
+ * * channel - The channel number
+ */
+/datum/controller/subsystem/sounds/proc/free_sound_channel(channel)
+ var/text_channel = num2text(channel)
+ var/using = using_channels[text_channel]
+ using_channels -= text_channel
+ if(!using) // datum channel
+ using_channels_by_datum[using] -= channel
+ if(!length(using_channels_by_datum[using]))
+ using_channels_by_datum -= using
+ free_channel(channel)
+
+/**
+ * Frees all the channels a datum is using
+ *
+ * Arguments:
+ * * D - The datum
+ */
+/datum/controller/subsystem/sounds/proc/free_datum_channels(datum/D)
+ var/list/L = using_channels_by_datum[D]
+ if(!L)
+ return
+ for(var/channel in L)
+ using_channels -= num2text(channel)
+ free_channel(channel)
+ using_channels_by_datum -= D
+
+/**
+ * Frees all datumless channels
+ */
+/datum/controller/subsystem/sounds/proc/free_datumless_channels()
+ free_datum_channels(DATUMLESS)
+
+/**
+ * NO AUTOMATIC CLEANUP - If you use this, you better manually free it later!
+ *
+ * Returns an integer for channel
+ */
+/datum/controller/subsystem/sounds/proc/reserve_sound_channel_datumless()
+ . = reserve_channel()
+ if(!.) // oh no..
+ return FALSE
+ var/text_channel = num2text(.)
+ using_channels[text_channel] = DATUMLESS
+ LAZYADD(using_channels_by_datum[DATUMLESS], .)
+
+/**
+ * Reserves a channel for a datum. Automatic cleanup only when the datum is deleted.
+ *
+ * Returns an integer for channel
+ * Arguments:
+ * * D - The datum
+ */
+/datum/controller/subsystem/sounds/proc/reserve_sound_channel(datum/D)
+ if(!D) // i don't like typechecks but someone will fuck it up
+ CRASH("Attempted to reserve sound channel without datum using the managed proc.")
+ . = reserve_channel()
+ if(!.)
+ return FALSE
+ var/text_channel = num2text(.)
+ using_channels[text_channel] = D
+ LAZYADD(using_channels_by_datum[D], .)
+
+/**
+ * Reserves a channel and updates the datastructure. Private proc.
+ */
+/datum/controller/subsystem/sounds/proc/reserve_channel()
+ PRIVATE_PROC(TRUE)
+ if(channel_reserve_high <= random_channels_min) // out of channels
+ return
+ var/channel = channel_list[channel_reserve_high]
+ reserved_channels[num2text(channel)] = channel_reserve_high--
+ return channel
+
+/**
+ * Frees a channel and updates the datastructure. Private proc.
+ */
+/datum/controller/subsystem/sounds/proc/free_channel(number)
+ PRIVATE_PROC(TRUE)
+ var/text_channel = num2text(number)
+ var/index = reserved_channels[text_channel]
+ if(!index)
+ CRASH("Attempted to (internally) free a channel that wasn't reserved.")
+ reserved_channels -= text_channel
+ // push reserve index up, which makes it now on a channel that is reserved
+ channel_reserve_high++
+ // swap the reserved channel with the unreserved channel so the reserve index is now on an unoccupied channel and the freed channel is next to be used.
+ channel_list.Swap(channel_reserve_high, index)
+ // now, an existing reserved channel will likely (exception: unreserving last reserved channel) be at index
+ // get it, and update position.
+ var/text_reserved = num2text(channel_list[index])
+ if(!reserved_channels[text_reserved]) // if it isn't already reserved make sure we don't accidently mistakenly put it on reserved list!
+ return
+ reserved_channels[text_reserved] = index
+
+/**
+ * Random available channel, returns text
+ */
+/datum/controller/subsystem/sounds/proc/random_available_channel_text()
+ if(channel_random_low > channel_reserve_high)
+ channel_random_low = 1
+ . = "[channel_list[channel_random_low++]]"
+
+/**
+ * Random available channel, returns number
+ */
+/datum/controller/subsystem/sounds/proc/random_available_channel()
+ if(channel_random_low > channel_reserve_high)
+ channel_random_low = 1
+ . = channel_list[channel_random_low++]
+
+/**
+ * How many channels we have left
+ */
+/datum/controller/subsystem/sounds/proc/available_channels_left()
+ return length(channel_list) - random_channels_min
+
+#undef DATUMLESS
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 5d0a53c221e..e53c91ac20d 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -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, "Welcome to the pre-game lobby!")
+ to_chat(world, "Welcome to the pre-game lobby!")
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, "Enjoy the game!")
+ to_chat(world, "Enjoy the game!")
world << sound('sound/AI/welcome.ogg')// Skie
if(SSholiday.holidays)
- to_chat(world, "and...")
+ to_chat(world, "and...")
for(var/holidayname in SSholiday.holidays)
var/datum/holiday/holiday = SSholiday.holidays[holidayname]
to_chat(world, "
[holiday.greet()]
")
diff --git a/code/controllers/subsystem/tickets/mentor_tickets.dm b/code/controllers/subsystem/tickets/mentor_tickets.dm
index 3fd003418a4..af4ea2e914d 100644
--- a/code/controllers/subsystem/tickets/mentor_tickets.dm
+++ b/code/controllers/subsystem/tickets/mentor_tickets.dm
@@ -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("- [ticket_name] Closed -",
"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.",
"Your [ticket_name] has now been closed.")
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)
diff --git a/code/controllers/subsystem/tickets/tickets.dm b/code/controllers/subsystem/tickets/tickets.dm
index 879ee35abee..64f91e96b6c 100644
--- a/code/controllers/subsystem/tickets/tickets.dm
+++ b/code/controllers/subsystem/tickets/tickets.dm
@@ -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), "Your [ticket_name] has now been resolved.")
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("[key_name_hidden(C)] has converted your ticket to a [other_ticket_name] ticket.",\
+ "Be sure to use the correct type of help next time!"))
+ message_staff("[C] has converted ticket number [T.ticketNum] to a [other_ticket_name] ticket.")
+ 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: [message_key] ")
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), "[key_name_hidden(C)] is autoresponding with: [response_phrases[message_key]]")//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), "[key_name_hidden(C)] is autoresponding with: [response_phrases[message_key]]")//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: [message_key] ") //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 += "
"
-
- usr << browse(dat, "window=players;size=640x480")
-
-
/datum/admins/proc/check_antagonists_line(mob/M, caption = "", close = 1)
var/logout_status
diff --git a/code/modules/admin/tickets/adminticketsverbs.dm b/code/modules/admin/tickets/adminticketsverbs.dm
index 406019745f8..4e8e79f2a26 100644
--- a/code/modules/admin/tickets/adminticketsverbs.dm
+++ b/code/modules/admin/tickets/adminticketsverbs.dm
@@ -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")
diff --git a/code/modules/admin/tickets/mentorticketsverbs.dm b/code/modules/admin/tickets/mentorticketsverbs.dm
index d65f4a30220..c7bec3e043d 100644
--- a/code/modules/admin/tickets/mentorticketsverbs.dm
+++ b/code/modules/admin/tickets/mentorticketsverbs.dm
@@ -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")
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 1d2c75aff0a..2390394b280 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -14,7 +14,7 @@
if(!check_rights(R_ADMIN|R_MOD))
return
var/client/C = locateUID(href_list["rejectadminhelp"])
- if(!C)
+ if(!isclient(C))
return
C << 'sound/effects/adminhelp.ogg'
@@ -114,39 +114,39 @@
switch(bantype)
if(BANTYPE_PERMA)
if(!banckey || !banreason)
- to_chat(usr, "Not enough parameters (Requires ckey and reason)")
+ to_chat(usr, "Not enough parameters (Requires ckey and reason)")
return
banduration = null
banjob = null
if(BANTYPE_TEMP)
if(!banckey || !banreason || !banduration)
- to_chat(usr, "Not enough parameters (Requires ckey, reason and duration)")
+ to_chat(usr, "Not enough parameters (Requires ckey, reason and duration)")
return
banjob = null
if(BANTYPE_JOB_PERMA)
if(!banckey || !banreason || !banjob)
- to_chat(usr, "Not enough parameters (Requires ckey, reason and job)")
+ to_chat(usr, "Not enough parameters (Requires ckey, reason and job)")
return
banduration = null
if(BANTYPE_JOB_TEMP)
if(!banckey || !banreason || !banjob || !banduration)
- to_chat(usr, "Not enough parameters (Requires ckey, reason and job)")
+ to_chat(usr, "Not enough parameters (Requires ckey, reason and job)")
return
if(BANTYPE_APPEARANCE)
if(!banckey || !banreason)
- to_chat(usr, "Not enough parameters (Requires ckey and reason)")
+ to_chat(usr, "Not enough parameters (Requires ckey and reason)")
return
banduration = null
banjob = null
if(BANTYPE_ADMIN_PERMA)
if(!banckey || !banreason)
- to_chat(usr, "Not enough parameters (Requires ckey and reason)")
+ to_chat(usr, "Not enough parameters (Requires ckey and reason)")
return
banduration = null
banjob = null
if(BANTYPE_ADMIN_TEMP)
if(!banckey || !banreason || !banduration)
- to_chat(usr, "Not enough parameters (Requires ckey, reason and duration)")
+ to_chat(usr, "Not enough parameters (Requires ckey, reason and duration)")
return
banjob = null
@@ -324,8 +324,8 @@
if(!check_rights(R_SPAWN)) return
var/mob/M = locateUID(href_list["mob"])
- if(!ismob(M))
- to_chat(usr, "This can only be used on instances of type /mob")
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
return
var/delmob = 0
@@ -436,18 +436,18 @@
if(!check_rights(R_BAN))
return
var/mob/M = locateUID(href_list["appearanceban"])
- if(!ismob(M))
- to_chat(usr, "This can only be used on instances of type /mob")
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
return
if(!M.ckey) //sanity
- to_chat(usr, "This mob has no ckey")
+ to_chat(usr, "This mob has no ckey")
return
var/ban_ckey_param = href_list["dbbanaddckey"]
var/banreason = appearance_isbanned(M)
if(banreason)
/* if(!config.ban_legacy_system)
- to_chat(usr, "Unfortunately, database based unbanning cannot be done through this panel")
+ to_chat(usr, "Unfortunately, database based unbanning cannot be done through this panel")
DB_ban_panel(M.ckey)
return */
switch(alert("Reason: '[banreason]' Remove appearance ban?","Please Confirm","Yes","No"))
@@ -458,7 +458,7 @@
DB_ban_unban(M.ckey, BANTYPE_APPEARANCE)
appearance_unban(M)
message_admins("[key_name_admin(usr)] removed [key_name_admin(M)]'s appearance ban", 1)
- to_chat(M, "[usr.client.ckey] has removed your appearance ban.")
+ to_chat(M, "[usr.client.ckey] has removed your appearance ban.")
else switch(alert("Appearance ban [M.ckey]?",,"Yes","No", "Cancel"))
if("Yes")
@@ -473,7 +473,7 @@
appearance_fullban(M, "[reason]; By [usr.ckey] on [time2text(world.realtime)]")
add_note(M.ckey, "Appearance banned - [reason]", null, usr.ckey, 0)
message_admins("[key_name_admin(usr)] appearance banned [key_name_admin(M)]", 1)
- to_chat(M, "You have been appearance banned by [usr.client.ckey].")
+ to_chat(M, "You have been appearance banned by [usr.client.ckey].")
to_chat(M, "The reason is: [reason]")
to_chat(M, "Appearance ban can be lifted only upon request.")
if(config.banappeals)
@@ -487,15 +487,15 @@
// if(!check_rights(R_BAN)) return
var/mob/M = locateUID(href_list["jobban2"])
- if(!ismob(M))
- to_chat(usr, "This can only be used on instances of type /mob")
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
return
if(!M.ckey) //sanity
- to_chat(usr, "This mob has no ckey")
+ to_chat(usr, "This mob has no ckey")
return
if(!SSjobs)
- to_chat(usr, "SSjobs has not been setup!")
+ to_chat(usr, "SSjobs has not been setup!")
return
var/dat = ""
@@ -735,8 +735,8 @@
if(!check_rights(R_BAN)) return
var/mob/M = locateUID(href_list["jobban4"])
- if(!ismob(M))
- to_chat(usr, "This can only be used on instances of type /mob")
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
return
if(M != usr) //we can jobban ourselves
@@ -747,7 +747,7 @@
var/ban_ckey_param = href_list["dbbanaddckey"]
if(!SSjobs)
- to_chat(usr, "SSjobs has not been setup!")
+ to_chat(usr, "SSjobs has not been setup!")
return
//get jobs for department if specified, otherwise just returnt he one job in a list.
@@ -840,7 +840,7 @@
msg += ", [job]"
add_note(M.ckey, "Banned from [msg] - [reason]", null, usr.ckey, 0)
message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg] for [mins] minutes", 1)
- to_chat(M, "You have been jobbanned by [usr.client.ckey] from: [msg].")
+ to_chat(M, "You have been jobbanned by [usr.client.ckey] from: [msg].")
to_chat(M, "The reason is: [reason]")
to_chat(M, "This jobban will be lifted in [mins] minutes.")
href_list["jobban2"] = 1 // lets it fall through and refresh
@@ -861,7 +861,7 @@
else msg += ", [job]"
add_note(M.ckey, "Banned from [msg] - [reason]", null, usr.ckey, 0)
message_admins("[key_name_admin(usr)] banned [key_name_admin(M)] from [msg]", 1)
- to_chat(M, "You have been jobbanned by [usr.client.ckey] from: [msg].")
+ to_chat(M, "You have been jobbanned by [usr.client.ckey] from: [msg].")
to_chat(M, "The reason is: [reason]")
to_chat(M, "Jobban can be lifted only upon request.")
href_list["jobban2"] = 1 // lets it fall through and refresh
@@ -873,7 +873,7 @@
//all jobs in joblist are banned already OR we didn't give a reason (implying they shouldn't be banned)
if(joblist.len) //at least 1 banned job exists in joblist so we have stuff to unban.
if(!config.ban_legacy_system)
- to_chat(usr, "Unfortunately, database based unbanning cannot be done through this panel")
+ to_chat(usr, "Unfortunately, database based unbanning cannot be done through this panel")
DB_ban_panel(M.ckey)
return
var/msg
@@ -894,22 +894,28 @@
continue
if(msg)
message_admins("[key_name_admin(usr)] unbanned [key_name_admin(M)] from [msg]", 1)
- to_chat(M, "You have been un-jobbanned by [usr.client.ckey] from [msg].")
+ to_chat(M, "You have been un-jobbanned by [usr.client.ckey] from [msg].")
href_list["jobban2"] = 1 // lets it fall through and refresh
return 1
return 0 //we didn't do anything!
else if(href_list["boot2"])
var/mob/M = locateUID(href_list["boot2"])
- if(ismob(M))
- if(M.client && M.client.holder && (M.client.holder.rights & R_BAN))
- to_chat(usr, "[key_name_admin(M)] cannot be kicked from the server.")
+ if(!ismob(M))
+ return
+ var/client/C = M.client
+ if(C == null)
+ to_chat(usr, "Mob has no client to kick.")
+ return
+ if(alert("Kick [C.ckey]?",,"Yes","No") == "Yes")
+ if(C && C.holder && (C.holder.rights & R_BAN))
+ to_chat(usr, "[key_name_admin(C)] cannot be kicked from the server.")
return
- to_chat(M, "You have been kicked from the server")
- log_admin("[key_name(usr)] booted [key_name(M)].")
- message_admins("[key_name_admin(usr)] booted [key_name_admin(M)].", 1)
- //M.client = null
- qdel(M.client)
+ to_chat(C, "You have been kicked from the server")
+ log_admin("[key_name(usr)] booted [key_name(C)].")
+ message_admins("[key_name_admin(usr)] booted [key_name_admin(C)].", 1)
+ //C = null
+ qdel(C)
else if(href_list["open_logging_view"])
var/mob/M = locateUID(href_list["open_logging_view"])
@@ -986,7 +992,7 @@
if(!check_rights(R_BAN)) return
var/mob/M = locateUID(href_list["newban"])
- if(!ismob(M))
+ if(!istype(M, /mob))
return
var/ban_ckey_param = href_list["dbbanaddckey"]
@@ -1002,7 +1008,7 @@
M = admin_ban_mobsearch(M, ban_ckey_param, usr)
AddBan(M.ckey, M.computer_id, reason, usr.ckey, 1, mins)
ban_unban_log_save("[usr.client.ckey] has banned [M.ckey]. - Reason: [reason] - This will be removed in [mins] minutes.")
- to_chat(M, "You have been banned by [usr.client.ckey].\nReason: [reason].")
+ to_chat(M, "You have been banned by [usr.client.ckey].\nReason: [reason].")
to_chat(M, "This is a temporary ban, it will be removed in [mins] minutes.")
feedback_inc("ban_tmp",1)
DB_ban_record(BANTYPE_TEMP, M, mins, reason)
@@ -1022,7 +1028,7 @@
if(!reason)
return
AddBan(M.ckey, M.computer_id, reason, usr.ckey, 0, 0, M.lastKnownIP)
- to_chat(M, "You have been banned by [usr.client.ckey].\nReason: [reason].")
+ to_chat(M, "You have been banned by [usr.client.ckey].\nReason: [reason].")
to_chat(M, "This ban does not expire automatically and must be appealed.")
if(M.client)
M.client.link_forum_account(TRUE)
@@ -1090,7 +1096,7 @@
return
var/mob/M = locateUID(href_list["mute"])
- if(!ismob(M)) return
+ if(!istype(M, /mob)) return
if(!M.client) return
var/mute_type = href_list["mute_type"]
@@ -1104,7 +1110,7 @@
if(SSticker && SSticker.mode)
return alert(usr, "The game has already started.", null, null, null, null)
- var/dat = {"What mode do you wish to play?"}
+ var/dat = {"What mode do you wish to play?"}
for(var/mode in config.modes)
dat += {"[config.mode_names[mode]] "}
dat += {"Secret "}
@@ -1119,7 +1125,7 @@
return alert(usr, "The game has already started.", null, null, null, null)
if(GLOB.master_mode != "secret")
return alert(usr, "The game mode has to be secret!", null, null, null, null)
- var/dat = {"What game mode do you want to force secret to be? Use this if you want to change the game mode, but want the players to believe it's secret. This will only work if the current game mode is secret."}
+ var/dat = {"What game mode do you want to force secret to be? Use this if you want to change the game mode, but want the players to believe it's secret. This will only work if the current game mode is secret."}
for(var/mode in config.modes)
dat += {"[config.mode_names[mode]] "}
dat += {"Random (default) "}
@@ -1157,7 +1163,7 @@
var/mob/living/carbon/human/H = locateUID(href_list["monkeyone"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
if(alert(usr, "Confirm make monkey?",, "Yes", "No") != "Yes")
return
@@ -1172,7 +1178,7 @@
var/mob/living/carbon/human/H = locateUID(href_list["corgione"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
if(alert(usr, "Confirm make corgi?",, "Yes", "No") != "Yes")
@@ -1187,7 +1193,7 @@
var/mob/living/carbon/human/H = locateUID(href_list["makePAI"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
if(alert(usr, "Confirm make pai?",, "Yes", "No") != "Yes")
return
@@ -1210,8 +1216,9 @@
if(!check_rights(R_SERVER|R_EVENT)) return
var/mob/M = locateUID(href_list["forcespeech"])
- if(!ismob(M))
- to_chat(usr, "this can only be used on instances of type /mob")
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
var/speech = input("What will [key_name(M)] say?.", "Force speech", "")// Don't need to sanitize, since it does that in say(), we also trust our admins.
if(!speech) return
@@ -1227,11 +1234,11 @@
return
var/mob/M = locateUID(href_list["sendtoprison"])
- if(!ismob(M))
- to_chat(usr, "This can only be used on instances of type /mob")
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
return
if(istype(M, /mob/living/silicon/ai))
- to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai")
+ to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai")
return
var/turf/prison_cell = pick(GLOB.prisonwarp)
@@ -1290,6 +1297,71 @@
NP.ckey = M.ckey
qdel(M)
+ else if(href_list["eraseflavortext"])
+ if(!check_rights(R_ADMIN))
+ return
+
+ var/mob/M = locateUID(href_list["eraseflavortext"])
+
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
+
+ if(!M.client)
+ to_chat(usr, "[M] doesn't seem to have an active client.")
+ return
+
+ if(M.flavor_text == "" && M.client.prefs.flavor_text == "")
+ to_chat(usr, "[M] has no flavor text set.")
+ return
+
+ if(alert(usr, "Erase [key_name(M)]'s flavor text?", "Message", "Yes", "No") != "Yes")
+ return
+
+ log_admin("[key_name(usr)] has erased [key_name(M)]'s flavor text.")
+ message_admins("[key_name_admin(usr)] has erased [key_name_admin(M)]'s flavor text.")
+
+ // Clears the mob's flavor text
+ M.flavor_text = ""
+
+ // Clear and save the DB character's flavor text
+ M.client.prefs.flavor_text = ""
+ M.client.prefs.save_character(M.client)
+
+ else if(href_list["userandomname"])
+ if(!check_rights(R_ADMIN))
+ return
+
+ var/mob/M = locateUID(href_list["userandomname"])
+
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
+
+ if(!M.client)
+ to_chat(usr, "[M] doesn't seem to have an active client.")
+ return
+
+ if(alert(usr, "Force [key_name(M)] to use a random name?", "Message", "Yes", "No") != "Yes")
+ return
+
+ log_admin("[key_name(usr)] has forced [key_name(M)] to use a random name.")
+ message_admins("[key_name_admin(usr)] has forced [key_name_admin(M)] to use a random name.")
+
+ // Update the mob's name with a random one straight away
+ var/random_name = random_name(M.client.prefs.gender, M.client.prefs.species)
+ M.rename_character(M.real_name, random_name)
+
+ // Save that random name for next rounds
+ M.client.prefs.real_name = random_name
+ M.client.prefs.save_character(M.client)
+
+ else if(href_list["asays"])
+ if(!check_rights(R_ADMIN))
+ return
+
+ usr.client.view_asays()
+
else if(href_list["tdome1"])
if(!check_rights(R_SERVER|R_EVENT)) return
@@ -1297,11 +1369,11 @@
return
var/mob/M = locateUID(href_list["tdome1"])
- if(!ismob(M))
- to_chat(usr, "This can only be used on instances of type /mob")
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
return
if(istype(M, /mob/living/silicon/ai))
- to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai")
+ to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai")
return
for(var/obj/item/I in M)
@@ -1327,11 +1399,11 @@
return
var/mob/M = locateUID(href_list["tdome2"])
- if(!ismob(M))
- to_chat(usr, "This can only be used on instances of type /mob")
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
return
if(istype(M, /mob/living/silicon/ai))
- to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai")
+ to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai")
return
for(var/obj/item/I in M)
@@ -1357,11 +1429,11 @@
return
var/mob/M = locateUID(href_list["tdomeadmin"])
- if(!ismob(M))
- to_chat(usr, "This can only be used on instances of type /mob")
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
return
if(istype(M, /mob/living/silicon/ai))
- to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai")
+ to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai")
return
M.Paralyse(5)
@@ -1379,11 +1451,11 @@
return
var/mob/M = locateUID(href_list["tdomeobserve"])
- if(!ismob(M))
- to_chat(usr, "This can only be used on instances of type /mob")
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
return
if(istype(M, /mob/living/silicon/ai))
- to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai")
+ to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai")
return
for(var/obj/item/I in M)
@@ -1413,11 +1485,11 @@
return
var/mob/M = locateUID(href_list["aroomwarp"])
- if(!ismob(M))
- to_chat(usr, "This can only be used on instances of type /mob")
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
return
if(istype(M, /mob/living/silicon/ai))
- to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai")
+ to_chat(usr, "This cannot be used on instances of type /mob/living/silicon/ai")
return
M.Paralyse(5)
@@ -1434,7 +1506,7 @@
var/mob/living/L = locateUID(href_list["revive"])
if(!istype(L))
- to_chat(usr, "This can only be used on instances of type /mob/living")
+ to_chat(usr, "This can only be used on instances of type /mob/living")
return
L.revive()
@@ -1446,7 +1518,7 @@
var/mob/living/carbon/human/H = locateUID(href_list["makeai"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
if(alert(usr, "Confirm make ai?",, "Yes", "No") != "Yes")
@@ -1462,7 +1534,7 @@
var/mob/living/carbon/human/H = locateUID(href_list["makealien"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
if(alert(usr, "Confirm make alien?",, "Yes", "No") != "Yes")
return
@@ -1474,7 +1546,7 @@
var/mob/living/carbon/human/H = locateUID(href_list["makeslime"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
if(alert(usr, "Confirm make slime?",, "Yes", "No") != "Yes")
return
@@ -1486,7 +1558,7 @@
var/mob/living/carbon/human/H = locateUID(href_list["makesuper"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
if(alert(usr, "Confirm make superhero?",, "Yes", "No") != "Yes")
@@ -1499,7 +1571,7 @@
var/mob/living/carbon/human/H = locateUID(href_list["makerobot"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
if(alert(usr, "Confirm make robot?",, "Yes", "No") != "Yes")
return
@@ -1511,7 +1583,7 @@
var/mob/M = locateUID(href_list["makeanimal"])
if(isnewplayer(M))
- to_chat(usr, "This cannot be used on instances of type /mob/new_player")
+ to_chat(usr, "This cannot be used on instances of type /mob/new_player")
return
if(alert(usr, "Confirm make animal?",, "Yes", "No") != "Yes")
return
@@ -1524,10 +1596,14 @@
var/mob/dead/observer/G = locateUID(href_list["incarn_ghost"])
if(!istype(G))
- to_chat(usr, "This will only work on /mob/dead/observer")
+ to_chat(usr, "This will only work on /mob/dead/observer")
+ return
var/posttransformoutfit = usr.client.robust_dress_shop()
+ if(!posttransformoutfit)
+ return
+
var/mob/living/carbon/human/H = G.incarnate_ghost()
if(posttransformoutfit && istype(H))
@@ -1541,7 +1617,7 @@
var/mob/living/carbon/human/H = locateUID(href_list["togmutate"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
var/block=text2num(href_list["block"])
//testing("togmutate([href_list["block"]] -> [block])")
@@ -1551,6 +1627,11 @@
else if(href_list["adminplayeropts"])
var/mob/M = locateUID(href_list["adminplayeropts"])
+
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
+
show_player_panel(M)
else if(href_list["adminplayerobservefollow"])
@@ -1560,6 +1641,11 @@
return
C.admin_ghost()
var/mob/M = locateUID(href_list["adminplayerobservefollow"])
+
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
+
var/mob/dead/observer/A = C.mob
sleep(2)
A.ManualFollow(M)
@@ -1588,6 +1674,12 @@
return
SStickets.autoRespond(index)
+ if(href_list["convert_ticket"])
+ var/indexNum = text2num(href_list["convert_ticket"])
+ if(href_list["is_mhelp"])
+ SSmentor_tickets.convert_to_other_ticket(indexNum)
+ else
+ SStickets.convert_to_other_ticket(indexNum)
else if(href_list["cult_nextobj"])
if(alert(usr, "Validate the current Cult objective and unlock the next one?", "Cult Cheat Code", "Yes", "No") != "Yes")
return
@@ -1608,10 +1700,10 @@
for(var/datum/mind/H in SSticker.mode.cult)
if (H.current)
- to_chat(H.current, "[SSticker.cultdat.entity_name] murmurs, [input]")
+ to_chat(H.current, "[SSticker.cultdat.entity_name] murmurs, [input]")
for(var/mob/dead/observer/O in GLOB.player_list)
- to_chat(O, "[SSticker.cultdat.entity_name] murmurs, [input]")
+ to_chat(O, "[SSticker.cultdat.entity_name] murmurs, [input]")
message_admins("Admin [key_name_admin(usr)] has talked with the Voice of [SSticker.cultdat.entity_name].")
log_admin("[key_name(usr)] Voice of [SSticker.cultdat.entity_name]: [input]")
@@ -1633,6 +1725,11 @@
else if(href_list["adminmoreinfo"])
var/mob/M = locateUID(href_list["adminmoreinfo"])
+
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
+
admin_mob_info(M)
else if(href_list["adminspawncookie"])
@@ -1640,7 +1737,7 @@
var/mob/living/carbon/human/H = locateUID(href_list["adminspawncookie"])
if(!ishuman(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
H.equip_to_slot_or_del( new /obj/item/reagent_containers/food/snacks/cookie(H), slot_l_hand )
@@ -1664,7 +1761,7 @@
var/mob/living/M = locateUID(href_list["BlueSpaceArtillery"])
if(!isliving(M))
- to_chat(usr, "This can only be used on instances of type /mob/living")
+ to_chat(usr, "This can only be used on instances of type /mob/living")
return
if(alert(owner, "Are you sure you wish to hit [key_name(M)] with Bluespace Artillery?", "Confirm Firing?" , "Yes" , "No") != "Yes")
@@ -1702,6 +1799,11 @@
return
var/mob/M = locateUID(href_list["CentcommReply"])
+
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
+
usr.client.admin_headset_message(M, "Centcomm")
else if(href_list["SyndicateReply"])
@@ -1709,6 +1811,11 @@
return
var/mob/M = locateUID(href_list["SyndicateReply"])
+
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
+
usr.client.admin_headset_message(M, "Syndicate")
else if(href_list["HeadsetMessage"])
@@ -1716,6 +1823,11 @@
return
var/mob/M = locateUID(href_list["HeadsetMessage"])
+
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
+
usr.client.admin_headset_message(M)
else if(href_list["EvilFax"])
@@ -1723,7 +1835,7 @@
return
var/mob/living/carbon/human/H = locateUID(href_list["EvilFax"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
var/etypes = list("Borgification", "Corgification", "Death By Fire", "Total Brain Death", "Honk Tumor", "Cluwne", "Demote", "Demote with Bot", "Revoke Fax Access", "Angry Fax Machine")
var/eviltype = input(src.owner, "Which type of evil fax do you wish to send [H]?","Its good to be baaaad...", "") as null|anything in etypes
@@ -1757,12 +1869,12 @@
P.ico = new
P.ico += "paper_stamp-[stampvalue]"
P.overlays += stampoverlay
- P.stamps += ""
+ P.stamps += ""
P.update_icon()
P.faxmachineid = fax.UID()
P.loc = fax.loc // Do not use fax.receivefax(P) here, as it won't preserve the type. Physically teleporting the fax paper is required.
if(istype(H) && H.stat == CONSCIOUS && (istype(H.l_ear, /obj/item/radio/headset) || istype(H.r_ear, /obj/item/radio/headset)))
- to_chat(H, "Your headset pings, notifying you that a reply to your fax has arrived.")
+ to_chat(H, "Your headset pings, notifying you that a reply to your fax has arrived.")
to_chat(src.owner, "You sent a [eviltype] fax to [H]")
log_admin("[key_name(src.owner)] sent [key_name(H)] a [eviltype] fax")
message_admins("[key_name_admin(src.owner)] replied to [key_name_admin(H)] with a [eviltype] fax")
@@ -1771,7 +1883,7 @@
return
var/mob/living/M = locateUID(href_list["Bless"])
if(!istype(M))
- to_chat(usr, "This can only be used on instances of type /mob/living")
+ to_chat(usr, "This can only be used on instances of type /mob/living")
return
var/btypes = list("To Arrivals", "Moderate Heal")
var/mob/living/carbon/human/H
@@ -1838,7 +1950,7 @@
var/petchoice = input("Select pet type", "Pets") as null|anything in pets
if(isnull(petchoice))
return
- var/list/mob/dead/observer/candidates = pollCandidates("Play as the special event pet [H]?", poll_time = 200, min_hours = 10)
+ var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Play as the special event pet [H]?", poll_time = 20 SECONDS, min_hours = 10, source = petchoice)
var/mob/dead/observer/theghost = null
if(candidates.len)
var/mob/living/simple_animal/pet/P = new petchoice(H.loc)
@@ -1891,7 +2003,7 @@
var/mob/living/M = locateUID(href_list["Smite"])
var/mob/living/carbon/human/H
if(!istype(M))
- to_chat(usr, "This can only be used on instances of type /mob/living")
+ to_chat(usr, "This can only be used on instances of type /mob/living")
return
var/ptypes = list("Lightning bolt", "Fire Death", "Gib")
if(ishuman(M))
@@ -2002,7 +2114,7 @@
var/datum/antagonist/traitor/T = new()
T.give_objectives = FALSE
to_chat(newtraitormind.current, "ATTENTION: It is time to pay your debt to the Syndicate...")
- to_chat(newtraitormind.current, "Goal: KILL [H.real_name], currently in [get_area(H.loc)]")
+ to_chat(newtraitormind.current, "Goal: KILL [H.real_name], currently in [get_area(H.loc)]")
newtraitormind.add_antag_datum(T)
else
to_chat(usr, "ERROR: Unable to find any valid candidate to send after [H].")
@@ -2031,10 +2143,10 @@
return
var/mob/living/carbon/human/H = locateUID(href_list["cryossd"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
if(!href_list["cryoafk"] && !isLivingSSD(H))
- to_chat(usr, "This can only be used on living, SSD players.")
+ to_chat(usr, "This can only be used on living, SSD players.")
return
if(istype(H.loc, /obj/machinery/cryopod))
var/obj/machinery/cryopod/P = H.loc
@@ -2054,28 +2166,28 @@
return
var/mob/living/carbon/human/H = locateUID(href_list["FaxReplyTemplate"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
var/obj/item/paper/P = new /obj/item/paper(null)
var/obj/machinery/photocopier/faxmachine/fax = locate(href_list["originfax"])
P.name = "Central Command - paper"
var/stypes = list("Handle it yourselves!","Illegible fax","Fax not signed","Not Right Now","You are wasting our time", "Keep up the good work", "ERT Instructions")
var/stype = input(src.owner, "Which type of standard reply do you wish to send to [H]?","Choose your paperwork", "") as null|anything in stypes
- var/tmsg = "
Nanotrasen Science Station [GLOB.using_map.station_short]
NAS Trurl Communications Department Report
"
+ var/tmsg = "
Nanotrasen Science Station [GLOB.using_map.station_short]
NAS Trurl Communications Department Report
"
if(stype == "Handle it yourselves!")
- tmsg += "Greetings, esteemed crewmember. Your fax has been DECLINED automatically by NAS Trurl Fax Registration.
Please proceed in accordance with Standard Operating Procedure and/or Space Law. You are fully trained to handle this situation without Central Command intervention.
This is an automatic message."
+ tmsg += "Greetings, esteemed crewmember. Your fax has been DECLINED automatically by NAS Trurl Fax Registration.
Please proceed in accordance with Standard Operating Procedure and/or Space Law. You are fully trained to handle this situation without Central Command intervention.
This is an automatic message."
else if(stype == "Illegible fax")
- tmsg += "Greetings, esteemed crewmember. Your fax has been DECLINED automatically by NAS Trurl Fax Registration.
Your fax's grammar, syntax and/or typography are of a sub-par level and do not allow us to understand the contents of the message.
Please consult your nearest dictionary and/or thesaurus and try again.
This is an automatic message."
+ tmsg += "Greetings, esteemed crewmember. Your fax has been DECLINED automatically by NAS Trurl Fax Registration.
Your fax's grammar, syntax and/or typography are of a sub-par level and do not allow us to understand the contents of the message.
Please consult your nearest dictionary and/or thesaurus and try again.
This is an automatic message."
else if(stype == "Fax not signed")
- tmsg += "Greetings, esteemed crewmember. Your fax has been DECLINED automatically by NAS Trurl Fax Registration.
Your fax has not been correctly signed and, as such, we cannot verify your identity.
Please sign your faxes before sending them so that we may verify your identity.
This is an automatic message."
+ tmsg += "Greetings, esteemed crewmember. Your fax has been DECLINED automatically by NAS Trurl Fax Registration.
Your fax has not been correctly signed and, as such, we cannot verify your identity.
Please sign your faxes before sending them so that we may verify your identity.
This is an automatic message."
else if(stype == "Not Right Now")
- tmsg += "Greetings, esteemed crewmember. Your fax has been DECLINED automatically by NAS Trurl Fax Registration.
Due to pressing concerns of a matter above your current paygrade, we are unable to provide assistance in whatever matter your fax referenced.
This can be either due to a power outage, bureaucratic audit, pest infestation, Ascendance Event, corgi outbreak, or any other situation that would affect the proper functioning of the NAS Trurl.
Please try again later.
This is an automatic message."
+ tmsg += "Greetings, esteemed crewmember. Your fax has been DECLINED automatically by NAS Trurl Fax Registration.
Due to pressing concerns of a matter above your current paygrade, we are unable to provide assistance in whatever matter your fax referenced.
This can be either due to a power outage, bureaucratic audit, pest infestation, Ascendance Event, corgi outbreak, or any other situation that would affect the proper functioning of the NAS Trurl.
Please try again later.
This is an automatic message."
else if(stype == "You are wasting our time")
- tmsg += "Greetings, esteemed crewmember. Your fax has been DECLINED automatically by NAS Trurl Fax Registration.
In the interest of preventing further mismanagement of company resources, please avoid wasting our time with such petty drivel.
Do kindly remember that we expect our workforce to maintain at least a semi-decent level of profesionalism. Do not test our patience.
This is an automatic message."
+ tmsg += "Greetings, esteemed crewmember. Your fax has been DECLINED automatically by NAS Trurl Fax Registration.
In the interest of preventing further mismanagement of company resources, please avoid wasting our time with such petty drivel.
Do kindly remember that we expect our workforce to maintain at least a semi-decent level of profesionalism. Do not test our patience.
This is an automatic message."
else if(stype == "Keep up the good work")
tmsg += "Greetings, esteemed crewmember. Your fax has been received successfully by NAS Trurl Fax Registration.
We at the NAS Trurl appreciate the good work that you have done here, and sincerely recommend that you continue such a display of dedication to the company.
This is absolutely not an automated message."
else if(stype == "ERT Instructions")
- tmsg += "Greetings, esteemed crewmember. Your fax has been DECLINED automatically by NAS Trurl Fax Registration.
Please utilize the Card Swipers if you wish to call for an ERT.
This is an automated message."
+ tmsg += "Greetings, esteemed crewmember. Your fax has been DECLINED automatically by NAS Trurl Fax Registration.
Please utilize the Card Swipers if you wish to call for an ERT.
This is an automated message."
else
return
tmsg += ""
@@ -2096,11 +2208,11 @@
P.ico = new
P.ico += "paper_stamp-[stampvalue]"
P.overlays += stampoverlay
- P.stamps += ""
+ P.stamps += ""
P.update_icon()
fax.receivefax(P)
if(istype(H) && H.stat == CONSCIOUS && (istype(H.l_ear, /obj/item/radio/headset) || istype(H.r_ear, /obj/item/radio/headset)))
- to_chat(H, "Your headset pings, notifying you that a reply to your fax has arrived.")
+ to_chat(H, "Your headset pings, notifying you that a reply to your fax has arrived.")
to_chat(src.owner, "You sent a standard '[stype]' fax to [H]")
log_admin("[key_name(src.owner)] sent [key_name(H)] a standard '[stype]' fax")
message_admins("[key_name_admin(src.owner)] replied to [key_name_admin(H)] with a standard '[stype]' fax")
@@ -2108,10 +2220,10 @@
else if(href_list["HONKReply"])
var/mob/living/carbon/human/H = locateUID(href_list["HONKReply"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
if(!istype(H.l_ear, /obj/item/radio/headset) && !istype(H.r_ear, /obj/item/radio/headset))
- to_chat(usr, "The person you are trying to contact is not wearing a headset")
+ to_chat(usr, "The person you are trying to contact is not wearing a headset")
return
var/input = input(src.owner, "Please enter a message to reply to [key_name(H)] via [H.p_their()] headset.","Outgoing message from HONKplanet", "")
@@ -2128,13 +2240,13 @@
if(alert(src.owner, "Accept or Deny ERT request?", "CentComm Response", "Accept", "Deny") == "Deny")
var/mob/living/carbon/human/H = locateUID(href_list["ErtReply"])
if(!istype(H))
- to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
+ to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human")
return
if(H.stat != 0)
- to_chat(usr, "The person you are trying to contact is not conscious.")
+ to_chat(usr, "The person you are trying to contact is not conscious.")
return
if(!istype(H.l_ear, /obj/item/radio/headset) && !istype(H.r_ear, /obj/item/radio/headset))
- to_chat(usr, "The person you are trying to contact is not wearing a headset")
+ to_chat(usr, "The person you are trying to contact is not wearing a headset")
return
var/input = input(src.owner, "Please enter a reason for denying [key_name(H)]'s ERT request.","Outgoing message from CentComm", "")
@@ -2142,7 +2254,7 @@
GLOB.ert_request_answered = TRUE
to_chat(src.owner, "You sent [input] to [H] via a secure channel.")
log_admin("[src.owner] denied [key_name(H)]'s ERT request with the message [input].")
- to_chat(H, "Incoming priority transmission from Central Command. Message as follows, Your ERT request has been denied for the following reasons: [input].")
+ to_chat(H, "Incoming priority transmission from Central Command. Message as follows, Your ERT request has been denied for the following reasons: [input].")
else
src.owner.response_team()
@@ -2297,14 +2409,14 @@
P.stamped = new
P.stamped += /obj/item/stamp/centcom
P.overlays += stampoverlay
- P.stamps += ""
+ P.stamps += ""
else if(stamptype == "text")
if(!P.stamped)
P.stamped = new
P.stamped += /obj/item/stamp
P.overlays += stampoverlay
- P.stamps += "[stampvalue]"
+ P.stamps += "[stampvalue]"
if(destination != "All Departments")
if(!fax.receivefax(P))
@@ -2334,7 +2446,7 @@
if(notify == "Yes")
var/mob/living/carbon/human/H = sender
if(istype(H) && H.stat == CONSCIOUS && (istype(H.l_ear, /obj/item/radio/headset) || istype(H.r_ear, /obj/item/radio/headset)))
- to_chat(sender, "Your headset pings, notifying you that a reply to your fax has arrived.")
+ to_chat(sender, "Your headset pings, notifying you that a reply to your fax has arrived.")
if(sender)
log_admin("[key_name(src.owner)] replied to a fax message from [key_name(sender)]: [input]")
message_admins("[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(sender)] (VIEW).", 1)
@@ -2353,8 +2465,8 @@
if(!check_rights(R_ADMIN))
return
var/mob/M = locateUID(href_list["getplaytimewindow"])
- if(!M)
- to_chat(usr, "ERROR: Mob not found.")
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
return
cmd_mentor_show_exp_panel(M.client)
@@ -2362,6 +2474,9 @@
if(!check_rights(R_ADMIN)) return
var/mob/M = locateUID(href_list["jumpto"])
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
usr.client.jumptomob(M)
else if(href_list["getmob"])
@@ -2369,24 +2484,37 @@
if(alert(usr, "Confirm?", "Message", "Yes", "No") != "Yes") return
var/mob/M = locateUID(href_list["getmob"])
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
usr.client.Getmob(M)
else if(href_list["sendmob"])
if(!check_rights(R_ADMIN)) return
var/mob/M = locateUID(href_list["sendmob"])
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
usr.client.sendmob(M)
else if(href_list["narrateto"])
if(!check_rights(R_ADMIN)) return
var/mob/M = locateUID(href_list["narrateto"])
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
usr.client.cmd_admin_direct_narrate(M)
else if(href_list["subtlemessage"])
- if(!check_rights(R_ADMIN)) return
+ if(!check_rights(R_EVENT))
+ return
var/mob/M = locateUID(href_list["subtlemessage"])
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
+ return
usr.client.cmd_admin_subtle_message(M)
else if(href_list["traitor"])
@@ -2397,8 +2525,8 @@
return
var/mob/M = locateUID(href_list["traitor"])
- if(!ismob(M))
- to_chat(usr, "This can only be used on instances of type /mob.")
+ if(!istype(M, /mob))
+ to_chat(usr, "This can only be used on instances of type /mob")
return
show_traitor_panel(M)
@@ -2467,7 +2595,7 @@
switch(where)
if("inhand")
if(!iscarbon(usr) && !isrobot(usr))
- to_chat(usr, "Can only spawn in hand when you're a carbon mob or cyborg.")
+ to_chat(usr, "Can only spawn in hand when you're a carbon mob or cyborg.")
where = "onfloor"
target = usr
@@ -2479,10 +2607,10 @@
target = locate(loc.x + X,loc.y + Y,loc.z + Z)
if("inmarked")
if(!marked_datum)
- to_chat(usr, "You don't have any object marked. Abandoning spawn.")
+ to_chat(usr, "You don't have any object marked. Abandoning spawn.")
return
else if(!istype(marked_datum,/atom))
- to_chat(usr, "The object you have marked cannot be used as a target. Target must be of type /atom. Abandoning spawn.")
+ to_chat(usr, "The object you have marked cannot be used as a target. Target must be of type /atom. Abandoning spawn.")
return
else
target = marked_datum
@@ -2547,7 +2675,7 @@
message_admins("[key_name_admin(usr)] has kicked [afkonly ? "all AFK" : "all"] clients from the lobby. [length(listkicked)] clients kicked: [strkicked ? strkicked : "--"]")
log_admin("[key_name(usr)] has kicked [afkonly ? "all AFK" : "all"] clients from the lobby. [length(listkicked)] clients kicked: [strkicked ? strkicked : "--"]")
else
- to_chat(usr, "You may only use this when the game is running.")
+ to_chat(usr, "You may only use this when the game is running.")
else if(href_list["memoeditlist"])
if(!check_rights(R_SERVER)) return
@@ -2627,7 +2755,7 @@
feedback_add_details("admin_secrets_fun_used","TriAI")
if("gravity")
if(!(SSticker && SSticker.mode))
- to_chat(usr, "Please wait until the game starts! Not sure how it will work otherwise.")
+ to_chat(usr, "Please wait until the game starts! Not sure how it will work otherwise.")
return
GLOB.gravity_is_on = !GLOB.gravity_is_on
for(var/area/A in world)
@@ -2964,7 +3092,7 @@
if(usr)
log_admin("[key_name(usr)] used secret [href_list["secretsfun"]]")
if(ok)
- to_chat(world, text("A secret has been activated by []!", usr.key))
+ to_chat(world, text("A secret has been activated by []!", usr.key))
else if(href_list["secretsadmin"])
if(!check_rights(R_ADMIN)) return
@@ -2972,17 +3100,17 @@
var/ok = 0
switch(href_list["secretsadmin"])
if("list_signalers")
- var/dat = "Showing last [length(GLOB.lastsignalers)] signalers."
+ var/dat = "Showing last [length(GLOB.lastsignalers)] signalers."
for(var/sig in GLOB.lastsignalers)
dat += "[sig] "
usr << browse(dat, "window=lastsignalers;size=800x500")
if("list_lawchanges")
- var/dat = "Showing last [length(GLOB.lawchanges)] law changes."
+ var/dat = "Showing last [length(GLOB.lawchanges)] law changes."
for(var/sig in GLOB.lawchanges)
dat += "[sig] "
usr << browse(dat, "window=lawchanges;size=800x500")
if("list_job_debug")
- var/dat = "Job Debug info."
+ var/dat = "Job Debug info."
if(SSjobs)
for(var/line in SSjobs.job_debug)
dat += "[line] "
@@ -3000,7 +3128,7 @@
alert("The game mode is [SSticker.mode.name]")
else alert("For some reason there's a ticker, but not a game mode")
if("manifest")
- var/dat = "Showing Crew Manifest."
+ var/dat = "Showing Crew Manifest."
dat += "
Name
Position
"
for(var/thing in GLOB.human_list)
var/mob/living/carbon/human/H = thing
@@ -3011,7 +3139,7 @@
if("check_antagonist")
check_antagonists()
if("DNA")
- var/dat = "Showing DNA from blood."
+ var/dat = "Showing DNA from blood."
dat += "
Name
DNA
Blood Type
"
for(var/thing in GLOB.human_list)
var/mob/living/carbon/human/H = thing
@@ -3020,7 +3148,7 @@
dat += "
Do not use punctuation as you would normally, if you want a pause you can use the full stop and comma characters by separating them with spaces, like so: 'Alpha . Test , Bravo'.
\
WARNING: Misuse of the announcement system will get you job banned."
- var/index = 0
- for(var/word in GLOB.vox_sounds)
- index++
- dat += "[capitalize(word)]"
- if(index != GLOB.vox_sounds.len)
- dat += " / "
+ // Show alert and voice sounds separately
+ var/vox_words = GLOB.vox_sounds - GLOB.vox_alerts
+ dat = help_format(GLOB.vox_alerts, dat)
+ dat = help_format(vox_words, dat)
var/datum/browser/popup = new(src, "announce_help", "Announcement Help", 500, 400)
popup.set_content(dat)
popup.open()
+/mob/living/silicon/ai/proc/help_format(word_list, dat)
+ var/index = 0
+ for(var/word in word_list)
+ index++
+ dat += "[capitalize(word)]"
+ if(index != length(word_list))
+ dat += " / "
+ else
+ dat += ""
+ return dat
+
/mob/living/silicon/ai/proc/ai_announcement()
if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO))
return
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 2a5a7b0aa08..0a4e4cee898 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -517,7 +517,7 @@
/mob/living/silicon/pai/Bumped()
return
-/mob/living/silicon/pai/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
+/mob/living/silicon/pai/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)
return FALSE
/mob/living/silicon/pai/update_canmove(delay_action_updates = 0)
@@ -563,6 +563,10 @@
var/obj/item/holder/H = ..()
if(!istype(H))
return
+ if(stat == DEAD)
+ H.icon = 'icons/mob/pai.dmi'
+ H.icon_state = "[chassis]_dead"
+ return
if(resting)
icon_state = "[chassis]"
resting = 0
diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm
index 2a1662b064d..52d58ad659d 100644
--- a/code/modules/mob/living/silicon/robot/component.dm
+++ b/code/modules/mob/living/silicon/robot/component.dm
@@ -312,8 +312,3 @@ proc/robot_healthscan(mob/user, mob/living/M)
to_chat(user, "[capitalize(O.name)]: [O.damage]")
if(!organ_found)
to_chat(user, "No prosthetics located.")
-
- if(ismachineperson(H))
- to_chat(user, "Internal Fluid Level:[H.blood_volume]/[H.max_blood]")
- if(H.bleed_rate)
- to_chat(user, "Warning:External component leak detected!")
diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm
index 72d9b210712..65847c3a9b1 100644
--- a/code/modules/mob/living/silicon/robot/death.dm
+++ b/code/modules/mob/living/silicon/robot/death.dm
@@ -53,7 +53,7 @@
emote("deathgasp", force = TRUE)
if(module)
- module.handle_death(gibbed)
+ module.handle_death(src, gibbed)
// Only execute the below if we successfully died
. = ..(gibbed)
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index 91970d030a6..270606361cb 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -19,6 +19,7 @@
ventcrawler = 2
magpulse = 1
mob_size = MOB_SIZE_SMALL
+ pull_force = MOVE_FORCE_VERY_WEAK // Can only drag small items
modules_break = FALSE
@@ -35,6 +36,14 @@
var/reboot_cooldown = 60 // one minute
var/last_reboot
var/emagged_time
+ var/list/pullable_drone_items = list(
+ /obj/item/pipe,
+ /obj/structure/disposalconstruct,
+ /obj/item/stack/cable_coil,
+ /obj/item/stack/rods,
+ /obj/item/stack/sheet,
+ /obj/item/stack/tile
+ )
holder_type = /obj/item/holder/drone
// var/sprite[0]
@@ -50,7 +59,7 @@
// Disable the microphone wire on Drones
if(radio)
- radio.wires.CutWireIndex(RADIO_WIRE_TRANSMIT)
+ radio.wires.cut(WIRE_RADIO_TRANSMIT)
if(camera && ("Robots" in camera.network))
camera.network.Add("Engineering")
@@ -69,6 +78,10 @@
verbs -= /mob/living/silicon/robot/verb/Namepick
module = new /obj/item/robot_module/drone(src)
+ //Allows Drones to hear the Engineering channel.
+ module.channels = list("Engineering" = 1)
+ radio.recalculateChannels()
+
//Grab stacks.
stack_metal = locate(/obj/item/stack/sheet/metal/cyborg) in src.module
stack_wood = locate(/obj/item/stack/sheet/wood) in src.module
@@ -154,15 +167,17 @@
return
else
- user.visible_message("\the [user] swipes [user.p_their()] ID card through [src], attempting to shut it down.", "You swipe your ID card through \the [src], attempting to shut it down.")
+ var/confirm = alert("Using your ID on a Maintenance Drone will shut it down, are you sure you want to do this?", "Disable Drone", "Yes", "No")
+ if(confirm == ("Yes") && (user in range(3, src)))
+ user.visible_message("\the [user] swipes [user.p_their()] ID card through [src], attempting to shut it down.", "You swipe your ID card through \the [src], attempting to shut it down.")
- if(emagged)
- return
+ if(emagged)
+ return
- if(allowed(W))
- shut_down()
- else
- to_chat(user, "Access denied.")
+ if(allowed(W))
+ shut_down()
+ else
+ to_chat(user, "Access denied.")
return
@@ -321,20 +336,22 @@
/mob/living/silicon/robot/drone/Bumped(atom/movable/AM)
return
-/mob/living/silicon/robot/drone/start_pulling(var/atom/movable/AM)
+/mob/living/silicon/robot/drone/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)
+
+ if(is_type_in_list(AM, pullable_drone_items))
+ ..(AM, force = INFINITY) // Drone power! Makes them able to drag pipes and such
- if(istype(AM,/obj/item/pipe) || istype(AM,/obj/structure/disposalconstruct))
- ..()
else if(istype(AM,/obj/item))
var/obj/item/O = AM
if(O.w_class > WEIGHT_CLASS_SMALL)
- to_chat(src, "You are too small to pull that.")
+ if(show_message)
+ to_chat(src, "You are too small to pull that.")
return
else
..()
else
- to_chat(src, "You are too small to pull that.")
- return
+ if(show_message)
+ to_chat(src, "You are too small to pull that.")
/mob/living/silicon/robot/drone/add_robot_verbs()
src.verbs |= silicon_subsystems
diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm
index a0582c135e4..16e81f53276 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm
@@ -8,7 +8,6 @@
//Has a list of items that it can hold.
var/list/can_hold = list(
- /obj/item/stock_parts/cell,
/obj/item/firealarm_electronics,
/obj/item/airalarm_electronics,
/obj/item/airlock_electronics,
@@ -24,6 +23,8 @@
/obj/item/mounted/frame/firealarm,
/obj/item/mounted/frame/newscaster_frame,
/obj/item/mounted/frame/intercom,
+ /obj/item/mounted/frame/extinguisher,
+ /obj/item/mounted/frame/light_switch,
/obj/item/rack_parts,
/obj/item/camera_assembly,
/obj/item/tank,
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index 07080e694bf..a183a8fc455 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -13,7 +13,6 @@
handle_robot_cell()
process_locks()
update_items()
- process_queued_alarms()
/mob/living/silicon/robot/proc/handle_robot_cell()
@@ -46,7 +45,7 @@
/mob/living/silicon/robot/proc/handle_equipment()
if(camera && !scrambledcodes)
- if(stat == DEAD || wires.IsCameraCut())
+ if(stat == DEAD || wires.is_cut(WIRE_BORG_CAMERA))
camera.status = 0
else
camera.status = 1
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index faa51a58ec0..ee9cec18c89 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -59,7 +59,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/ear_protection = 0
var/damage_protection = 0
var/emp_protection = FALSE
- var/xeno_disarm_chance = 85
var/list/force_modules = list()
var/allow_rename = TRUE
@@ -72,11 +71,10 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/list/req_access
var/ident = 0
//var/list/laws = list()
- var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list())
var/viewalerts = 0
var/modtype = "Default"
var/lower_mod = 0
- var/datum/effect_system/spark_spread/spark_system//So they can initialize sparks whenever/N
+ var/datum/effect_system/spark_spread/spark_system //So they can initialize sparks whenever/N
var/jeton = 0
var/low_power_mode = 0 //whether the robot has no charge left.
var/weapon_lock = 0
@@ -112,7 +110,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/get_cell()
return cell
-/mob/living/silicon/robot/New(loc, syndie = FALSE, unfinished = FALSE, alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
+/mob/living/silicon/robot/New(loc, syndie = FALSE, unfinished = FALSE, alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
spark_system = new /datum/effect_system/spark_spread()
spark_system.set_up(5, 0, src)
spark_system.attach(src)
@@ -134,13 +132,13 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
radio = new /obj/item/radio/borg(src)
common_radio = radio
- init(ai_to_sync_to = ai_to_sync_to)
+ init(alien, connect_to_AI, ai_to_sync_to)
if(has_camera && !camera)
camera = new /obj/machinery/camera(src)
camera.c_tag = real_name
camera.network = list("SS13","Robots")
- if(wires.IsCameraCut()) // 5 = BORG CAMERA
+ if(wires.is_cut(WIRE_BORG_CAMERA)) // 5 = BORG CAMERA
camera.status = 0
if(mmi == null)
@@ -172,18 +170,20 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
scanner = new(src)
scanner.Grant(src)
-/mob/living/silicon/robot/proc/init(alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
+/mob/living/silicon/robot/proc/init(alien, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
aiCamera = new/obj/item/camera/siliconcam/robot_camera(src)
make_laws()
additional_law_channels["Binary"] = ":b "
+ if(!connect_to_AI)
+ return
var/found_ai = ai_to_sync_to
if(!found_ai)
found_ai = select_active_ai_with_fewest_borgs()
if(found_ai)
- lawupdate = 1
+ lawupdate = TRUE
connect_to_ai(found_ai)
else
- lawupdate = 0
+ lawupdate = FALSE
playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
@@ -270,6 +270,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO
//Improved /N
/mob/living/silicon/robot/Destroy()
+ SStgui.close_uis(wires)
if(mmi && mind)//Safety for when a cyborg gets dust()ed. Or there is no MMI inside.
var/turf/T = get_turf(loc)//To hopefully prevent run time errors.
if(T) mmi.loc = T
@@ -543,6 +544,43 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
src.verbs -= GLOB.robot_verbs_default
src.verbs -= silicon_subsystems
+/mob/living/silicon/robot/verb/cmd_robot_alerts()
+ set category = "Robot Commands"
+ set name = "Show Alerts"
+ if(usr.stat == DEAD)
+ to_chat(src, "Alert: You are dead.")
+ return //won't work if dead
+ robot_alerts()
+
+/mob/living/silicon/robot/proc/robot_alerts()
+ var/list/dat = list()
+ var/list/list/temp_alarm_list = SSalarm.alarms.Copy()
+ for(var/cat in temp_alarm_list)
+ if(!(cat in alarms_listend_for))
+ continue
+ dat += text("[cat] \n")
+ var/list/list/L = temp_alarm_list[cat].Copy()
+ for(var/alarm in L)
+ var/list/list/alm = L[alarm].Copy()
+ var/list/list/sources = alm[3].Copy()
+ var/area_name = alm[1]
+ for(var/thing in sources)
+ var/atom/A = locateUID(thing)
+ if(A && A.z != z)
+ L -= alarm
+ continue
+ dat += ""
+ dat += text("-- [area_name]")
+ dat += " \n"
+ if(!L.len)
+ dat += "-- All Systems Nominal \n"
+ dat += " \n"
+
+ var/datum/browser/alerts = new(usr, "robotalerts", "Current Station Alerts", 400, 410)
+ var/dat_text = dat.Join("")
+ alerts.set_content(dat_text)
+ alerts.open()
+
/mob/living/silicon/robot/proc/ionpulse()
if(!ionpulse_on)
return
@@ -604,6 +642,23 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/InCritical()
return low_power_mode
+/mob/living/silicon/robot/alarm_triggered(src, class, area/A, list/O, obj/alarmsource)
+ if(!(class in alarms_listend_for))
+ return
+ if(alarmsource.z != z)
+ return
+ if(stat == DEAD)
+ return
+ queueAlarm(text("--- [class] alarm detected in [A.name]!"), class)
+
+/mob/living/silicon/robot/alarm_cancelled(src, class, area/A, obj/origin, cleared)
+ if(cleared)
+ if(!(class in alarms_listend_for))
+ return
+ if(origin.z != z)
+ return
+ queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0)
+
/mob/living/silicon/robot/ex_act(severity)
switch(severity)
if(1.0)
@@ -795,7 +850,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
opened = FALSE
update_icons()
return
- else if(wiresexposed && wires.IsAllCut())
+ else if(wiresexposed && wires.is_all_cut())
//Cell is out, wires are exposed, remove MMI, produce damaged chassis, baleet original mob.
if(!mmi)
to_chat(user, "[src] has no brain to remove.")
@@ -1023,10 +1078,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
src << browse(null, t1)
return 1
- if(href_list["showalerts"])
- subsystem_alarm_monitor()
- return 1
-
if(href_list["mod"])
var/obj/item/O = locate(href_list["mod"])
if(istype(O) && (O.loc == src))
@@ -1041,6 +1092,11 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
activate_module(O)
installed_modules()
+ //Show alerts window if user clicked on "Show alerts" in chat
+ if(href_list["showalerts"])
+ robot_alerts()
+ return TRUE
+
if(href_list["deact"])
var/obj/item/O = locate(href_list["deact"])
if(activated(O))
@@ -1063,7 +1119,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
return 1
/mob/living/silicon/robot/proc/radio_menu()
- radio.interact(src)//Just use the radio's Topic() instead of bullshit special-snowflake code
+ radio.interact(src)
/mob/living/silicon/robot/proc/control_headlamp()
if(stat || lamp_recharging || low_power_mode)
@@ -1233,7 +1289,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/proc/SetLockdown(var/state = 1)
// They stay locked down if their wire is cut.
- if(wires.LockedCut())
+ if(wires.is_cut(WIRE_BORG_LOCKED))
state = 1
if(state)
throw_alert("locked", /obj/screen/alert/locked)
@@ -1343,14 +1399,13 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
eye_protection = 2 // Immunity to flashes and the visual part of flashbangs
ear_protection = 1 // Immunity to the audio part of flashbangs
damage_protection = 10 // Reduce all incoming damage by this number
- xeno_disarm_chance = 20
allow_rename = FALSE
modtype = "Commando"
faction = list("nanotrasen")
is_emaggable = FALSE
default_cell_type = /obj/item/stock_parts/cell/bluespace
-/mob/living/silicon/robot/deathsquad/init(alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
+/mob/living/silicon/robot/deathsquad/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
laws = new /datum/ai_laws/deathsquad
module = new /obj/item/robot_module/deathsquad(src)
aiCamera = new/obj/item/camera/siliconcam/robot_camera(src)
@@ -1380,7 +1435,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/eprefix = "Amber"
-/mob/living/silicon/robot/ert/init(alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
+/mob/living/silicon/robot/ert/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
laws = new /datum/ai_laws/ert_override
radio = new /obj/item/radio/borg/ert(src)
radio.recalculateChannels()
@@ -1413,7 +1468,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
damage_protection = 5 // Reduce all incoming damage by this number
eprefix = "Gamma"
magpulse = 1
- xeno_disarm_chance = 40
/mob/living/silicon/robot/destroyer
@@ -1433,11 +1487,12 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
ear_protection = 1 // Immunity to the audio part of flashbangs
emp_protection = TRUE // Immunity to EMP, due to heavy shielding
damage_protection = 20 // Reduce all incoming damage by this number. Very high in the case of /destroyer borgs, since it is an admin-only borg.
- xeno_disarm_chance = 10
default_cell_type = /obj/item/stock_parts/cell/bluespace
-/mob/living/silicon/robot/destroyer/init(alien = FALSE, mob/living/silicon/ai/ai_to_sync_to = null)
- ..()
+/mob/living/silicon/robot/destroyer/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
+ aiCamera = new/obj/item/camera/siliconcam/robot_camera(src)
+ additional_law_channels["Binary"] = ":b "
+ laws = new /datum/ai_laws/deathsquad
module = new /obj/item/robot_module/destroyer(src)
module.add_languages(src)
module.add_subsystems_and_actions(src)
@@ -1446,6 +1501,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
qdel(radio)
radio = new /obj/item/radio/borg/ert/specops(src)
radio.recalculateChannels()
+ playsound(loc, 'sound/mecha/nominalsyndi.ogg', 75, 0)
/mob/living/silicon/robot/destroyer/borg_icons()
if(base_icon == "")
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index 8445a399582..84eb782833b 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -2,19 +2,17 @@
if(M.a_intent == INTENT_DISARM)
if(!lying)
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
- if(prob(xeno_disarm_chance))
- Stun(7)
- step(src, get_dir(M,src))
- spawn(5)
- step(src, get_dir(M,src))
- add_attack_logs(M, src, "Alien pushed over")
- playsound(loc, 'sound/weapons/pierce.ogg', 50, 1, -1)
- visible_message("[M] has forced back [src]!",\
- "[M] has forced back [src]!")
+ var/obj/item/I = get_active_hand()
+ if(I)
+ uneq_active()
+ visible_message("[M] disarmed [src]!", "[M] has disabled [src]'s active module!")
+ add_attack_logs(M, src, "alien disarmed")
else
- playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
- visible_message("[M] took a swipe at [src]!",\
- "[M] took a swipe at [src]!")
+ Stun(2)
+ step(src, get_dir(M,src))
+ add_attack_logs(M, src, "Alien pushed over")
+ visible_message("[M] forces back [src]!", "[M] forces back [src]!")
+ playsound(loc, 'sound/weapons/pierce.ogg', 50, TRUE, -1)
else
..()
return
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 8e8c67693c5..ff967354131 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -114,7 +114,7 @@
/obj/item/robot_module/proc/handle_custom_removal(component_id, mob/living/user, obj/item/W)
return FALSE
-/obj/item/robot_module/proc/handle_death(gibbed)
+/obj/item/robot_module/proc/handle_death(mob/living/silicon/robot/R, gibbed)
return
/obj/item/robot_module/standard
@@ -255,7 +255,7 @@
fix_modules()
-/obj/item/robot_module/engineering/handle_death()
+/obj/item/robot_module/engineering/handle_death(mob/living/silicon/robot/R, gibbed)
var/obj/item/gripper/G = locate(/obj/item/gripper) in modules
if(G)
G.drop_gripped_item(silent = TRUE)
@@ -368,6 +368,11 @@
R.add_language("Clownish",1)
R.add_language("Neo-Russkiya", 1)
+/obj/item/robot_module/butler/handle_death(mob/living/silicon/robot/R, gibbed)
+ var/obj/item/storage/bag/tray/cyborg/T = locate(/obj/item/storage/bag/tray/cyborg) in modules
+ if(istype(T))
+ T.drop_inventory(R)
+
/obj/item/robot_module/miner
name = "miner robot module"
@@ -623,7 +628,7 @@
..()
-/obj/item/robot_module/drone/handle_death()
+/obj/item/robot_module/drone/handle_death(mob/living/silicon/robot/R, gibbed)
var/obj/item/gripper/G = locate(/obj/item/gripper) in modules
if(G)
G.drop_gripped_item(silent = TRUE)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index c923e0912b7..7f9c0849d9c 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -11,9 +11,11 @@
var/list/stating_laws = list()// Channels laws are currently being stated on
var/list/alarms_to_show = list()
var/list/alarms_to_clear = list()
+ var/list/alarm_types_show = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
+ var/list/alarm_types_clear = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
+ var/list/alarms_listend_for = list("Motion", "Fire", "Atmosphere", "Power", "Camera")
//var/list/hud_list[10]
var/list/speech_synthesizer_langs = list() //which languages can be vocalized by the speech synthesizer
- var/list/alarm_handlers = list() // List of alarm handlers this silicon is registered to
var/designation = ""
var/obj/item/camera/siliconcam/aiCamera = null //photography
//Used in say.dm, allows for pAIs to have different say flavor text, as well as silicons, although the latter is not implemented.
@@ -25,9 +27,6 @@
//var/sensor_mode = 0 //Determines the current HUD.
- var/next_alarm_notice
- var/list/datum/alarm/queued_alarms = new()
-
hud_possible = list(SPECIALROLE_HUD, DIAG_STAT_HUD, DIAG_HUD)
@@ -46,6 +45,8 @@
diag_hud_set_health()
add_language("Galactic Common")
init_subsystems()
+ RegisterSignal(SSalarm, COMSIG_TRIGGERED_ALARM, .proc/alarm_triggered)
+ RegisterSignal(SSalarm, COMSIG_CANCELLED_ALARM, .proc/alarm_cancelled)
/mob/living/silicon/med_hud_set_health()
return //we use a different hud
@@ -55,10 +56,93 @@
/mob/living/silicon/Destroy()
GLOB.silicon_mob_list -= src
- for(var/datum/alarm_handler/AH in alarm_handlers)
- AH.unregister(src)
return ..()
+/mob/living/silicon/proc/alarm_triggered(src, class, area/A, list/O, obj/alarmsource)
+ return
+
+/mob/living/silicon/proc/alarm_cancelled(src, class, area/A, obj/origin, cleared)
+ return
+
+/mob/living/silicon/proc/queueAlarm(message, type, incoming = TRUE)
+ var/in_cooldown = (alarms_to_show.len > 0 || alarms_to_clear.len > 0)
+ if(incoming)
+ alarms_to_show += message
+ alarm_types_show[type] += 1
+ else
+ alarms_to_clear += message
+ alarm_types_clear[type] += 1
+
+ if(in_cooldown)
+ return
+
+ addtimer(CALLBACK(src, .proc/show_alarms), 3 SECONDS)
+
+/mob/living/silicon/proc/show_alarms()
+ if(alarms_to_show.len < 5)
+ for(var/msg in alarms_to_show)
+ to_chat(src, msg)
+ else if(length(alarms_to_show))
+
+ var/list/msg = list("--- ")
+
+ if(alarm_types_show["Burglar"])
+ msg += "BURGLAR: [alarm_types_show["Burglar"]] alarms detected. - "
+
+ if(alarm_types_show["Motion"])
+ msg += "MOTION: [alarm_types_show["Motion"]] alarms detected. - "
+
+ if(alarm_types_show["Fire"])
+ msg += "FIRE: [alarm_types_show["Fire"]] alarms detected. - "
+
+ if(alarm_types_show["Atmosphere"])
+ msg += "ATMOSPHERE: [alarm_types_show["Atmosphere"]] alarms detected. - "
+
+ if(alarm_types_show["Power"])
+ msg += "POWER: [alarm_types_show["Power"]] alarms detected. - "
+
+ if(alarm_types_show["Camera"])
+ msg += "CAMERA: [alarm_types_show["Camera"]] alarms detected. - "
+
+ msg += "\[Show Alerts\]"
+ var/msg_text = msg.Join("")
+ to_chat(src, msg_text)
+
+ if(alarms_to_clear.len < 3)
+ for(var/msg in alarms_to_clear)
+ to_chat(src, msg)
+
+ else if(alarms_to_clear.len)
+ var/list/msg = list("--- ")
+
+ if(alarm_types_clear["Motion"])
+ msg += "MOTION: [alarm_types_clear["Motion"]] alarms cleared. - "
+
+ if(alarm_types_clear["Fire"])
+ msg += "FIRE: [alarm_types_clear["Fire"]] alarms cleared. - "
+
+ if(alarm_types_clear["Atmosphere"])
+ msg += "ATMOSPHERE: [alarm_types_clear["Atmosphere"]] alarms cleared. - "
+
+ if(alarm_types_clear["Power"])
+ msg += "POWER: [alarm_types_clear["Power"]] alarms cleared. - "
+
+ if(alarm_types_show["Camera"])
+ msg += "CAMERA: [alarm_types_clear["Camera"]] alarms cleared. - "
+
+ msg += "\[Show Alerts\]"
+
+ var/msg_text = msg.Join("")
+ to_chat(src, msg_text)
+
+
+ alarms_to_show.Cut()
+ alarms_to_clear.Cut()
+ for(var/key in alarm_types_show)
+ alarm_types_show[key] = 0
+ for(var/key in alarm_types_clear)
+ alarm_types_clear[key] = 0
+
/mob/living/silicon/rename_character(oldname, newname)
// we actually don't want it changing minds and stuff
if(!newname)
@@ -283,63 +367,6 @@
if("Disable")
to_chat(src, "Sensor augmentations disabled.")
-/mob/living/silicon/proc/receive_alarm(var/datum/alarm_handler/alarm_handler, var/datum/alarm/alarm, was_raised)
- if(!next_alarm_notice)
- next_alarm_notice = world.time + 10 SECONDS
-
- var/list/alarms = queued_alarms[alarm_handler]
- if(was_raised)
- // Raised alarms are always set
- alarms[alarm] = 1
- else
- // Alarms that were raised but then cleared before the next notice are instead removed
- if(alarm in alarms)
- alarms -= alarm
- // And alarms that have only been cleared thus far are set as such
- else
- alarms[alarm] = -1
-
-/mob/living/silicon/proc/process_queued_alarms()
- if(next_alarm_notice && (world.time > next_alarm_notice))
- next_alarm_notice = 0
-
- var/alarm_raised = 0
- for(var/datum/alarm_handler/AH in queued_alarms)
- var/list/alarms = queued_alarms[AH]
- var/reported = 0
- for(var/datum/alarm/A in alarms)
- if(alarms[A] == 1)
- if(!reported)
- reported = 1
- to_chat(src, "--- [AH.category] Detected ---")
- raised_alarm(A)
-
- for(var/datum/alarm_handler/AH in queued_alarms)
- var/list/alarms = queued_alarms[AH]
- var/reported = 0
- for(var/datum/alarm/A in alarms)
- if(alarms[A] == -1)
- if(!reported)
- reported = 1
- to_chat(src, "--- [AH.category] Cleared ---")
- to_chat(src, "\The [A.alarm_name()].")
-
- if(alarm_raised)
- to_chat(src, "\[Show Alerts\]")
-
- for(var/datum/alarm_handler/AH in queued_alarms)
- var/list/alarms = queued_alarms[AH]
- alarms.Cut()
-
-/mob/living/silicon/proc/raised_alarm(var/datum/alarm/A)
- to_chat(src, "[A.alarm_name()]!")
-
-/mob/living/silicon/ai/raised_alarm(var/datum/alarm/A)
- var/cameratext = ""
- for(var/obj/machinery/camera/C in A.cameras())
- cameratext += "[(cameratext == "")? "" : "|"][C.c_tag]"
- to_chat(src, "[A.alarm_name()]! ([(cameratext)? cameratext : "No Camera"])")
-
/mob/living/silicon/adjustToxLoss(var/amount)
return STATUS_UPDATE_NONE
diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm
index e720400abd5..6ac5f8cded2 100644
--- a/code/modules/mob/living/silicon/silicon_defense.dm
+++ b/code/modules/mob/living/silicon/silicon_defense.dm
@@ -3,11 +3,10 @@
/mob/living/silicon/attack_alien(mob/living/carbon/alien/humanoid/M)
if(..()) //if harm or disarm intent
- var/damage = rand(10, 20)
+ var/damage = 20
if(prob(90))
playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
- visible_message("[M] has slashed at [src]!", \
- "[M] has slashed at [src]!")
+ visible_message("[M] has slashed at [src]!", "[M] has slashed at [src]!")
if(prob(8))
flash_eyes(affect_silicon = 1)
add_attack_logs(M, src, "Alien attacked")
@@ -64,6 +63,6 @@
else
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
playsound(loc, 'sound/effects/bang.ogg', 10, 1)
- visible_message("[M] punches [src], but doesn't leave a dent.", \
- "[M] punches [src], but doesn't leave a dent.!")
+ visible_message("[M] punches [src], but doesn't leave a dent.", \
+ "[M] punches [src], but doesn't leave a dent.")
return FALSE
diff --git a/code/modules/mob/living/silicon/subsystems.dm b/code/modules/mob/living/silicon/subsystems.dm
index d18d41a40cf..65a92d07008 100644
--- a/code/modules/mob/living/silicon/subsystems.dm
+++ b/code/modules/mob/living/silicon/subsystems.dm
@@ -8,13 +8,11 @@
/mob/living/silicon
var/list/silicon_subsystems = list(
- /mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_law_manager
)
/mob/living/silicon/ai
silicon_subsystems = list(
- /mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_atmos_control,
/mob/living/silicon/proc/subsystem_crew_monitor,
/mob/living/silicon/proc/subsystem_law_manager,
@@ -23,7 +21,6 @@
/mob/living/silicon/robot/drone
silicon_subsystems = list(
- /mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_law_manager,
/mob/living/silicon/proc/subsystem_power_monitor
)
@@ -32,30 +29,11 @@
register_alarms = 0
/mob/living/silicon/proc/init_subsystems()
- alarm_monitor = new(src)
atmos_control = new(src)
crew_monitor = new(src)
law_manager = new(src)
power_monitor = new(src)
- if(!register_alarms)
- return
-
- var/list/register_to = list(SSalarms.atmosphere_alarm, SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.fire_alarm, SSalarms.motion_alarm, SSalarms.power_alarm)
- for(var/datum/alarm_handler/AH in register_to)
- AH.register(src, /mob/living/silicon/proc/receive_alarm)
- queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order
- alarm_handlers |= AH
-
-/********************
-* Alarm Monitor *
-********************/
-/mob/living/silicon/proc/subsystem_alarm_monitor()
- set name = "Alarm Monitor"
- set category = "Subsystems"
-
- alarm_monitor.ui_interact(usr, state = GLOB.self_state)
-
/********************
* Atmos Control *
********************/
diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm
index b42f3275997..28fff50a124 100644
--- a/code/modules/mob/living/simple_animal/animal_defense.dm
+++ b/code/modules/mob/living/simple_animal/animal_defense.dm
@@ -42,13 +42,18 @@
/mob/living/simple_animal/attack_alien(mob/living/carbon/alien/humanoid/M)
if(..()) //if harm or disarm intent.
- var/damage = rand(15, 30)
- visible_message("[M] has slashed at [src]!", \
- "[M] has slashed at [src]!")
- playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
- add_attack_logs(M, src, "Alien attacked")
- attack_threshold_check(damage)
- return
+ if(M.a_intent == INTENT_DISARM)
+ playsound(loc, 'sound/weapons/pierce.ogg', 25, TRUE, -1)
+ visible_message("[M] [response_disarm] [name]!", "[M] [response_disarm] you!")
+ add_attack_logs(M, src, "Alien disarmed")
+ else
+ var/damage = rand(15, 30)
+ visible_message("[M] has slashed at [src]!", \
+ "[M] has slashed at [src]!")
+ playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
+ add_attack_logs(M, src, "Alien attacked")
+ attack_threshold_check(damage)
+ return TRUE
/mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L)
if(..()) //successful larva bite
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index e51dc527832..97fc3ac469c 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -94,7 +94,6 @@
hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD, DIAG_PATH_HUD = HUD_LIST_LIST)//Diagnostic HUD views
/obj/item/radio/headset/bot
- subspace_transmission = 1
requires_tcomms = FALSE
canhear_range = 0
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index f1278918898..dbd8ae6033a 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -66,6 +66,7 @@
RegisterSignal(src, COMSIG_CROSSED_MOVABLE, .proc/human_squish_check)
/mob/living/simple_animal/bot/mulebot/Destroy()
+ SStgui.close_uis(wires)
unload(0)
QDEL_NULL(wires)
QDEL_NULL(cell)
@@ -142,7 +143,7 @@
if(open)
icon_state="mulebot-hatch"
else
- icon_state = "mulebot[!wires.MobAvoid()]"
+ icon_state = "mulebot[wires.is_cut(WIRE_MOB_AVOIDANCE)]"
overlays.Cut()
if(load && !ismob(load))//buckling handles the mob offsets
load.pixel_y = initial(load.pixel_y) + 9
@@ -158,9 +159,9 @@
qdel(src)
if(2)
for(var/i = 1; i < 3; i++)
- wires.RandomCut()
+ wires.cut_random()
if(3)
- wires.RandomCut()
+ wires.cut_random()
return
/mob/living/simple_animal/bot/mulebot/bullet_act(obj/item/projectile/Proj)
@@ -169,7 +170,7 @@
unload(0)
if(prob(25))
visible_message("Something shorts out inside [src]!")
- wires.RandomCut()
+ wires.cut_random()
/mob/living/simple_animal/bot/mulebot/Topic(href, list/href_list)
if(..())
@@ -318,7 +319,7 @@
// returns true if the bot has power
/mob/living/simple_animal/bot/mulebot/proc/has_power()
- return !open && cell && cell.charge > 0 && wires.HasPower()
+ return !open && cell && cell.charge > 0 && !wires.is_cut(WIRE_MAIN_POWER1) && !wires.is_cut(WIRE_MAIN_POWER2)
/mob/living/simple_animal/bot/mulebot/proc/buzz(type)
switch(type)
@@ -362,7 +363,7 @@
if(istype(AM,/obj/structure/closet/crate))
CRATE = AM
else
- if(wires.LoadCheck())
+ if(!wires.is_cut(WIRE_LOADCHECK))
buzz(SIGH)
return // if not hacked, only allow crates to be loaded
@@ -459,8 +460,7 @@
on = 0
return
if(on)
- var/speed = (wires.Motor1() ? 1 : 0) + (wires.Motor2() ? 2 : 0)
-// to_chat(world, "speed: [speed]")
+ var/speed = (wires.is_cut(WIRE_MOTOR1) ? 1 : 0) + (wires.is_cut(WIRE_MOTOR2) ? 2 : 0)
var/num_steps = 0
switch(speed)
if(0)
@@ -624,7 +624,7 @@
// not loaded
if(auto_pickup) // find a crate
var/atom/movable/AM
- if(wires.LoadCheck()) // if hacked, load first unanchored thing we find
+ if(wires.is_cut(WIRE_LOADCHECK)) // if hacked, load first unanchored thing we find
for(var/atom/movable/A in get_step(loc, loaddir))
if(!A.anchored)
AM = A
@@ -672,7 +672,7 @@
// called when bot bumps into anything
/mob/living/simple_animal/bot/mulebot/Bump(atom/obs)
- if(!wires.MobAvoid()) // usually just bumps, but if avoidance disabled knock over mobs
+ if(wires.is_cut(WIRE_MOB_AVOIDANCE)) // usually just bumps, but if avoidance disabled knock over mobs
var/mob/M = obs
if(ismob(M))
if(istype(M,/mob/living/silicon/robot))
@@ -736,8 +736,8 @@
..()
/mob/living/simple_animal/bot/mulebot/receive_signal(datum/signal/signal)
- if(!wires.RemoteRX() || ..())
- return 1
+ if(wires.is_cut(WIRE_REMOTE_RX) || ..())
+ return TRUE
var/recv = signal.data["command"]
@@ -772,7 +772,7 @@
// send a radio signal with multiple data key/values
/mob/living/simple_animal/bot/mulebot/post_signal_multiple(var/freq, var/list/keyval)
- if(!wires.RemoteTX())
+ if(wires.is_cut(WIRE_REMOTE_TX))
return
..()
@@ -803,7 +803,7 @@
//Update navigation data. Called when commanded to deliver, return home, or a route update is needed...
/mob/living/simple_animal/bot/mulebot/proc/get_nav()
- if(!on || !wires.BeaconRX())
+ if(!on || wires.is_cut(WIRE_BEACON_RX))
return
for(var/obj/machinery/navbeacon/NB in GLOB.deliverybeacons)
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index f150005116e..4c2c2332924 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -17,7 +17,7 @@
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
faction = list("cult")
- flying = 1
+ flying = TRUE
pressure_resistance = 100
universal_speak = 1
AIStatus = AI_OFF //normal constructs don't have AI
diff --git a/code/modules/mob/living/simple_animal/friendly/butterfly.dm b/code/modules/mob/living/simple_animal/friendly/butterfly.dm
index 9aaffc6ef8f..ebf068ff130 100644
--- a/code/modules/mob/living/simple_animal/friendly/butterfly.dm
+++ b/code/modules/mob/living/simple_animal/friendly/butterfly.dm
@@ -15,6 +15,7 @@
harm_intent_damage = 1
friendly = "nudges"
density = 0
+ flying = TRUE
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
ventcrawler = 2
mob_size = MOB_SIZE_TINY
diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
index ea8e949f1c7..58e3ad54089 100644
--- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
@@ -126,6 +126,7 @@
gold_core_spawnable = FRIENDLY_SPAWN
blood_volume = BLOOD_VOLUME_NORMAL
var/obj/item/udder/udder = null
+ gender = FEMALE
/mob/living/simple_animal/cow/Initialize()
udder = new()
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index 2881141f4dd..be3f985db2e 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -85,8 +85,11 @@
get_scooped(M)
..()
-/mob/living/simple_animal/mouse/start_pulling(var/atom/movable/AM)//Prevents mouse from pulling things
- to_chat(src, "You are too small to pull anything.")
+/mob/living/simple_animal/mouse/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)//Prevents mouse from pulling things
+ if(istype(AM, /obj/item/reagent_containers/food/snacks/cheesewedge))
+ return ..() // Get dem
+ if(show_message)
+ to_chat(src, "You are too small to pull anything except cheese.")
return
/mob/living/simple_animal/mouse/Crossed(AM as mob|obj, oldloc)
diff --git a/code/modules/mob/living/simple_animal/hostile/bat.dm b/code/modules/mob/living/simple_animal/hostile/bat.dm
index be04fc217e9..b47b0eb1f23 100644
--- a/code/modules/mob/living/simple_animal/hostile/bat.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bat.dm
@@ -16,6 +16,7 @@
maxHealth = 20
health = 20
mob_size = MOB_SIZE_TINY
+ flying = TRUE
harm_intent_damage = 8
melee_damage_lower = 10
melee_damage_upper = 10
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index b8c72d7cf84..2f97001d3ae 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -241,6 +241,14 @@ Difficulty: Very Hard
AT.pixel_y += random_y
return ..()
+/mob/living/simple_animal/hostile/megafauna/colossus/float(on) //we don't want this guy to float, messes up his animations
+ if(throwing)
+ return
+ if(on && !floating)
+ floating = TRUE
+ else if(!on && floating)
+ floating = FALSE
+
/obj/item/projectile/colossus
name ="death bolt"
icon_state= "chronobolt"
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/fish.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/fish.dm
index f44e6c1f88a..ca6987d735c 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/fish.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/fish.dm
@@ -26,21 +26,34 @@
flying = 1
var/carp_color = "carp" //holder for icon set
- var/list/icon_sets = list("carp", "blue", "yellow", "grape", "rust", "teal", "purple")
+ var/static/list/carp_colors = list(\
+ "lightpurple" = "#c3b9f1", \
+ "lightpink" = "#da77a8", \
+ "green" = "#70ff25", \
+ "grape" = "#df0afb", \
+ "swamp" = "#e5e75a", \
+ "turquoise" = "#04e1ed", \
+ "brown" = "#ca805a", \
+ "teal" = "#20e28e", \
+ "lightblue" = "#4d88cc", \
+ "rusty" = "#dd5f34", \
+ "beige" = "#bbaeaf", \
+ "yellow" = "#f3ca4a", \
+ "blue" = "#09bae1", \
+ "palegreen" = "#7ef099", \
+ )
/mob/living/simple_animal/hostile/retaliate/carp/Initialize(mapload)
. = ..()
carp_randomify()
update_icons()
-/mob/living/simple_animal/hostile/retaliate/carp/proc/carp_randomify()
- if(prob(1))
- carp_color = pick("white", "black")
- else
- carp_color = pick(icon_sets)
- icon_state = "[carp_color]"
- icon_living = "[carp_color]"
- icon_dead = "[carp_color]_dead"
+/mob/living/simple_animal/hostile/retaliate/carp/proc/carp_randomify(rarechance)
+ // Simplified version of: /mob/living/simple_animal/hostile/carp/proc/carp_randomify(rarechance)
+ var/our_color
+ our_color = pick(carp_colors)
+ add_atom_colour(carp_colors[our_color], FIXED_COLOUR_PRIORITY)
+ regenerate_icons()
/mob/living/simple_animal/hostile/retaliate/carp/koi
name = "space koi"
@@ -61,13 +74,15 @@
maxbodytemp = 1500
gold_core_spawnable = HOSTILE_SPAWN
+ var/randomize_icon = TRUE
/mob/living/simple_animal/hostile/retaliate/carp/koi/Initialize(mapload)
. = ..()
- var/koinum = rand(1, 4)
- icon_state = "koi[koinum]"
- icon_living = "koi[koinum]"
- icon_dead = "koi[koinum]-dead"
+ if(randomize_icon)
+ var/koinum = rand(1, 4)
+ icon_state = "koi[koinum]"
+ icon_living = "koi[koinum]"
+ icon_dead = "koi[koinum]-dead"
/mob/living/simple_animal/hostile/retaliate/carp/koi/Process_Spacemove(var/movement_dir)
return TRUE
@@ -76,3 +91,4 @@
icon_state = "koi5"
icon_living = "koi5"
icon_dead = "koi5-dead"
+ randomize_icon = FALSE
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm
index a3e32e9d35e..5d946662854 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm
@@ -46,6 +46,7 @@
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
+ flying = TRUE
pressure_resistance = 300
gold_core_spawnable = NO_SPAWN //too spooky for science
faction = list("undead") // did I mention ghost
diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
index decfc7146cf..f992bb3cc10 100644
--- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
@@ -362,7 +362,7 @@
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
mob_size = MOB_SIZE_TINY
- flying = 1
+ flying = TRUE
bubble_icon = "syndibot"
gold_core_spawnable = HOSTILE_SPAWN
del_on_death = 1
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/green.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/green.dm
index e7daced65ff..1946f1a32ee 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/green.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/green.dm
@@ -51,6 +51,10 @@
if(!(eggtype in eggtypes))
to_chat(src, "Unrecognized egg type.")
return 0
+ if(fed < feedings_to_lay)
+ // We have to check this again after the popup, to account for people spam-clicking the button, then doing all the popups at once.
+ to_chat(src, "You must wrap more humanoid prey before you can do this!")
+ return
visible_message("[src] lays a cluster of eggs.")
if(eggtype == TS_DESC_RED)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/red, 1)
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/purple.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/purple.dm
index 7e36b411bae..907e46b523e 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/purple.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/purple.dm
@@ -47,7 +47,7 @@
/mob/living/simple_animal/hostile/poison/terror_spider/purple/Life(seconds, times_fired)
. = ..()
- if(.) // if mob is NOT dead
+ if(stat != DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
if(!degenerate && spider_myqueen)
if(dcheck_counter >= 10)
dcheck_counter = 0
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
index bf3c98bb86a..737b6eba22a 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
@@ -66,7 +66,7 @@
/mob/living/simple_animal/hostile/poison/terror_spider/queen/Life(seconds, times_fired)
. = ..()
- if(.) // if mob is NOT dead
+ if(stat != DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
if(ckey && canlay < 12 && hasnested) // max 12 eggs worth stored at any one time, realistically that's tons.
if(world.time > (spider_lastspawn + spider_spawnfrequency))
if(eggslaid >= 20)
@@ -287,6 +287,10 @@
if(eggtype == null || numlings == null)
to_chat(src, "Cancelled.")
return
+ if(canlay < numlings)
+ // We have to check this again after the popups, to account for people spam-clicking the button, then doing all the popups at once.
+ to_chat(src, "Too soon to do this again!")
+ return
canlay -= numlings
eggslaid += numlings
if(eggtype == TS_DESC_RED)
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm
index 520143d71d0..ab36c6ca313 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm
@@ -298,7 +298,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
/mob/living/simple_animal/hostile/poison/terror_spider/Life(seconds, times_fired)
. = ..()
- if(!.) // if mob is dead
+ if(stat == DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
if(prob(2))
// 2% chance every cycle to decompose
visible_message("\The dead body of the [src] decomposes!")
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index 41786017ea2..8d6db8ade3c 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -86,6 +86,7 @@
//Parrots are kleptomaniacs. This variable ... stores the item a parrot is holding.
var/obj/item/held_item = null
+ flying = TRUE
gold_core_spawnable = FRIENDLY_SPAWN
@@ -710,7 +711,7 @@
ears.talk_into(src, message_pieces, message_mode, verb)
used_radios += ears
-/mob/living/simple_animal/parrot/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency)
+/mob/living/simple_animal/parrot/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency, use_voice = TRUE)
if(speaker != src && prob(50))
parrot_hear(html_decode(multilingual_to_message(message_pieces)))
..()
diff --git a/code/modules/mob/living/simple_animal/posessed_object.dm b/code/modules/mob/living/simple_animal/posessed_object.dm
index c3cb61d5970..729790d098c 100644
--- a/code/modules/mob/living/simple_animal/posessed_object.dm
+++ b/code/modules/mob/living/simple_animal/posessed_object.dm
@@ -32,8 +32,9 @@
animate_ghostly_presence(src, -1, 20, 1) // Restart the floating animation after the attack animation, as it will be cancelled.
-/mob/living/simple_animal/possessed_object/start_pulling(var/atom/movable/AM) // Silly motherfuckers think they can pull things.
- to_chat(src, "You are unable to pull [AM]!")
+/mob/living/simple_animal/possessed_object/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE) // Silly motherfuckers think they can pull things.
+ if(show_message)
+ to_chat(src, "You are unable to pull [AM]!")
/mob/living/simple_animal/possessed_object/ghost() // Ghosting will return the object to normal, and will not disqualify the ghoster from various mid-round antag positions.
diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm
index 663838d3a45..1e3c723b278 100644
--- a/code/modules/mob/living/simple_animal/shade.dm
+++ b/code/modules/mob/living/simple_animal/shade.dm
@@ -24,6 +24,7 @@
status_flags = 0
faction = list("cult")
status_flags = CANPUSH
+ flying = TRUE
loot = list(/obj/item/reagent_containers/food/snacks/ectoplasm)
del_on_death = 1
deathmessage = "lets out a contented sigh as their form unwinds."
diff --git a/code/modules/mob/living/simple_animal/slime/say.dm b/code/modules/mob/living/simple_animal/slime/say.dm
index 74241dc676c..8679d64a699 100644
--- a/code/modules/mob/living/simple_animal/slime/say.dm
+++ b/code/modules/mob/living/simple_animal/slime/say.dm
@@ -9,7 +9,7 @@
return verb
-/mob/living/simple_animal/slime/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency)
+/mob/living/simple_animal/slime/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency, use_voice = TRUE)
if(speaker != src && !stat)
if(speaker in Friends)
speech_buffer = list()
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index 15f483bef76..1b67b53119a 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -265,7 +265,7 @@
/mob/living/simple_animal/slime/unEquip(obj/item/I, force)
return
-/mob/living/simple_animal/slime/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
+/mob/living/simple_animal/slime/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)
return
/mob/living/simple_animal/slime/attack_ui(slot)
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index 7cd2b4414f7..ce266ba5b8f 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -141,18 +141,6 @@
if(updating && val_change)
update_canmove()
-/mob/living/proc/StartFlying()
- var/val_change = !flying
- flying = TRUE
- if(val_change)
- update_animations()
-
-/mob/living/proc/StopFlying()
- var/val_change = !!flying
- flying = FALSE
- if(val_change)
- update_animations()
-
// SCALAR STATUS EFFECTS
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index 5345bda5b94..c222f76eadb 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -28,6 +28,7 @@
/mob/Login()
GLOB.player_list |= src
+ last_known_ckey = ckey
update_Login_details()
world.update_status()
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 1c7f8fa6ae9..848606be3ec 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -19,7 +19,6 @@
for(var/datum/alternate_appearance/AA in viewing_alternate_appearances)
AA.viewers -= src
viewing_alternate_appearances = null
- logs.Cut()
LAssailant = null
return ..()
@@ -578,6 +577,8 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
changeNext_move(CLICK_CD_POINT)
var/obj/P = new /obj/effect/temp_visual/point(tile)
P.invisibility = invisibility
+ P.pixel_x = A.pixel_x
+ P.pixel_y = A.pixel_y
return 1
/mob/proc/ret_grab(obj/effect/list_container/mobl/L as obj, flag)
@@ -1238,10 +1239,13 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
create_log_in_list(debug_log, text, collapse, world.timeofday)
/mob/proc/create_log(log_type, what, target = null, turf/where = get_turf(src))
- LAZYINITLIST(logs[log_type])
- var/list/log_list = logs[log_type]
+ if(!ckey)
+ return
+ var/real_ckey = ckey
+ if(ckey[1] == "@") // Admin aghosting will do this
+ real_ckey = copytext(ckey, 2)
var/datum/log_record/record = new(log_type, src, what, target, where, world.time)
- log_list.Add(record)
+ GLOB.logging.add_log(real_ckey, record)
/proc/create_log_in_list(list/target, text, collapse = TRUE, last_log)//forgive me code gods for this shitcode proc
//this proc enables lovely stuff like an attack log that looks like this: "[18:20:29-18:20:45]21x John Smith attacked Andrew Jackson with a crowbar."
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 1477be47d89..80404460b50 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -36,7 +36,7 @@
var/list/attack_log_old = list( )
var/list/debug_log = null
- var/list/logs = list() // Logs for each log type defined in __DEFINES/logs.dm
+ var/last_known_ckey = null // Used in logging
var/last_log = 0
var/obj/machinery/machine = null
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 5fb5bcb06c8..ff01fbe5cc9 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -113,7 +113,7 @@
var/question = "Do you want to play as [M.real_name ? M.real_name : M.name][M.job ? " ([M.job])" : ""]"
if(alert("Do you want to show the antag status?","Show antag status","Yes","No") == "Yes")
question += ", [M.mind?.special_role ? M.mind?.special_role : "No special role"]"
- var/list/mob/dead/observer/candidates = pollCandidates("[question]?", poll_time = 100, min_hours = minhours)
+ var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("[question]?", poll_time = 10 SECONDS, min_hours = minhours, source = M)
var/mob/dead/observer/theghost = null
if(LAZYLEN(candidates))
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 4797c685fe1..0325d13faf0 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -369,8 +369,9 @@
step(pulling, get_dir(pulling.loc, A))
return
-/mob/proc/update_gravity()
+/mob/proc/update_gravity(has_gravity)
return
+
/client/proc/check_has_body_select()
return mob && mob.hud_used && mob.hud_used.zone_select && istype(mob.hud_used.zone_select, /obj/screen/zone_sel)
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index 0417e28f546..7a26de718b6 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -44,17 +44,27 @@
usr.emote(message)
-/mob/proc/say_dead(var/message)
- if(!(client && client.holder))
- if(!config.dsay_allowed)
- to_chat(src, "Deadchat is globally muted.")
+/mob/proc/say_dead(message)
+ if(client)
+ if(!client.holder)
+ if(!config.dsay_allowed)
+ to_chat(src, "Deadchat is globally muted.")
+ return
+
+ if(client.prefs.muted & MUTE_DEADCHAT)
+ to_chat(src, "You cannot talk in deadchat (muted).")
return
- if(client && !(client.prefs.toggles & CHAT_DEAD))
- to_chat(usr, "You have deadchat muted.")
- return
+ if(!(client.prefs.toggles & CHAT_DEAD))
+ to_chat(src, "You have deadchat muted.")
+ return
+
+ if(client.handle_spam_prevention(message, MUTE_DEADCHAT))
+ return
say_dead_direct("[pick("complains", "moans", "whines", "laments", "blubbers", "salts")], \"[message]\"", src)
+ create_log(DEADCHAT_LOG, message)
+ log_ghostsay(message, src)
/mob/proc/say_understands(var/mob/other, var/datum/language/speaking = null)
if(stat == DEAD)
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 8e7adea666b..d151a98309f 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -44,26 +44,37 @@
-//human -> robot
-/mob/living/carbon/human/proc/Robotize()
+/**
+ For transforming humans into robots (cyborgs).
+
+ Arguments:
+ * cell_type: A type path of the cell the new borg should receive.
+ * connect_to_default_AI: TRUE if you want /robot/New() to handle connecting the borg to the AI with the least borgs.
+ * AI: A reference to the AI we want to connect to.
+*/
+/mob/living/carbon/human/proc/Robotize(cell_type = null, connect_to_default_AI = TRUE, mob/living/silicon/ai/AI = null)
if(notransform)
return
for(var/obj/item/W in src)
unEquip(W)
- regenerate_icons()
+
notransform = 1
canmove = 0
icon = null
invisibility = 101
- for(var/t in bodyparts)
- qdel(t)
- for(var/i in internal_organs)
- qdel(i)
- var/mob/living/silicon/robot/O = new /mob/living/silicon/robot( loc )
+ // Creating a new borg here will connect them to a default AI and notify that AI, if `connect_to_default_AI` is TRUE.
+ var/mob/living/silicon/robot/O = new /mob/living/silicon/robot(loc, connect_to_AI = connect_to_default_AI)
- // cyborgs produced by Robotize get an automatic power cell
- O.cell = new /obj/item/stock_parts/cell/high(O)
+ // If `AI` is passed in, we want to connect to that AI specifically.
+ if(AI)
+ O.lawupdate = TRUE
+ O.connect_to_ai(AI)
+
+ if(!cell_type)
+ O.cell = new /obj/item/stock_parts/cell/high(O)
+ else
+ O.cell = new cell_type(O)
O.gender = gender
O.invisibility = 0
@@ -77,9 +88,8 @@
else
O.key = key
- O.loc = loc
+ O.forceMove(loc)
O.job = "Cyborg"
- O.notify_ai(1)
if(O.mind && O.mind.assigned_role == "Cyborg")
if(O.mind.role_alt_title == "Robot")
diff --git a/code/modules/mob/update_status.dm b/code/modules/mob/update_status.dm
index 1708bcfb7a2..b603fc5974e 100644
--- a/code/modules/mob/update_status.dm
+++ b/code/modules/mob/update_status.dm
@@ -55,12 +55,6 @@
// Procs that update other things about the mob
-// Does various animations - Jitter, Flying, Spinning
-/mob/proc/update_animations()
- if(flying)
- animate(src, pixel_y = pixel_y + 5 , time = 10, loop = 1, easing = SINE_EASING)
- animate(pixel_y = pixel_y - 5, time = 10, loop = 1, easing = SINE_EASING)
-
/mob/proc/update_stat()
return
diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm
index 4f1bd269337..a2357fd9ebe 100644
--- a/code/modules/modular_computers/computers/machinery/console_presets.dm
+++ b/code/modules/modular_computers/computers/machinery/console_presets.dm
@@ -35,7 +35,7 @@
/obj/machinery/modular_computer/console/preset/engineering/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/power_monitor())
- hard_drive.store_file(new/datum/computer_file/program/alarm_monitor())
+// hard_drive.store_file(new/datum/computer_file/program/alarm_monitor()) //TO-DO:TGUI--Uncomment Modular computers
hard_drive.store_file(new/datum/computer_file/program/supermatter_monitor())
// ===== RESEARCH CONSOLE =====
diff --git a/code/modules/modular_computers/file_system/programs/command/card.dm b/code/modules/modular_computers/file_system/programs/command/card.dm
index b85fb710e38..cae4b5ed2e2 100644
--- a/code/modules/modular_computers/file_system/programs/command/card.dm
+++ b/code/modules/modular_computers/file_system/programs/command/card.dm
@@ -222,7 +222,7 @@
if(is_authenticated(usr) && modify)
var/t1 = href_list["assign_target"]
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)
@@ -251,7 +251,8 @@
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))
@@ -266,7 +267,7 @@
if("PRG_reg")
if(is_authenticated(usr))
- 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
@@ -290,6 +291,8 @@
if(is_authenticated(usr))
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)
if("PRG_print")
@@ -331,9 +334,14 @@
if("PRG_terminate")
if(is_authenticated(usr))
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
+ log_game("[key_name(usr)] has terminated the employment of \"[modify.registered_name]\" the \"[jobnamedata]\" for: \"[reason]\".")
+ message_admins("[key_name_admin(usr)] has terminated the employment of \"[modify.registered_name]\" the \"[jobnamedata]\" for: \"[reason]\".")
+ usr.create_log(MISC_LOG, "terminated the employment of \"[modify.registered_name]\" 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()
diff --git a/code/modules/modular_computers/file_system/programs/engineering/alarm.dm b/code/modules/modular_computers/file_system/programs/engineering/alarm.dm
index 8cb47337a6d..2f2f4a08232 100644
--- a/code/modules/modular_computers/file_system/programs/engineering/alarm.dm
+++ b/code/modules/modular_computers/file_system/programs/engineering/alarm.dm
@@ -7,65 +7,71 @@
requires_ntnet = 1
network_destination = "alarm monitoring network"
size = 5
- var/list/datum/alarm_handler/alarm_handlers
+ var/tgui_id = "NtosStationAlertConsole"
+ var/ui_x = 315
+ var/ui_y = 500
+ var/has_alert = 0
+ var/list/alarms_listend_for = list("Fire", "Atmosphere", "Power")
-/datum/computer_file/program/alarm_monitor/New()
+/datum/computer_file/program/alarm_monitor/process_tick()
..()
- alarm_handlers = list(SSalarms.atmosphere_alarm, SSalarms.fire_alarm, SSalarms.power_alarm)
- for(var/datum/alarm_handler/AH in alarm_handlers)
- AH.register(src, /datum/computer_file/program/alarm_monitor/proc/update_icon)
-/datum/computer_file/program/alarm_monitor/Destroy()
- for(var/datum/alarm_handler/AH in alarm_handlers)
- AH.unregister(src)
- QDEL_NULL(alarm_handlers)
- return ..()
+ if(has_alert)
+ program_icon_state = "alert-red"
+ ui_header = "alarm_red.gif"
+ update_computer_icon()
+ else
+ program_icon_state = "alert-green"
+ ui_header = "alarm_green.gif"
+ update_computer_icon()
+ return TRUE
-/datum/computer_file/program/alarm_monitor/proc/update_icon()
- for(var/datum/alarm_handler/AH in alarm_handlers)
- if(AH.has_major_alarms())
- program_icon_state = "alert-red"
- ui_header = "alarm_red.gif"
- update_computer_icon()
- return 1
- program_icon_state = "alert-green"
- ui_header = "alarm_green.gif"
- update_computer_icon()
- return 0
-
-/datum/computer_file/program/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
- assets.send(user)
- ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring", 575, 700)
- ui.set_auto_update(1)
- ui.set_layout_key("program")
- ui.open()
-
-/datum/computer_file/program/alarm_monitor/ui_data(mob/user)
+/datum/computer_file/program/alarm_monitor/tgui_data(mob/user)
var/list/data = get_header_data()
- var/categories[0]
- for(var/datum/alarm_handler/AH in alarm_handlers)
- categories[++categories.len] = list("category" = AH.category, "alarms" = list())
- for(var/datum/alarm/A in AH.major_alarms())
- var/cameras[0]
- var/lost_sources[0]
-
- if(isAI(user))
- for(var/obj/machinery/camera/C in A.cameras())
- cameras[++cameras.len] = C.nano_structure()
- for(var/datum/alarm_source/AS in A.sources)
- if(!AS.source)
- lost_sources[++lost_sources.len] = AS.source_name
-
- categories[categories.len]["alarms"] += list(list(
- "name" = sanitize(A.alarm_name()),
- "origin_lost" = A.origin == null,
- "has_cameras" = cameras.len,
- "cameras" = cameras,
- "lost_sources" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : ""))
- data["categories"] = categories
+ data["alarms"] = list()
+ for(var/class in SSalarm.alarms)
+ if(!(class in alarms_listend_for))
+ continue
+ data["alarms"][class] = list()
+ for(var/area in alarms[class])
+ data["alarms"][class] += area
return data
+
+/datum/computer_file/program/alarm_monitor/proc/alarm_triggered(src, class, area/A, list/O, obj/alarmsource)
+ if(is_station_level(alarmsource.z))
+ if(!(A.type in GLOB.the_station_areas))
+ return
+ else if(!is_mining_level(alarmsource.z) || istype(A, /area/ruin))
+ return
+ update_alarm_display()
+
+/datum/computer_file/program/alarm_monitor/proc/alarm_cancelled(src, class, area/A, obj/origin, cleared)
+ if(is_station_level(origin.z))
+ if(!(A.type in GLOB.the_station_areas))
+ return
+ else if(!is_mining_level(origin.z) || istype(A, /area/ruin))
+ return
+ update_alarm_display()
+
+/datum/computer_file/program/alarm_monitor/proc/update_alarm_display()
+ has_alert = FALSE
+ for(var/cat in alarms)
+ if(!(cat in alarms_listend_for))
+ continue
+ var/list/L = alarms[cat]
+ if(length(L))
+ has_alert = TRUE
+
+/datum/computer_file/program/alarm_monitor/run_program(mob/user)
+ . = ..(user)
+ GLOB.alarmdisplay += src
+ RegisterSignal(SSalarm, COMSIG_TRIGGERED_ALARM, .proc/alarm_triggered)
+ RegisterSignal(SSalarm, COMSIG_CANCELLED_ALARM, .proc/alarm_cancelled)
+
+/datum/computer_file/program/alarm_monitor/kill_program(forced = FALSE)
+ GLOB.alarmdisplay -= src
+ UnregisterSignal(SSalarm, COMSIG_TRIGGERED_ALARM)
+ UnregisterSignal(SSalarm, COMSIG_CANCELLED_ALARM)
+ ..()
diff --git a/code/modules/nano/modules/alarm_monitor.dm b/code/modules/nano/modules/alarm_monitor.dm
deleted file mode 100644
index cee3820b102..00000000000
--- a/code/modules/nano/modules/alarm_monitor.dm
+++ /dev/null
@@ -1,90 +0,0 @@
-/datum/nano_module/alarm_monitor
- name = "Alarm monitor"
- var/list_cameras = 0 // Whether or not to list camera references. A future goal would be to merge this with the enginering/security camera console. Currently really only for AI-use.
- var/list/datum/alarm_handler/alarm_handlers // The particular list of alarm handlers this alarm monitor should present to the user.
-
-/datum/nano_module/alarm_monitor/all/New()
- ..()
- alarm_handlers = list(SSalarms.atmosphere_alarm, SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.fire_alarm, SSalarms.motion_alarm, SSalarms.power_alarm)
-
-/datum/nano_module/alarm_monitor/engineering/New()
- ..()
- alarm_handlers = list(SSalarms.atmosphere_alarm, SSalarms.fire_alarm, SSalarms.power_alarm)
-
-/datum/nano_module/alarm_monitor/security/New()
- ..()
- alarm_handlers = list(SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.motion_alarm)
-
-/datum/nano_module/alarm_monitor/proc/register(var/object, var/procName)
- for(var/datum/alarm_handler/AH in alarm_handlers)
- AH.register(object, procName)
-
-/datum/nano_module/alarm_monitor/proc/unregister(var/object)
- for(var/datum/alarm_handler/AH in alarm_handlers)
- AH.unregister(object)
-
-/datum/nano_module/alarm_monitor/proc/all_alarms()
- var/list/all_alarms = new()
- for(var/datum/alarm_handler/AH in alarm_handlers)
- all_alarms += AH.alarms
-
- return all_alarms
-
-/datum/nano_module/alarm_monitor/proc/major_alarms()
- var/list/all_alarms = new()
- for(var/datum/alarm_handler/AH in alarm_handlers)
- all_alarms += AH.major_alarms()
-
- return all_alarms
-
-/datum/nano_module/alarm_monitor/proc/minor_alarms()
- var/list/all_alarms = new()
- for(var/datum/alarm_handler/AH in alarm_handlers)
- all_alarms += AH.minor_alarms()
-
- return all_alarms
-
-/datum/nano_module/alarm_monitor/Topic(ref, href_list)
- if(..())
- return 1
- if(href_list["switchTo"])
- var/obj/machinery/camera/C = locate(href_list["switchTo"]) in GLOB.cameranet.cameras
- if(!C || !isAI(usr))
- return
-
- usr.switch_to_camera(C)
- return 1
-
-/datum/nano_module/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state)
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring Console", 800, 800, state = state)
- ui.open()
- ui.set_auto_update(1)
-
-/datum/nano_module/alarm_monitor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
- var/data[0]
-
- var/categories[0]
- for(var/datum/alarm_handler/AH in alarm_handlers)
- categories[++categories.len] = list("category" = AH.category, "alarms" = list())
- for(var/datum/alarm/A in AH.major_alarms())
- var/cameras[0]
- var/lost_sources[0]
-
- if(isAI(user))
- for(var/obj/machinery/camera/C in A.cameras())
- cameras[++cameras.len] = C.nano_structure()
- for(var/datum/alarm_source/AS in A.sources)
- if(!AS.source)
- lost_sources[++lost_sources.len] = AS.source_name
-
- categories[categories.len]["alarms"] += list(list(
- "name" = sanitize(A.alarm_name()),
- "origin_lost" = A.origin == null,
- "has_cameras" = cameras.len,
- "cameras" = cameras,
- "lost_sources" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : ""))
- data["categories"] = categories
-
- return data
diff --git a/code/modules/ninja/suit/suit_initialisation.dm b/code/modules/ninja/suit/suit_initialisation.dm
index 59303b4707c..b9200d0e771 100644
--- a/code/modules/ninja/suit/suit_initialisation.dm
+++ b/code/modules/ninja/suit/suit_initialisation.dm
@@ -14,30 +14,30 @@
suitBusy = 1
if(suitActive && (alert("Confirm suit systems shutdown? This cannot be halted once it has started.", "Confirm Shutdown", "Yes", "No") == "Yes"))
- to_chat(usr, "Now de-initializing...")
+ to_chat(usr, "Now de-initializing...")
sleep(15)
- to_chat(usr, "Logging off, [usr.real_name]. Shutting down SpiderOS.")
+ to_chat(usr, "Logging off, [usr.real_name]. Shutting down SpiderOS.")
sleep(10)
- to_chat(usr, "Primary system status: OFFLINE.\nBackup system status: OFFLINE.")
+ to_chat(usr, "Primary system status: OFFLINE.\nBackup system status: OFFLINE.")
sleep(5)
- to_chat(usr, "VOID-shift device status: OFFLINE.\nCLOAK-tech device status: OFFLINE.")
+ to_chat(usr, "VOID-shift device status: OFFLINE.\nCLOAK-tech device status: OFFLINE.")
//TODO: Shut down any active abilities
sleep(10)
- to_chat(usr, "Disconnecting neural-net interface...Success.")
+ to_chat(usr, "Disconnecting neural-net interface...Success.")
QDEL_NULL(usr.hud_used)
usr.create_mob_hud()
usr.regenerate_icons()
sleep(5)
- to_chat(usr, "Disengaging neural-net interface...Success.")
+ to_chat(usr, "Disengaging neural-net interface...Success.")
sleep(10)
- to_chat(usr, "Unsecuring external locking mechanism...\nNeural-net abolished.\nOperation status: FINISHED.")
+ to_chat(usr, "Unsecuring external locking mechanism...\nNeural-net abolished.\nOperation status: FINISHED.")
//TODO: Grant verbs
toggle_suit_lock(usr)
usr.regenerate_icons()
@@ -45,24 +45,24 @@
suitActive = 0
else if(!suitActive) // Activate the suit.
- to_chat(usr, "Now initializing...")
+ to_chat(usr, "Now initializing...")
sleep(15)
- to_chat(usr, "Now establishing neural-net interface...")
+ to_chat(usr, "Now establishing neural-net interface...")
if(usr.mind.special_role != "Ninja")
to_chat(usr, "FĆAL �Rr�R: ŧer nt recgnized, c-cntr-r䣧-ç äcked.")
return
sleep(10)
- to_chat(usr, "Neural-net established. Now monitoring brainwave pattern. \nBrainwave patternGREEN, proceeding.")
+ to_chat(usr, "Neural-net established. Now monitoring brainwave pattern. \nBrainwave patternGREEN, proceeding.")
sleep(10)
- to_chat(usr, "Securing external locking mechanism...")
+ to_chat(usr, "Securing external locking mechanism...")
if(!toggle_suit_lock(usr))
return
sleep(5)
- to_chat(usr, "Suit secured, extending neural-net interface...")
+ to_chat(usr, "Suit secured, extending neural-net interface...")
QDEL_NULL(usr.hud_used)
usr.hud_used = new /datum/hud/human(usr, 'icons/mob/screen_ninja.dmi', "#ffffff", 255)
@@ -71,22 +71,22 @@
usr.regenerate_icons()
sleep(10)
- to_chat(usr, "VOID-shift device status: ONLINE.\nCLOAK-tech device status:ONLINE")
+ to_chat(usr, "VOID-shift device status: ONLINE.\nCLOAK-tech device status:ONLINE")
sleep(5)
- to_chat(usr, "Primary system status: ONLINE.\nBackup system status: ONLINE.")
+ to_chat(usr, "Primary system status: ONLINE.\nBackup system status: ONLINE.")
if(suitCell)
- to_chat(usr, "Current energy capacity: [suitCell.charge]/[suitCell.maxcharge].")
+ to_chat(usr, "Current energy capacity: [suitCell.charge]/[suitCell.maxcharge].")
sleep(10)
- to_chat(usr, "All systems operational. Welcome to SpiderOS, [usr.real_name].")
+ to_chat(usr, "All systems operational. Welcome to SpiderOS, [usr.real_name].")
//TODO: Grant ninja verbs here.
suitBusy = 0
suitActive = 1
else
suitBusy = 0
- to_chat(usr, "NOTICE: Suit de-activation protocals aborted.")
+ to_chat(usr, "NOTICE: Suit de-activation protocals aborted.")
else
to_chat(usr, "FĆAL �Rr�R: ŧer nt recgnized, c-cntr-r䣧-ç äcked.")
return
diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm
index 09858073142..32416a8d5e7 100644
--- a/code/modules/paperwork/faxmachine.dm
+++ b/code/modules/paperwork/faxmachine.dm
@@ -12,24 +12,32 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
insert_anim = "faxsend"
pass_flags = PASSTABLE
var/fax_network = "Local Fax Network"
- var/syndie_restricted = FALSE //is it a syndicate base fax restricted from contacting NT assets?
+ /// If true, prevents fax machine from sending messages to NT machines
+ var/syndie_restricted = FALSE
- var/long_range_enabled = 0 // Can we send messages off the station?
+ /// Can we send messages off-station?
+ var/long_range_enabled = FALSE
req_one_access = list(ACCESS_LAWYER, ACCESS_HEADS, ACCESS_ARMORY)
use_power = IDLE_POWER_USE
idle_power_usage = 30
active_power_usage = 200
- var/obj/item/card/id/scan = null // identification
+ /// ID card inserted into the machine, used to log in with
+ var/obj/item/card/id/scan = null
- var/authenticated = 0
- var/sendcooldown = 0 // to avoid spamming fax messages
+ /// Whether the machine is "logged in" or not
+ var/authenticated = FALSE
+ /// Next world.time at which this fax machine can send a message to CC/syndicate
+ var/sendcooldown = 0
+ /// After sending a message to CC/syndicate, cannot send another to them for this many deciseconds
var/cooldown_time = 1800
- var/department = "Unknown" // our department
+ /// Our department, determines whether this machine gets faxes sent to a department
+ var/department = "Unknown"
- var/destination = "Not Selected" // the department we're sending to
+ /// Target department to send outgoing faxes to
+ var/destination
/obj/machinery/photocopier/faxmachine/New()
..()
@@ -44,7 +52,7 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
/obj/machinery/photocopier/faxmachine/longrange
name = "long range fax machine"
fax_network = "Central Command Quantum Entanglement Network"
- long_range_enabled = 1
+ long_range_enabled = TRUE
/obj/machinery/photocopier/faxmachine/longrange/syndie
name = "syndicate long range fax machine"
@@ -58,17 +66,17 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
GLOB.hidden_departments |= department
/obj/machinery/photocopier/faxmachine/attack_hand(mob/user)
- ui_interact(user)
+ tgui_interact(user)
/obj/machinery/photocopier/faxmachine/attack_ghost(mob/user)
- ui_interact(user)
+ tgui_interact(user)
/obj/machinery/photocopier/faxmachine/attackby(obj/item/item, mob/user, params)
if(istype(item,/obj/item/card/id) && !scan)
scan(item)
else if(istype(item, /obj/item/paper) || istype(item, /obj/item/photo) || istype(item, /obj/item/paper_bundle))
..()
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
else
return ..()
@@ -80,42 +88,6 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
else
to_chat(user, "You swipe the card through [src], but nothing happens.")
-/obj/machinery/photocopier/faxmachine/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "faxmachine.tmpl", "Fax Machine UI", 540, 450)
- ui.open()
-
-/obj/machinery/photocopier/faxmachine/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
- var/data[0]
- var/is_authenticated = is_authenticated(user)
-
- if(scan)
- data["scan_name"] = scan.name
- else
- data["scan_name"] = "-----"
- data["authenticated"] = is_authenticated
- if(!is_authenticated)
- data["network"] = "Disconnected"
- else if(!emagged)
- data["network"] = fax_network
- else
- data["network"] = "ERR*?*%!*"
- if(copyitem)
- data["paper"] = copyitem.name
- data["paperinserted"] = 1
- else
- data["paper"] = "-----"
- data["paperinserted"] = 0
- data["destination"] = destination
- data["cooldown"] = sendcooldown
- if((destination in GLOB.admin_departments) || (destination in GLOB.hidden_admin_departments))
- data["respectcooldown"] = 1
- else
- data["respectcooldown"] = 0
-
- return data
-
/obj/machinery/photocopier/faxmachine/proc/is_authenticated(mob/user)
if(authenticated)
return TRUE
@@ -123,87 +95,134 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
return TRUE
return FALSE
-/obj/machinery/photocopier/faxmachine/Topic(href, href_list)
- if(..())
- return 1
+/obj/machinery/photocopier/faxmachine/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "FaxMachine", name, 540, 300, master_ui, state)
+ ui.open()
+/obj/machinery/photocopier/faxmachine/tgui_data(mob/user)
+ var/list/data = list()
+ data["authenticated"] = is_authenticated(user)
+ data["scan_name"] = scan ? scan.name : FALSE
+ if(!data["authenticated"])
+ data["network"] = "Disconnected"
+ else if(!emagged)
+ data["network"] = fax_network
+ else
+ data["network"] = "ERR*?*%!*"
+ data["paper"] = copyitem ? copyitem.name : FALSE
+ data["paperinserted"] = copyitem ? TRUE : FALSE
+ data["destination"] = destination ? destination : FALSE
+ data["sendError"] = FALSE
+ if(stat & (BROKEN|NOPOWER))
+ data["sendError"] = "No Power"
+ else if(!data["authenticated"])
+ data["sendError"] = "Not Logged In"
+ else if(!data["paper"])
+ data["sendError"] = "Nothing Inserted"
+ else if(!data["destination"])
+ data["sendError"] = "Destination Not Set"
+ else if((destination in GLOB.admin_departments) || (destination in GLOB.hidden_admin_departments))
+ var/cooldown_seconds = cooldown_seconds()
+ if(cooldown_seconds)
+ data["sendError"] = "Re-aligning in [cooldown_seconds] seconds..."
+ return data
+
+
+/obj/machinery/photocopier/faxmachine/tgui_act(action, params)
+ if(..())
+ return
var/is_authenticated = is_authenticated(usr)
- if(href_list["send"])
- if(copyitem && is_authenticated)
+ . = TRUE
+ switch(action)
+ if("scan") // insert/remove your ID card
+ scan()
+ if("auth") // log in/out
+ if(!is_authenticated && scan)
+ if(scan.registered_name in GLOB.fax_blacklist)
+ to_chat(usr, "Login rejected: individual is blacklisted from fax network.")
+ playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ . = FALSE
+ else if(check_access(scan))
+ authenticated = TRUE
+ else // ID doesn't have access to this machine
+ to_chat(usr, "Login rejected: ID card does not have required access.")
+ playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ . = FALSE
+ else if(is_authenticated)
+ authenticated = FALSE
+ if("paper") // insert/eject paper/paperbundle/photo
+ if(copyitem)
+ copyitem.forceMove(get_turf(src))
+ if(ishuman(usr))
+ if(!usr.get_active_hand() && Adjacent(usr))
+ usr.put_in_hands(copyitem)
+ to_chat(usr, "You eject [copyitem] from [src].")
+ copyitem = null
+ else
+ var/obj/item/I = usr.get_active_hand()
+ if(istype(I, /obj/item/paper) || istype(I, /obj/item/photo) || istype(I, /obj/item/paper_bundle))
+ usr.drop_item()
+ copyitem = I
+ I.forceMove(src)
+ to_chat(usr, "You insert [I] into [src].")
+ flick(insert_anim, src)
+ else
+ to_chat(usr, "[src] only accepts paper, paper bundles, and photos.")
+ . = FALSE
+ if("rename") // rename the item that is currently in the fax machine
+ if(copyitem)
+ var/n_name = sanitize(copytext(input(usr, "What would you like to label the fax?", "Fax Labelling", copyitem.name) as text, 1, MAX_MESSAGE_LEN))
+ if((copyitem && copyitem.loc == src && usr.stat == 0))
+ if(istype(copyitem, /obj/item/paper))
+ copyitem.name = "[(n_name ? text("[n_name]") : initial(copyitem.name))]"
+ copyitem.desc = "This is a paper titled '" + copyitem.name + "'."
+ else if(istype(copyitem, /obj/item/photo))
+ copyitem.name = "[(n_name ? text("[n_name]") : "photo")]"
+ else if(istype(copyitem, /obj/item/paper_bundle))
+ copyitem.name = "[(n_name ? text("[n_name]") : "paper")]"
+ else
+ . = FALSE
+ else
+ . = FALSE
+ else
+ . = FALSE
+ if("dept") // choose which department receives the fax
+ if(is_authenticated)
+ var/lastdestination = destination
+ var/list/combineddepartments = GLOB.alldepartments.Copy()
+ if(long_range_enabled)
+ combineddepartments += GLOB.admin_departments.Copy()
+ if(emagged)
+ combineddepartments += GLOB.hidden_admin_departments.Copy()
+ combineddepartments += GLOB.hidden_departments.Copy()
+ if(syndie_restricted)
+ combineddepartments = GLOB.hidden_admin_departments.Copy()
+ combineddepartments += GLOB.hidden_departments.Copy()
+ for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes)
+ if(F.emagged)//we can contact emagged faxes on the station
+ combineddepartments |= F.department
+ destination = input(usr, "To which department?", "Choose a department", "") as null|anything in combineddepartments
+ if(!destination)
+ destination = lastdestination
+ if("send") // actually send the fax
+ if(!copyitem || !is_authenticated || !destination)
+ return
+ if(stat & (BROKEN|NOPOWER))
+ return
if((destination in GLOB.admin_departments) || (destination in GLOB.hidden_admin_departments))
+ var/cooldown_seconds = cooldown_seconds()
+ if(cooldown_seconds > 0)
+ playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ to_chat(usr, "[src] is not ready for another [cooldown_seconds] seconds.")
+ return
send_admin_fax(usr, destination)
+ sendcooldown = world.time + cooldown_time
else
sendfax(destination, usr)
-
- if(sendcooldown)
- spawn(sendcooldown) // cooldown time
- sendcooldown = 0
- SSnanoui.update_uis(src)
-
- if(href_list["paper"])
- if(copyitem)
- copyitem.forceMove(get_turf(src))
- if(ishuman(usr))
- if(!usr.get_active_hand() && Adjacent(usr))
- usr.put_in_hands(copyitem)
- to_chat(usr, "You eject \the [copyitem] from \the [src].")
- copyitem = null
- else
- var/obj/item/I = usr.get_active_hand()
- if(istype(I, /obj/item/paper) || istype(I, /obj/item/photo) || istype(I, /obj/item/paper_bundle))
- usr.drop_item()
- copyitem = I
- I.forceMove(src)
- to_chat(usr, "You insert \the [I] into \the [src].")
- flick(insert_anim, src)
-
- if(href_list["scan"])
- scan()
-
- if(href_list["dept"])
- if(is_authenticated)
- var/lastdestination = destination
- var/list/combineddepartments = GLOB.alldepartments.Copy()
- if(long_range_enabled)
- combineddepartments += GLOB.admin_departments.Copy()
-
- if(emagged)
- combineddepartments += GLOB.hidden_admin_departments.Copy()
- combineddepartments += GLOB.hidden_departments.Copy()
-
- if(syndie_restricted)
- combineddepartments = GLOB.hidden_admin_departments.Copy()
- combineddepartments += GLOB.hidden_departments.Copy()
- for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes)
- if(F.emagged)//we can contact emagged faxes on the station
- combineddepartments |= F.department
-
- destination = input(usr, "To which department?", "Choose a department", "") as null|anything in combineddepartments
- if(!destination)
- destination = lastdestination
-
- if(href_list["auth"])
- if(!is_authenticated && scan)
- if(scan.registered_name in GLOB.fax_blacklist)
- playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
- else if(check_access(scan))
- authenticated = 1
- else if(is_authenticated)
- authenticated = 0
-
- if(href_list["rename"])
- if(copyitem)
- var/n_name = sanitize(copytext(input(usr, "What would you like to label the fax?", "Fax Labelling", copyitem.name) as text, 1, MAX_MESSAGE_LEN))
- if((copyitem && copyitem.loc == src && usr.stat == 0))
- if(istype(copyitem, /obj/item/paper))
- copyitem.name = "[(n_name ? text("[n_name]") : initial(copyitem.name))]"
- copyitem.desc = "This is a paper titled '" + copyitem.name + "'."
- else if(istype(copyitem, /obj/item/photo))
- copyitem.name = "[(n_name ? text("[n_name]") : "photo")]"
- else if(istype(copyitem, /obj/item/paper_bundle))
- copyitem.name = "[(n_name ? text("[n_name]") : "paper")]"
-
- SSnanoui.update_uis(src)
+ if(.)
+ add_fingerprint(usr)
/obj/machinery/photocopier/faxmachine/proc/scan(var/obj/item/card/id/card = null)
if(scan) // Card is in machine
@@ -226,7 +245,7 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
usr.drop_item()
card.forceMove(src)
scan = card
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
/obj/machinery/photocopier/faxmachine/verb/eject_id()
set category = null
@@ -237,25 +256,20 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
return
if(scan)
- to_chat(usr, "You remove \the [scan] from \the [src].")
+ to_chat(usr, "You remove [scan] from [src].")
scan.forceMove(get_turf(src))
if(!usr.get_active_hand() && Adjacent(usr))
usr.put_in_hands(scan)
scan = null
else
- to_chat(usr, "There is nothing to remove from \the [src].")
+ to_chat(usr, "There is nothing to remove from [src].")
/obj/machinery/photocopier/faxmachine/proc/sendfax(var/destination,var/mob/sender)
- if(stat & (BROKEN|NOPOWER))
- return
-
- use_power(200)
-
+ use_power(active_power_usage)
var/success = 0
for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes)
if(F.department == destination)
success = F.receivefax(copyitem)
-
if(success)
var/datum/fax/F = new /datum/fax()
F.name = copyitem.name
@@ -272,10 +286,10 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
/obj/machinery/photocopier/faxmachine/proc/receivefax(var/obj/item/incoming)
if(stat & (BROKEN|NOPOWER))
- return 0
+ return FALSE
if(department == "Unknown")
- return 0 //You can't send faxes to "Unknown"
+ return FALSE //You can't send faxes to "Unknown"
flick("faxreceive", src)
@@ -291,19 +305,13 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
else if(istype(incoming, /obj/item/paper_bundle))
bundlecopy(incoming)
else
- return 0
+ return FALSE
use_power(active_power_usage)
- return 1
+ return TRUE
/obj/machinery/photocopier/faxmachine/proc/send_admin_fax(var/mob/sender, var/destination)
- if(stat & (BROKEN|NOPOWER))
- return
-
- if(sendcooldown)
- return
-
- use_power(200)
+ use_power(active_power_usage)
if(!(istype(copyitem, /obj/item/paper) || istype(copyitem, /obj/item/paper_bundle) || istype(copyitem, /obj/item/photo)))
visible_message("[src] beeps, \"Error transmitting message.\"")
@@ -327,10 +335,12 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes)
if(F.department == destination)
F.receivefax(copyitem)
- sendcooldown = cooldown_time
- spawn(50)
- visible_message("[src] beeps, \"Message transmitted successfully.\"")
+ visible_message("[src] beeps, \"Message transmitted successfully.\"")
+/obj/machinery/photocopier/faxmachine/proc/cooldown_seconds()
+ if(sendcooldown < world.time)
+ return 0
+ return round((sendcooldown - world.time) / 10)
/obj/machinery/photocopier/faxmachine/proc/message_admins(var/mob/sender, var/faxname, var/faxtype, var/obj/item/sent, font_colour="#9A04D1")
var/msg = "[faxname]: [key_name_admin(sender)] | REPLY: (RADIO) (FAX) ([ADMIN_SM(sender,"SM")]) | REJECT: (TEMPLATE) ([ADMIN_BSA(sender,"BSA")]) (EVILFAX) : Receiving '[sent.name]' via secure connection... view message"
diff --git a/code/modules/paperwork/ticketmachine.dm b/code/modules/paperwork/ticketmachine.dm
index 2234e2911a6..0492d3da694 100644
--- a/code/modules/paperwork/ticketmachine.dm
+++ b/code/modules/paperwork/ticketmachine.dm
@@ -7,6 +7,7 @@
icon_state = "ticketmachine"
desc = "A marvel of bureaucratic engineering encased in an efficient plastic shell. It can be refilled with a hand labeler refill roll and linked to buttons with a multitool."
density = FALSE
+ anchored = TRUE
maptext_height = 26
maptext_width = 32
maptext_x = 7
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 409abe3d724..4b64266f2b7 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -25,6 +25,11 @@
#define APC_UPDATE_ICON_COOLDOWN 200 // 20 seconds
+// main_status var
+#define APC_EXTERNAL_POWER_NOTCONNECTED 0
+#define APC_EXTERNAL_POWER_NOENERGY 1
+#define APC_EXTERNAL_POWER_GOOD 2
+
// APC malf status
#define APC_MALF_NOT_HACKED 1
#define APC_MALF_HACKED 2 // APC hacked by user, and user is in its core.
@@ -75,7 +80,7 @@
var/lastused_equip = 0
var/lastused_environ = 0
var/lastused_total = 0
- var/main_status = 0
+ var/main_status = APC_EXTERNAL_POWER_NOTCONNECTED
powernet = 0 // set so that APCs aren't found as powernet nodes //Hackish, Horrible, was like this before I changed it :(
var/malfhack = 0 //New var for my changes to AI malf. --NeoFite
var/mob/living/silicon/ai/malfai = null //See above --NeoFite
@@ -170,6 +175,7 @@
addtimer(CALLBACK(src, .proc/update), 5)
/obj/machinery/power/apc/Destroy()
+ SStgui.close_uis(wires)
GLOB.apcs -= src
if(malfai && operating)
malfai.malf_picker.processing_time = clamp(malfai.malf_picker.processing_time - 10,0,1000)
@@ -212,12 +218,11 @@
if(isarea(A))
area = A
// no-op, keep the name
- else if(isarea(A) && src.areastring == null)
+ else if(isarea(A) && !areastring)
area = A
name = "\improper [area.name] APC"
else
- area = get_area_name(areastring)
- name = "\improper [area.name] APC"
+ name = "\improper [get_area_name(area, TRUE)] APC"
area.apc |= src
update_icon()
@@ -429,8 +434,8 @@
//attack with an item - open/close cover, insert cell, or (un)lock interface
/obj/machinery/power/apc/attackby(obj/item/W, mob/living/user, params)
- if(issilicon(user) && get_dist(src,user)>1)
- return src.attack_hand(user)
+ if(issilicon(user) && get_dist(src, user) > 1)
+ return attack_hand(user)
else if (istype(W, /obj/item/stock_parts/cell) && opened) // trying to put a cell inside
if(cell)
@@ -445,7 +450,7 @@
W.forceMove(src)
cell = W
user.visible_message(\
- "[user.name] has inserted the power cell to [src.name]!",\
+ "[user.name] has inserted the power cell to [name]!",\
"You insert the power cell.")
chargecount = 0
update_icon()
@@ -474,7 +479,7 @@
return
user.visible_message("[user.name] adds cables to the APC frame.", \
"You start adding cables to the APC frame...")
- playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
+ playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
if(do_after(user, 20, target = src))
if(C.get_amount() < 10 || !C)
return
@@ -499,10 +504,10 @@
user.visible_message("[user.name] inserts the power control board into [src].", \
"You start to insert the power control board into the frame...")
- playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
+ playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
if(do_after(user, 10, target = src))
- if(has_electronics==0)
- has_electronics = 1
+ if(!has_electronics)
+ has_electronics = TRUE
locked = FALSE
to_chat(user, "You place the power control board inside the frame.")
qdel(W)
@@ -549,11 +554,11 @@
return
to_chat(user, "You are trying to remove the power control board..." )
if(I.use_tool(src, user, 50, volume = I.tool_volume))
- if(has_electronics==1)
- has_electronics = 0
+ if(has_electronics)
+ has_electronics = FALSE
if(stat & BROKEN)
user.visible_message(\
- "[user.name] has broken the power control board inside [src.name]!",
+ "[user.name] has broken the power control board inside [name]!",
"You break the charred power control board and remove the remains.",
"You hear a crack.")
return
@@ -561,19 +566,19 @@
else if(emagged) // We emag board, not APC's frame
emagged = FALSE
user.visible_message(
- "[user.name] has discarded emaged power control board from [src.name]!",
- "You discarded shorten board.")
+ "[user.name] has discarded the shorted power control board from [name]!",
+ "You discarded the shorted board.")
return
else if(malfhack) // AI hacks board, not APC's frame
user.visible_message(\
- "[user.name] has discarded strangely programmed power control board from [src.name]!",
- "You discarded strangely programmed board.")
+ "[user.name] has discarded strangely the programmed power control board from [name]!",
+ "You discarded the strangely programmed board.")
malfai = null
malfhack = 0
return
else
user.visible_message(\
- "[user.name] has removed the power control board from [src.name]!",
+ "[user.name] has removed the power control board from [name]!",
"You remove the power control board.")
new /obj/item/apc_electronics(loc)
return
@@ -648,7 +653,7 @@
else if(stat & (BROKEN|MAINT))
to_chat(user, "Nothing happens!")
else
- if(allowed(usr) && !isWireCut(APC_WIRE_IDSCAN) && !malfhack)
+ if(allowed(usr) && !wires.is_cut(WIRE_IDSCAN) && !malfhack)
locked = !locked
to_chat(user, "You [ locked ? "lock" : "unlock"] the APC interface.")
update_icon()
@@ -711,36 +716,29 @@
// attack with hand - remove cell (if cover open) or interact with the APC
/obj/machinery/power/apc/attack_hand(mob/user)
-// if(!can_use(user)) This already gets called in interact() and in topic()
-// return
if(!user)
return
- src.add_fingerprint(user)
+ add_fingerprint(user)
- if(usr == user && opened && (!issilicon(user)))
+ if(usr == user && opened && !issilicon(user))
if(cell)
- if(issilicon(user))
- cell.loc=src.loc // Drop it, whoops.
- else
- user.put_in_hands(cell)
+ user.put_in_hands(cell)
cell.add_fingerprint(user)
cell.update_icon()
-
- src.cell = null
- user.visible_message("[user.name] removes the power cell from [src.name]!", "You remove the power cell.")
-// to_chat(user, "You remove the power cell.")
- charging = 0
- src.update_icon()
+ cell = null
+ user.visible_message("[user.name] removes [cell] from [src]!", "You remove the [cell].")
+ charging = FALSE
+ update_icon()
return
if(stat & (BROKEN|MAINT))
return
- src.interact(user)
+ interact(user)
/obj/machinery/power/apc/attack_ghost(mob/user)
if(panel_open)
wires.Interact(user)
- return ui_interact(user)
+ return tgui_interact(user)
/obj/machinery/power/apc/interact(mob/user)
if(!user)
@@ -749,7 +747,7 @@
if(panel_open)
wires.Interact(user)
- return ui_interact(user)
+ return tgui_interact(user)
/obj/machinery/power/apc/proc/get_malf_status(mob/living/silicon/ai/malf)
@@ -770,22 +768,16 @@
else
return APC_MALF_NOT_HACKED
-/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- if(!user)
- return
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
+/obj/machinery/power/apc/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
- // the ui does not exist, so we'll create a new one
- ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 510, issilicon(user) ? 535 : 460)
+ ui = new(user, src, ui_key, "APC", name, 510, 460, master_ui, state)
ui.open()
- // Auto update every Master Controller tick
- ui.set_auto_update(1)
-/obj/machinery/power/apc/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
- var/data[0]
+/obj/machinery/power/apc/tgui_data(mob/user)
+ var/list/data = list()
data["locked"] = is_locked(user)
+ data["normallyLocked"] = locked
data["isOperating"] = operating
data["externalPower"] = main_status
data["powerCellStatus"] = cell ? cell.percent() : null
@@ -853,10 +845,6 @@
// to_chat(world, "[area.power_equip]")
area.power_change()
-/obj/machinery/power/apc/proc/isWireCut(var/wireIndex)
- return wires.IsIndexCut(wireIndex)
-
-
/obj/machinery/power/apc/proc/can_use(var/mob/user, var/loud = 0) //used by attack_hand() and Topic()
if(user.can_admin_interact())
return 1
@@ -866,7 +854,7 @@
var/mob/living/silicon/ai/AI = user
var/mob/living/silicon/robot/robot = user
if( \
- src.aidisabled || \
+ aidisabled || \
malfhack && istype(malfai) && \
( \
(istype(AI) && (malfai!=AI && malfai != AI.parent)) || \
@@ -877,21 +865,21 @@
to_chat(user, "\The [src] has AI control disabled!")
user << browse(null, "window=apc")
user.unset_machine()
- return 0
+ return FALSE
else
- if((!in_range(src, user) || !istype(src.loc, /turf)))
- return 0
+ if((!in_range(src, user) || !istype(loc, /turf)))
+ return FALSE
var/mob/living/carbon/human/H = user
if(istype(H))
if(H.getBrainLoss() >= 60)
for(var/mob/M in viewers(src, null))
to_chat(M, "[H] stares cluelessly at [src] and drools.")
- return 0
+ return FALSE
else if(prob(H.getBrainLoss()))
to_chat(user, "You momentarily forget how to use [src].")
- return 0
- return 1
+ return FALSE
+ return TRUE
/obj/machinery/power/apc/proc/is_authenticated(mob/user as mob)
if(user.can_admin_interact())
@@ -909,104 +897,59 @@
else
return locked
-/obj/machinery/power/apc/Topic(href, href_list, var/usingUI = 1)
- if(..())
- return 1
-
- if(!can_use(usr, 1))
- return 1
-
- if(href_list["lock"])
- if(!is_authenticated(usr))
- return
-
- coverlocked = !coverlocked
-
- else if(href_list["breaker"])
- if(!is_authenticated(usr))
- return
-
- toggle_breaker()
-
- else if(href_list["toggle_nightshift"])
- if(!is_authenticated(usr))
- return
-
- if(last_nightshift_switch > world.time + 100) // don't spam...
- to_chat(usr, "[src]'s night lighting circuit breaker is still cycling!")
- return
- last_nightshift_switch = world.time
- set_nightshift(!nightshift_lights)
-
- else if(href_list["cmode"])
- if(!is_authenticated(usr))
- return
-
- chargemode = !chargemode
- if(!chargemode)
- charging = 0
- update_icon()
-
- else if(href_list["eqp"])
- if(!is_authenticated(usr))
- return
-
- var/val = text2num(href_list["eqp"])
- equipment = setsubsystem(val)
- update_icon()
- update()
-
- else if(href_list["lgt"])
- if(!is_authenticated(usr))
- return
-
- var/val = text2num(href_list["lgt"])
- lighting = setsubsystem(val)
- update_icon()
- update()
-
- else if(href_list["env"])
- if(!is_authenticated(usr))
- return
-
- var/val = text2num(href_list["env"])
- environ = setsubsystem(val)
- update_icon()
- update()
- else if( href_list["close"] )
- SSnanoui.close_user_uis(usr, src)
-
- return 0
- else if(href_list["close2"])
- usr << browse(null, "window=apcwires")
-
- return 0
-
- else if(href_list["overload"])
- if(issilicon(usr) && !aidisabled)
- overload_lighting()
-
- else if(href_list["malfhack"])
- if(get_malf_status(usr))
- malfhack(usr)
-
- else if(href_list["occupyapc"])
- if(get_malf_status(usr))
- malfoccupy(usr)
-
- else if(href_list["deoccupyapc"])
- if(get_malf_status(usr))
- malfvacate()
-
- else if(href_list["toggleaccess"])
- if(istype(usr, /mob/living/silicon))
- if(emagged || aidisabled || (stat & (BROKEN|MAINT)))
- to_chat(usr, "The APC does not respond to the command.")
+/obj/machinery/power/apc/tgui_act(action, params)
+ if(..() || !can_use(usr, TRUE) || (locked && !usr.has_unlimited_silicon_privilege && (action != "toggle_nightshift") && !usr.can_admin_interact()))
+ return
+ . = TRUE
+ switch(action)
+ if("lock")
+ if(usr.has_unlimited_silicon_privilege)
+ if(emagged || stat & BROKEN)
+ to_chat(usr, "The APC does not respond to the command!")
+ return FALSE
+ else
+ locked = !locked
+ update_icon()
else
- locked = !locked
+ to_chat(usr, "Access Denied!")
+ return FALSE
+ if("cover")
+ coverlocked = !coverlocked
+ if("breaker")
+ toggle_breaker(usr)
+ if("toggle_nightshift")
+ if(last_nightshift_switch > world.time + 100) // don't spam...
+ to_chat(usr, "[src]'s night lighting circuit breaker is still cycling!")
+ return FALSE
+ last_nightshift_switch = world.time
+ set_nightshift(!nightshift_lights)
+ if("charge")
+ chargemode = !chargemode
+ if("channel")
+ if(params["eqp"])
+ equipment = setsubsystem(text2num(params["eqp"]))
update_icon()
-
- return 0
+ update()
+ else if(params["lgt"])
+ lighting = setsubsystem(text2num(params["lgt"]))
+ update_icon()
+ update()
+ else if(params["env"])
+ environ = setsubsystem(text2num(params["env"]))
+ update_icon()
+ update()
+ if("overload")
+ if(usr.has_unlimited_silicon_privilege)
+ overload_lighting()
+ if("hack")
+ if(get_malf_status(usr))
+ malfhack(usr)
+ if("occupy")
+ if(get_malf_status(usr))
+ malfoccupy(usr)
+ if("deoccupy")
+ if(get_malf_status(usr))
+ malfvacate()
/obj/machinery/power/apc/proc/toggle_breaker()
operating = !operating
@@ -1037,7 +980,7 @@
if(!malf.can_shunt)
to_chat(malf, "You cannot shunt!")
return
- if(!is_station_level(src.z))
+ if(!is_station_level(z))
return
occupier = new /mob/living/silicon/ai(src,malf.laws,null,1)
occupier.adjustOxyLoss(malf.getOxyLoss())
@@ -1084,21 +1027,21 @@
/obj/machinery/power/apc/proc/ion_act()
//intended to be exactly the same as an AI malf attack
- if(!src.malfhack && is_station_level(src.z))
+ if(!malfhack && is_station_level(z))
if(prob(3))
- src.locked = 1
- if(src.cell.charge > 0)
- src.cell.charge = 0
+ locked = TRUE
+ if(cell.charge > 0)
+ cell.charge = 0
cell.corrupt()
- src.malfhack = 1
+ malfhack = TRUE
update_icon()
var/datum/effect_system/smoke_spread/smoke = new
- smoke.set_up(3, 0, src.loc)
+ smoke.set_up(3, 0, loc)
smoke.attach(src)
smoke.start()
do_sparks(3, 1, src)
for(var/mob/M in viewers(src))
- M.show_message("The [src.name] suddenly lets out a blast of smoke and some sparks!", 3, "You hear sizzling electronics.", 2)
+ M.show_message("The [name] suddenly lets out a blast of smoke and some sparks!", 3, "You hear sizzling electronics.", 2)
/obj/machinery/power/apc/surplus()
@@ -1141,12 +1084,12 @@
var/excess = surplus()
- if(!src.avail())
- main_status = 0
+ if(!avail())
+ main_status = APC_EXTERNAL_POWER_NOTCONNECTED
else if(excess < 0)
- main_status = 1
+ main_status = APC_EXTERNAL_POWER_NOENERGY
else
- main_status = 2
+ main_status = APC_EXTERNAL_POWER_GOOD
if(debug)
log_debug("Status: [main_status] - Excess: [excess] - Last Equip: [lastused_equip] - Last Light: [lastused_light] - Longterm: [longtermpower]")
@@ -1192,31 +1135,31 @@
lighting = autoset(lighting, 1)
environ = autoset(environ, 1)
autoflag = 3
- if(report_power_alarm && is_station_contact(z))
- SSalarms.power_alarm.clearAlarm(loc, src)
+ if(report_power_alarm)
+ area.poweralert(TRUE, src)
else if(cell.charge < 1250 && cell.charge > 750 && longtermpower < 0) // <30%, turn off equipment
if(autoflag != 2)
equipment = autoset(equipment, 2)
lighting = autoset(lighting, 1)
environ = autoset(environ, 1)
- if(report_power_alarm && is_station_contact(z))
- SSalarms.power_alarm.triggerAlarm(loc, src)
+ if(report_power_alarm)
+ area.poweralert(FALSE, src)
autoflag = 2
else if(cell.charge < 750 && cell.charge > 10) // <15%, turn off lighting & equipment
if((autoflag > 1 && longtermpower < 0) || (autoflag > 1 && longtermpower >= 0))
equipment = autoset(equipment, 2)
lighting = autoset(lighting, 2)
environ = autoset(environ, 1)
- if(report_power_alarm && is_station_contact(z))
- SSalarms.power_alarm.triggerAlarm(loc, src)
+ if(report_power_alarm)
+ area.poweralert(FALSE, src)
autoflag = 1
else if(cell.charge <= 0) // zero charge, turn all off
if(autoflag != 0)
equipment = autoset(equipment, 0)
lighting = autoset(lighting, 0)
environ = autoset(environ, 0)
- if(report_power_alarm && is_station_contact(z))
- SSalarms.power_alarm.triggerAlarm(loc, src)
+ if(report_power_alarm)
+ area.poweralert(FALSE, src)
autoflag = 0
// now trickle-charge the cell
@@ -1261,7 +1204,7 @@
if(shock_mobs.len)
var/mob/living/L = pick(shock_mobs)
L.electrocute_act(rand(5, 25), "electrical arc")
- playsound(get_turf(L), 'sound/effects/eleczap.ogg', 75, 1)
+ playsound(get_turf(L), 'sound/effects/eleczap.ogg', 75, TRUE)
Beam(L, icon_state = "lightning[rand(1, 12)]", icon = 'icons/effects/effects.dmi', time = 5)
else // no cell, switch everything off
@@ -1271,8 +1214,8 @@
equipment = autoset(equipment, 0)
lighting = autoset(lighting, 0)
environ = autoset(environ, 0)
- if(report_power_alarm && is_station_contact(z))
- SSalarms.power_alarm.triggerAlarm(loc, src)
+ if(report_power_alarm)
+ area.poweralert(FALSE, src)
autoflag = 0
// update icon & area power if anything changed
@@ -1372,4 +1315,22 @@
L.update(FALSE)
CHECK_TICK
+/obj/machinery/power/apc/proc/relock_callback()
+ locked = TRUE
+ updateDialog()
+
+/obj/machinery/power/apc/proc/check_main_power_callback()
+ if(!wires.is_cut(WIRE_MAIN_POWER1) && !wires.is_cut(WIRE_MAIN_POWER2))
+ shorted = FALSE
+ updateDialog()
+
+/obj/machinery/power/apc/proc/check_ai_control_callback()
+ if(!wires.is_cut(WIRE_AI_CONTROL))
+ aidisabled = FALSE
+ updateDialog()
+
#undef APC_UPDATE_ICON_COOLDOWN
+
+#undef APC_EXTERNAL_POWER_NOTCONNECTED
+#undef APC_EXTERNAL_POWER_NOENERGY
+#undef APC_EXTERNAL_POWER_GOOD
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index b6c65d979cf..992020e7090 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -229,14 +229,15 @@ By design, d1 is the smallest direction and d2 is the highest
if(current_size >= STAGE_FIVE)
deconstruct()
-obj/structure/cable/proc/cable_color(var/colorC)
- if(colorC)
- if(colorC == "rainbow")
- color = color_rainbow()
- else
- color = colorC
+obj/structure/cable/proc/cable_color(colorC)
+ if(!colorC)
+ color = COLOR_RED
+ else if(colorC == "rainbow")
+ color = color_rainbow()
+ else if(colorC == "orange") //byond only knows 16 colors by name, and orange isn't one of them
+ color = COLOR_ORANGE
else
- color = "#DD0000"
+ color = colorC
/obj/structure/cable/proc/color_rainbow()
color = pick(COLOR_RED, COLOR_BLUE, COLOR_GREEN, COLOR_PINK, COLOR_YELLOW, COLOR_CYAN)
@@ -845,13 +846,15 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
color = pick(COLOR_RED, COLOR_BLUE, COLOR_GREEN, COLOR_WHITE, COLOR_PINK, COLOR_YELLOW, COLOR_CYAN)
..()
-/obj/item/stack/cable_coil/proc/cable_color(var/colorC)
- if(colorC)
- if(colorC == "rainbow")
- colorC = color_rainbow()
- color = colorC
- else
+/obj/item/stack/cable_coil/proc/cable_color(colorC)
+ if(!colorC)
color = COLOR_RED
+ else if(colorC == "rainbow")
+ color = color_rainbow()
+ else if(colorC == "orange") //byond only knows 16 colors by name, and orange isn't one of them
+ color = COLOR_ORANGE
+ else
+ color = colorC
/obj/item/stack/cable_coil/proc/color_rainbow()
color = pick(COLOR_RED, COLOR_BLUE, COLOR_GREEN, COLOR_PINK, COLOR_YELLOW, COLOR_CYAN)
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index 3e8d71b3280..9305faf6637 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -177,6 +177,8 @@
var/nightshift_light_power = 0.45
var/nightshift_light_color = "#FFDDCC"
+ var/bulb_emergency_colour = "#FF3232" // determines the colour of the light while it's in emergency mode
+
// the smaller bulb light fixture
/obj/machinery/light/small
@@ -238,7 +240,11 @@
switch(status) // set icon_states
if(LIGHT_OK)
- icon_state = "[base_state][on]"
+ var/area/A = get_area(src)
+ if(A && A.fire)
+ icon_state = "[base_state]_emergency"
+ else
+ icon_state = "[base_state][on]"
if(LIGHT_EMPTY)
icon_state = "[base_state]-empty"
on = FALSE
@@ -260,10 +266,20 @@
on = FALSE
update_icon()
if(on)
- var/BR = nightshift_enabled ? nightshift_light_range : brightness_range
- var/PO = nightshift_enabled ? nightshift_light_power : brightness_power
- var/CO = nightshift_enabled ? nightshift_light_color : brightness_color
- var/matching = light_range == BR && light_power == PO && light_color == CO
+ var/BR = brightness_range
+ var/PO = brightness_power
+ var/CO = brightness_color
+ if(color)
+ CO = color
+ var/area/A = get_area(src)
+ if(A && A.fire)
+ CO = bulb_emergency_colour
+ else if(nightshift_enabled)
+ BR = nightshift_light_range
+ PO = nightshift_light_power
+ if(!color)
+ CO = nightshift_light_color
+ var/matching = light && BR == light.light_range && PO == light.light_power && CO == light.light_color
if(!matching)
switchcount++
if(rigged)
@@ -627,7 +643,7 @@
/obj/item/light/Crossed(mob/living/L)
if(istype(L) && has_gravity(loc))
- if(L.incorporeal_move || L.flying)
+ if(L.incorporeal_move || L.flying || L.floating)
return
playsound(loc, 'sound/effects/glass_step.ogg', 50, TRUE)
if(status == LIGHT_BURNED || status == LIGHT_OK)
diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm
index 046cf68a543..960340e90b6 100644
--- a/code/modules/power/singularity/field_generator.dm
+++ b/code/modules/power/singularity/field_generator.dm
@@ -310,16 +310,25 @@ field_generator power level display
//This is here to help fight the "hurr durr, release singulo cos nobody will notice before the
//singulo eats the evidence". It's not fool-proof but better than nothing.
//I want to avoid using global variables.
- spawn(1)
- var/temp = 1 //stops spam
- for(var/thing in GLOB.singularities)
- var/obj/singularity/O = thing
- if(O.last_warning && temp)
- if((world.time - O.last_warning) > 50) //to stop message-spam
- temp = 0
- message_admins("A singulo exists and a containment field has failed. Location: [get_area(src)] (JMP)",1)
- investigate_log("has failed whilst a singulo exists.","singulo")
- O.last_warning = world.time
+ INVOKE_ASYNC(src, .proc/admin_alert)
+
+/obj/machinery/field/generator/proc/admin_alert()
+ var/temp = TRUE //stops spam
+ for(var/thing in GLOB.singularities)
+ var/obj/singularity/O = thing
+ if(O.last_warning && temp && atoms_share_level(O, src))
+ if((world.time - O.last_warning) > 50) //to stop message-spam
+ temp = FALSE
+ // To the person who asks "Hey affected, why are you using this massive operator when you can use AREACOORD?" Well, ill tell you
+ // get_area_name is fucking broken and uses a for(x in world) search
+ // It doesnt even work, is expensive, and returns 0
+ // Im not refactoring one thing which could risk breaking all admin location logs
+ // Fight me
+ // [src ? "[get_location_name(src, TRUE)] [COORD(src)]" : "nonexistent location"] [ADMIN_JMP(src)] works much better and actually works at all
+ // Oh and yes, this exact comment was pasted from the exact same thing I did to tcomms code. Dont at me.
+ message_admins("A singularity exists and a containment field has failed on the same Z-Level. Singulo location: [O ? "[get_location_name(O, TRUE)] [COORD(O)]" : "nonexistent location"] [ADMIN_JMP(O)] | Field generator location: [src ? "[get_location_name(src, TRUE)] [COORD(src)]" : "nonexistent location"] [ADMIN_JMP(src)]")
+ investigate_log("has failed whilst a singulo exists.","singulo")
+ O.last_warning = world.time
/obj/machinery/field/generator/shock_field(mob/living/user)
if(fields.len)
diff --git a/code/modules/power/singularity/investigate.dm b/code/modules/power/singularity/investigate.dm
index 43e8c9f8a8b..4835e09411c 100644
--- a/code/modules/power/singularity/investigate.dm
+++ b/code/modules/power/singularity/investigate.dm
@@ -1,4 +1,4 @@
-/area/engine/engineering/power_alert(var/alarming)
- if(alarming)
- investigate_log("has a power alarm!","singulo")
+/area/engine/engineering/poweralert(state, source)
+ if(state != poweralm)
+ investigate_log("has a power alarm!", "singulo")
..()
diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm
index b8ba53ae432..3ad96050123 100644
--- a/code/modules/power/singularity/particle_accelerator/particle_control.dm
+++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm
@@ -27,6 +27,7 @@
use_log = list()
/obj/machinery/particle_accelerator/control_box/Destroy()
+ SStgui.close_uis(wires)
if(active)
toggle_power()
QDEL_NULL(wires)
@@ -41,6 +42,11 @@
else if(construction_state == 2) // Wires exposed
wires.Interact(user)
+/obj/machinery/particle_accelerator/control_box/multitool_act(mob/living/user, obj/item/I)
+ if(construction_state == 2) // Wires exposed
+ wires.Interact(user)
+ return TRUE
+
/obj/machinery/particle_accelerator/control_box/update_state()
if(construction_state < 3)
use_power = NO_POWER_USE
@@ -93,18 +99,18 @@
usr.unset_machine()
return
if(href_list["togglep"])
- if(!wires.IsIndexCut(PARTICLE_TOGGLE_WIRE))
+ if(!wires.is_cut(WIRE_PARTICLE_POWER))
toggle_power()
else if(href_list["scan"])
part_scan()
else if(href_list["strengthup"])
- if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE))
+ if(!wires.is_cut(WIRE_PARTICLE_STRENGTH))
add_strength()
else if(href_list["strengthdown"])
- if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE))
+ if(!wires.is_cut(WIRE_PARTICLE_STRENGTH))
remove_strength()
updateDialog()
diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm
index 59ce091b170..2fa2c4c1573 100644
--- a/code/modules/power/smes.dm
+++ b/code/modules/power/smes.dm
@@ -227,8 +227,8 @@
if(terminal)
terminal.master = null
terminal = null
- return 1
- return 0
+ return TRUE
+ return FALSE
/obj/machinery/power/smes/proc/make_terminal(user, tempDir, tempLoc)
// create a terminal object at the same position as original turf loc
@@ -339,89 +339,91 @@
/obj/machinery/power/smes/attack_ai(mob/user)
add_hiddenprint(user)
- ui_interact(user)
+ tgui_interact(user)
/obj/machinery/power/smes/attack_ghost(mob/user)
- ui_interact(user)
+ tgui_interact(user)
/obj/machinery/power/smes/attack_hand(mob/user)
add_fingerprint(user)
- ui_interact(user)
+ tgui_interact(user)
-/obj/machinery/power/smes/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+/obj/machinery/power/smes/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
if(stat & BROKEN)
return
-
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "smes.tmpl", "SMES Power Storage Unit", 540, 380)
- // open the new ui window
+ ui = new(user, src, ui_key, "Smes", name, 340, 350, master_ui, state)
ui.open()
- // auto update every Master Controller tick
- ui.set_auto_update(1)
-
-/obj/machinery/power/smes/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
- var/data[0]
-
- data["nameTag"] = name_tag
- data["storedCapacity"] = round(100.0*charge/capacity, 0.1)
- data["charging"] = inputting
- data["chargeMode"] = input_attempt
- data["chargeLevel"] = input_level
- data["chargeMax"] = input_level_max
- data["outputOnline"] = output_attempt
- data["outputLevel"] = output_level
- data["outputMax"] = output_level_max
- data["outputLoad"] = round(output_used)
-
- if(outputting)
- data["outputting"] = 2 // smes is outputting
- else if(!outputting && output_attempt)
- data["outputting"] = 1 // smes is online but not outputting because it's charge level is too low
- else
- data["outputting"] = 0 // smes is not outputting
+/obj/machinery/power/smes/tgui_data(mob/user)
+ var/list/data = list(
+ "capacity" = capacity,
+ "capacityPercent" = round(100*charge/capacity, 0.1),
+ "charge" = charge,
+ "inputAttempt" = input_attempt,
+ "inputting" = inputting,
+ "inputLevel" = input_level,
+ "inputLevel_text" = DisplayPower(input_level),
+ "inputLevelMax" = input_level_max,
+ "inputAvailable" = input_available,
+ "outputAttempt" = output_attempt,
+ "outputting" = outputting,
+ "outputLevel" = output_level,
+ "outputLevel_text" = DisplayPower(output_level),
+ "outputLevelMax" = output_level_max,
+ "outputUsed" = round(output_used),
+ )
return data
-/obj/machinery/power/smes/Topic(href, href_list)
+/obj/machinery/power/smes/tgui_act(action, params)
if(..())
- return 1
+ return
+ . = TRUE
+ switch(action)
+ if("tryinput")
+ inputting(!input_attempt)
+ update_icon()
+ if("tryoutput")
+ outputting(!output_attempt)
+ update_icon()
+ if("input")
+ var/target = params["target"]
+ var/adjust = text2num(params["adjust"])
+ if(target == "min")
+ target = 0
+ else if(target == "max")
+ target = input_level_max
+ else if(adjust)
+ target = input_level + adjust
+ else if(text2num(target) != null)
+ target = text2num(target)
+ else
+ . = FALSE
+ if(.)
+ input_level = clamp(target, 0, input_level_max)
+ if("output")
+ var/target = params["target"]
+ var/adjust = text2num(params["adjust"])
+ if(target == "min")
+ target = 0
+ else if(target == "max")
+ target = output_level_max
+ else if(adjust)
+ target = output_level + adjust
+ else if(text2num(target) != null)
+ target = text2num(target)
+ else
+ . = FALSE
+ if(.)
+ output_level = clamp(target, 0, output_level_max)
+ else
+ . = FALSE
+ if(.)
+ log_smes(usr)
- if( href_list["cmode"] )
- inputting(!input_attempt)
- update_icon()
-
- else if( href_list["online"] )
- outputting(!output_attempt)
- update_icon()
-
- else if( href_list["input"] )
- switch( href_list["input"] )
- if("min")
- input_level = 0
- if("max")
- input_level = input_level_max
- if("set")
- input_level = input(usr, "Enter new input level (0-[input_level_max])", "SMES Input Power Control", input_level) as num
- input_level = max(0, min(input_level_max, input_level)) // clamp to range
-
- else if( href_list["output"] )
- switch( href_list["output"] )
- if("min")
- output_level = 0
- if("max")
- output_level = output_level_max
- if("set")
- output_level = input(usr, "Enter new output level (0-[output_level_max])", "SMES Output Power Control", output_level) as num
- output_level = max(0, min(output_level_max, output_level)) // clamp to range
-
- investigate_log("input/output; [input_level>output_level?"":""][input_level]/[output_level] | Output-mode: [output_attempt?"on":"off"] | Input-mode: [input_attempt?"auto":"off"] by [usr.key]","singulo")
-
- return 1
+/obj/machinery/power/smes/proc/log_smes(mob/user)
+ investigate_log("input/output; [input_level>output_level?"":""][input_level]/[output_level] | Charge: [charge] | Output-mode: [output_attempt?"on":"off"] | Input-mode: [input_attempt?"auto":"off"] by [user ? key_name(user) : "outside forces"]", "singulo")
/obj/machinery/power/smes/proc/ion_act()
if(is_station_level(src.z))
@@ -448,6 +450,7 @@
smoke.attach(src)
smoke.start()
+
/obj/machinery/power/smes/proc/inputting(var/do_input)
input_attempt = do_input
if(!input_attempt)
@@ -459,14 +462,15 @@
outputting = 0
/obj/machinery/power/smes/emp_act(severity)
- inputting(rand(0,1))
- outputting(rand(0,1))
+ inputting(rand(0, 1))
+ outputting(rand(0, 1))
output_level = rand(0, output_level_max)
input_level = rand(0, input_level_max)
charge -= 1e6/severity
if(charge < 0)
charge = 0
update_icon()
+ log_smes()
..()
/obj/machinery/power/smes/engineering
diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm
index 5f58bcb5dd4..5743bea8475 100644
--- a/code/modules/power/tesla/coil.dm
+++ b/code/modules/power/tesla/coil.dm
@@ -21,6 +21,7 @@
RefreshParts()
/obj/machinery/power/tesla_coil/Destroy()
+ SStgui.close_uis(wires)
QDEL_NULL(wires)
return ..()
diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm
index 8536a0195e3..e6165103234 100644
--- a/code/modules/projectiles/ammunition.dm
+++ b/code/modules/projectiles/ammunition.dm
@@ -123,6 +123,7 @@
if(keep)
stored_ammo.Insert(1,b)
update_mat_value()
+ update_icon()
return b
/obj/item/ammo_box/proc/give_round(obj/item/ammo_casing/R, replace_spent = 0)
diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm
index 8cb48f8e36a..5cc6a19b840 100644
--- a/code/modules/projectiles/ammunition/magazines.dm
+++ b/code/modules/projectiles/ammunition/magazines.dm
@@ -133,6 +133,9 @@
/obj/item/ammo_box/magazine/internal/shot/riot/short
max_ammo = 3
+/obj/item/ammo_box/magazine/internal/shot/riot/buckshot
+ ammo_type = /obj/item/ammo_casing/shotgun/buckshot
+
/obj/item/ammo_box/magazine/internal/grenadelauncher
name = "grenade launcher internal magazine"
ammo_type = /obj/item/ammo_casing/a40mm
@@ -380,10 +383,7 @@
origin_tech = "combat=3;syndicate=1"
caliber = "shotgun"
max_ammo = 8
-
-/obj/item/ammo_box/magazine/m12g/update_icon()
- ..()
- icon_state = "[initial(icon_state)]-[CEILING(ammo_count(0)/8, 1)*8]"
+ multiple_sprites = 2
/obj/item/ammo_box/magazine/m12g/buckshot
name = "shotgun magazine (12g buckshot slugs)"
@@ -411,6 +411,24 @@
icon_state = "m12gbc"
ammo_type = /obj/item/ammo_casing/shotgun/breaching
+/obj/item/ammo_box/magazine/m12g/XtrLrg
+ name = "\improper XL shotgun magazine (12g slugs)"
+ desc = "An extra large drum magazine."
+ icon_state = "m12gXlSl"
+ w_class = WEIGHT_CLASS_NORMAL
+ ammo_type = /obj/item/ammo_casing/shotgun
+ max_ammo = 16
+
+/obj/item/ammo_box/magazine/m12g/XtrLrg/buckshot
+ name = "\improper XL shotgun magazine (12g buckshot)"
+ icon_state = "m12gXlBs"
+ ammo_type = /obj/item/ammo_casing/shotgun/buckshot
+
+/obj/item/ammo_box/magazine/m12g/XtrLrg/dragon
+ name = "\improper XL shotgun magazine (12g dragon's breath)"
+ icon_state = "m12gXlDb"
+ ammo_type = /obj/item/ammo_casing/shotgun/incendiary/dragonsbreath
+
/obj/item/ammo_box/magazine/toy
name = "foam force META magazine"
ammo_type = /obj/item/ammo_casing/caseless/foam_dart
diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm
index 25db1f10dcb..ca4499c8832 100644
--- a/code/modules/projectiles/guns/projectile.dm
+++ b/code/modules/projectiles/guns/projectile.dm
@@ -95,6 +95,7 @@
if(!user.unEquip(A))
return
to_chat(user, "You screw [S] onto [src].")
+ playsound(src, 'sound/items/screwdriver.ogg', 40, 1)
suppressed = A
S.oldsound = fire_sound
S.initial_w_class = w_class
@@ -120,6 +121,7 @@
..()
return
to_chat(user, "You unscrew [suppressed] from [src].")
+ playsound(src, 'sound/items/screwdriver.ogg', 40, 1)
user.put_in_hands(suppressed)
fire_sound = S.oldsound
w_class = S.initial_w_class
diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm
index 17a20f82d59..ea52a954a5b 100644
--- a/code/modules/projectiles/guns/projectile/automatic.dm
+++ b/code/modules/projectiles/guns/projectile/automatic.dm
@@ -275,13 +275,27 @@
if(magazine)
overlays.Cut()
overlays += "[magazine.icon_state]"
- return
+ if(istype(magazine, /obj/item/ammo_box/magazine/m12g/XtrLrg))
+ w_class = WEIGHT_CLASS_BULKY
+ else
+ w_class = WEIGHT_CLASS_NORMAL
+ else
+ w_class = WEIGHT_CLASS_NORMAL
/obj/item/gun/projectile/automatic/shotgun/bulldog/update_icon()
overlays.Cut()
update_magazine()
icon_state = "bulldog[chambered ? "" : "-e"]"
+/obj/item/gun/projectile/automatic/shotgun/bulldog/attackby(var/obj/item/A as obj, mob/user as mob, params)
+ if(istype(A, /obj/item/ammo_box/magazine/m12g/XtrLrg))
+ if(istype(loc, /obj/item/storage)) // To prevent inventory exploits
+ var/obj/item/storage/Strg = loc
+ if(Strg.max_w_class < WEIGHT_CLASS_BULKY)
+ to_chat(user, "You can't reload [src], with a XL mag, while it's in a normal bag.")
+ return
+ return ..()
+
/obj/item/gun/projectile/automatic/shotgun/bulldog/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
..()
empty_alarm()
diff --git a/code/modules/projectiles/guns/projectile/shotgun.dm b/code/modules/projectiles/guns/projectile/shotgun.dm
index 17a55722d2c..6c11fda5fd7 100644
--- a/code/modules/projectiles/guns/projectile/shotgun.dm
+++ b/code/modules/projectiles/guns/projectile/shotgun.dm
@@ -197,6 +197,8 @@
..()
post_sawoff()
+/obj/item/gun/projectile/shotgun/riot/buckshot //comes pre-loaded with buckshot rather than rubber
+ mag_type = /obj/item/ammo_box/magazine/internal/shot/riot/buckshot
///////////////////////
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index 4aee2398b68..080114554bb 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -270,7 +270,6 @@
M.mind.transfer_to(new_mob)
else
new_mob.attack_log_old = M.attack_log_old.Copy()
- new_mob.logs = M.logs.Copy()
new_mob.key = M.key
to_chat(new_mob, "Your form morphs into that of a [randomize].")
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index 91d5900610d..bacf2285c83 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -24,6 +24,7 @@
var/list/hacked_reagents = list("toxin")
var/hack_message = "You disable the safety safeguards, enabling the \"Mad Scientist\" mode."
var/unhack_message = "You re-enable the safety safeguards, enabling the \"NT Standard\" mode."
+ var/is_drink = FALSE
/obj/machinery/chem_dispenser/get_cell()
return cell
@@ -120,7 +121,6 @@
var/usedpower = cell.give(recharge_amount)
if(usedpower)
use_power(15 * recharge_amount)
- SSnanoui.update_uis(src) // update all UIs attached to src
recharge_counter = 0
return
recharge_counter++
@@ -131,7 +131,6 @@
else
spawn(rand(0, 15))
stat |= NOPOWER
- SSnanoui.update_uis(src) // update all UIs attached to src
/obj/machinery/chem_dispenser/ex_act(severity)
if(severity < 3)
@@ -145,19 +144,17 @@
beaker = null
overlays.Cut()
-/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
+/obj/machinery/chem_dispenser/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
// update the ui if it exists, returns null if no ui is passed/found
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "chem_dispenser.tmpl", ui_title, 390, 655)
- // open the new ui window
+ ui = new(user, src, ui_key, "ChemDispenser", ui_title, 390, 655)
ui.open()
-/obj/machinery/chem_dispenser/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
+/obj/machinery/chem_dispenser/tgui_data(mob/user)
var/data[0]
+ data["glass"] = is_drink
data["amount"] = amount
data["energy"] = cell.charge ? cell.charge * powerefficiency : "0" //To prevent NaN in the UI.
data["maxEnergy"] = cell.maxcharge * powerefficiency
@@ -187,63 +184,59 @@
return data
-/obj/machinery/chem_dispenser/Topic(href, href_list)
+/obj/machinery/chem_dispenser/tgui_act(actions, params)
if(..())
- return TRUE
+ return
+ if(stat & (NOPOWER|BROKEN))
+ return
- if(href_list["amount"])
- amount = round(text2num(href_list["amount"]), 1) // round to nearest 1
- if(amount < 0) // Since the user can actually type the commands himself, some sanity checking
- amount = 0
- if(amount > 100)
- amount = 100
-
- if(href_list["dispense"])
- if(!is_operational() || QDELETED(cell))
- return
- if(beaker && dispensable_reagents.Find(href_list["dispense"]))
+ . = TRUE
+ switch(actions)
+ if("amount")
+ amount = clamp(round(text2num(params["amount"]), 1), 0, 50) // round to nearest 1 and clamp to 0 - 50
+ if("dispense")
+ if(!is_operational() || QDELETED(cell))
+ return
+ if(!beaker || !dispensable_reagents.Find(params["reagent"]))
+ return
var/datum/reagents/R = beaker.reagents
var/free = R.maximum_volume - R.total_volume
var/actual = min(amount, (cell.charge * powerefficiency) * 10, free)
-
if(!cell.use(actual / powerefficiency))
atom_say("Not enough energy to complete operation!")
return
-
- R.add_reagent(href_list["dispense"], actual)
+ R.add_reagent(params["reagent"], actual)
overlays.Cut()
if(!icon_beaker)
- icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position.
+ icon_beaker = mutable_appearance('icons/obj/chemical.dmi', "disp_beaker") //randomize beaker overlay position.
icon_beaker.pixel_x = rand(-10, 5)
overlays += icon_beaker
-
- if(href_list["remove"])
- if(beaker)
- if(href_list["removeamount"])
- var/amount = text2num(href_list["removeamount"])
- if(isnum(amount) && (amount > 0))
- var/datum/reagents/R = beaker.reagents
- var/id = href_list["remove"]
- R.remove_reagent(id, amount)
- else if(isnum(amount) && (amount == -1)) //Isolate instead
- var/datum/reagents/R = beaker.reagents
- var/id = href_list["remove"]
- R.isolate_reagent(id)
-
- if(href_list["ejectBeaker"])
- if(beaker)
+ if("remove")
+ var/amount = text2num(params["amount"])
+ if(!beaker || !amount)
+ return
+ var/datum/reagents/R = beaker.reagents
+ var/id = params["reagent"]
+ if(amount > 0)
+ R.remove_reagent(id, amount)
+ else if(amount == -1) //Isolate instead
+ R.isolate_reagent(id)
+ if("ejectBeaker")
+ if(!beaker)
+ return
beaker.forceMove(loc)
if(Adjacent(usr) && !issilicon(usr))
usr.put_in_hands(beaker)
beaker = null
overlays.Cut()
+ else
+ return FALSE
add_fingerprint(usr)
- return TRUE // update UIs attached to this object
/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params)
if(exchange_parts(user, I))
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
return
if(isrobot(user))
@@ -263,9 +256,9 @@
beaker = I
I.forceMove(src)
to_chat(user, "You set [I] on the machine.")
- SSnanoui.update_uis(src) // update all UIs attached to src
+ SStgui.update_uis(src) // update all UIs attached to src
if(!icon_beaker)
- icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position.
+ icon_beaker = mutable_appearance('icons/obj/chemical.dmi', "disp_beaker") //randomize beaker overlay position.
icon_beaker.pixel_x = rand(-10, 5)
overlays += icon_beaker
return
@@ -299,8 +292,7 @@
to_chat(user, unhack_message)
dispensable_reagents -= hacked_reagents
hackedcheck = FALSE
- SSnanoui.update_uis(src)
-
+ SStgui.update_uis(src)
/obj/machinery/chem_dispenser/screwdriver_act(mob/user, obj/item/I)
if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", "[initial(icon_state)]", I))
@@ -321,14 +313,14 @@
return attack_hand(user)
/obj/machinery/chem_dispenser/attack_ghost(mob/user)
- if(user.can_admin_interact())
- return attack_hand(user)
+ if(stat & BROKEN)
+ return
+ tgui_interact(user)
/obj/machinery/chem_dispenser/attack_hand(mob/user)
if(stat & BROKEN)
return
-
- ui_interact(user)
+ tgui_interact(user)
/obj/machinery/chem_dispenser/soda
icon_state = "soda_dispenser"
@@ -342,6 +334,7 @@
hacked_reagents = list("thirteenloko")
hack_message = "You change the mode from 'McNano' to 'Pizza King'."
unhack_message = "You change the mode from 'Pizza King' to 'McNano'."
+ is_drink = TRUE
/obj/machinery/chem_dispenser/soda/New()
..()
@@ -377,6 +370,7 @@
hacked_reagents = list("goldschlager", "patron", "absinthe", "ethanol", "nothing", "sake")
hack_message = "You disable the 'nanotrasen-are-cheap-bastards' lock, enabling hidden and very expensive boozes."
unhack_message = "You re-enable the 'nanotrasen-are-cheap-bastards' lock, disabling hidden and very expensive boozes."
+ is_drink = TRUE
/obj/machinery/chem_dispenser/beer/New()
..()
diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm
index 39aa91099c0..8fddc97537f 100644
--- a/code/modules/reagents/chemistry/machinery/chem_heater.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm
@@ -1,15 +1,19 @@
/obj/machinery/chem_heater
name = "chemical heater"
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
icon = 'icons/obj/chemical.dmi'
icon_state = "mixer0b"
use_power = IDLE_POWER_USE
idle_power_usage = 40
- resistance_flags = FIRE_PROOF | ACID_PROOF
+ resistance_flags = FIRE_PROOF|ACID_PROOF
var/obj/item/reagent_containers/beaker = null
var/desired_temp = T0C
var/on = FALSE
+ /// Whether this should auto-eject the beaker once done heating/cooling.
+ var/auto_eject = FALSE
+ /// The higher this number, the faster reagents will heat/cool.
+ var/speed_increase = 0
/obj/machinery/chem_heater/New()
..()
@@ -19,35 +23,36 @@
component_parts += new /obj/item/stack/sheet/glass(null)
RefreshParts()
+/obj/machinery/chem_heater/RefreshParts()
+ speed_increase = initial(speed_increase)
+ for(var/obj/item/stock_parts/micro_laser/M in component_parts)
+ speed_increase += 5 * (M.rating - 1)
+
/obj/machinery/chem_heater/process()
..()
- if(stat & NOPOWER)
+ if(stat & (NOPOWER|BROKEN))
return
- var/state_change = FALSE
if(on)
if(beaker)
if(!beaker.reagents.total_volume)
on = FALSE
- SSnanoui.update_uis(src)
return
- beaker.reagents.temperature_reagents(desired_temp)
- beaker.reagents.temperature_reagents(desired_temp)
- if(abs(beaker.reagents.chem_temp - desired_temp) <= 3)
+ beaker.reagents.temperature_reagents(desired_temp, max(1, 35 - speed_increase))
+ if(round(beaker.reagents.chem_temp) == round(desired_temp))
+ playsound(loc, 'sound/machines/ding.ogg', 50, 1)
on = FALSE
- state_change = TRUE
-
- if(state_change)
- SSnanoui.update_uis(src)
+ if(auto_eject)
+ eject_beaker()
/obj/machinery/chem_heater/proc/eject_beaker(mob/user)
if(beaker)
beaker.forceMove(get_turf(src))
- if(Adjacent(user) && !issilicon(user))
+ if(user && Adjacent(user) && !issilicon(user))
user.put_in_hands(beaker)
beaker = null
icon_state = "mixer0b"
on = FALSE
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
/obj/machinery/chem_heater/power_change()
if(powered())
@@ -55,7 +60,6 @@
else
spawn(rand(0, 15))
stat |= NOPOWER
- SSnanoui.update_uis(src)
/obj/machinery/chem_heater/attackby(obj/item/I, mob/user)
if(isrobot(user))
@@ -71,7 +75,7 @@
I.forceMove(src)
to_chat(user, "You add the beaker to the machine!")
icon_state = "mixer1b"
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
return
if(exchange_parts(user, I))
@@ -95,62 +99,62 @@
default_deconstruction_crowbar(user, I)
/obj/machinery/chem_heater/attack_hand(mob/user)
- ui_interact(user)
+ tgui_interact(user)
/obj/machinery/chem_heater/attack_ghost(mob/user)
- if(user.can_admin_interact())
- return attack_hand(user)
+ tgui_interact(user)
/obj/machinery/chem_heater/attack_ai(mob/user)
add_hiddenprint(user)
return attack_hand(user)
-/obj/machinery/chem_heater/Topic(href, href_list)
+/obj/machinery/chem_heater/tgui_act(action, params)
if(..())
- return FALSE
+ return
+ if(stat & (NOPOWER|BROKEN))
+ return
- if(href_list["toggle_on"])
- if(!beaker.reagents.total_volume)
- return FALSE
- on = !on
- . = 1
-
- if(href_list["adjust_temperature"])
- var/val = href_list["adjust_temperature"]
- if(isnum(val))
- desired_temp = clamp(desired_temp+val, 0, 1000)
- else if(val == "input")
- var/target = input("Please input the target temperature", name) as num
- desired_temp = clamp(target, 0, 1000)
+ . = TRUE
+ switch(action)
+ if("toggle_on")
+ on = !on
+ if("adjust_temperature")
+ desired_temp = clamp(text2num(params["target"]), 0, 1000)
+ if("eject_beaker")
+ eject_beaker(usr)
+ . = FALSE
+ if("toggle_autoeject")
+ auto_eject = !auto_eject
else
return FALSE
- . = 1
+ add_fingerprint(usr)
- if(href_list["eject_beaker"])
- eject_beaker(usr)
- . = 0 //updated in eject_beaker() already
-
-/obj/machinery/chem_heater/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null)
+/obj/machinery/chem_heater/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
if(user.stat || user.restrained())
return
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
- ui = new(user, src, ui_key, "chem_heater.tmpl", "ChemHeater", 350, 270)
+ ui = new(user, src, ui_key, "ChemHeater", "Chemical Heater", 350, 270, master_ui, state)
ui.open()
-/obj/machinery/chem_heater/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
+/obj/machinery/chem_heater/tgui_data(mob/user)
var/data[0]
+ var/cur_temp = beaker ? beaker.reagents.chem_temp : null
data["targetTemp"] = desired_temp
+ data["targetTempReached"] = FALSE
+ data["autoEject"] = auto_eject
data["isActive"] = on
- data["isBeakerLoaded"] = beaker ? 1 : 0
+ data["isBeakerLoaded"] = beaker ? TRUE : FALSE
- data["currentTemp"] = beaker ? beaker.reagents.chem_temp : null
+ data["currentTemp"] = cur_temp
data["beakerCurrentVolume"] = beaker ? beaker.reagents.total_volume : null
data["beakerMaxVolume"] = beaker ? beaker.volume : null
+ if(cur_temp)
+ data["targetTempReached"] = round(cur_temp) == round(desired_temp)
+
//copy-pasted from chem dispenser
var/beakerContents[0]
if(beaker)
diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm
index 4d1f577969c..f2b3247fe4b 100644
--- a/code/modules/reagents/chemistry/machinery/chem_master.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_master.dm
@@ -1,3 +1,9 @@
+#define MAX_PILL_SPRITE 20 //max icon state of the pill sprites
+#define MAX_MULTI_AMOUNT 20 // Max number of pills/patches that can be made at once
+#define MAX_UNITS_PER_PILL 100 // Max amount of units in a pill
+#define MAX_UNITS_PER_PATCH 30 // Max amount of units in a patch
+#define MAX_CUSTOM_NAME_LEN 64 // Max length of a custom pill/condiment/whatever
+
/obj/machinery/chem_master
name = "\improper ChemMaster 3000"
density = TRUE
@@ -14,10 +20,12 @@
var/useramount = 30 // Last used amount
var/pillamount = 10
var/patchamount = 10
- var/bottlesprite = "bottle"
- var/pillsprite = "1"
+ var/bottlesprite = 1
+ var/pillsprite = 1
var/client/has_sprites = list()
var/printing = FALSE
+ var/static/list/pill_bottle_wrappers
+ var/static/list/bottle_styles
/obj/machinery/chem_master/New()
..()
@@ -94,7 +102,7 @@
beaker = I
I.forceMove(src)
to_chat(user, "You add the beaker to the machine!")
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
update_icon()
else if(istype(I, /obj/item/storage/pill_bottle))
@@ -109,14 +117,10 @@
loaded_pill_bottle = I
I.forceMove(src)
to_chat(user, "You add [I] into the dispenser slot!")
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
else
return ..()
-
-
-
-
/obj/machinery/chem_master/crowbar_act(mob/user, obj/item/I)
if(!panel_open)
return
@@ -142,319 +146,127 @@
power_change()
return TRUE
-/obj/machinery/chem_master/Topic(href, href_list)
+/obj/machinery/chem_master/tgui_act(action, params, datum/tgui/ui, datum/tgui_state/state)
if(..())
+ return
+ if(stat & (NOPOWER|BROKEN))
+ return
+
+ if(tgui_act_modal(action, params, ui, state))
return TRUE
add_fingerprint(usr)
usr.set_machine(src)
-
- if(href_list["ejectp"])
- if(loaded_pill_bottle)
- loaded_pill_bottle.forceMove(loc)
- loaded_pill_bottle = null
- else if(href_list["change_pillbottle"])
- if(loaded_pill_bottle)
- var/list/wrappers = list("Default wrapper", "Red wrapper", "Green wrapper", "Pale green wrapper", "Blue wrapper", "Light blue wrapper", "Teal wrapper", "Yellow wrapper", "Orange wrapper", "Pink wrapper", "Brown wrapper")
- var/chosen = input(usr, "Select a pillbottle wrapper", "Pillbottle wrapper", wrappers[1]) as null|anything in wrappers
- if(!chosen)
+ . = TRUE
+ switch(action)
+ if("toggle")
+ mode = !mode
+ if("ejectp")
+ if(loaded_pill_bottle)
+ loaded_pill_bottle.forceMove(loc)
+ loaded_pill_bottle = null
+ if("print")
+ if(printing || condi)
return
- var/color
- switch(chosen)
- if("Default wrapper")
- loaded_pill_bottle.cut_overlays()
- return
- if("Red wrapper")
- color = COLOR_RED
- if("Green wrapper")
- color = COLOR_GREEN
- if("Pink wrapper")
- color = COLOR_PINK
- if("Teal wrapper")
- color = COLOR_TEAL
- if("Blue wrapper")
- color = COLOR_BLUE
- if("Brown wrapper")
- color = COLOR_MAROON
- if("Light blue wrapper")
- color = COLOR_CYAN_BLUE
- if("Yellow wrapper")
- color = COLOR_YELLOW
- if("Pale green wrapper")
- color = COLOR_PALE_BTL_GREEN
- if("Orange wrapper")
- color = COLOR_ORANGE
- loaded_pill_bottle.wrapper_color = color
- loaded_pill_bottle.apply_wrap()
- else if(href_list["close"])
- usr << browse(null, "window=chem_master")
- onclose(usr, "chem_master")
- usr.unset_machine()
- return
- if(href_list["print_p"])
- if(!printing)
+ var/idx = text2num(params["idx"]) || 0
+ var/from_beaker = text2num(params["beaker"]) || FALSE
+ var/reagent_list = from_beaker ? beaker.reagents.reagent_list : reagents.reagent_list
+ if(idx < 1 || idx > length(reagent_list))
+ return
+
+ var/datum/reagent/R = reagent_list[idx]
+
printing = TRUE
visible_message("[src] rattles and prints out a sheet of paper.")
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
+
var/obj/item/paper/P = new /obj/item/paper(loc)
- P.info = "
Chemical Analysis
"
+ P.info = "
Chemical Analysis
"
P.info += "Time of analysis: [station_time_timestamp()]
', 'internal');
+
+ opts.rebootIntervalHandler = setInterval(function() {
+ timeLeftSecs -= intervalSecs;
+ if (timeLeftSecs <= 0) {
+ $("#reconnectTimer").text('Reconnecting...');
+ window.location.href = 'byond://winset?command=.reconnect';
+ clearInterval(opts.rebootIntervalHandler)
+ opts.rebootIntervalHandler = null;
+ } else {
+ $("#reconnectTimer").text('Reconnect (' + timeLeftSecs + ')');
+ }
+ }, intervalSecs * 1000);
+}
+
+function rebootFinished() {
+ if (opts.rebootIntervalHandler != null) {
+ clearInterval(opts.rebootIntervalHandler)
+ }
+ $(" Reconnected automatically!").insertBefore("#reconnectTimer");
+ $("#reconnectTimer").remove();
+}
+
/*****************************************
*
* MAKE MACRO DICTIONARY
@@ -652,7 +683,7 @@ $(function() {
'shideSpam': getCookie('hidespam'),
'darkChat': getCookie('darkChat'),
};
-
+
if (savedConfig.sfontSize) {
$messages.css('font-size', savedConfig.sfontSize);
internalOutput('Loaded font size setting of: '+savedConfig.sfontSize+'', 'internal');
@@ -1010,18 +1041,18 @@ $(function() {
} else {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
-
+
// synchronous requests are depricated in modern browsers
- xmlHttp.open('GET', 'browserOutput.css', true);
+ xmlHttp.open('GET', 'browserOutput.css', true);
xmlHttp.onload = function (e) {
if (xmlHttp.status === 200) { // request successful
-
+
// Generate Log
var saved = '';
saved += $messages.html();
saved = saved.replace(/&/g, '&');
saved = saved.replace(/Chat Log \
'+
@@ -1031,7 +1062,7 @@ $(function() {
openWindow('Style Doc Retrieve Error: '+xmlHttp.statusText);
}
}
-
+
// timeout and request errors
xmlHttp.timeout = 300;
xmlHttp.ontimeout = function (e) {
diff --git a/goon/code/datums/browserOutput.dm b/goon/code/datums/browserOutput.dm
index 74c9d844728..b073bece409 100644
--- a/goon/code/datums/browserOutput.dm
+++ b/goon/code/datums/browserOutput.dm
@@ -109,6 +109,7 @@ var/list/chatResources = list(
loaded = TRUE
winset(owner, "browseroutput", "is-disabled=false")
+ owner << output(null, "browseroutput:rebootFinished")
if(owner.holder)
loadAdmin()
for(var/message in messageQueue)
@@ -245,8 +246,8 @@ var/list/chatResources = list(
var/to_chat_filename
var/to_chat_line
var/to_chat_src
-// Call using macro: to_chat(target, message, flag)
-/proc/to_chat_immediate(target, message, flag)
+
+/proc/to_chat(target, message, flag)
if(!is_valid_tochat_message(message) || !is_valid_tochat_target(target))
target << message
@@ -304,17 +305,4 @@ var/to_chat_src
target << output(output_message, "browseroutput:output")
-/proc/to_chat(target, message, flag)
- /*
- If any of the following conditions are met, do NOT use SSchat. These conditions include:
- - Is the MC still initializing?
- - Has SSchat initialized?
- - Has SSchat been offlined due to MC crashes?
- If any of these are met, use the old chat system, otherwise people wont see messages
- */
- if(Master.current_runlevel == RUNLEVEL_INIT || !SSchat?.initialized || SSchat?.flags & SS_NO_FIRE)
- to_chat_immediate(target, message, flag)
- return
- SSchat.queue(target, message, flag)
-
#undef MAX_COOKIE_LENGTH
diff --git a/html/browser/marked-paradise.js b/html/browser/marked-paradise.js
index 03519139409..a92cadb1cfe 100644
--- a/html/browser/marked-paradise.js
+++ b/html/browser/marked-paradise.js
@@ -4,24 +4,22 @@
var $ = document.querySelector.bind(document);
function parse(node) {
- for (var i = 0; i < node.childNodes.length; i++) {
- parse(node.childNodes[i]);
- }
-
- if (!node.innerHTML) {
- return;
- }
-
- node.innerHTML = marked(node.innerHTML.replace(/ /gi, '\n').replace(/\t/gi, ''), { breaks: false, gfm: false })
- // marked.js wraps content into
tags, which is looks atrocious when we call it recursively.
- // The following line unwraps it.
- if (node.children.length == 1) {
- node.innerHTML = node.children[0].innerHTML;
- }
+ for (var i = 0; i < node.childNodes.length; i++)
+ parse(node.childNodes[i]);
+
+ if (!node.innerHTML)
+ return;
+
+ if (node.children.length == 0) {
+ node.innerHTML = marked(node.innerHTML.replace(/ /gi, '\n').replace(/\t/gi, ''), { breaks: false, gfm: false });
+ // marked.js wraps content into
tags, which is looks atrocious when we call it recursively.
+ // The following line unwraps it.
+ if (node.children.length == 1 && node.children[0].tagName == "P")
+ node.innerHTML = node.children[0].innerHTML;
+ }
}
-
+
window.onload = function() {
- if ($('#markdown')) {
- parse($('#markdown'));
- }
+ if ($('#markdown'))
+ parse($('#markdown'));
}
diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi
index 5200ad72e5a..1bd516110e5 100644
Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ
diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi
index 92006f54cc2..07593d09c0c 100644
Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ
diff --git a/icons/mob/inhands/clothing_lefthand.dmi b/icons/mob/inhands/clothing_lefthand.dmi
index 589135b8701..379c727930f 100644
Binary files a/icons/mob/inhands/clothing_lefthand.dmi and b/icons/mob/inhands/clothing_lefthand.dmi differ
diff --git a/icons/mob/inhands/clothing_righthand.dmi b/icons/mob/inhands/clothing_righthand.dmi
index 8fd5f7d71b8..2fc6aa9c4c1 100644
Binary files a/icons/mob/inhands/clothing_righthand.dmi and b/icons/mob/inhands/clothing_righthand.dmi differ
diff --git a/icons/mob/inhands/equipment/instruments_lefthand.dmi b/icons/mob/inhands/equipment/instruments_lefthand.dmi
index 225f1768d99..aa3608fec28 100644
Binary files a/icons/mob/inhands/equipment/instruments_lefthand.dmi and b/icons/mob/inhands/equipment/instruments_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/instruments_righthand.dmi b/icons/mob/inhands/equipment/instruments_righthand.dmi
index cc1df97183a..28085ff746d 100644
Binary files a/icons/mob/inhands/equipment/instruments_righthand.dmi and b/icons/mob/inhands/equipment/instruments_righthand.dmi differ
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index a378d2e5b04..b2f1bfa90c6 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 0a8847d7e4a..a7772c3ebf4 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/mob/species/drask/head.dmi b/icons/mob/species/drask/head.dmi
index b9f0604c960..f0c888e9f68 100644
Binary files a/icons/mob/species/drask/head.dmi and b/icons/mob/species/drask/head.dmi differ
diff --git a/icons/mob/species/drask/suit.dmi b/icons/mob/species/drask/suit.dmi
index d75a28f2bee..cef6dbdf836 100644
Binary files a/icons/mob/species/drask/suit.dmi and b/icons/mob/species/drask/suit.dmi differ
diff --git a/icons/mob/species/grey/head.dmi b/icons/mob/species/grey/head.dmi
index 4ff783bbb74..c059a3bff9d 100644
Binary files a/icons/mob/species/grey/head.dmi and b/icons/mob/species/grey/head.dmi differ
diff --git a/icons/mob/species/grey/helmet.dmi b/icons/mob/species/grey/helmet.dmi
index cf244cec6b2..3e592369adc 100644
Binary files a/icons/mob/species/grey/helmet.dmi and b/icons/mob/species/grey/helmet.dmi differ
diff --git a/icons/mob/species/grey/mask.dmi b/icons/mob/species/grey/mask.dmi
index cbbd722ae69..348a39c0f03 100644
Binary files a/icons/mob/species/grey/mask.dmi and b/icons/mob/species/grey/mask.dmi differ
diff --git a/icons/mob/species/grey/suit.dmi b/icons/mob/species/grey/suit.dmi
index 3070f6627ea..c22c9daf3dd 100644
Binary files a/icons/mob/species/grey/suit.dmi and b/icons/mob/species/grey/suit.dmi differ
diff --git a/icons/mob/species/grey/uniform.dmi b/icons/mob/species/grey/uniform.dmi
index c956187ffa1..7a74f930598 100644
Binary files a/icons/mob/species/grey/uniform.dmi and b/icons/mob/species/grey/uniform.dmi differ
diff --git a/icons/mob/species/skrell/helmet.dmi b/icons/mob/species/skrell/helmet.dmi
index ef05daf5115..e54cdb52d0f 100644
Binary files a/icons/mob/species/skrell/helmet.dmi and b/icons/mob/species/skrell/helmet.dmi differ
diff --git a/icons/mob/species/vox/head.dmi b/icons/mob/species/vox/head.dmi
index 6c4b2b43f6a..fb5d153d30d 100644
Binary files a/icons/mob/species/vox/head.dmi and b/icons/mob/species/vox/head.dmi differ
diff --git a/icons/mob/species/vox/suit.dmi b/icons/mob/species/vox/suit.dmi
index 827b67b4332..4161227ac79 100644
Binary files a/icons/mob/species/vox/suit.dmi and b/icons/mob/species/vox/suit.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index 26c2a7ea734..12a0a371a94 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi
index 4a250a1fffc..b1876a7d063 100644
Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ
diff --git a/icons/obj/atmos.dmi b/icons/obj/atmos.dmi
index 2209f3bd769..b2668980aec 100644
Binary files a/icons/obj/atmos.dmi and b/icons/obj/atmos.dmi differ
diff --git a/icons/obj/atmospherics/blue_pipe_tank.dmi b/icons/obj/atmospherics/blue_pipe_tank.dmi
deleted file mode 100644
index 3d2ee4c9d69..00000000000
Binary files a/icons/obj/atmospherics/blue_pipe_tank.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/digital_valve.dmi b/icons/obj/atmospherics/digital_valve.dmi
deleted file mode 100644
index 136523b7223..00000000000
Binary files a/icons/obj/atmospherics/digital_valve.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/dp_vent_pump.dmi b/icons/obj/atmospherics/dp_vent_pump.dmi
deleted file mode 100644
index 86dae2cf435..00000000000
Binary files a/icons/obj/atmospherics/dp_vent_pump.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/filter.dmi b/icons/obj/atmospherics/filter.dmi
deleted file mode 100644
index 99afb55d22b..00000000000
Binary files a/icons/obj/atmospherics/filter.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/mainspipe.dmi b/icons/obj/atmospherics/mainspipe.dmi
deleted file mode 100644
index df6c2bc0d3a..00000000000
Binary files a/icons/obj/atmospherics/mainspipe.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/n2o_pipe_tank.dmi b/icons/obj/atmospherics/n2o_pipe_tank.dmi
deleted file mode 100644
index 40efbd9f15d..00000000000
Binary files a/icons/obj/atmospherics/n2o_pipe_tank.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/omni_devices.dmi b/icons/obj/atmospherics/omni_devices.dmi
deleted file mode 100644
index 44497310026..00000000000
Binary files a/icons/obj/atmospherics/omni_devices.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/orange_pipe_tank.dmi b/icons/obj/atmospherics/orange_pipe_tank.dmi
deleted file mode 100644
index cc9442b8033..00000000000
Binary files a/icons/obj/atmospherics/orange_pipe_tank.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/passive_gate.dmi b/icons/obj/atmospherics/passive_gate.dmi
deleted file mode 100644
index 42e8c9dc74f..00000000000
Binary files a/icons/obj/atmospherics/passive_gate.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/pipe_manifold.dmi b/icons/obj/atmospherics/pipe_manifold.dmi
deleted file mode 100644
index 1e6f5750d1b..00000000000
Binary files a/icons/obj/atmospherics/pipe_manifold.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/pipe_tank.dmi b/icons/obj/atmospherics/pipe_tank.dmi
deleted file mode 100644
index 72310a2657d..00000000000
Binary files a/icons/obj/atmospherics/pipe_tank.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/pipe_vent.dmi b/icons/obj/atmospherics/pipe_vent.dmi
deleted file mode 100644
index e40f5946cf8..00000000000
Binary files a/icons/obj/atmospherics/pipe_vent.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/portables_connector.dmi b/icons/obj/atmospherics/portables_connector.dmi
deleted file mode 100644
index c651b959990..00000000000
Binary files a/icons/obj/atmospherics/portables_connector.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/pump.dmi b/icons/obj/atmospherics/pump.dmi
deleted file mode 100644
index e44a21991ba..00000000000
Binary files a/icons/obj/atmospherics/pump.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/red_orange_pipe_tank.dmi b/icons/obj/atmospherics/red_orange_pipe_tank.dmi
deleted file mode 100644
index 1770c46312a..00000000000
Binary files a/icons/obj/atmospherics/red_orange_pipe_tank.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/red_pipe_tank.dmi b/icons/obj/atmospherics/red_pipe_tank.dmi
deleted file mode 100644
index 3fedc659e03..00000000000
Binary files a/icons/obj/atmospherics/red_pipe_tank.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/relief_valve.dmi b/icons/obj/atmospherics/relief_valve.dmi
deleted file mode 100644
index 485bf792b19..00000000000
Binary files a/icons/obj/atmospherics/relief_valve.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/valve.dmi b/icons/obj/atmospherics/valve.dmi
deleted file mode 100644
index 9ce45199bd7..00000000000
Binary files a/icons/obj/atmospherics/valve.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/vent_pump.dmi b/icons/obj/atmospherics/vent_pump.dmi
deleted file mode 100644
index 6b1f57baa44..00000000000
Binary files a/icons/obj/atmospherics/vent_pump.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/vent_scrubber.dmi b/icons/obj/atmospherics/vent_scrubber.dmi
deleted file mode 100644
index 7133072cd79..00000000000
Binary files a/icons/obj/atmospherics/vent_scrubber.dmi and /dev/null differ
diff --git a/icons/obj/atmospherics/volume_pump.dmi b/icons/obj/atmospherics/volume_pump.dmi
deleted file mode 100644
index e3ff3cf9854..00000000000
Binary files a/icons/obj/atmospherics/volume_pump.dmi and /dev/null differ
diff --git a/icons/obj/bureaucracy.dmi b/icons/obj/bureaucracy.dmi
index 1847e985d89..3f66fa90cd6 100644
Binary files a/icons/obj/bureaucracy.dmi and b/icons/obj/bureaucracy.dmi differ
diff --git a/icons/obj/cigarettes.dmi b/icons/obj/cigarettes.dmi
index a0133e5b383..97710ac4805 100644
Binary files a/icons/obj/cigarettes.dmi and b/icons/obj/cigarettes.dmi differ
diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi
index c9ebceba369..30f34f01b4f 100644
Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index acb6af50d18..62fc0a6120c 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/clothing/uniforms.dmi b/icons/obj/clothing/uniforms.dmi
index bb7a1ce9188..39789326c49 100644
Binary files a/icons/obj/clothing/uniforms.dmi and b/icons/obj/clothing/uniforms.dmi differ
diff --git a/icons/obj/computer.dmi b/icons/obj/computer.dmi
index ac416274ebe..042b5fe7f38 100644
Binary files a/icons/obj/computer.dmi and b/icons/obj/computer.dmi differ
diff --git a/icons/obj/contraband.dmi b/icons/obj/contraband.dmi
index 97a11d05cad..444863abd71 100644
Binary files a/icons/obj/contraband.dmi and b/icons/obj/contraband.dmi differ
diff --git a/icons/obj/decals.dmi b/icons/obj/decals.dmi
index 7351c8c7483..35ce076db6c 100644
Binary files a/icons/obj/decals.dmi and b/icons/obj/decals.dmi differ
diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi
index f1d09247bbd..1e61cebb799 100644
Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ
diff --git a/icons/obj/hydroponics/equipment.dmi b/icons/obj/hydroponics/equipment.dmi
index 9ad33b40e9d..3cb9e63cb38 100644
Binary files a/icons/obj/hydroponics/equipment.dmi and b/icons/obj/hydroponics/equipment.dmi differ
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index a82f3fa10a2..e30f3e44392 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ
diff --git a/icons/obj/lighting.dmi b/icons/obj/lighting.dmi
index f8943c2c39b..49b594c1656 100644
Binary files a/icons/obj/lighting.dmi and b/icons/obj/lighting.dmi differ
diff --git a/icons/obj/musician.dmi b/icons/obj/musician.dmi
index 21078c58969..d55ecb7ebc0 100644
Binary files a/icons/obj/musician.dmi and b/icons/obj/musician.dmi differ
diff --git a/icons/obj/paper.dmi b/icons/obj/paper.dmi
deleted file mode 100644
index 55781076833..00000000000
Binary files a/icons/obj/paper.dmi and /dev/null differ
diff --git a/icons/obj/reagentfillings.dmi b/icons/obj/reagentfillings.dmi
index 60eb897b2b1..51e9b66ee30 100644
Binary files a/icons/obj/reagentfillings.dmi and b/icons/obj/reagentfillings.dmi differ
diff --git a/icons/obj/recycling.dmi b/icons/obj/recycling.dmi
index 2a47e6817bb..c30eb425dda 100644
Binary files a/icons/obj/recycling.dmi and b/icons/obj/recycling.dmi differ
diff --git a/icons/obj/toy.dmi b/icons/obj/toy.dmi
index 1ef7016307d..c51d2903b14 100644
Binary files a/icons/obj/toy.dmi and b/icons/obj/toy.dmi differ
diff --git a/nano/templates/adv_med.tmpl b/nano/templates/adv_med.tmpl
deleted file mode 100644
index a1ca2815679..00000000000
--- a/nano/templates/adv_med.tmpl
+++ /dev/null
@@ -1,231 +0,0 @@
-
-
-{{if !data.occupied}}
-
-
- {{else}}
- {{if data.locked}}
- Swipe an ID card to unlock this interface
- {{else}}
- Swipe an ID card to lock this interface
- {{/if}}
- {{/if}}
-
-{{else}}
-
-Deployment of weapon authorized by Nanotrasen Naval Command. Remember, friendly fire is grounds for termination of your contract and life.
-{{/if}}
\ No newline at end of file
diff --git a/nano/templates/canister.tmpl b/nano/templates/canister.tmpl
deleted file mode 100644
index 5aaa15d4fe3..00000000000
--- a/nano/templates/canister.tmpl
+++ /dev/null
@@ -1,158 +0,0 @@
-{{if data.menu == 0}}
-
- {{if data.isBeakerLoaded}}
- {{:helper.smoothRound(data.beakerFreeSpace)}} units of space remaining
- {{else}}
- No Dialysis Output Beaker Loaded
- {{/if}}
-
- Lines are a series of chords, separated by commas (,), each with notes seperated by hyphens (-).
-
- Every note in a chord will play together, with the chord timed by the tempo as defined above.
-
-
- Notes are played by the names of the note, and optionally, the accidental, and/or the octave number.
-
- By default, every note is natural and in octave 3. Defining a different state for either is remembered for each note.
-
-
Example:C,D,E,F,G,A,B will play a Cmajor scale.
-
After a note has an accidental or octave placed, it will be remembered: C,C4,C#,C3 is C3,C4,C4#,C3#
-
-
-
- Chords can be played simply by seperating each note with a hyphon: A-C#,Cn-E,E-G#,Gn-B.
- A pause may be denoted by an empty chord: C,E,,C,G.
-
- To make a chord be a different time, end it with /x, where the chord length will be length defined by tempo / x, eg:C,G/2,E/4.
-
-
- Combined, an example line is: E-E4/4,F#/2,G#/8,B/8,E3-E4/4.
-
-
Lines may be up to 50 characters.
-
A song may only contain up to 50 lines.
-
-
- {{/if}}
-
-
\ No newline at end of file
diff --git a/nano/templates/tanks.tmpl b/nano/templates/tanks.tmpl
deleted file mode 100644
index 2cf12746f01..00000000000
--- a/nano/templates/tanks.tmpl
+++ /dev/null
@@ -1,47 +0,0 @@
-{{if data.maskConnected}}
-
-{{/if}}
diff --git a/paradise.dme b/paradise.dme
index abbedaf2208..4a5c6350f91 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -40,6 +40,7 @@
#include "code\__DEFINES\genetics.dm"
#include "code\__DEFINES\hud.dm"
#include "code\__DEFINES\hydroponics.dm"
+#include "code\__DEFINES\instruments.dm"
#include "code\__DEFINES\inventory.dm"
#include "code\__DEFINES\is_helpers.dm"
#include "code\__DEFINES\job.dm"
@@ -71,9 +72,11 @@
#include "code\__DEFINES\station_goals.dm"
#include "code\__DEFINES\status_effects.dm"
#include "code\__DEFINES\subsystems.dm"
+#include "code\__DEFINES\tgui.dm"
#include "code\__DEFINES\tools.dm"
#include "code\__DEFINES\typeids.dm"
#include "code\__DEFINES\vv.dm"
+#include "code\__DEFINES\wires.dm"
#include "code\__DEFINES\zlevel.dm"
#include "code\__DEFINES\dcs\flags.dm"
#include "code\__DEFINES\dcs\helpers.dm"
@@ -215,10 +218,10 @@
#include "code\controllers\subsystem\assets.dm"
#include "code\controllers\subsystem\atoms.dm"
#include "code\controllers\subsystem\changelog.dm"
-#include "code\controllers\subsystem\chat.dm"
#include "code\controllers\subsystem\events.dm"
#include "code\controllers\subsystem\fires.dm"
#include "code\controllers\subsystem\garbage.dm"
+#include "code\controllers\subsystem\ghost_spawns.dm"
#include "code\controllers\subsystem\holiday.dm"
#include "code\controllers\subsystem\icon_smooth.dm"
#include "code\controllers\subsystem\idlenpcpool.dm"
@@ -238,6 +241,7 @@
#include "code\controllers\subsystem\parallax.dm"
#include "code\controllers\subsystem\radio.dm"
#include "code\controllers\subsystem\shuttles.dm"
+#include "code\controllers\subsystem\sounds.dm"
#include "code\controllers\subsystem\spacedrift.dm"
#include "code\controllers\subsystem\statistics.dm"
#include "code\controllers\subsystem\sun.dm"
@@ -250,6 +254,7 @@
#include "code\controllers\subsystem\weather.dm"
#include "code\controllers\subsystem\processing\dcs.dm"
#include "code\controllers\subsystem\processing\fastprocess.dm"
+#include "code\controllers\subsystem\processing\instruments.dm"
#include "code\controllers\subsystem\processing\obj.dm"
#include "code\controllers\subsystem\processing\processing.dm"
#include "code\controllers\subsystem\tickets\mentor_tickets.dm"
@@ -271,6 +276,7 @@
#include "code\datums\hud.dm"
#include "code\datums\log_record.dm"
#include "code\datums\log_viewer.dm"
+#include "code\datums\logging.dm"
#include "code\datums\mind.dm"
#include "code\datums\mixed.dm"
#include "code\datums\mutable_appearance.dm"
@@ -303,6 +309,7 @@
#include "code\datums\components\paintable.dm"
#include "code\datums\components\slippery.dm"
#include "code\datums\components\spawner.dm"
+#include "code\datums\components\spooky.dm"
#include "code\datums\components\squeak.dm"
#include "code\datums\components\swarming.dm"
#include "code\datums\diseases\_disease.dm"
@@ -726,6 +733,7 @@
#include "code\game\machinery\computer\robot.dm"
#include "code\game\machinery\computer\salvage_ship.dm"
#include "code\game\machinery\computer\security.dm"
+#include "code\game\machinery\computer\sm_monitor.dm"
#include "code\game\machinery\computer\specops_shuttle.dm"
#include "code\game\machinery\computer\station_alert.dm"
#include "code\game\machinery\computer\store.dm"
@@ -875,7 +883,6 @@
#include "code\game\objects\items\devices\flashlight.dm"
#include "code\game\objects\items\devices\floor_painter.dm"
#include "code\game\objects\items\devices\handheld_defib.dm"
-#include "code\game\objects\items\devices\instruments.dm"
#include "code\game\objects\items\devices\laserpointer.dm"
#include "code\game\objects\items\devices\lightreplacer.dm"
#include "code\game\objects\items\devices\machineprototype.dm"
@@ -936,6 +943,7 @@
#include "code\game\objects\items\tools\wrench.dm"
#include "code\game\objects\items\weapons\AI_modules.dm"
#include "code\game\objects\items\weapons\alien_specific.dm"
+#include "code\game\objects\items\weapons\batons.dm"
#include "code\game\objects\items\weapons\bee_briefcase.dm"
#include "code\game\objects\items\weapons\cards_ids.dm"
#include "code\game\objects\items\weapons\cash.dm"
@@ -984,7 +992,6 @@
#include "code\game\objects\items\weapons\staff.dm"
#include "code\game\objects\items\weapons\stock_parts.dm"
#include "code\game\objects\items\weapons\stunbaton.dm"
-#include "code\game\objects\items\weapons\swords_axes_etc.dm"
#include "code\game\objects\items\weapons\tape.dm"
#include "code\game\objects\items\weapons\teleportation.dm"
#include "code\game\objects\items\weapons\teleprod.dm"
@@ -1080,7 +1087,6 @@
#include "code\game\objects\structures\misc.dm"
#include "code\game\objects\structures\mop_bucket.dm"
#include "code\game\objects\structures\morgue.dm"
-#include "code\game\objects\structures\musician.dm"
#include "code\game\objects\structures\noticeboard.dm"
#include "code\game\objects\structures\plasticflaps.dm"
#include "code\game\objects\structures\reflector.dm"
@@ -1202,8 +1208,8 @@
#include "code\modules\admin\verbs\adminjump.dm"
#include "code\modules\admin\verbs\adminpm.dm"
#include "code\modules\admin\verbs\adminsay.dm"
-#include "code\modules\admin\verbs\alt_check.dm"
#include "code\modules\admin\verbs\antag-ooc.dm"
+#include "code\modules\admin\verbs\asays.dm"
#include "code\modules\admin\verbs\atmosdebug.dm"
#include "code\modules\admin\verbs\BrokenInhands.dm"
#include "code\modules\admin\verbs\cinematic.dm"
@@ -1231,7 +1237,6 @@
#include "code\modules\admin\verbs\randomverbs.dm"
#include "code\modules\admin\verbs\serialization.dm"
#include "code\modules\admin\verbs\space_transitions.dm"
-#include "code\modules\admin\verbs\spawnfloorcluwne.dm"
#include "code\modules\admin\verbs\striketeam.dm"
#include "code\modules\admin\verbs\striketeam_syndicate.dm"
#include "code\modules\admin\verbs\ticklag.dm"
@@ -1241,14 +1246,6 @@
#include "code\modules\admin\verbs\SDQL2\SDQL_2.dm"
#include "code\modules\admin\verbs\SDQL2\SDQL_2_parser.dm"
#include "code\modules\admin\verbs\SDQL2\useful_procs.dm"
-#include "code\modules\alarm\alarm.dm"
-#include "code\modules\alarm\alarm_handler.dm"
-#include "code\modules\alarm\atmosphere_alarm.dm"
-#include "code\modules\alarm\burglar_alarm.dm"
-#include "code\modules\alarm\camera_alarm.dm"
-#include "code\modules\alarm\fire_alarm.dm"
-#include "code\modules\alarm\motion_alarm.dm"
-#include "code\modules\alarm\power_alarm.dm"
#include "code\modules\antagonists\_common\antag_datum.dm"
#include "code\modules\antagonists\_common\antag_helpers.dm"
#include "code\modules\antagonists\_common\antag_hud.dm"
@@ -1609,6 +1606,25 @@
#include "code\modules\hydroponics\grown\tobacco.dm"
#include "code\modules\hydroponics\grown\tomato.dm"
#include "code\modules\hydroponics\grown\towercap.dm"
+#include "code\modules\instruments\_instrument_data.dm"
+#include "code\modules\instruments\_instrument_key.dm"
+#include "code\modules\instruments\brass.dm"
+#include "code\modules\instruments\chromatic_percussion.dm"
+#include "code\modules\instruments\fun.dm"
+#include "code\modules\instruments\guitar.dm"
+#include "code\modules\instruments\hardcoded.dm"
+#include "code\modules\instruments\organ.dm"
+#include "code\modules\instruments\piano.dm"
+#include "code\modules\instruments\synth_tones.dm"
+#include "code\modules\instruments\objs\items\_instrument.dm"
+#include "code\modules\instruments\objs\items\headphones.dm"
+#include "code\modules\instruments\objs\items\instruments.dm"
+#include "code\modules\instruments\objs\structures\_musician.dm"
+#include "code\modules\instruments\objs\structures\piano.dm"
+#include "code\modules\instruments\songs\_song.dm"
+#include "code\modules\instruments\songs\_song_ui.dm"
+#include "code\modules\instruments\songs\play_legacy.dm"
+#include "code\modules\instruments\songs\play_synthesized.dm"
#include "code\modules\karma\karma.dm"
#include "code\modules\keybindings\bindings_admin.dm"
#include "code\modules\keybindings\bindings_ai.dm"
@@ -2066,7 +2082,6 @@
#include "code\modules\modular_computers\file_system\programs\antagonist\revelation.dm"
#include "code\modules\modular_computers\file_system\programs\command\card.dm"
#include "code\modules\modular_computers\file_system\programs\command\comms.dm"
-#include "code\modules\modular_computers\file_system\programs\engineering\alarm.dm"
#include "code\modules\modular_computers\file_system\programs\engineering\power_monitor.dm"
#include "code\modules\modular_computers\file_system\programs\engineering\sm_monitor.dm"
#include "code\modules\modular_computers\file_system\programs\generic\configurator.dm"
@@ -2104,7 +2119,6 @@
#include "code\modules\nano\interaction\physical.dm"
#include "code\modules\nano\interaction\self.dm"
#include "code\modules\nano\interaction\zlevel.dm"
-#include "code\modules\nano\modules\alarm_monitor.dm"
#include "code\modules\nano\modules\atmos_control.dm"
#include "code\modules\nano\modules\ert_manager.dm"
#include "code\modules\nano\modules\human_appearance.dm"
@@ -2441,6 +2455,7 @@
#include "code\modules\telesci\telepad.dm"
#include "code\modules\telesci\telesci_computer.dm"
#include "code\modules\tgui\external.dm"
+#include "code\modules\tgui\modal.dm"
#include "code\modules\tgui\states.dm"
#include "code\modules\tgui\tgui.dm"
#include "code\modules\tgui\modules\_base.dm"
diff --git a/sound/instruments/banjo/Ab3.ogg b/sound/instruments/banjo/Ab3.ogg
new file mode 100644
index 00000000000..66e263bd615
Binary files /dev/null and b/sound/instruments/banjo/Ab3.ogg differ
diff --git a/sound/instruments/banjo/Ab4.ogg b/sound/instruments/banjo/Ab4.ogg
new file mode 100644
index 00000000000..f003e03233a
Binary files /dev/null and b/sound/instruments/banjo/Ab4.ogg differ
diff --git a/sound/instruments/banjo/Ab5.ogg b/sound/instruments/banjo/Ab5.ogg
new file mode 100644
index 00000000000..c405725208e
Binary files /dev/null and b/sound/instruments/banjo/Ab5.ogg differ
diff --git a/sound/instruments/banjo/An3.ogg b/sound/instruments/banjo/An3.ogg
new file mode 100644
index 00000000000..1700704c9c1
Binary files /dev/null and b/sound/instruments/banjo/An3.ogg differ
diff --git a/sound/instruments/banjo/An4.ogg b/sound/instruments/banjo/An4.ogg
new file mode 100644
index 00000000000..eb7279f869e
Binary files /dev/null and b/sound/instruments/banjo/An4.ogg differ
diff --git a/sound/instruments/banjo/An5.ogg b/sound/instruments/banjo/An5.ogg
new file mode 100644
index 00000000000..d9cf57c0feb
Binary files /dev/null and b/sound/instruments/banjo/An5.ogg differ
diff --git a/sound/instruments/banjo/Bb3.ogg b/sound/instruments/banjo/Bb3.ogg
new file mode 100644
index 00000000000..d3f757c0ace
Binary files /dev/null and b/sound/instruments/banjo/Bb3.ogg differ
diff --git a/sound/instruments/banjo/Bb4.ogg b/sound/instruments/banjo/Bb4.ogg
new file mode 100644
index 00000000000..a9d869091bf
Binary files /dev/null and b/sound/instruments/banjo/Bb4.ogg differ
diff --git a/sound/instruments/banjo/Bb5.ogg b/sound/instruments/banjo/Bb5.ogg
new file mode 100644
index 00000000000..a56e6c25005
Binary files /dev/null and b/sound/instruments/banjo/Bb5.ogg differ
diff --git a/sound/instruments/banjo/Bn2.ogg b/sound/instruments/banjo/Bn2.ogg
new file mode 100644
index 00000000000..3154f974193
Binary files /dev/null and b/sound/instruments/banjo/Bn2.ogg differ
diff --git a/sound/instruments/banjo/Bn3.ogg b/sound/instruments/banjo/Bn3.ogg
new file mode 100644
index 00000000000..6c72ec2fd5a
Binary files /dev/null and b/sound/instruments/banjo/Bn3.ogg differ
diff --git a/sound/instruments/banjo/Bn4.ogg b/sound/instruments/banjo/Bn4.ogg
new file mode 100644
index 00000000000..b0e9a2b3b2f
Binary files /dev/null and b/sound/instruments/banjo/Bn4.ogg differ
diff --git a/sound/instruments/banjo/Bn5.ogg b/sound/instruments/banjo/Bn5.ogg
new file mode 100644
index 00000000000..1b002140b87
Binary files /dev/null and b/sound/instruments/banjo/Bn5.ogg differ
diff --git a/sound/instruments/banjo/Cn3.ogg b/sound/instruments/banjo/Cn3.ogg
new file mode 100644
index 00000000000..6ef414d9d01
Binary files /dev/null and b/sound/instruments/banjo/Cn3.ogg differ
diff --git a/sound/instruments/banjo/Cn4.ogg b/sound/instruments/banjo/Cn4.ogg
new file mode 100644
index 00000000000..4a26a6741db
Binary files /dev/null and b/sound/instruments/banjo/Cn4.ogg differ
diff --git a/sound/instruments/banjo/Cn5.ogg b/sound/instruments/banjo/Cn5.ogg
new file mode 100644
index 00000000000..901ed3bc08b
Binary files /dev/null and b/sound/instruments/banjo/Cn5.ogg differ
diff --git a/sound/instruments/banjo/Cn6.ogg b/sound/instruments/banjo/Cn6.ogg
new file mode 100644
index 00000000000..5cdbbb17cea
Binary files /dev/null and b/sound/instruments/banjo/Cn6.ogg differ
diff --git a/sound/instruments/banjo/Db3.ogg b/sound/instruments/banjo/Db3.ogg
new file mode 100644
index 00000000000..1ebffdf5025
Binary files /dev/null and b/sound/instruments/banjo/Db3.ogg differ
diff --git a/sound/instruments/banjo/Db4.ogg b/sound/instruments/banjo/Db4.ogg
new file mode 100644
index 00000000000..5b939365086
Binary files /dev/null and b/sound/instruments/banjo/Db4.ogg differ
diff --git a/sound/instruments/banjo/Db5.ogg b/sound/instruments/banjo/Db5.ogg
new file mode 100644
index 00000000000..6ee4dde9479
Binary files /dev/null and b/sound/instruments/banjo/Db5.ogg differ
diff --git a/sound/instruments/banjo/Db6.ogg b/sound/instruments/banjo/Db6.ogg
new file mode 100644
index 00000000000..fd73894fda6
Binary files /dev/null and b/sound/instruments/banjo/Db6.ogg differ
diff --git a/sound/instruments/banjo/Dn3.ogg b/sound/instruments/banjo/Dn3.ogg
new file mode 100644
index 00000000000..77491b01b8c
Binary files /dev/null and b/sound/instruments/banjo/Dn3.ogg differ
diff --git a/sound/instruments/banjo/Dn4.ogg b/sound/instruments/banjo/Dn4.ogg
new file mode 100644
index 00000000000..11f68b5a157
Binary files /dev/null and b/sound/instruments/banjo/Dn4.ogg differ
diff --git a/sound/instruments/banjo/Dn5.ogg b/sound/instruments/banjo/Dn5.ogg
new file mode 100644
index 00000000000..2e9ebe49891
Binary files /dev/null and b/sound/instruments/banjo/Dn5.ogg differ
diff --git a/sound/instruments/banjo/Dn6.ogg b/sound/instruments/banjo/Dn6.ogg
new file mode 100644
index 00000000000..89ae62361dc
Binary files /dev/null and b/sound/instruments/banjo/Dn6.ogg differ
diff --git a/sound/instruments/banjo/Eb3.ogg b/sound/instruments/banjo/Eb3.ogg
new file mode 100644
index 00000000000..1d1e43049d2
Binary files /dev/null and b/sound/instruments/banjo/Eb3.ogg differ
diff --git a/sound/instruments/banjo/Eb4.ogg b/sound/instruments/banjo/Eb4.ogg
new file mode 100644
index 00000000000..2722655f5a3
Binary files /dev/null and b/sound/instruments/banjo/Eb4.ogg differ
diff --git a/sound/instruments/banjo/Eb5.ogg b/sound/instruments/banjo/Eb5.ogg
new file mode 100644
index 00000000000..7a109dfdf79
Binary files /dev/null and b/sound/instruments/banjo/Eb5.ogg differ
diff --git a/sound/instruments/banjo/En3.ogg b/sound/instruments/banjo/En3.ogg
new file mode 100644
index 00000000000..4610efdd4f0
Binary files /dev/null and b/sound/instruments/banjo/En3.ogg differ
diff --git a/sound/instruments/banjo/En4.ogg b/sound/instruments/banjo/En4.ogg
new file mode 100644
index 00000000000..64c14daf915
Binary files /dev/null and b/sound/instruments/banjo/En4.ogg differ
diff --git a/sound/instruments/banjo/En5.ogg b/sound/instruments/banjo/En5.ogg
new file mode 100644
index 00000000000..8e0b6c1637e
Binary files /dev/null and b/sound/instruments/banjo/En5.ogg differ
diff --git a/sound/instruments/banjo/Fn3.ogg b/sound/instruments/banjo/Fn3.ogg
new file mode 100644
index 00000000000..5cdc4f13fb3
Binary files /dev/null and b/sound/instruments/banjo/Fn3.ogg differ
diff --git a/sound/instruments/banjo/Fn4.ogg b/sound/instruments/banjo/Fn4.ogg
new file mode 100644
index 00000000000..78d5454f186
Binary files /dev/null and b/sound/instruments/banjo/Fn4.ogg differ
diff --git a/sound/instruments/banjo/Fn5.ogg b/sound/instruments/banjo/Fn5.ogg
new file mode 100644
index 00000000000..b21559b4656
Binary files /dev/null and b/sound/instruments/banjo/Fn5.ogg differ
diff --git a/sound/instruments/banjo/Gb3.ogg b/sound/instruments/banjo/Gb3.ogg
new file mode 100644
index 00000000000..fd055b74717
Binary files /dev/null and b/sound/instruments/banjo/Gb3.ogg differ
diff --git a/sound/instruments/banjo/Gb4.ogg b/sound/instruments/banjo/Gb4.ogg
new file mode 100644
index 00000000000..f2c62510ed0
Binary files /dev/null and b/sound/instruments/banjo/Gb4.ogg differ
diff --git a/sound/instruments/banjo/Gb5.ogg b/sound/instruments/banjo/Gb5.ogg
new file mode 100644
index 00000000000..ab17347912b
Binary files /dev/null and b/sound/instruments/banjo/Gb5.ogg differ
diff --git a/sound/instruments/banjo/Gn3.ogg b/sound/instruments/banjo/Gn3.ogg
new file mode 100644
index 00000000000..ad52ef85c08
Binary files /dev/null and b/sound/instruments/banjo/Gn3.ogg differ
diff --git a/sound/instruments/banjo/Gn4.ogg b/sound/instruments/banjo/Gn4.ogg
new file mode 100644
index 00000000000..2ddb13b86b3
Binary files /dev/null and b/sound/instruments/banjo/Gn4.ogg differ
diff --git a/sound/instruments/banjo/Gn5.ogg b/sound/instruments/banjo/Gn5.ogg
new file mode 100644
index 00000000000..d5a7886c4cf
Binary files /dev/null and b/sound/instruments/banjo/Gn5.ogg differ
diff --git a/sound/instruments/synthesis_samples/brass/crisis_brass/c2.ogg b/sound/instruments/synthesis_samples/brass/crisis_brass/c2.ogg
new file mode 100644
index 00000000000..aaa1e27ab89
Binary files /dev/null and b/sound/instruments/synthesis_samples/brass/crisis_brass/c2.ogg differ
diff --git a/sound/instruments/synthesis_samples/brass/crisis_brass/c3.ogg b/sound/instruments/synthesis_samples/brass/crisis_brass/c3.ogg
new file mode 100644
index 00000000000..ce50e76aae6
Binary files /dev/null and b/sound/instruments/synthesis_samples/brass/crisis_brass/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/brass/crisis_brass/c4.ogg b/sound/instruments/synthesis_samples/brass/crisis_brass/c4.ogg
new file mode 100644
index 00000000000..22f34d67592
Binary files /dev/null and b/sound/instruments/synthesis_samples/brass/crisis_brass/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/brass/crisis_brass/c5.ogg b/sound/instruments/synthesis_samples/brass/crisis_brass/c5.ogg
new file mode 100644
index 00000000000..eb5bb7c295e
Binary files /dev/null and b/sound/instruments/synthesis_samples/brass/crisis_brass/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/brass/crisis_trombone/C2.ogg b/sound/instruments/synthesis_samples/brass/crisis_trombone/C2.ogg
new file mode 100644
index 00000000000..bd299e321ab
Binary files /dev/null and b/sound/instruments/synthesis_samples/brass/crisis_trombone/C2.ogg differ
diff --git a/sound/instruments/synthesis_samples/brass/crisis_trombone/C3.ogg b/sound/instruments/synthesis_samples/brass/crisis_trombone/C3.ogg
new file mode 100644
index 00000000000..0519d2d20dd
Binary files /dev/null and b/sound/instruments/synthesis_samples/brass/crisis_trombone/C3.ogg differ
diff --git a/sound/instruments/synthesis_samples/brass/crisis_trombone/C4.ogg b/sound/instruments/synthesis_samples/brass/crisis_trombone/C4.ogg
new file mode 100644
index 00000000000..3b969a34b1c
Binary files /dev/null and b/sound/instruments/synthesis_samples/brass/crisis_trombone/C4.ogg differ
diff --git a/sound/instruments/synthesis_samples/brass/crisis_trombone/C5.ogg b/sound/instruments/synthesis_samples/brass/crisis_trombone/C5.ogg
new file mode 100644
index 00000000000..75f709c16fe
Binary files /dev/null and b/sound/instruments/synthesis_samples/brass/crisis_trombone/C5.ogg differ
diff --git a/sound/instruments/synthesis_samples/brass/crisis_trumpet/C4.ogg b/sound/instruments/synthesis_samples/brass/crisis_trumpet/C4.ogg
new file mode 100644
index 00000000000..ba347f80034
Binary files /dev/null and b/sound/instruments/synthesis_samples/brass/crisis_trumpet/C4.ogg differ
diff --git a/sound/instruments/synthesis_samples/brass/crisis_trumpet/C5.ogg b/sound/instruments/synthesis_samples/brass/crisis_trumpet/C5.ogg
new file mode 100644
index 00000000000..cee89761d0d
Binary files /dev/null and b/sound/instruments/synthesis_samples/brass/crisis_trumpet/C5.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C2.ogg b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C2.ogg
new file mode 100644
index 00000000000..105f7676557
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C2.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C3.ogg b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C3.ogg
new file mode 100644
index 00000000000..4aa33b6cded
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C3.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C4.ogg b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C4.ogg
new file mode 100644
index 00000000000..d661e8d7580
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C4.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C5.ogg b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C5.ogg
new file mode 100644
index 00000000000..bf650f1a6fa
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C5.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C6.ogg b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C6.ogg
new file mode 100644
index 00000000000..c00f7949b7e
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C6.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C7.ogg b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C7.ogg
new file mode 100644
index 00000000000..72588e9ca4c
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C7.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C8.ogg b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C8.ogg
new file mode 100644
index 00000000000..b2a0b445b92
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/fluid_celeste/C8.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/sgmbox/c2.ogg b/sound/instruments/synthesis_samples/chromatic/sgmbox/c2.ogg
new file mode 100644
index 00000000000..ecf6778343b
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/sgmbox/c2.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/sgmbox/c3.ogg b/sound/instruments/synthesis_samples/chromatic/sgmbox/c3.ogg
new file mode 100644
index 00000000000..867e9ce00d0
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/sgmbox/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/sgmbox/c4.ogg b/sound/instruments/synthesis_samples/chromatic/sgmbox/c4.ogg
new file mode 100644
index 00000000000..446d45993e8
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/sgmbox/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/sgmbox/c5.ogg b/sound/instruments/synthesis_samples/chromatic/sgmbox/c5.ogg
new file mode 100644
index 00000000000..54d56400c03
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/sgmbox/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/vibraphone1/c2.ogg b/sound/instruments/synthesis_samples/chromatic/vibraphone1/c2.ogg
new file mode 100644
index 00000000000..f3770c1f1a0
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/vibraphone1/c2.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/vibraphone1/c3.ogg b/sound/instruments/synthesis_samples/chromatic/vibraphone1/c3.ogg
new file mode 100644
index 00000000000..28954fbb47f
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/vibraphone1/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/vibraphone1/c4.ogg b/sound/instruments/synthesis_samples/chromatic/vibraphone1/c4.ogg
new file mode 100644
index 00000000000..1233f5314a3
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/vibraphone1/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/chromatic/vibraphone1/c5.ogg b/sound/instruments/synthesis_samples/chromatic/vibraphone1/c5.ogg
new file mode 100644
index 00000000000..00daf331357
Binary files /dev/null and b/sound/instruments/synthesis_samples/chromatic/vibraphone1/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_clean/C2.ogg b/sound/instruments/synthesis_samples/guitar/crisis_clean/C2.ogg
new file mode 100644
index 00000000000..13ad54bff00
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_clean/C2.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_clean/C3.ogg b/sound/instruments/synthesis_samples/guitar/crisis_clean/C3.ogg
new file mode 100644
index 00000000000..17bf392c4b2
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_clean/C3.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_clean/C4.ogg b/sound/instruments/synthesis_samples/guitar/crisis_clean/C4.ogg
new file mode 100644
index 00000000000..feda419a0ad
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_clean/C4.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_clean/C5.ogg b/sound/instruments/synthesis_samples/guitar/crisis_clean/C5.ogg
new file mode 100644
index 00000000000..bd088dd850e
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_clean/C5.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_muted/C2.ogg b/sound/instruments/synthesis_samples/guitar/crisis_muted/C2.ogg
new file mode 100644
index 00000000000..09cdbeec42c
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_muted/C2.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_muted/C3.ogg b/sound/instruments/synthesis_samples/guitar/crisis_muted/C3.ogg
new file mode 100644
index 00000000000..f82c39cee5b
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_muted/C3.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_muted/C4.ogg b/sound/instruments/synthesis_samples/guitar/crisis_muted/C4.ogg
new file mode 100644
index 00000000000..23bfd113d6c
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_muted/C4.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_muted/C5.ogg b/sound/instruments/synthesis_samples/guitar/crisis_muted/C5.ogg
new file mode 100644
index 00000000000..e5ec38d5ab8
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_muted/C5.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_nylon/c2.ogg b/sound/instruments/synthesis_samples/guitar/crisis_nylon/c2.ogg
new file mode 100644
index 00000000000..42a6cdfad3c
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_nylon/c2.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_nylon/c3.ogg b/sound/instruments/synthesis_samples/guitar/crisis_nylon/c3.ogg
new file mode 100644
index 00000000000..cd6414c0aa2
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_nylon/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_nylon/c4.ogg b/sound/instruments/synthesis_samples/guitar/crisis_nylon/c4.ogg
new file mode 100644
index 00000000000..e5366018653
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_nylon/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_nylon/c5.ogg b/sound/instruments/synthesis_samples/guitar/crisis_nylon/c5.ogg
new file mode 100644
index 00000000000..60382228374
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_nylon/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_steel/c2.ogg b/sound/instruments/synthesis_samples/guitar/crisis_steel/c2.ogg
new file mode 100644
index 00000000000..648549d594a
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_steel/c2.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_steel/c3.ogg b/sound/instruments/synthesis_samples/guitar/crisis_steel/c3.ogg
new file mode 100644
index 00000000000..01ba59a908c
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_steel/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_steel/c4.ogg b/sound/instruments/synthesis_samples/guitar/crisis_steel/c4.ogg
new file mode 100644
index 00000000000..7cfaa8ca72b
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_steel/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/guitar/crisis_steel/c5.ogg b/sound/instruments/synthesis_samples/guitar/crisis_steel/c5.ogg
new file mode 100644
index 00000000000..b4ca49dc047
Binary files /dev/null and b/sound/instruments/synthesis_samples/guitar/crisis_steel/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_accordian/c2.ogg b/sound/instruments/synthesis_samples/organ/crisis_accordian/c2.ogg
new file mode 100644
index 00000000000..7c9870a7c3b
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_accordian/c2.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_accordian/c3.ogg b/sound/instruments/synthesis_samples/organ/crisis_accordian/c3.ogg
new file mode 100644
index 00000000000..5723c2edd27
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_accordian/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_accordian/c4.ogg b/sound/instruments/synthesis_samples/organ/crisis_accordian/c4.ogg
new file mode 100644
index 00000000000..329f14f6feb
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_accordian/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_accordian/c5.ogg b/sound/instruments/synthesis_samples/organ/crisis_accordian/c5.ogg
new file mode 100644
index 00000000000..5e8ac69de28
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_accordian/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_church/c2.ogg b/sound/instruments/synthesis_samples/organ/crisis_church/c2.ogg
new file mode 100644
index 00000000000..ddc44c69c29
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_church/c2.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_church/c3.ogg b/sound/instruments/synthesis_samples/organ/crisis_church/c3.ogg
new file mode 100644
index 00000000000..28557475284
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_church/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_church/c4.ogg b/sound/instruments/synthesis_samples/organ/crisis_church/c4.ogg
new file mode 100644
index 00000000000..906fff5bd8d
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_church/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_church/c5.ogg b/sound/instruments/synthesis_samples/organ/crisis_church/c5.ogg
new file mode 100644
index 00000000000..96d28a7206d
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_church/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_hammond/c2.ogg b/sound/instruments/synthesis_samples/organ/crisis_hammond/c2.ogg
new file mode 100644
index 00000000000..9b917b7eb53
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_hammond/c2.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_hammond/c3.ogg b/sound/instruments/synthesis_samples/organ/crisis_hammond/c3.ogg
new file mode 100644
index 00000000000..c68410d6f09
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_hammond/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_hammond/c4.ogg b/sound/instruments/synthesis_samples/organ/crisis_hammond/c4.ogg
new file mode 100644
index 00000000000..df84ba99e8e
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_hammond/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_hammond/c5.ogg b/sound/instruments/synthesis_samples/organ/crisis_hammond/c5.ogg
new file mode 100644
index 00000000000..af8c178efe8
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_hammond/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_harmonica/c3.ogg b/sound/instruments/synthesis_samples/organ/crisis_harmonica/c3.ogg
new file mode 100644
index 00000000000..268b41f1fce
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_harmonica/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_harmonica/c4.ogg b/sound/instruments/synthesis_samples/organ/crisis_harmonica/c4.ogg
new file mode 100644
index 00000000000..04ceb54bfc2
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_harmonica/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_harmonica/c5.ogg b/sound/instruments/synthesis_samples/organ/crisis_harmonica/c5.ogg
new file mode 100644
index 00000000000..b321983e74f
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_harmonica/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c2.ogg b/sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c2.ogg
new file mode 100644
index 00000000000..250a5c08e08
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c2.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c3.ogg b/sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c3.ogg
new file mode 100644
index 00000000000..8b1c23007bb
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c4.ogg b/sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c4.ogg
new file mode 100644
index 00000000000..098587183bb
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c5.ogg b/sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c5.ogg
new file mode 100644
index 00000000000..81b60ef4c2f
Binary files /dev/null and b/sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c2.ogg b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c2.ogg
new file mode 100644
index 00000000000..39e992fbd85
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c2.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c3.ogg b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c3.ogg
new file mode 100644
index 00000000000..04aa9852815
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c4.ogg b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c4.ogg
new file mode 100644
index 00000000000..aff97942e9e
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c5.ogg b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c5.ogg
new file mode 100644
index 00000000000..19fd937707a
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c6.ogg b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c6.ogg
new file mode 100644
index 00000000000..452e7485be1
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c6.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c7.ogg b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c7.ogg
new file mode 100644
index 00000000000..66c88185a73
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c7.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c8.ogg b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c8.ogg
new file mode 100644
index 00000000000..d93c5176ced
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_bright_piano/c8.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c2.ogg b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c2.ogg
new file mode 100644
index 00000000000..fabd90d2e6a
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c2.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c3.ogg b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c3.ogg
new file mode 100644
index 00000000000..e4cda1487aa
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c4.ogg b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c4.ogg
new file mode 100644
index 00000000000..c596994b3eb
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c5.ogg b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c5.ogg
new file mode 100644
index 00000000000..d265514e27b
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c6.ogg b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c6.ogg
new file mode 100644
index 00000000000..3e17b3f99a6
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c6.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c7.ogg b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c7.ogg
new file mode 100644
index 00000000000..b57a8a9109a
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c7.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c8.ogg b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c8.ogg
new file mode 100644
index 00000000000..ce4d9535e84
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_grand_piano/c8.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_harpsichord/c2.ogg b/sound/instruments/synthesis_samples/piano/crisis_harpsichord/c2.ogg
new file mode 100644
index 00000000000..bb02363fffb
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_harpsichord/c2.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_harpsichord/c3.ogg b/sound/instruments/synthesis_samples/piano/crisis_harpsichord/c3.ogg
new file mode 100644
index 00000000000..1a532ac8d42
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_harpsichord/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_harpsichord/c4.ogg b/sound/instruments/synthesis_samples/piano/crisis_harpsichord/c4.ogg
new file mode 100644
index 00000000000..16ff313baa3
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_harpsichord/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/crisis_harpsichord/c5.ogg b/sound/instruments/synthesis_samples/piano/crisis_harpsichord/c5.ogg
new file mode 100644
index 00000000000..04161d2571b
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/crisis_harpsichord/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_harpsi/C2.ogg b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C2.ogg
new file mode 100644
index 00000000000..30a3c653a1c
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C2.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_harpsi/C3.ogg b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C3.ogg
new file mode 100644
index 00000000000..f6bc891506c
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C3.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_harpsi/C4.ogg b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C4.ogg
new file mode 100644
index 00000000000..ab47f6940c9
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C4.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_harpsi/C5.ogg b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C5.ogg
new file mode 100644
index 00000000000..5dfb9aa5291
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C5.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_harpsi/C6.ogg b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C6.ogg
new file mode 100644
index 00000000000..7bc8784207e
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C6.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_harpsi/C7.ogg b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C7.ogg
new file mode 100644
index 00000000000..185b4d3db64
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C7.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_harpsi/C8.ogg b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C8.ogg
new file mode 100644
index 00000000000..f358ef0810d
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_harpsi/C8.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_piano/c2.ogg b/sound/instruments/synthesis_samples/piano/fluid_piano/c2.ogg
new file mode 100644
index 00000000000..048f9640bfe
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_piano/c2.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_piano/c3.ogg b/sound/instruments/synthesis_samples/piano/fluid_piano/c3.ogg
new file mode 100644
index 00000000000..f1083d7dcb2
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_piano/c3.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_piano/c4.ogg b/sound/instruments/synthesis_samples/piano/fluid_piano/c4.ogg
new file mode 100644
index 00000000000..244ebc3d5f2
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_piano/c4.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_piano/c5.ogg b/sound/instruments/synthesis_samples/piano/fluid_piano/c5.ogg
new file mode 100644
index 00000000000..d3c68d64e9c
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_piano/c5.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_piano/c6.ogg b/sound/instruments/synthesis_samples/piano/fluid_piano/c6.ogg
new file mode 100644
index 00000000000..2666ee66134
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_piano/c6.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_piano/c7.ogg b/sound/instruments/synthesis_samples/piano/fluid_piano/c7.ogg
new file mode 100644
index 00000000000..050e463c0d1
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_piano/c7.ogg differ
diff --git a/sound/instruments/synthesis_samples/piano/fluid_piano/c8.ogg b/sound/instruments/synthesis_samples/piano/fluid_piano/c8.ogg
new file mode 100644
index 00000000000..4793c5b7fd7
Binary files /dev/null and b/sound/instruments/synthesis_samples/piano/fluid_piano/c8.ogg differ
diff --git a/sound/instruments/synthesis_samples/tones/Sawtooth.ogg b/sound/instruments/synthesis_samples/tones/Sawtooth.ogg
new file mode 100644
index 00000000000..10b1930a64c
Binary files /dev/null and b/sound/instruments/synthesis_samples/tones/Sawtooth.ogg differ
diff --git a/sound/instruments/synthesis_samples/tones/Sine.ogg b/sound/instruments/synthesis_samples/tones/Sine.ogg
new file mode 100644
index 00000000000..96a09d501b5
Binary files /dev/null and b/sound/instruments/synthesis_samples/tones/Sine.ogg differ
diff --git a/sound/instruments/synthesis_samples/tones/Square.ogg b/sound/instruments/synthesis_samples/tones/Square.ogg
new file mode 100644
index 00000000000..71029c07f95
Binary files /dev/null and b/sound/instruments/synthesis_samples/tones/Square.ogg differ
diff --git a/sound/instruments/violin/Ab1.mid b/sound/instruments/violin/Ab1.mid
new file mode 100644
index 00000000000..b8253364b4e
Binary files /dev/null and b/sound/instruments/violin/Ab1.mid differ
diff --git a/sound/instruments/violin/Ab2.mid b/sound/instruments/violin/Ab2.mid
new file mode 100644
index 00000000000..4cd7f9b55a7
Binary files /dev/null and b/sound/instruments/violin/Ab2.mid differ
diff --git a/sound/instruments/violin/Ab3.mid b/sound/instruments/violin/Ab3.mid
new file mode 100644
index 00000000000..e827cfc635e
Binary files /dev/null and b/sound/instruments/violin/Ab3.mid differ
diff --git a/sound/instruments/violin/Ab4.mid b/sound/instruments/violin/Ab4.mid
new file mode 100644
index 00000000000..57e1f76c976
Binary files /dev/null and b/sound/instruments/violin/Ab4.mid differ
diff --git a/sound/instruments/violin/Ab5.mid b/sound/instruments/violin/Ab5.mid
new file mode 100644
index 00000000000..59e95a6d997
Binary files /dev/null and b/sound/instruments/violin/Ab5.mid differ
diff --git a/sound/instruments/violin/Ab6.mid b/sound/instruments/violin/Ab6.mid
new file mode 100644
index 00000000000..9bd3436287b
Binary files /dev/null and b/sound/instruments/violin/Ab6.mid differ
diff --git a/sound/instruments/violin/Ab7.mid b/sound/instruments/violin/Ab7.mid
new file mode 100644
index 00000000000..3c90af807e2
Binary files /dev/null and b/sound/instruments/violin/Ab7.mid differ
diff --git a/sound/instruments/violin/Ab8.mid b/sound/instruments/violin/Ab8.mid
new file mode 100644
index 00000000000..873d771f2ae
Binary files /dev/null and b/sound/instruments/violin/Ab8.mid differ
diff --git a/sound/instruments/violin/An1.mid b/sound/instruments/violin/An1.mid
new file mode 100644
index 00000000000..d7f8a001d93
Binary files /dev/null and b/sound/instruments/violin/An1.mid differ
diff --git a/sound/instruments/violin/An2.mid b/sound/instruments/violin/An2.mid
new file mode 100644
index 00000000000..2f01800a075
Binary files /dev/null and b/sound/instruments/violin/An2.mid differ
diff --git a/sound/instruments/violin/An3.mid b/sound/instruments/violin/An3.mid
new file mode 100644
index 00000000000..c8ed3cdfa6c
Binary files /dev/null and b/sound/instruments/violin/An3.mid differ
diff --git a/sound/instruments/violin/An4.mid b/sound/instruments/violin/An4.mid
new file mode 100644
index 00000000000..e7984ca7e62
Binary files /dev/null and b/sound/instruments/violin/An4.mid differ
diff --git a/sound/instruments/violin/An5.mid b/sound/instruments/violin/An5.mid
new file mode 100644
index 00000000000..e1fd228f7a9
Binary files /dev/null and b/sound/instruments/violin/An5.mid differ
diff --git a/sound/instruments/violin/An6.mid b/sound/instruments/violin/An6.mid
new file mode 100644
index 00000000000..1c8df6c98e5
Binary files /dev/null and b/sound/instruments/violin/An6.mid differ
diff --git a/sound/instruments/violin/An7.mid b/sound/instruments/violin/An7.mid
new file mode 100644
index 00000000000..2784428daf9
Binary files /dev/null and b/sound/instruments/violin/An7.mid differ
diff --git a/sound/instruments/violin/An8.mid b/sound/instruments/violin/An8.mid
new file mode 100644
index 00000000000..2db2ab70a7d
Binary files /dev/null and b/sound/instruments/violin/An8.mid differ
diff --git a/sound/instruments/violin/Bb1.mid b/sound/instruments/violin/Bb1.mid
new file mode 100644
index 00000000000..693b73f5420
Binary files /dev/null and b/sound/instruments/violin/Bb1.mid differ
diff --git a/sound/instruments/violin/Bb2.mid b/sound/instruments/violin/Bb2.mid
new file mode 100644
index 00000000000..40da5f3da15
Binary files /dev/null and b/sound/instruments/violin/Bb2.mid differ
diff --git a/sound/instruments/violin/Bb3.mid b/sound/instruments/violin/Bb3.mid
new file mode 100644
index 00000000000..5bab6ccd636
Binary files /dev/null and b/sound/instruments/violin/Bb3.mid differ
diff --git a/sound/instruments/violin/Bb4.mid b/sound/instruments/violin/Bb4.mid
new file mode 100644
index 00000000000..dce830448ef
Binary files /dev/null and b/sound/instruments/violin/Bb4.mid differ
diff --git a/sound/instruments/violin/Bb5.mid b/sound/instruments/violin/Bb5.mid
new file mode 100644
index 00000000000..fda796e27b9
Binary files /dev/null and b/sound/instruments/violin/Bb5.mid differ
diff --git a/sound/instruments/violin/Bb6.mid b/sound/instruments/violin/Bb6.mid
new file mode 100644
index 00000000000..9e5da684f43
Binary files /dev/null and b/sound/instruments/violin/Bb6.mid differ
diff --git a/sound/instruments/violin/Bb7.mid b/sound/instruments/violin/Bb7.mid
new file mode 100644
index 00000000000..215c56cbe7e
Binary files /dev/null and b/sound/instruments/violin/Bb7.mid differ
diff --git a/sound/instruments/violin/Bb8.mid b/sound/instruments/violin/Bb8.mid
new file mode 100644
index 00000000000..4b55c34691f
Binary files /dev/null and b/sound/instruments/violin/Bb8.mid differ
diff --git a/sound/instruments/violin/Bn1.mid b/sound/instruments/violin/Bn1.mid
new file mode 100644
index 00000000000..27968b5f9e7
Binary files /dev/null and b/sound/instruments/violin/Bn1.mid differ
diff --git a/sound/instruments/violin/Bn2.mid b/sound/instruments/violin/Bn2.mid
new file mode 100644
index 00000000000..54c9b99d03f
Binary files /dev/null and b/sound/instruments/violin/Bn2.mid differ
diff --git a/sound/instruments/violin/Bn3.mid b/sound/instruments/violin/Bn3.mid
new file mode 100644
index 00000000000..f73476fb7bb
Binary files /dev/null and b/sound/instruments/violin/Bn3.mid differ
diff --git a/sound/instruments/violin/Bn4.mid b/sound/instruments/violin/Bn4.mid
new file mode 100644
index 00000000000..2aa30708a6c
Binary files /dev/null and b/sound/instruments/violin/Bn4.mid differ
diff --git a/sound/instruments/violin/Bn5.mid b/sound/instruments/violin/Bn5.mid
new file mode 100644
index 00000000000..0ebe636b714
Binary files /dev/null and b/sound/instruments/violin/Bn5.mid differ
diff --git a/sound/instruments/violin/Bn6.mid b/sound/instruments/violin/Bn6.mid
new file mode 100644
index 00000000000..3b8e1c217f7
Binary files /dev/null and b/sound/instruments/violin/Bn6.mid differ
diff --git a/sound/instruments/violin/Bn7.mid b/sound/instruments/violin/Bn7.mid
new file mode 100644
index 00000000000..afcb1982a13
Binary files /dev/null and b/sound/instruments/violin/Bn7.mid differ
diff --git a/sound/instruments/violin/Bn8.mid b/sound/instruments/violin/Bn8.mid
new file mode 100644
index 00000000000..3afd469256c
Binary files /dev/null and b/sound/instruments/violin/Bn8.mid differ
diff --git a/sound/instruments/violin/Cn1.mid b/sound/instruments/violin/Cn1.mid
new file mode 100644
index 00000000000..857120f31f4
Binary files /dev/null and b/sound/instruments/violin/Cn1.mid differ
diff --git a/sound/instruments/violin/Cn2.mid b/sound/instruments/violin/Cn2.mid
new file mode 100644
index 00000000000..3ccd6670e87
Binary files /dev/null and b/sound/instruments/violin/Cn2.mid differ
diff --git a/sound/instruments/violin/Cn3.mid b/sound/instruments/violin/Cn3.mid
new file mode 100644
index 00000000000..1851e4f8d27
Binary files /dev/null and b/sound/instruments/violin/Cn3.mid differ
diff --git a/sound/instruments/violin/Cn4.mid b/sound/instruments/violin/Cn4.mid
new file mode 100644
index 00000000000..65e8b0efe4e
Binary files /dev/null and b/sound/instruments/violin/Cn4.mid differ
diff --git a/sound/instruments/violin/Cn5.mid b/sound/instruments/violin/Cn5.mid
new file mode 100644
index 00000000000..544f921e43b
Binary files /dev/null and b/sound/instruments/violin/Cn5.mid differ
diff --git a/sound/instruments/violin/Cn6.mid b/sound/instruments/violin/Cn6.mid
new file mode 100644
index 00000000000..7c78dab2f07
Binary files /dev/null and b/sound/instruments/violin/Cn6.mid differ
diff --git a/sound/instruments/violin/Cn7.mid b/sound/instruments/violin/Cn7.mid
new file mode 100644
index 00000000000..3abe4cde086
Binary files /dev/null and b/sound/instruments/violin/Cn7.mid differ
diff --git a/sound/instruments/violin/Cn8.mid b/sound/instruments/violin/Cn8.mid
new file mode 100644
index 00000000000..06f14081b3b
Binary files /dev/null and b/sound/instruments/violin/Cn8.mid differ
diff --git a/sound/instruments/violin/Cn9.mid b/sound/instruments/violin/Cn9.mid
new file mode 100644
index 00000000000..62f4eef045a
Binary files /dev/null and b/sound/instruments/violin/Cn9.mid differ
diff --git a/sound/instruments/violin/Db1.mid b/sound/instruments/violin/Db1.mid
new file mode 100644
index 00000000000..88dba851452
Binary files /dev/null and b/sound/instruments/violin/Db1.mid differ
diff --git a/sound/instruments/violin/Db2.mid b/sound/instruments/violin/Db2.mid
new file mode 100644
index 00000000000..b510926b45f
Binary files /dev/null and b/sound/instruments/violin/Db2.mid differ
diff --git a/sound/instruments/violin/Db3.mid b/sound/instruments/violin/Db3.mid
new file mode 100644
index 00000000000..9954bbe478a
Binary files /dev/null and b/sound/instruments/violin/Db3.mid differ
diff --git a/sound/instruments/violin/Db4.mid b/sound/instruments/violin/Db4.mid
new file mode 100644
index 00000000000..2c5ff74db0a
Binary files /dev/null and b/sound/instruments/violin/Db4.mid differ
diff --git a/sound/instruments/violin/Db5.mid b/sound/instruments/violin/Db5.mid
new file mode 100644
index 00000000000..e5850a3fd04
Binary files /dev/null and b/sound/instruments/violin/Db5.mid differ
diff --git a/sound/instruments/violin/Db6.mid b/sound/instruments/violin/Db6.mid
new file mode 100644
index 00000000000..217c0ad014c
Binary files /dev/null and b/sound/instruments/violin/Db6.mid differ
diff --git a/sound/instruments/violin/Db7.mid b/sound/instruments/violin/Db7.mid
new file mode 100644
index 00000000000..ec32bdbf904
Binary files /dev/null and b/sound/instruments/violin/Db7.mid differ
diff --git a/sound/instruments/violin/Db8.mid b/sound/instruments/violin/Db8.mid
new file mode 100644
index 00000000000..555bce3db0d
Binary files /dev/null and b/sound/instruments/violin/Db8.mid differ
diff --git a/sound/instruments/violin/Dn1.mid b/sound/instruments/violin/Dn1.mid
new file mode 100644
index 00000000000..92e4e0d9581
Binary files /dev/null and b/sound/instruments/violin/Dn1.mid differ
diff --git a/sound/instruments/violin/Dn2.mid b/sound/instruments/violin/Dn2.mid
new file mode 100644
index 00000000000..34eb9d1db1b
Binary files /dev/null and b/sound/instruments/violin/Dn2.mid differ
diff --git a/sound/instruments/violin/Dn3.mid b/sound/instruments/violin/Dn3.mid
new file mode 100644
index 00000000000..fbd56085aaf
Binary files /dev/null and b/sound/instruments/violin/Dn3.mid differ
diff --git a/sound/instruments/violin/Dn4.mid b/sound/instruments/violin/Dn4.mid
new file mode 100644
index 00000000000..e13c7448292
Binary files /dev/null and b/sound/instruments/violin/Dn4.mid differ
diff --git a/sound/instruments/violin/Dn5.mid b/sound/instruments/violin/Dn5.mid
new file mode 100644
index 00000000000..8fd41e5c6fe
Binary files /dev/null and b/sound/instruments/violin/Dn5.mid differ
diff --git a/sound/instruments/violin/Dn6.mid b/sound/instruments/violin/Dn6.mid
new file mode 100644
index 00000000000..d47329e8f9e
Binary files /dev/null and b/sound/instruments/violin/Dn6.mid differ
diff --git a/sound/instruments/violin/Dn7.mid b/sound/instruments/violin/Dn7.mid
new file mode 100644
index 00000000000..b2496603876
Binary files /dev/null and b/sound/instruments/violin/Dn7.mid differ
diff --git a/sound/instruments/violin/Dn8.mid b/sound/instruments/violin/Dn8.mid
new file mode 100644
index 00000000000..56667a1a86d
Binary files /dev/null and b/sound/instruments/violin/Dn8.mid differ
diff --git a/sound/instruments/violin/Eb1.mid b/sound/instruments/violin/Eb1.mid
new file mode 100644
index 00000000000..829e6fcf185
Binary files /dev/null and b/sound/instruments/violin/Eb1.mid differ
diff --git a/sound/instruments/violin/Eb2.mid b/sound/instruments/violin/Eb2.mid
new file mode 100644
index 00000000000..66029b340cc
Binary files /dev/null and b/sound/instruments/violin/Eb2.mid differ
diff --git a/sound/instruments/violin/Eb3.mid b/sound/instruments/violin/Eb3.mid
new file mode 100644
index 00000000000..c982375941e
Binary files /dev/null and b/sound/instruments/violin/Eb3.mid differ
diff --git a/sound/instruments/violin/Eb4.mid b/sound/instruments/violin/Eb4.mid
new file mode 100644
index 00000000000..016ed4f1edf
Binary files /dev/null and b/sound/instruments/violin/Eb4.mid differ
diff --git a/sound/instruments/violin/Eb5.mid b/sound/instruments/violin/Eb5.mid
new file mode 100644
index 00000000000..ddb511795df
Binary files /dev/null and b/sound/instruments/violin/Eb5.mid differ
diff --git a/sound/instruments/violin/Eb6.mid b/sound/instruments/violin/Eb6.mid
new file mode 100644
index 00000000000..b7242b9ab99
Binary files /dev/null and b/sound/instruments/violin/Eb6.mid differ
diff --git a/sound/instruments/violin/Eb7.mid b/sound/instruments/violin/Eb7.mid
new file mode 100644
index 00000000000..773538340a5
Binary files /dev/null and b/sound/instruments/violin/Eb7.mid differ
diff --git a/sound/instruments/violin/Eb8.mid b/sound/instruments/violin/Eb8.mid
new file mode 100644
index 00000000000..4ad074e173b
Binary files /dev/null and b/sound/instruments/violin/Eb8.mid differ
diff --git a/sound/instruments/violin/En1.mid b/sound/instruments/violin/En1.mid
new file mode 100644
index 00000000000..79ab68df9df
Binary files /dev/null and b/sound/instruments/violin/En1.mid differ
diff --git a/sound/instruments/violin/En2.mid b/sound/instruments/violin/En2.mid
new file mode 100644
index 00000000000..cd61c8d0de5
Binary files /dev/null and b/sound/instruments/violin/En2.mid differ
diff --git a/sound/instruments/violin/En3.mid b/sound/instruments/violin/En3.mid
new file mode 100644
index 00000000000..da5b703d545
Binary files /dev/null and b/sound/instruments/violin/En3.mid differ
diff --git a/sound/instruments/violin/En4.mid b/sound/instruments/violin/En4.mid
new file mode 100644
index 00000000000..f7d3af024ff
Binary files /dev/null and b/sound/instruments/violin/En4.mid differ
diff --git a/sound/instruments/violin/En5.mid b/sound/instruments/violin/En5.mid
new file mode 100644
index 00000000000..d3d353943f9
Binary files /dev/null and b/sound/instruments/violin/En5.mid differ
diff --git a/sound/instruments/violin/En6.mid b/sound/instruments/violin/En6.mid
new file mode 100644
index 00000000000..73eb5b0697d
Binary files /dev/null and b/sound/instruments/violin/En6.mid differ
diff --git a/sound/instruments/violin/En7.mid b/sound/instruments/violin/En7.mid
new file mode 100644
index 00000000000..79a9462c844
Binary files /dev/null and b/sound/instruments/violin/En7.mid differ
diff --git a/sound/instruments/violin/En8.mid b/sound/instruments/violin/En8.mid
new file mode 100644
index 00000000000..88947fc7318
Binary files /dev/null and b/sound/instruments/violin/En8.mid differ
diff --git a/sound/instruments/violin/Fn1.mid b/sound/instruments/violin/Fn1.mid
new file mode 100644
index 00000000000..abe0d4e4051
Binary files /dev/null and b/sound/instruments/violin/Fn1.mid differ
diff --git a/sound/instruments/violin/Fn2.mid b/sound/instruments/violin/Fn2.mid
new file mode 100644
index 00000000000..d245bef3b54
Binary files /dev/null and b/sound/instruments/violin/Fn2.mid differ
diff --git a/sound/instruments/violin/Fn3.mid b/sound/instruments/violin/Fn3.mid
new file mode 100644
index 00000000000..e532e30dac9
Binary files /dev/null and b/sound/instruments/violin/Fn3.mid differ
diff --git a/sound/instruments/violin/Fn4.mid b/sound/instruments/violin/Fn4.mid
new file mode 100644
index 00000000000..47219c72fa2
Binary files /dev/null and b/sound/instruments/violin/Fn4.mid differ
diff --git a/sound/instruments/violin/Fn5.mid b/sound/instruments/violin/Fn5.mid
new file mode 100644
index 00000000000..630d16371d9
Binary files /dev/null and b/sound/instruments/violin/Fn5.mid differ
diff --git a/sound/instruments/violin/Fn6.mid b/sound/instruments/violin/Fn6.mid
new file mode 100644
index 00000000000..08cbc981bdb
Binary files /dev/null and b/sound/instruments/violin/Fn6.mid differ
diff --git a/sound/instruments/violin/Fn7.mid b/sound/instruments/violin/Fn7.mid
new file mode 100644
index 00000000000..6c28c7d272e
Binary files /dev/null and b/sound/instruments/violin/Fn7.mid differ
diff --git a/sound/instruments/violin/Fn8.mid b/sound/instruments/violin/Fn8.mid
new file mode 100644
index 00000000000..2d73762f269
Binary files /dev/null and b/sound/instruments/violin/Fn8.mid differ
diff --git a/sound/instruments/violin/Gb1.mid b/sound/instruments/violin/Gb1.mid
new file mode 100644
index 00000000000..d18668e8911
Binary files /dev/null and b/sound/instruments/violin/Gb1.mid differ
diff --git a/sound/instruments/violin/Gb2.mid b/sound/instruments/violin/Gb2.mid
new file mode 100644
index 00000000000..302f0c6fdc1
Binary files /dev/null and b/sound/instruments/violin/Gb2.mid differ
diff --git a/sound/instruments/violin/Gb3.mid b/sound/instruments/violin/Gb3.mid
new file mode 100644
index 00000000000..1f592fc9039
Binary files /dev/null and b/sound/instruments/violin/Gb3.mid differ
diff --git a/sound/instruments/violin/Gb4.mid b/sound/instruments/violin/Gb4.mid
new file mode 100644
index 00000000000..45854126f98
Binary files /dev/null and b/sound/instruments/violin/Gb4.mid differ
diff --git a/sound/instruments/violin/Gb5.mid b/sound/instruments/violin/Gb5.mid
new file mode 100644
index 00000000000..fb1e1da339a
Binary files /dev/null and b/sound/instruments/violin/Gb5.mid differ
diff --git a/sound/instruments/violin/Gb6.mid b/sound/instruments/violin/Gb6.mid
new file mode 100644
index 00000000000..bfa896bb784
Binary files /dev/null and b/sound/instruments/violin/Gb6.mid differ
diff --git a/sound/instruments/violin/Gb7.mid b/sound/instruments/violin/Gb7.mid
new file mode 100644
index 00000000000..a27763c1d47
Binary files /dev/null and b/sound/instruments/violin/Gb7.mid differ
diff --git a/sound/instruments/violin/Gb8.mid b/sound/instruments/violin/Gb8.mid
new file mode 100644
index 00000000000..aaab80a7276
Binary files /dev/null and b/sound/instruments/violin/Gb8.mid differ
diff --git a/sound/instruments/violin/Gn1.mid b/sound/instruments/violin/Gn1.mid
new file mode 100644
index 00000000000..1df52ab0760
Binary files /dev/null and b/sound/instruments/violin/Gn1.mid differ
diff --git a/sound/instruments/violin/Gn2.mid b/sound/instruments/violin/Gn2.mid
new file mode 100644
index 00000000000..6e0ca383127
Binary files /dev/null and b/sound/instruments/violin/Gn2.mid differ
diff --git a/sound/instruments/violin/Gn3.mid b/sound/instruments/violin/Gn3.mid
new file mode 100644
index 00000000000..bb3e6dedcbf
Binary files /dev/null and b/sound/instruments/violin/Gn3.mid differ
diff --git a/sound/instruments/violin/Gn4.mid b/sound/instruments/violin/Gn4.mid
new file mode 100644
index 00000000000..0c46432afee
Binary files /dev/null and b/sound/instruments/violin/Gn4.mid differ
diff --git a/sound/instruments/violin/Gn5.mid b/sound/instruments/violin/Gn5.mid
new file mode 100644
index 00000000000..f39dcf5e2b9
Binary files /dev/null and b/sound/instruments/violin/Gn5.mid differ
diff --git a/sound/instruments/violin/Gn6.mid b/sound/instruments/violin/Gn6.mid
new file mode 100644
index 00000000000..0efa2259ca1
Binary files /dev/null and b/sound/instruments/violin/Gn6.mid differ
diff --git a/sound/instruments/violin/Gn7.mid b/sound/instruments/violin/Gn7.mid
new file mode 100644
index 00000000000..22fd1b6bcb0
Binary files /dev/null and b/sound/instruments/violin/Gn7.mid differ
diff --git a/sound/instruments/violin/Gn8.mid b/sound/instruments/violin/Gn8.mid
new file mode 100644
index 00000000000..16b7171d627
Binary files /dev/null and b/sound/instruments/violin/Gn8.mid differ
diff --git a/sound/machines/machine_vend.ogg b/sound/machines/machine_vend.ogg
new file mode 100644
index 00000000000..92867a1f3d3
Binary files /dev/null and b/sound/machines/machine_vend.ogg differ
diff --git a/sound/music/thunderdome.ogg b/sound/music/thunderdome.ogg
index 26b18df5e05..82780e416d4 100644
Binary files a/sound/music/thunderdome.ogg and b/sound/music/thunderdome.ogg differ
diff --git a/sound/weapons/banjoslap.ogg b/sound/weapons/banjoslap.ogg
new file mode 100644
index 00000000000..06a86a535dd
Binary files /dev/null and b/sound/weapons/banjoslap.ogg differ
diff --git a/sound/weapons/guitarslam.ogg b/sound/weapons/guitarslam.ogg
new file mode 100644
index 00000000000..4fa53db9404
Binary files /dev/null and b/sound/weapons/guitarslam.ogg differ
diff --git a/strings/tips.txt b/strings/tips.txt
index b2df1c17482..4218e01bbfe 100644
--- a/strings/tips.txt
+++ b/strings/tips.txt
@@ -1,4 +1,4 @@
-Where the space map levels connect is randomized every round, but are otherwise kept consistent within rounds.
+Space map levels' connections are randomized between rounds, but are otherwise kept consistent in the same round.
You can catch thrown items by toggling on your throw mode with an empty hand active.
To crack the safe in the vault, use a stethoscope or thermal drill.
You can climb onto a table by dragging yourself onto one. This takes some time. Clicking on a table that someone else is climbing onto will knock them down.
@@ -9,8 +9,8 @@ You can change the control scheme by pressing tab. One uses WASD for movement, w
Firesuits and winter coats offer mild protection from the cold, allowing you to spend longer periods of time near breaches and space than if wearing nothing at all.
Glass shards can be welded to make glass, and metal rods can be welded to make metal. Ores can be welded too, but this takes a lot of fuel.
If you need to drag multiple people either to safety or to space, bring a locker over and stuff them all in before hauling them off.
-You can grab someone by clicking on them with the grab intent, then upgrade the grab by clicking on them once more. An aggressive grab will momentarily stun someone, allow you to place them on a table by clicking on it, or throw them by toggling on throwing.
-Holding alt and left clicking a tile will allow you to see its contents in the top right window pane, which is much faster than right clicking.
+You can grab someone by clicking on them with the grab intent, then upgrade the grab by clicking on the grab itself. An aggressive grab will allow you to place them on a table by clicking on it, or throw them by toggling on throwing.
+Holding alt and left clicking a tile will allow you to see its contents in the top right window panel, which is much faster than right clicking.
The resist button will allow you to resist out of handcuffs, being buckled to a chair or bed, out of locked lockers and more. Whenever you're stuck, try resisting!
You can move an item out of the way by dragging it and then clicking on an adjacent tile with an empty hand.
You can recolor certain items like jumpsuits and gloves in washing machines by also throwing in a crayon.
@@ -21,7 +21,7 @@ When in doubt about technicial issues, clear your cache (byond launcher > cogwhe
Most things have special interactions with your middle mouse button, alt, shift, and control click. Experiment!
If you find yourself in a fistfight with another player, running away and calling for help is a perfectly viable option.
Different weapons have different strengths. Some weapons, such as spears, floor tiles, and throwing stars, deal more damage when thrown compared to when attacked normally.
-A thrown glass of water can make a slippery tile, allowing you to slow down your pursuers in a pinch.
+Clicking on a tile on harm intent with a glass of water can make a slippery tile, allowing you to slow down your pursuers in a pinch.
When dealing with security, you can often get your sentence negated entirely through cooperation and deception.
The P2P chat function found on tablet computers allows for a stealthy way to communicate with people.
We were all new once, be patient and guide new players in the right direction.
@@ -36,8 +36,8 @@ As the Captain, you have absolute access and control over the station, but this
As the Chief Medical Officer, your hypospray is like a refillable instant injection syringe that can hold 30 units and the unlike standard hypospray, yours is able to be filled with harmful reagents and injects without telling anyone what have you exactly injected the person with.
As the Chief Medical Officer, coordinate and communicate with your doctors, chemists, and geneticists during a nuclear emergency, blob infestation, or some other crisis to keep people alive and fighting.
As a Medical Doctor, you can surgically implant or extract things from people's chests. This can range from putting in a bomb to pulling out an alien larva.
-As a Medical Doctor, you must target the correct limb and be on help intent when trying to perform surgery on someone. Using disarm intent will intentionally fail the surgery step.
-As a Medical Doctor, corpses with the "...and their soul has departed" description no longer have a ghost attached to them and aren't revivable or clonable.
+As a Medical Doctor, you must target the correct limb and be on help intent when trying to perform surgery on someone.
+As a Medical Doctor, corpses with the "...and their soul has departed" description no longer have a ghost attached to them and aren't revivable or clonable right now, but they might be clonable later.
As a Medical Doctor, treating plasmamen is not impossible! Salbutamol stops them from suffocating and showers stop them from burning alive. You can even perform surgery on them by doing the procedure on a roller bed under a shower.
As a Chemist, there are dozens of chemicals that can heal, and even more that can cause harm. Experiment!
As a Chemist, some chemicals can only be synthesized by heating up the contents with a chemical heater or manually with lighters and similar tools.
@@ -50,7 +50,7 @@ As the Research Director, you can take AIs out of their cores by loading them in
As the Research Director, you can lock down cyborgs instead of blowing them up. Then you can have their laws reset or if that doesn't work, safely dismantled.
As the Research Director, you can spy on and even forge PDA communications with the message monitor console! The key is in your office.
As a Scientist, you can maximize the number of uses you get out of a slime by feeding it slime steroid, created from purple slimes, while alive. You can then apply extract enhancer, created from cerulean slimes, on each extract.
-As a Scientist, you can disable anomalies by scanning them with an analyzer, then send a signal on the frequency it gives you with a remote signaling device, or if researched, hit the anomaly with an anomaly analyzer. This will leave behind an anomaly core, which can be used to construct a Phazon mech or reactive armors!
+As a Scientist, you can disable anomalies by scanning them with an analyzer, then send a signal on the frequency it gives you with a remote signaling device. This will leave behind an anomaly core, which can be used to construct a Phazon mech!
As a Scientist, researchable stock parts can seriously improve the efficiency and speed of machines around the station. In some cases, it can even unlock new functions.
As a Roboticist, keep an ear out for anomaly announcements. If you get your hands on an anomaly core, you can build a Phazon mech!
As a Roboticist, you can repair your cyborgs with a welding tool. If they have taken burn damage, you can remove their battery, expose the wiring with a screwdriver and replace their wires with a cable coil.
@@ -59,12 +59,12 @@ As a Roboticist, you can augment people with cyborg limbs. Augmented limbs can e
As the AI, you can click on people's names to look at them. This only works if there are cameras that can see them, they aren't wearing agent IDs, or aren't using digital camouflage as changelings.
As the AI, you can quickly open and close doors by holding shift while clicking them, bolt them when holding ctrl, and even shock them while holding alt.
As the AI, you can take pictures with your camera and upload them to newscasters.
-As a Cyborg, choose your module carefully, as only cutting and mending your reset wire or using a cyborg reset module will let you repick it. If possible, refrain from choosing a module until a situation that requires one occurs.
+As a Cyborg, choose your module carefully, as only a cyborg reset module will let you repick it.
As a Cyborg, you are immune to most forms of stunning, and excel at almost everything far better than humans. However, flashes can easily stunlock you and you cannot do any precision work as you lack hands.
As a Cyborg, you are impervious to fires and heat. If you are rogue, you can release plasma fires everywhere and walk through them without a care in the world!
As a Cyborg, you are extremely vulnerable to EMPs as EMPs both stun you and damage you. The ion rifle in the armory or a traitor with an EMP kit can kill you in seconds.
-As an Engineering Cyborg, you can attach air alarm/fire alarm/APC frames to walls by placing them on the floor and using a screwdriver on them.
-As a Medical Cyborg, you can fully perform surgery and even augment people.
+As an Engineering Cyborg, you can attach air alarm/fire alarm/APC frames to walls by using your magnetic gripper.
+As a Medical Cyborg, you can partially perform surgery, as you cannot replace organs, but you cannot fail any surgery steps.
As a Janitor Cyborg, you are the bane of all slaughter demons. Cleaning up blood stains will severely gimp them.
As the Chief Engineer, you can rename areas or create entirely new ones using your station blueprints.
As the Chief Engineer, your hardsuit is significantly better than everybody else's. It has the best features of both engineering and atmospherics hardsuits, boasting nigh-invulnerability to radiation and all atmospheric conditions.
@@ -73,10 +73,10 @@ As an Engineer, you can electrify grilles by placing wire "nodes" beneath them:
As an Engineer, return to Engineering once in a while to check on the engine and SMES cells. It's always a good idea to make sure containment isn't compromised.
As an Engineer, you can power the station solely with the solar arrays. They will provide just enough electricity to power the station, however their output is still much worse compared to the true engine.
As an Engineer, you can cool a supermatter shard by spraying it with a fire extinguisher. Only for the brave!
-As an Engineer, you can repair windows by using a welding tool on them while on any intent other than harm.
+As an Engineer, you can repair windows by using a welding tool on them while on help intent.
As an Engineer, you can lock APCs, fire alarms, emitters, and radiation collectors using your ID card to prevent others from disabling them.
As an Engineer, don't underestimate the humble P.A.C.M.A.N. generators. With upgraded parts, a couple units working in tandem are sufficient to take over for an exploded engine or shattered solars.
-As an Engineer, you can pry open secure storage blast doors by disabling the engine room APC's main breaker. This is obviously a bad idea if the engine is running.
+As an Engineer, you can pry open secure storage blast doors by turning off the secure storage APC's enviroment power channel.
As an Atmospheric Technician, look into replacing your gas pumps with volumetric gas pumps, as those move air in flat numerical amounts, rather than percentages which leave trace gases.
As an Atmospheric Technician, you are better suited to fighting fires than anyone else. As such, you have access to better firesuits, backpack firefighter tanks, and a completely heat and fire proof hardsuit.
As an Atmospheric Technician, your backpack firefighter tank can launch cryofrost. This resin will extinguish fires and very quickly; it's ideal for plasma fires!
@@ -88,7 +88,7 @@ As the Warden, keep a close eye on the armory at all times, as it is a favored s
As the Warden, if a prisoner's crimes are heinous enough you can put them in permabrig or the gulag. Make sure to check on them once in a while!
As the Warden, you can implant criminals you suspect might re-offend with devices that will track their location and allow you to remotely inject them with disabling chemicals.
As a Security Officer, communicate and coordinate with your fellow officers using the security channel (:s) to avoid confusion.
-As a Security Officer, your sechuds or HUDsunglasses can not only see crewmates' job assignments and criminal status, but also if they are mindshield implanted. You can tell by the flashing blue outline around their job icon.
+As a Security Officer, your sechuds or HUDsunglasses let you see crewmates' job assignments, their criminal status, and whether they have a mindshield or not. A flashing green border around their job icon means they are mindshielded.
As a Security Officer, mindshield implants can only prevent someone from being turned into a cultist. It will not de-cult them if they have already been converted.
As a Security Officer, examining someone while wearing sechuds or HUDsunglasses will let you set their arrest level, which will cause Beepsky and other security bots to chase after them.
As the Detective, keep in mind that people leave fingerprints everywhere and on everything. With the exception of white latex, gloves will hide them. All is not lost, however, as gloves leave fibers specific to their kind such as black or nitrile, pointing to a general department.
@@ -111,7 +111,7 @@ As the Chaplain, you are much more likely to get a response by praying to the go
As a Botanist, you can hack the MegaSeed Vendor to get access to more exotic seeds. These seeds can alternatively be ordered from cargo.
As a Botanist, you can mutate the plants growing in your hydroponics trays with unstable mutagen or, as an alternative, crude radioactives from chemistry to get special variations.
As a Botanist, you should look into increasing the potency of your plants. This increases the size, amount of chemicals, points gained from grinding them in the biogenerator, and lets people know you are a proficient botanist.
-As a Botanist, you can combine production trait chemicals just like a Chemist. Chlorine (blumpkin) + radium and phosphorus (glowshrooms) equals unstable mutagen!
+As a Botanist, you can combine production trait chemicals just like a Chemist. Chlorine and plasma (blumpkin) + radium (glowshrooms) equals unstable mutagen!
As the Chef, you can create a very wide variety of food with the crafting menu. You can find it by looking for the hammer icon near your intents.
As the Chef, you can rename your custom made food with a pen.
As the Chef, if you are low on ingredients, consider making something that has several servings to last longer among the crew.
@@ -121,8 +121,8 @@ As a Janitor, mousetraps can be used to create bombs or booby-trap containers.
As the Librarian, be sure to keep the shelves stocked and the library clean for crew.
As a Cargo Technician, you can hack MULEbots to make them faster, run over people in their way, and even let you ride them!
As a Cargo Technician, you can order contraband items from the supply shuttle console by de-constructing it and using a multitool on the circuit board, the re-assembling it.
-As a Cargo Technician, you can earn more cargo points by shipping back crates from maintenance, liquid containers, plasma sheets, rare seeds from hydroponics, and more!
-As a Shaft Miner, the western side of the Asteroid has a lot more rare minerals than on the east, but is a lot more dangerous.
+As a Cargo Technician, you can earn more cargo points by shipping back crates from maintenance, plasma sheets, rare seeds from hydroponics, technology disks from R&D, and more!
+As a Shaft Miner, the north side of Lavaland has a lot more rare minerals than on the south, but is a lot more dangerous.
As a Shaft Miner, always have a GPS on you, so a fellow miner or cyborg can come to save you if you die.
As a Traitor, the cryptographic sequencer (emag) can not only open doors, but also lockers, crates, APCs and more. It can hack cyborgs, and even cause bots to go berserk. Use it on the right machines, and you can even order more traitor gear or contact the Syndicate. Experiment!
As a Traitor, subverting the AI to serve you can make it an extremely powerful ally. However, be careful of the wording in the laws you give it, as it may use your poorly written laws against you!
@@ -130,14 +130,14 @@ As a Traitor, the Captain and the Head of Security are two of the most difficult
As a Traitor, you can manufacture and recycle revolver bullets at a hacked autolathe, making the revolver an extremely powerful tool.
As a Traitor, you may sometimes be assigned to hunt other traitors, and in turn be hunted by others.
As a Traitor, the syndicate encryption key is very useful for coordinating plans with your fellow traitors -- or, of course, betraying them.
-As a Traitor, plasma can be injected into many things to sabotage them. Power cells, light bulbs, welding tools, cigars and e-cigs will all explode when used.
+As a Traitor, plasma can be injected into many things to sabotage them. Power cells, light bulbs, cigars and e-cigs will all explode when used.
As a Traitor, if you can find another Traitor and pool your TC you can buy a mega surplus crate, which costs 40TC but contains a lot of random syndicate gear.
As a Nuclear Operative, communication is key! Use ; to speak to your fellow operatives and coordinate an attack plan.
As a Nuclear Operative, you should look into purchasing a syndicate cyborg, as they can provide heavy fire support, full access, are immune to conventional stuns, and can easily take down the AI.
As a Nuclear Operative, stick together! While your equipment is robust, your fellow operatives are much better at saving your life: they can drag you away from danger while stunned and provide cover fire.
As a Nuclear Operative, you might end up in a situation where the AI has bolted you into a room. Having some spare C4 in your pocket can save your life.
As a Monkey, you can still wear a few human items, such as backpacks, gas masks, and hats, and still have two free hands.
-As the Malfunctioning AI, you can shunt to an APC if the situation gets bad. This disables your doomsday device if it is active.
+As the Malfunctioning AI, you can shunt to an APC if the situation gets bad.
As the Malfunctioning AI, you should either order your cyborgs to dismantle the robotics console or blow it up yourself in order to protect them.
As an Alien, your melee prowess is unmatched, but your ranged abilities are sorely lacking. Make use of corners to force a melee confrontation!
As an Alien, you take double damage from all burn attacks, such as lasers, welding tools, and fires. Furthermore, fire can destroy your resin and eggs. Expose areas to space to starve away any flamethrower fires before they can do damage!
@@ -155,11 +155,10 @@ As a Changeling, the Extract DNA sting counts for your genome absorb objective,
As a Changeling, you can absorb someone by strangling them and using the Absorb verb; this gives you the ability to rechoose your powers, the DNA of whoever you absorbed, the memory of the absorbed, and some samples of things the absorbed said.
As a Cultist, do not cause too much chaos before your objective is completed. If the shuttle gets called too soon, you may not have enough time to win.
As a Cultist, your team starts off very weak, but if necessary can quickly convert everything they have into raw power. Make sure you have the numbers and equipment to support going loud, or the cult will fall flat on its face.
-As a Cultist, the Blood Boil rune will deal massive amounts of brute damage to non-cultists, and some damage to fellow cultists of Nar'Sie nearby, but will create a fire where the rune stands on use.
+As a Cultist, the Blood Boil rune will deal massive amounts of brute damage to non-cultists, and some damage to fellow cultists nearby, but will create a fire where the rune stands on use.
As a Cultist, you can create an army of manifested goons using a combination of the Manifest rune, which creates homunculi from ghosts, and the Blood Drain rune, which drains life from anyone standing on any blood drain rune.
-As a Cultist, check the alert in the upper-right of your screen for all the details about your cult's current status and objective.
You can deconvert Cultists by feeding them large amounts of holy water.
-The Chaplain can bless any container with water by hitting it with their bible. Holy water has a myriad of uses against both cults and large amounts of it are a great contributor to success against them.
+The Chaplain can bless any container with water by hitting it with their bible. Holy water has a myriad of uses against cults and large amounts of it are a great contributor to success against them.
As a Wizard, you can turn people to stone, then animate the resulting statue with a staff of animation to create an extremely powerful minion, for all of 5 minutes at least.
As a Wizard, the fireball spell performs very poorly at close range, as it can easily catch you in the blast. It is best used as a form of artillery down long hallways.
As a Wizard, summoning guns will give everyone anything from a floral somatoray to a pulse rifle. Use at your own risk!
@@ -170,11 +169,10 @@ As an Abductor Agent, the combat mode vest has much higher resistance to every k
As an Abductor, the baton can cycle between four modes: stun, sleep, cuff and probe.
As a Revenant, the Chaplain is your worst enemy, as they can damage you massively with the null rod and make large swaths of the station impassable with holy water.
As a Revenant, your essence is also your health, so revealing yourself in front of humans to harvest the essence of the living is much safer if you've already stocked up on essences from poorly guarded corpses.
-As a Revenant, your Defile ability removes holy water from tiles in a small radius, along with salt, allowing you to reclaim the station from the chaplain if they've been covering the station in holy water. It can also be used to open morgue trays!
+As a Revenant, your Defile ability removes holy water from tiles in a small radius, allowing you to reclaim the station from the chaplain if they've been covering the station in holy water.
As a Revenant, your Overload Lights ability will only shock humans with lights if the lights are still on after a brief delay.
As a Revenant, your Malfunction ability in general damages machinery and mechanical objects, possibly even emagging some objects. Experiment!
-As a Revenant, the illness inflicted on humans by Blight can be easily cured by lying down or with holy water, making it best used on targets that have no time to lie down, such as humans in combat.
-As a Revenant, fastmos is your friend. Breaking windows to space can cause massive damage and mayhem.
+As a Revenant, space is your friend. Breaking windows to space can cause massive damage and mayhem.
As a Swarmer, you can deconstruct more things than you think. Try deconstructing light switches, buttons, air alarms and more. Experiment!
As a Swarmer, you can teleport fellow swarmers away if you think they are in danger.
As a Ghost, you can double click on just about anything to follow it. Or just warp around!
@@ -202,4 +200,4 @@ You can make lasertag turrets, for the ultimate lasertag tournament.
Blob structures take half damage from brute damage. Use lasers.
You can hide paper in vents, but you have to use a screwdriver to open it first.
While the Standard Operating Procedures aren't fully rules, they are there for safety and professional reasons.
-Killing the Wizard usually ends the round, unless they are a lich or Space Wizard Federation is RAGING.
\ No newline at end of file
+Killing the Wizard usually ends the round, unless they are a lich or Space Wizard Federation is RAGING.
diff --git a/tgui/packages/tgui/components/Box.js b/tgui/packages/tgui/components/Box.js
index 9d5e71c78a7..ada17f05d55 100644
--- a/tgui/packages/tgui/components/Box.js
+++ b/tgui/packages/tgui/components/Box.js
@@ -68,7 +68,10 @@ const mapColorPropTo = attrName => (style, value) => {
const styleMapperByPropName = {
// Direct mapping
+ display: mapRawPropTo('display'),
position: mapRawPropTo('position'),
+ float: mapRawPropTo('float'),
+ clear: mapRawPropTo('clear'),
overflow: mapRawPropTo('overflow'),
overflowX: mapRawPropTo('overflow-x'),
overflowY: mapRawPropTo('overflow-y'),
@@ -88,6 +91,9 @@ const styleMapperByPropName = {
opacity: mapRawPropTo('opacity'),
textAlign: mapRawPropTo('text-align'),
verticalAlign: mapRawPropTo('vertical-align'),
+ textTransform: mapRawPropTo('text-transform'),
+ wordWrap: mapRawPropTo('word-wrap'),
+ textOverflow: mapRawPropTo('text-overflow'),
// Boolean props
inline: mapBooleanPropTo('display', 'inline-block'),
bold: mapBooleanPropTo('font-weight', 'bold'),
@@ -125,6 +131,18 @@ const styleMapperByPropName = {
color: mapColorPropTo('color'),
textColor: mapColorPropTo('color'),
backgroundColor: mapColorPropTo('background-color'),
+ // Flex props
+ order: mapRawPropTo('order'),
+ flexDirection: mapRawPropTo('flex-direction'),
+ flexGrow: mapRawPropTo('flex-grow'),
+ flexShrink: mapRawPropTo('flex-shrink'),
+ flexWrap: mapRawPropTo('flex-wrap'),
+ flexFlow: mapRawPropTo('flex-flow'),
+ flexBasis: mapRawPropTo('flex-basis'),
+ flex: mapRawPropTo('flex'),
+ alignItems: mapRawPropTo('align-items'),
+ justifyContent: mapRawPropTo('justify-content'),
+ alignSelf: mapRawPropTo('align-self'),
// Utility props
fillPositionedParent: (style, value) => {
if (value) {
@@ -140,6 +158,9 @@ const styleMapperByPropName = {
export const computeBoxProps = props => {
const computedProps = {};
const computedStyles = {};
+ if (props.double) {
+ computedStyles["transform"] = "scale(2);";
+ }
// Compute props
for (let propName of Object.keys(props)) {
if (propName === 'style') {
diff --git a/tgui/packages/tgui/components/Collapsible.js b/tgui/packages/tgui/components/Collapsible.js
index 84af070fe18..080074e48ef 100644
--- a/tgui/packages/tgui/components/Collapsible.js
+++ b/tgui/packages/tgui/components/Collapsible.js
@@ -22,7 +22,7 @@ export class Collapsible extends Component {
...rest
} = props;
return (
-
+
+ Lines are a series of chords, separated by commas
+ (,),
+ each with notes seperated by hyphens
+ (-).
+
+ Every note in a chord will play together,
+ with the chord timed by the
+ tempo as defined above.
+
+
+ Notes are played by the
+ names of the note,
+ and optionally, the
+ accidental,
+ and/or the octave number.
+
+ By default, every note is
+ natural and in
+ octave 3.
+ Defining a different state for either is
+ remembered for each note.
+
+
+ Example:
+ C,D,E,F,G,A,B will play a
+ C
+ major scale.
+
+
+ After a note has an
+ accidental or
+ octave placed,
+ it will be remembered:
+ C,C4,C#,C3 is C3,C4,C4#,C3#
+
+
+
+
+ Chords
+ can be played simply by seperating each note
+ with a hyphen: A-C#,Cn-E,E-G#,Gn-B.
+ A pause
+ may be denoted by an empty chord: C,E,,C,G.
+
+ To make a chord be a different time, end it
+ with /x, where the chord length will be length defined by
+ tempo / x,
+ eg:C,G/2,E/4.
+
+
+ Combined, an example line is: E-E4/4,F#/2,G#/8,B/8,E3-E4/4.
+
+
Lines may be up to 300 characters.
+
A song may only contain up to 1,000 lines.
+
+
+
+ Lines are a series of chords, separated by commas
+ (,),
+ each with notes seperated by hyphens
+ (-).
+
+ Every note in a chord will play together,
+ with the chord timed by the
+ tempo as defined above.
+
+
+ Notes are played by the
+ names of the note,
+ and optionally, the
+ accidental,
+ and/or the octave number.
+
+ By default, every note is
+ natural and in
+ octave 3.
+ Defining a different state for either is
+ remembered for each note.
+
+
+ Example:
+ C,D,E,F,G,A,B will play a
+ C
+ major scale.
+
+
+ After a note has an
+ accidental or
+ octave placed,
+ it will be remembered:
+ C,C4,C#,C3 is C3,C4,C4#,C3#
+
+
+
+
+ Chords
+ can be played simply by seperating each note
+ with a hyphen: A-C#,Cn-E,E-G#,Gn-B.
+ A pause
+ may be denoted by an empty chord: C,E,,C,G.
+
+ To make a chord be a different time, end it
+ with /x, where the chord length will be length defined by
+ tempo / x,
+ eg:C,G/2,E/4.
+
+
+ Combined, an example line is: E-E4/4,F#/2,G#/8,B/8,E3-E4/4.
+
+
Lines may be up to 300 characters.
+
A song may only contain up to 1,000 lines.
+
+
+
Instrument Advanced Settings
+
+
+ Type:
+ Whether the instrument is legacy or synthesized.
+ Legacy instruments have a collection of sounds that are
+ selectively used depending on the note to play.
+ Synthesized instruments use a base sound and change its pitch to
+ match the note to play.
+
+
+ Current:
+ Which instrument sample to play. Some instruments
+ can be tuned to play different samples. Experiment!
+
+
+ Note Shift/Note Transpose:
+ The pitch to apply to all notes of the song.
+
+
+ Sustain Mode:
+ How a played note fades out.
+ Linear sustain means a note will fade out at a constant rate.
+
+ Exponential sustain means a note will fade out at an
+ exponential rate, sounding smoother.
+
+
+ Volume Dropoff Threshold:
+ The volume threshold at which a note is fully stopped.
+
+
+
+ Sustain indefinitely last held note:
+
+ Whether the last note should be sustained indefinitely.
+