diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm
index d5c344e9cd31a..3553672b1080c 100644
--- a/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm
+++ b/_maps/RandomRuins/IceRuins/icemoon_underground_comms_agent.dmm
@@ -993,9 +993,6 @@
/area/ruin/comms_agent)
"UI" = (
/obj/structure/table/reinforced,
-/obj/machinery/computer/records/security/laptop/syndie{
- dir = 1
- },
/obj/item/paper/monitorkey{
pixel_x = -15;
pixel_y = 7
diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm
index de9e1338f2939..125324bb07ea4 100644
--- a/_maps/map_files/Birdshot/birdshot.dmm
+++ b/_maps/map_files/Birdshot/birdshot.dmm
@@ -9394,10 +9394,9 @@
/obj/machinery/airalarm/directional/north,
/obj/structure/table/wood,
/obj/machinery/chem_dispenser/drinks,
-/obj/effect/turf_decal/siding/wood{
- dir = 5
+/obj/effect/turf_decal/siding/wood/end{
+ dir = 4
},
-/obj/effect/turf_decal/siding/wood,
/turf/open/floor/iron/dark/diagonal,
/area/station/service/bar)
"dxZ" = (
@@ -10072,6 +10071,7 @@
},
/obj/structure/disposalpipe/segment,
/obj/structure/cable,
+/obj/structure/extinguisher_cabinet/directional/west,
/turf/open/floor/stone,
/area/station/service/bar)
"dMm" = (
@@ -33247,11 +33247,10 @@
pixel_x = -7;
pixel_y = 15
},
-/obj/effect/turf_decal/siding/wood{
- dir = 9
- },
-/obj/effect/turf_decal/siding/wood,
/obj/structure/sign/warning/no_smoking/circle/directional/north,
+/obj/effect/turf_decal/siding/wood/end{
+ dir = 8
+ },
/turf/open/floor/iron/dark/diagonal,
/area/station/service/bar)
"lnI" = (
@@ -50833,12 +50832,6 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron/dark,
/area/station/service/lawoffice)
-"rrX" = (
-/obj/effect/turf_decal/siding/wood/corner{
- dir = 4
- },
-/turf/open/floor/stone,
-/area/station/service/bar)
"rrZ" = (
/obj/structure/closet/crate/trashcart,
/obj/effect/spawner/random/trash/garbage,
@@ -56445,11 +56438,14 @@
/turf/open/floor/eighties/red,
/area/station/hallway/primary/central/fore)
"tjT" = (
-/obj/structure/extinguisher_cabinet/directional/north,
+/obj/machinery/chem_master/condimaster,
+/obj/effect/turf_decal/siding/wood/end{
+ dir = 8
+ },
/obj/effect/turf_decal/siding/wood{
- dir = 5
+ dir = 4
},
-/turf/open/floor/stone,
+/turf/open/floor/iron/dark/diagonal,
/area/station/service/bar)
"tjY" = (
/obj/machinery/atmospherics/components/binary/pump/on{
@@ -100086,7 +100082,7 @@ iXW
dRb
sON
tjT
-rrX
+xkV
lAV
fYJ
eGU
diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
index aa3df4dfd8a93..6ee4db7790ea9 100644
--- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm
+++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
@@ -46005,6 +46005,13 @@
dir = 4
},
/area/station/hallway/secondary/entry)
+"nqI" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/effect/turf_decal/tile/neutral/half/contrasted,
+/obj/effect/landmark/start/hangover,
+/turf/open/floor/iron,
+/area/station/commons/fitness)
"nqP" = (
/obj/machinery/camera/directional/north{
c_tag = "Research Division West";
@@ -53846,8 +53853,8 @@
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
-/obj/item/kirbyplants/random,
/obj/structure/sign/flag/terragov/directional/north,
+/obj/structure/weightmachine/weightlifter,
/turf/open/floor/iron,
/area/station/commons/fitness)
"pyn" = (
@@ -81087,6 +81094,10 @@
/obj/structure/cable,
/turf/open/floor/plating,
/area/station/security/detectives_office)
+"xyg" = (
+/obj/structure/weightmachine,
+/turf/open/floor/iron,
+/area/station/commons/fitness)
"xyl" = (
/obj/effect/turf_decal/tile/blue/half/contrasted{
dir = 1
@@ -249315,7 +249326,7 @@ cGB
cGB
gsI
tLL
-spy
+nqI
kKL
kKL
kKL
@@ -250338,8 +250349,8 @@ dyA
skl
gaC
vfW
-eOl
vfW
+xyg
vfW
lvk
crv
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 6b4adfe0d4896..e6aabf579de2a 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -67095,10 +67095,6 @@
},
/turf/open/floor/iron,
/area/station/ai_monitored/command/storage/eva)
-"xBX" = (
-/obj/machinery/firealarm/directional/east,
-/turf/closed/wall,
-/area/station/security/checkpoint/customs)
"xCf" = (
/obj/item/clothing/suit/jacket/straight_jacket,
/obj/item/electropack,
@@ -83046,7 +83042,7 @@ wdr
fcq
xfI
fcq
-xBX
+xjh
qhW
xjh
yme
diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm
index 74c9120d804d4..ea5c52bf36f0f 100644
--- a/code/__DEFINES/admin.dm
+++ b/code/__DEFINES/admin.dm
@@ -45,40 +45,40 @@
#define R_EVERYTHING (1<<15)-1 //the sum of all other rank permissions, used for +EVERYTHING
-#define ADMIN_QUE(user) "(?)"
-#define ADMIN_FLW(user) "(FLW)"
-#define ADMIN_PP(user) "(PP)"
-#define ADMIN_VV(atom) "(VV)"
-#define ADMIN_SM(user) "(SM)"
-#define ADMIN_TP(user) "(TP)"
-#define ADMIN_SP(user) "(SP)"
-#define ADMIN_KICK(user) "(KICK)"
-#define ADMIN_CENTCOM_REPLY(user) "(RPLY)"
-#define ADMIN_SYNDICATE_REPLY(user) "(RPLY)"
-#define ADMIN_SC(user) "(SC)"
-#define ADMIN_SMITE(user) "(SMITE)"
+#define ADMIN_QUE(user) "(?)"
+#define ADMIN_FLW(user) "(FLW)"
+#define ADMIN_PP(user) "(PP)"
+#define ADMIN_VV(atom) "(VV)"
+#define ADMIN_SM(user) "(SM)"
+#define ADMIN_TP(user) "(TP)"
+#define ADMIN_SP(user) "(SP)"
+#define ADMIN_KICK(user) "(KICK)"
+#define ADMIN_CENTCOM_REPLY(user) "(RPLY)"
+#define ADMIN_SYNDICATE_REPLY(user) "(RPLY)"
+#define ADMIN_SC(user) "(SC)"
+#define ADMIN_SMITE(user) "(SMITE)"
#define ADMIN_LOOKUP(user) "[key_name_admin(user)][ADMIN_QUE(user)]"
#define ADMIN_LOOKUPFLW(user) "[key_name_admin(user)][ADMIN_QUE(user)] [ADMIN_FLW(user)]"
-#define ADMIN_SET_SD_CODE "(SETCODE)"
+#define ADMIN_SET_SD_CODE "(SETCODE)"
#define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)] [ADMIN_INDIVIDUALLOG(user)] [ADMIN_SMITE(user)]"
#define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]"
-#define ADMIN_JMP(src) "(JMP)"
+#define ADMIN_JMP(src) "(JMP)"
#define COORD(src) "[src ? src.Admin_Coordinates_Readable() : "nonexistent location"]"
#define AREACOORD(src) "[src ? src.Admin_Coordinates_Readable(TRUE) : "nonexistent location"]"
#define ADMIN_COORDJMP(src) "[src ? src.Admin_Coordinates_Readable(FALSE, TRUE) : "nonexistent location"]"
#define ADMIN_VERBOSEJMP(src) "[src ? src.Admin_Coordinates_Readable(TRUE, TRUE) : "nonexistent location"]"
-#define ADMIN_INDIVIDUALLOG(user) "(LOGS)"
-#define ADMIN_TAG(datum) "(TAG)"
-#define ADMIN_LUAVIEW(state) "(VIEW STATE)"
-#define ADMIN_LUAVIEW_CHUNK(state, log_index) "(VIEW CODE)"
+#define ADMIN_INDIVIDUALLOG(user) "(LOGS)"
+#define ADMIN_TAG(datum) "(TAG)"
+#define ADMIN_LUAVIEW(state) "(VIEW STATE)"
+#define ADMIN_LUAVIEW_CHUNK(state, log_index) "(VIEW CODE)"
/// Displays "(SHOW)" in the chat, when clicked it tries to show atom(paper). First you need to set the request_state variable to TRUE for the paper.
-#define ADMIN_SHOW_PAPER(atom) "(SHOW)"
+#define ADMIN_SHOW_PAPER(atom) "(SHOW)"
/// Displays "(PRINT)" in the chat, when clicked it will try to print the atom(paper) on the CentCom/Syndicate fax machine.
-#define ADMIN_PRINT_FAX(atom, sender, destination) "(PRINT)"
+#define ADMIN_PRINT_FAX(atom, sender, destination) "(PRINT)"
/// Displays "(PLAY)" in the chat, when clicked it tries to play internet sounds from the request.
-#define ADMIN_PLAY_INTERNET(text, credit) "(PLAY)"
+#define ADMIN_PLAY_INTERNET(text, credit) "(PLAY)"
/// Displays "(SEE Z-LEVEL LAYOUT)" in the chat, when clicked it shows the z-level layouts for the current world state.
-#define ADMIN_SEE_ZLEVEL_LAYOUT "(SEE Z-LEVEL LAYOUT)"
+#define ADMIN_SEE_ZLEVEL_LAYOUT "(SEE Z-LEVEL LAYOUT)"
/atom/proc/Admin_Coordinates_Readable(area_name, admin_jump_ref)
var/turf/turf_at_coords = Safe_COORD_Location()
diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm
index b5a7ad1ddfaac..f7f77a7169ea2 100644
--- a/code/__DEFINES/ai/ai_blackboard.dm
+++ b/code/__DEFINES/ai/ai_blackboard.dm
@@ -195,6 +195,14 @@
#define BB_DRILLABLE_ICE "BB_drillable_ice"
+//emotions we displays depending on our happiness
+///emotions we display when happy
+#define BB_HAPPY_EMOTIONS "happy_emotions"
+///emotions we display when neutral
+#define BB_MODERATE_EMOTIONS "moderate_emotions"
+///emotions we display when depressed
+#define BB_SAD_EMOTIONS "sad_emotions"
+
// Keys used by one and only one behavior
// Used to hold state without making bigass lists
/// For /datum/ai_behavior/find_potential_targets, what if any field are we using currently
diff --git a/code/__DEFINES/ai/monsters.dm b/code/__DEFINES/ai/monsters.dm
index 330e2d48eb226..d77817a203980 100644
--- a/code/__DEFINES/ai/monsters.dm
+++ b/code/__DEFINES/ai/monsters.dm
@@ -304,3 +304,11 @@
#define BB_DEER_RESTING "deer_resting"
///time till our next rest duration
#define BB_DEER_NEXT_REST_TIMER "deer_next_rest_timer"
+
+//turtle
+///our tree's ability
+#define BB_TURTLE_TREE_ABILITY "turtle_tree_ability"
+///people we headbutt!
+#define BB_TURTLE_HEADBUTT_VICTIM "turtle_headbutt_victim"
+///flore we must smell
+#define BB_TURTLE_FLORA_TARGET "turtle_flora_target"
diff --git a/code/__DEFINES/chat.dm b/code/__DEFINES/chat.dm
index 516fe8c4e193a..80fb1a07eccf3 100644
--- a/code/__DEFINES/chat.dm
+++ b/code/__DEFINES/chat.dm
@@ -44,9 +44,11 @@
/// Used for debug messages to the server
#define debug_world_log(msg) if (GLOB.Debug2) log_world("DEBUG: [msg]")
/// Adds a generic box around whatever message you're sending in chat. Really makes things stand out.
-#define examine_block(str) ("
" + str + "
")
-/// Makes a fieldset with a name in the middle top part. Can apply additional classes
-#define fieldset_block(title, content, classes) ("")
+#define boxed_message(str) ("
" + str + "
")
+/// Adds a box around whatever message you're sending in chat. Can apply color and/or additional classes. Available colors: red, green, blue, purple. Use it like red_box
+#define custom_boxed_message(classes, str) ("
" + str + "
")
+/// Makes a fieldset with a neaty styled name. Can apply additional classes.
+#define fieldset_block(title, content, classes) ("")
/// Makes a horizontal line with text in the middle
#define separator_hr(str) ("
" + str + "
")
/// Emboldens runechat messages
diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index 5cb838603c98e..867d8a51d4163 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -98,6 +98,7 @@ DEFINE_BITFIELD(status_flags, list(
#define CLICK_CD_RAPID 2
#define CLICK_CD_HYPER_RAPID 1
#define CLICK_CD_SLOW 10
+#define CLICK_CD_ACTIVATE_ABILITY 1
#define CLICK_CD_THROW 8
#define CLICK_CD_RANGE 4
diff --git a/code/__DEFINES/construction/rcd.dm b/code/__DEFINES/construction/rcd.dm
index a8d98215af1dc..4f898d5ae86ec 100644
--- a/code/__DEFINES/construction/rcd.dm
+++ b/code/__DEFINES/construction/rcd.dm
@@ -51,3 +51,6 @@
#define RCD_MEMORY_COST_BUFF 8
/// If set to TRUE in rcd_vals, will bypass the cooldown on slowing down frequent use
#define RCD_RESULT_BYPASS_FREQUENT_USE_COOLDOWN "bypass_frequent_use_cooldown"
+
+/// How much longer does it take to deconstruct rwalls?
+#define RCD_RWALL_DELAY_MULT 2
diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm
index bedfaf2fa0374..bb5b344a89a48 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm
@@ -92,3 +92,6 @@
/// from /obj/projectile/energy/fisher/on_hit() or /obj/item/gun/energy/recharge/fisher when striking a target
#define COMSIG_ATOM_SABOTEUR_ACT "hit_by_saboteur"
#define COMSIG_SABOTEUR_SUCCESS 1
+
+/// signal sent when a mouse is hovering over us, sent by atom/proc/on_mouse_entered
+#define COMSIG_ATOM_MOUSE_ENTERED "mouse_entered"
diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm
index 63ebfdf98b21f..a83badb9ee067 100644
--- a/code/__DEFINES/dcs/signals/signals_object.dm
+++ b/code/__DEFINES/dcs/signals/signals_object.dm
@@ -547,6 +547,9 @@
///Sent from /obj/item/skillchip/on_remove()
#define COMSIG_SKILLCHIP_REMOVED "skillchip_removed"
+/// from /obj/machinery/computer/camera_advanced/shuttle_docker/gatherNavComputerOverlays() : (list/images_out)
+#define COMSIG_SHUTTLE_NAV_COMPUTER_IMAGE_REQUESTED "shuttle_nav_computer_image_requested"
+
/// Sent from /obj/item/organ/wings/functional/proc/open_wings(): (mob/living/carbon/owner)
#define COMSIG_WINGS_OPENED "wings_opened"
/// Sent from /obj/item/organ/wings/functional/proc/close_wings(): (mob/living/carbon/owner)
diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm
index 5f025ad99cffb..8ae95933e646b 100644
--- a/code/__DEFINES/keybinding.dm
+++ b/code/__DEFINES/keybinding.dm
@@ -4,6 +4,9 @@
#define COMSIG_KB_ACTIVATED (1<<0)
#define COMSIG_KB_EMOTE "keybinding_emote_down"
+///Signal sent when a keybind is deactivated
+#define DEACTIVATE_KEYBIND(A) "[A]_DEACTIVATED"
+
//Admin
#define COMSIG_KB_ADMIN_ASAY_DOWN "keybinding_admin_asay_down"
#define COMSIG_KB_ADMIN_DSAY_DOWN "keybinding_admin_dsay_down"
@@ -54,6 +57,7 @@
#define COMSIG_KB_LIVING_DISABLE_COMBAT_DOWN "keybinding_living_disable_combat_down"
#define COMSIG_KB_LIVING_TOGGLEMOVEINTENT_DOWN "keybinding_mob_togglemoveintent_down"
#define COMSIG_KB_LIVING_TOGGLEMOVEINTENTALT_DOWN "keybinding_mob_togglemoveintentalt_down"
+#define COMSIG_KB_LIVING_VIEW_PET_COMMANDS "keybinding_living_view_pet_commands"
//Mob
#define COMSIG_KB_MOB_FACENORTH_DOWN "keybinding_mob_facenorth_down"
diff --git a/code/__DEFINES/radial_defines.dm b/code/__DEFINES/radial_defines.dm
new file mode 100644
index 0000000000000..35ae6eebb5984
--- /dev/null
+++ b/code/__DEFINES/radial_defines.dm
@@ -0,0 +1,6 @@
+#define NEXT_PAGE_ID "__next__"
+#define DEFAULT_CHECK_DELAY 2 SECONDS
+
+#define BUTTON_SLIDE_IN (1<<0)
+#define BUTTON_FADE_IN (1<<1)
+#define BUTTON_FADE_OUT (1<<2)
diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm
index 28172587e795a..bf3fd32918943 100644
--- a/code/__DEFINES/reagents.dm
+++ b/code/__DEFINES/reagents.dm
@@ -46,7 +46,8 @@
///Health threshold for synthflesh and rezadone to unhusk someone
#define UNHUSK_DAMAGE_THRESHOLD 50
///Amount of synthflesh required to unhusk someone
-#define SYNTHFLESH_UNHUSK_AMOUNT 100
+#define SYNTHFLESH_UNHUSK_AMOUNT 60
+#define SYNTHFLESH_UNHUSK_MAX 100
//used by chem masters and pill presses
// The categories of reagent packaging
diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm
index d905129b19b74..c3bd425af0a65 100644
--- a/code/__DEFINES/say.dm
+++ b/code/__DEFINES/say.dm
@@ -99,9 +99,9 @@
#define MODE_RANGE_INTERCOM 1
// A link given to ghost alice to follow bob
-#define FOLLOW_LINK(alice, bob) "(F)"
-#define TURF_LINK(alice, turfy) "(T)"
-#define FOLLOW_OR_TURF_LINK(alice, bob, turfy) "(F)"
+#define FOLLOW_LINK(alice, bob) "(F)"
+#define TURF_LINK(alice, turfy) "(T)"
+#define FOLLOW_OR_TURF_LINK(alice, bob, turfy) "(F)"
//Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam
#define MAX_MESSAGE_LEN 1024
diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm
index 88f46a53fd92c..1ce2d5d46cb9c 100644
--- a/code/__DEFINES/vv.dm
+++ b/code/__DEFINES/vv.dm
@@ -50,7 +50,7 @@
#define GET_VV_VAR_TARGET href_list[VV_HK_VARNAME]
//Helper for getting something to vv_do_topic in general
-#define VV_TOPIC_LINK(datum, href_key, text) "text"
+#define VV_TOPIC_LINK(datum, href_key, text) "text"
//Helpers for vv_get_dropdown()
#define VV_DROPDOWN_OPTION(href_key, name) . += ""
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 2c285a348fac2..9b80dbfc169c4 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -349,4 +349,4 @@
message = html_encode(message)
else
message = copytext(message, 2)
- to_chat(target, span_purple(examine_block("[source]: [message]")))
+ to_chat(target, custom_boxed_message("purple_box", span_purple("[source]: [message]")))
diff --git a/code/__HELPERS/logging/_logging.dm b/code/__HELPERS/logging/_logging.dm
index bfcaded67f021..8f8f733e6ba8b 100644
--- a/code/__HELPERS/logging/_logging.dm
+++ b/code/__HELPERS/logging/_logging.dm
@@ -215,11 +215,11 @@ GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global"))
if(key)
if(C?.holder && C.holder.fakekey && !include_name)
if(include_link)
- . += ""
+ . += ""
. += "Administrator"
else
if(include_link)
- . += ""
+ . += ""
. += key
if(!C)
. += "\[DC\]"
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index 292639f387682..19dec4a7fd442 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -335,7 +335,7 @@ GLOBAL_LIST_INIT(achievements_unlocked, list())
if(GLOB.round_id)
var/statspage = CONFIG_GET(string/roundstatsurl)
- var/info = statspage ? "[GLOB.round_id]" : GLOB.round_id
+ var/info = statspage ? "[GLOB.round_id]" : GLOB.round_id
parts += "[FOURSPACES]Round ID: [info]"
parts += "[FOURSPACES]Shift Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]"
parts += "[FOURSPACES]Station Integrity: [GLOB.station_was_nuked ? span_redtext("Destroyed") : "[popcount["station_integrity"]]%"]"
@@ -660,7 +660,7 @@ GLOBAL_LIST_INIT(achievements_unlocked, list())
var/datum/action/report/R = new
C.player_details.player_actions += R
R.Grant(C.mob)
- to_chat(C,span_infoplain("Show roundend report again"))
+ to_chat(C,span_infoplain("Show roundend report again"))
/datum/action/report
name = "Show roundend report"
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index 7cab2074c5485..6b6c6bc9050ab 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -1136,7 +1136,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
return FALSE
var/list/modifiers = params2list(params)
if(LAZYACCESS(modifiers, SHIFT_CLICK)) // screen objects don't do the normal Click() stuff so we'll cheat
- to_chat(usr, examine_block(jointext(examine(usr), "\n")))
+ to_chat(usr, boxed_message(jointext(examine(usr), "\n")))
return FALSE
var/datum/our_master = master_ref?.resolve()
if(our_master && click_master)
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 918f5f62a329b..e17757501cf9e 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -322,8 +322,6 @@
var/obj/item/organ/eyes/eyes = human_mob.get_organ_slot(ORGAN_SLOT_EYES)
if(eyes?.no_glasses)
blocked_slots |= ITEM_SLOT_EYES
- if(human_mob.bodyshape & BODYSHAPE_DIGITIGRADE)
- blocked_slots |= ITEM_SLOT_FEET
for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory))
if(!inv.slot_id)
diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm
index ab95d3bb392eb..041a16b12a132 100644
--- a/code/_onclick/hud/radial.dm
+++ b/code/_onclick/hud/radial.dm
@@ -1,6 +1,3 @@
-#define NEXT_PAGE_ID "__next__"
-#define DEFAULT_CHECK_DELAY 20
-
GLOBAL_LIST_EMPTY(radial_menus)
/atom/movable/screen/radial
@@ -113,7 +110,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
var/hudfix_method = TRUE //TRUE to change anchor to user, FALSE to shift by py_shift
var/py_shift = 0
- var/entry_animation = TRUE
+ var/button_animation_flags = BUTTON_SLIDE_IN
///A replacement icon state for the generic radial slice bg icon. Doesn't affect the next page nor the center buttons
var/radial_slice_icon
@@ -163,6 +160,8 @@ GLOBAL_LIST_EMPTY(radial_menus)
var/atom/movable/screen/radial/slice/new_element = new /atom/movable/screen/radial/slice
new_element.tooltips = use_tooltips
new_element.set_parent(src)
+ if(button_animation_flags & BUTTON_FADE_IN)
+ new_element.alpha = 0
elements += new_element
var/page = 1
@@ -186,9 +185,9 @@ GLOBAL_LIST_EMPTY(radial_menus)
page_data[page] = current
pages = page
current_page = clamp(set_page, 1, pages)
- update_screen_objects(entry_animation, click_on_hover)
+ update_screen_objects(button_animation_flags, click_on_hover)
-/datum/radial_menu/proc/update_screen_objects(anim = FALSE, click_on_hover = FALSE)
+/datum/radial_menu/proc/update_screen_objects(anim_flag = NONE, click_on_hover = FALSE)
var/list/page_choices = page_data[current_page]
var/angle_per_element = round(zone / page_choices.len)
for(var/i in 1 to elements.len)
@@ -198,11 +197,11 @@ GLOBAL_LIST_EMPTY(radial_menus)
HideElement(element)
element.click_on_hover = FALSE
else
- SetElement(element,page_choices[i],angle,anim = anim,anim_order = i)
+ SetElement(element,page_choices[i],angle,anim_flag = anim_flag,anim_order = i)
// Only activate click on hover after the animation plays
if (!click_on_hover)
continue
- if (anim)
+ if (anim_flag)
addtimer(VARSET_CALLBACK(element, click_on_hover, TRUE), i * 0.5)
else
element.click_on_hover = TRUE
@@ -217,11 +216,11 @@ GLOBAL_LIST_EMPTY(radial_menus)
E.choice = null
E.next_page = FALSE
-/datum/radial_menu/proc/SetElement(atom/movable/screen/radial/slice/E,choice_id,angle,anim,anim_order)
+/datum/radial_menu/proc/SetElement(atom/movable/screen/radial/slice/E, choice_id, angle, anim_flag, anim_order)
//Position
var/py = round(cos(angle) * radius) + py_shift
var/px = round(sin(angle) * radius)
- if(anim)
+ if(anim_flag & BUTTON_SLIDE_IN)
var/timing = anim_order * 0.5
var/matrix/starting = matrix()
starting.Scale(0.1,0.1)
@@ -232,8 +231,11 @@ GLOBAL_LIST_EMPTY(radial_menus)
E.pixel_y = py
E.pixel_x = px
- //Visuals
- E.alpha = 255
+ if(anim_flag & BUTTON_FADE_IN)
+ animate(E, alpha = 255, time = 0.15 SECONDS, easing = EASE_OUT)
+ else
+ E.alpha = 255
+
E.mouse_opacity = MOUSE_OPACITY_ICON
E.cut_overlays()
E.vis_contents.Cut()
@@ -266,7 +268,9 @@ GLOBAL_LIST_EMPTY(radial_menus)
info_button.layer = RADIAL_CONTENT_LAYER
E.vis_contents += info_button
-/datum/radial_menu/New()
+/datum/radial_menu/New(display_close_button)
+ if(!display_close_button)
+ return
close_button = new
close_button.set_parent(src)
@@ -327,7 +331,9 @@ GLOBAL_LIST_EMPTY(radial_menus)
menu_holder = image(icon='icons/effects/effects.dmi',loc=anchor,icon_state="nothing", layer = RADIAL_BACKGROUND_LAYER, pixel_x = offset_x, pixel_y = offset_y)
SET_PLANE_EXPLICIT(menu_holder, ABOVE_HUD_PLANE, M)
menu_holder.appearance_flags |= KEEP_APART|RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM
- menu_holder.vis_contents += elements + close_button
+ menu_holder.vis_contents += elements
+ if(!isnull(close_button))
+ menu_holder.vis_contents += close_button
current_user.images += menu_holder
/datum/radial_menu/proc/hide()
@@ -345,6 +351,14 @@ GLOBAL_LIST_EMPTY(radial_menus)
next_check = world.time + check_delay
stoplag(1)
+/datum/radial_menu/proc/remove_menu()
+ if(!(button_animation_flags & BUTTON_FADE_OUT))
+ qdel(src)
+ return
+ for(var/atom/movable/element as anything in elements)
+ animate(element, alpha = 0, time = 0.15 SECONDS)
+ QDEL_IN(src, 0.5 SECONDS)
+
/datum/radial_menu/Destroy()
Reset()
hide()
@@ -356,11 +370,11 @@ GLOBAL_LIST_EMPTY(radial_menus)
Choices should be a list where list keys are movables or text used for element names and return value
and list values are movables/icons/images used for element icons
*/
-/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE, radial_slice_icon = "radial_slice", autopick_single_option = TRUE, entry_animation = TRUE, click_on_hover = FALSE, user_space = FALSE)
+/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE, radial_slice_icon = "radial_slice", autopick_single_option = TRUE, button_animation_flags = BUTTON_SLIDE_IN, click_on_hover = FALSE, user_space = FALSE, check_delay = DEFAULT_CHECK_DELAY, display_close_button = TRUE, radial_menu_offset = list(0, 0))
if(!user || !anchor || !length(choices))
return
- if(length(choices)==1 && autopick_single_option)
+ if(length(choices) == 1 && autopick_single_option)
return choices[1]
if(!uniqueid)
@@ -372,8 +386,9 @@ GLOBAL_LIST_EMPTY(radial_menus)
menu.finished = TRUE
return
- var/datum/radial_menu/menu = new
- menu.entry_animation = entry_animation
+ var/datum/radial_menu/menu = new(display_close_button)
+ menu.button_animation_flags = button_animation_flags
+ menu.check_delay = check_delay
GLOB.radial_menus[uniqueid] = menu
if(radius)
menu.radius = radius
@@ -390,10 +405,12 @@ GLOBAL_LIST_EMPTY(radial_menus)
var/turf/anchor_turf = get_turf(anchor)
offset_x = (anchor_turf.x - user_turf.x) * ICON_SIZE_X + anchor.pixel_x - user.pixel_x
offset_y = (anchor_turf.y - user_turf.y) * ICON_SIZE_Y + anchor.pixel_y - user.pixel_y
+ offset_x += radial_menu_offset[1]
+ offset_y += radial_menu_offset[2]
menu.show_to(user, offset_x, offset_y)
menu.wait(user, anchor, require_near)
var/answer = menu.selected_choice
- qdel(menu)
+ menu.remove_menu()
GLOB.radial_menus -= uniqueid
if(require_near && !in_range(anchor, user))
return
diff --git a/code/_onclick/hud/radial_persistent.dm b/code/_onclick/hud/radial_persistent.dm
index 5fe81d005bd43..d48c8d9eb456c 100644
--- a/code/_onclick/hud/radial_persistent.dm
+++ b/code/_onclick/hud/radial_persistent.dm
@@ -43,7 +43,7 @@
/datum/radial_menu/persistent/proc/change_choices(list/newchoices, tooltips = FALSE, animate = FALSE, keep_same_page = FALSE)
if(!newchoices.len)
return
- entry_animation = FALSE
+ button_animation_flags = NONE
var/target_page = keep_same_page ? current_page : 1 //Stores the current_page value before it's set back to 1 on Reset()
Reset()
set_choices(newchoices,tooltips, set_page = target_page)
diff --git a/code/controllers/subsystem/dbcore.dm b/code/controllers/subsystem/dbcore.dm
index 115250104f008..805fe419c94b7 100644
--- a/code/controllers/subsystem/dbcore.dm
+++ b/code/controllers/subsystem/dbcore.dm
@@ -674,7 +674,7 @@ Ignore_errors instructes mysql to continue inserting rows if some of them have e
/datum/db_query/proc/slow_query_check()
- message_admins("HEY! A database query timed out. Did the server just hang? \[YES\]|\[NO\]")
+ message_admins("HEY! A database query timed out. Did the server just hang? \[YES\]|\[NO\]")
/datum/db_query/proc/NextRow(async = TRUE)
Activity("NextRow")
diff --git a/code/controllers/subsystem/dynamic/dynamic.dm b/code/controllers/subsystem/dynamic/dynamic.dm
index d22f30f209934..88238f8253b8d 100644
--- a/code/controllers/subsystem/dynamic/dynamic.dm
+++ b/code/controllers/subsystem/dynamic/dynamic.dm
@@ -203,23 +203,23 @@ SUBSYSTEM_DEF(dynamic)
/datum/controller/subsystem/dynamic/proc/admin_panel()
var/list/dat = list("Game Mode Panel
Game Mode Panel
")
- dat += "Dynamic Mode \[VV\]\[Refresh\] "
+ dat += "Dynamic Mode \[VV\]\[Refresh\] "
dat += "Threat Level: [threat_level] "
dat += "Budgets (Roundstart/Midrounds): [initial_round_start_budget]/[threat_level - initial_round_start_budget] "
- dat += "Midround budget to spend: [mid_round_budget]\[Adjust\]\[View Log\] "
+ dat += "Midround budget to spend: [mid_round_budget]\[Adjust\]\[View Log\] "
dat += " "
dat += "Parameters: centre = [threat_curve_centre] ; width = [threat_curve_width]. "
dat += "Split parameters: centre = [roundstart_split_curve_centre] ; width = [roundstart_split_curve_width]. "
dat += "On average, [clamp(peaceful_percentage, 1, 99)]% of the rounds are more peaceful. "
- dat += "Forced extended: [GLOB.dynamic_forced_extended ? "On" : "Off"] "
- dat += "No stacking (only one round-ender): [GLOB.dynamic_no_stacking ? "On" : "Off"] "
- dat += "Stacking limit: [GLOB.dynamic_stacking_limit] \[Adjust\]"
+ dat += "Forced extended: [GLOB.dynamic_forced_extended ? "On" : "Off"] "
+ dat += "No stacking (only one round-ender): [GLOB.dynamic_no_stacking ? "On" : "Off"] "
+ dat += "Stacking limit: [GLOB.dynamic_stacking_limit] \[Adjust\]"
dat += " "
- dat += "\[Force Next Latejoin Ruleset\] "
+ dat += "\[Force Next Latejoin Ruleset\] "
if (forced_latejoin_rule)
- dat += {"-> [forced_latejoin_rule.name] <- "}
- dat += "\[Execute Midround Ruleset\] "
+ dat += {"-> [forced_latejoin_rule.name] <- "}
+ dat += "\[Execute Midround Ruleset\] "
dat += " "
dat += "Executed rulesets: "
if (executed_rules.len > 0)
@@ -229,13 +229,13 @@ SUBSYSTEM_DEF(dynamic)
else
dat += "none. "
dat += " Injection Timers: ([get_heavy_midround_injection_chance(dry_run = TRUE)]% heavy midround chance) "
- dat += "Latejoin: [DisplayTimeText(latejoin_injection_cooldown-world.time)] \[Now!\] "
+ dat += "Latejoin: [DisplayTimeText(latejoin_injection_cooldown-world.time)] \[Now!\] "
var/next_injection = next_midround_injection()
if (next_injection == INFINITY)
dat += "All midrounds have been exhausted."
else
- dat += "Midround: [DisplayTimeText(next_injection - world.time)] \[Now!\] "
+ dat += "Midround: [DisplayTimeText(next_injection - world.time)] \[Now!\] "
usr << browse(dat.Join(), "window=gamemode_panel;size=500x500")
diff --git a/code/controllers/subsystem/dynamic/ruleset_picking.dm b/code/controllers/subsystem/dynamic/ruleset_picking.dm
index e3de3289899f7..f22ce3315740e 100644
--- a/code/controllers/subsystem/dynamic/ruleset_picking.dm
+++ b/code/controllers/subsystem/dynamic/ruleset_picking.dm
@@ -69,8 +69,8 @@
log_dynamic("[rule] ruleset executing...")
message_admins("DYNAMIC: Executing midround ruleset [rule] in [DisplayTimeText(ADMIN_CANCEL_MIDROUND_TIME)]. \
- CANCEL | \
- SOMETHING ELSE")
+ CANCEL | \
+ SOMETHING ELSE")
return rule
diff --git a/code/controllers/subsystem/explosions.dm b/code/controllers/subsystem/explosions.dm
index 20194e66626ca..2b61cabb86074 100644
--- a/code/controllers/subsystem/explosions.dm
+++ b/code/controllers/subsystem/explosions.dm
@@ -524,6 +524,7 @@ ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effec
/datum/controller/subsystem/explosions/proc/shake_the_room(turf/epicenter, near_distance, far_distance, quake_factor, echo_factor, creaking, sound/near_sound = sound(get_sfx(SFX_EXPLOSION)), sound/far_sound = sound('sound/effects/explosion/explosionfar.ogg'), sound/echo_sound = sound('sound/effects/explosion/explosion_distant.ogg'), sound/creaking_sound = sound(get_sfx(SFX_EXPLOSION_CREAKING)), hull_creaking_sound = sound(get_sfx(SFX_HULL_CREAKING)))
var/frequency = get_rand_frequency()
var/blast_z = epicenter.z
+ var/area/epicenter_area = get_area(epicenter)
if(isnull(creaking)) // Autoset creaking.
var/on_station = SSmapping.level_trait(epicenter.z, ZTRAIT_STATION)
if(on_station && prob((quake_factor * QUAKE_CREAK_PROB) + (echo_factor * ECHO_CREAK_PROB))) // Huge explosions are near guaranteed to make the station creak and whine, smaller ones might.
@@ -559,7 +560,7 @@ ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effec
base_shake_amount = max(base_shake_amount, quake_factor * 3, 0) // Devastating explosions rock the station and ground
shake_camera(listener, FAR_SHAKE_DURATION, min(base_shake_amount, FAR_SHAKE_CAP))
- else if(!isspaceturf(listener_turf) && echo_factor) // Big enough explosions echo through the hull.
+ else if(!isspaceturf(listener_turf) && !(!(epicenter_area.type in GLOB.the_station_areas) && SSmapping.is_planetary()) && echo_factor) // Big enough explosions echo through the hull. Except on planetary maps if the epicenter is not on the station's area.
var/echo_volume
if(quake_factor)
echo_volume = 60
diff --git a/code/controllers/subsystem/lag_switch.dm b/code/controllers/subsystem/lag_switch.dm
index c79db05186017..291e80fe18f1f 100644
--- a/code/controllers/subsystem/lag_switch.dm
+++ b/code/controllers/subsystem/lag_switch.dm
@@ -34,7 +34,7 @@ SUBSYSTEM_DEF(lag_switch)
auto_switch = FALSE
UnregisterSignal(SSdcs, COMSIG_GLOB_CLIENT_CONNECT)
veto_timer_id = addtimer(CALLBACK(src, PROC_REF(set_all_measures), TRUE, TRUE), 20 SECONDS, TIMER_STOPPABLE)
- message_admins("Lag Switch population threshold reached. Automatic activation of lag mitigation measures occuring in 20 seconds. (CANCEL)")
+ message_admins("Lag Switch population threshold reached. Automatic activation of lag mitigation measures occuring in 20 seconds. (CANCEL)")
log_admin("Lag Switch population threshold reached. Automatic activation of lag mitigation measures occuring in 20 seconds.")
/// (En/Dis)able automatic triggering of switches based on client count
diff --git a/code/controllers/subsystem/map_vote.dm b/code/controllers/subsystem/map_vote.dm
index ced1e65e3a215..f57d73d773e63 100644
--- a/code/controllers/subsystem/map_vote.dm
+++ b/code/controllers/subsystem/map_vote.dm
@@ -53,7 +53,7 @@ SUBSYSTEM_DEF(map_vote)
last_message_at = world.time
var/list/messages = args.Copy()
- to_chat(world, span_purple(examine_block("Map Vote\n[messages.Join("\n")]")))
+ to_chat(world, span_purple(boxed_message("Map Vote\n[messages.Join("\n")]")))
/datum/controller/subsystem/map_vote/proc/finalize_map_vote(datum/vote/map_vote/map_vote)
if(already_voted)
@@ -170,4 +170,4 @@ SUBSYSTEM_DEF(map_vote)
for(var/map_id in map_vote_cache)
var/datum/map_config/map = config.maplist[map_id]
data += "[map.map_name] - [map_vote_cache[map_id]]"
- tally_printout = examine_block("Current Tallies\n[data.Join("\n")]")
+ tally_printout = boxed_message("Current Tallies\n[data.Join("\n")]")
diff --git a/code/controllers/subsystem/polling.dm b/code/controllers/subsystem/polling.dm
index c9c7d3ea31167..6624c984cbb6a 100644
--- a/code/controllers/subsystem/polling.dm
+++ b/code/controllers/subsystem/polling.dm
@@ -148,11 +148,11 @@ SUBSYSTEM_DEF(polling)
var/custom_link_style_start = ""
var/custom_link_style_end = "style='color:DodgerBlue;font-weight:bold;-dm-text-outline: 1px black'"
if(isatom(alert_pic) && isobserver(candidate_mob))
- act_jump = "[custom_link_style_start]\[Teleport\]"
- var/act_signup = "[custom_link_style_start]\[[start_signed_up ? "Opt out" : "Sign Up"]\]"
+ act_jump = "[custom_link_style_start]\[Teleport\]"
+ var/act_signup = "[custom_link_style_start]\[[start_signed_up ? "Opt out" : "Sign Up"]\]"
var/act_never = ""
if(ignore_category)
- act_never = "[custom_link_style_start]\[Never For This Round\]"
+ act_never = "[custom_link_style_start]\[Never For This Round\]"
if(!duplicate_message_check(alert_poll)) //Only notify people once. They'll notice if there are multiple and we don't want to spam people.
SEND_SOUND(candidate_mob, 'sound/announcer/notice/notice2.ogg')
@@ -165,7 +165,7 @@ SUBSYSTEM_DEF(polling)
else
surrounding_image = image(chat_text_border_icon)
surrounding_icon = icon2html(surrounding_image, candidate_mob, extra_classes = "bigicon")
- var/final_message = examine_block("[surrounding_icon] [span_ooc(question)] [surrounding_icon]\n[act_jump] [act_signup] [act_never]")
+ var/final_message = boxed_message("[surrounding_icon] [span_ooc(question)] [surrounding_icon]\n[act_jump] [act_signup] [act_never]")
to_chat(candidate_mob, final_message)
// Start processing it so it updates visually the timer
diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index 4f573ee2f2224..ff19d6d4b265a 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -385,7 +385,7 @@ SUBSYSTEM_DEF(shuttle)
SSblackbox.record_feedback("text", "shuttle_reason", 1, "[call_reason]")
log_shuttle("Shuttle call reason: [call_reason]")
SSticker.emergency_reason = call_reason
- message_admins("[ADMIN_LOOKUPFLW(user)] has called the shuttle. (TRIGGER CENTCOM RECALL)")
+ message_admins("[ADMIN_LOOKUPFLW(user)] has called the shuttle. (TRIGGER CENTCOM RECALL)")
/// Call the emergency shuttle.
/// If you are doing this on behalf of a player, use requestEvac instead.
diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm
index 5be680744f676..066436d0ec698 100644
--- a/code/controllers/subsystem/statpanel.dm
+++ b/code/controllers/subsystem/statpanel.dm
@@ -39,6 +39,15 @@ SUBSYSTEM_DEF(statpanels)
var/ETA = SSshuttle.emergency.getModeStr()
if(ETA)
global_data += "[ETA] [SSshuttle.emergency.getTimerStr()]"
+
+ if(SSticker.reboot_timer)
+ var/reboot_time = timeleft(SSticker.reboot_timer)
+ if(reboot_time)
+ global_data += "Reboot: [DisplayTimeText(reboot_time, 1)]"
+ // admin must have delayed round end
+ else if(SSticker.ready_for_reboot)
+ global_data += "Reboot: DELAYED"
+
src.currentrun = GLOB.clients.Copy()
mc_data = null
@@ -94,11 +103,14 @@ SUBSYSTEM_DEF(statpanels)
return
/datum/controller/subsystem/statpanels/proc/set_status_tab(client/target)
+#if MIN_COMPILER_VERSION > 515
+ #warn 516 is most certainly out of beta, remove this beta notice if you haven't already
+#endif
+ var/static/list/beta_notice = list("", "You are on the BYOND 516 beta, various UIs and such may be broken!", "Please report issues, and switch back to BYOND 515 if things are causing too many issues for you.")
if(!global_data)//statbrowser hasnt fired yet and we were called from immediate_send_stat_data()
return
-
target.stat_panel.send_message("update_stat", list(
- "global_data" = global_data,
+ "global_data" = (target.byond_version < 516) ? global_data : (global_data + beta_notice),
"ping_str" = "Ping: [round(target.lastping, 1)]ms (Average: [round(target.avgping, 1)]ms)",
"other_str" = target.mob?.get_status_tab_items(),
))
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index bb18a45b72d9a..96cde0ef0dded 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -67,6 +67,9 @@ SUBSYSTEM_DEF(ticker)
/// Why an emergency shuttle was called
var/emergency_reason
+ /// ID of round reboot timer, if it exists
+ var/reboot_timer = null
+
/datum/controller/subsystem/ticker/Initialize()
var/list/byond_sound_formats = list(
"mid" = TRUE,
@@ -487,7 +490,7 @@ SUBSYSTEM_DEF(ticker)
if(!hard_popcap)
list_clear_nulls(queued_players)
for (var/mob/dead/new_player/new_player in queued_players)
- to_chat(new_player, span_userdanger("The alive players limit has been released! [html_encode(">>Join Game<<")]"))
+ to_chat(new_player, span_userdanger("The alive players limit has been released! [html_encode(">>Join Game<<")]"))
SEND_SOUND(new_player, sound('sound/announcer/notice/notice1.ogg'))
GLOB.latejoin_menu.ui_interact(new_player)
queued_players.len = 0
@@ -502,7 +505,7 @@ SUBSYSTEM_DEF(ticker)
list_clear_nulls(queued_players)
if(living_player_count() < hard_popcap)
if(next_in_line?.client)
- to_chat(next_in_line, span_userdanger("A slot has opened! You have approximately 20 seconds to join. \>\>Join Game\<\<"))
+ to_chat(next_in_line, span_userdanger("A slot has opened! You have approximately 20 seconds to join. \>\>Join Game\<\<"))
SEND_SOUND(next_in_line, sound('sound/announcer/notice/notice1.ogg'))
next_in_line.ui_interact(next_in_line)
return
@@ -698,11 +701,10 @@ SUBSYSTEM_DEF(ticker)
var/start_wait = world.time
UNTIL(round_end_sound_sent || (world.time - start_wait) > (delay * 2)) //don't wait forever
- sleep(delay - (world.time - start_wait))
+ reboot_timer = addtimer(CALLBACK(src, PROC_REF(reboot_callback), reason, end_string), delay - (world.time - start_wait), TIMER_STOPPABLE)
- if(delay_end && !skip_delay)
- to_chat(world, span_boldannounce("Reboot was cancelled by an admin."))
- return
+
+/datum/controller/subsystem/ticker/proc/reboot_callback(reason, end_string)
if(end_string)
end_state = end_string
@@ -710,6 +712,21 @@ SUBSYSTEM_DEF(ticker)
world.Reboot()
+/**
+ * Deletes the current reboot timer and nulls the var
+ *
+ * Arguments:
+ * * user - the user that cancelled the reboot, may be null
+ */
+/datum/controller/subsystem/ticker/proc/cancel_reboot(mob/user)
+ if(!reboot_timer)
+ to_chat(user, span_warning("There is no pending reboot!"))
+ return FALSE
+ to_chat(world, span_boldannounce("An admin has delayed the round end."))
+ deltimer(reboot_timer)
+ reboot_timer = null
+ return TRUE
+
/datum/controller/subsystem/ticker/Shutdown()
gather_newscaster() //called here so we ensure the log is created even upon admin reboot
if(!round_end_sound)
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index d0e642bd3aa2d..d9d796782c2b2 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -119,7 +119,7 @@ SUBSYSTEM_DEF(vote)
)
log_vote("vote finalized", vote_log_data)
if(to_display)
- to_chat(world, span_infoplain(vote_font("\n[to_display]")))
+ to_chat(world, span_infoplain(vote_font("[to_display]")))
// Finally, doing any effects on vote completion
current_vote.finalize_vote(final_winner)
@@ -230,9 +230,9 @@ SUBSYSTEM_DEF(vote)
var/to_display = current_vote.initiate_vote(vote_initiator_name, duration)
log_vote(to_display)
- to_chat(world, span_infoplain(vote_font("\n[span_bold(to_display)]\n\
+ to_chat(world, custom_boxed_message("purple_box center", span_infoplain(vote_font("[span_bold(to_display)] \
Type vote or click here to place your votes.\n\
- You have [DisplayTimeText(duration)] to vote.")))
+ You have [DisplayTimeText(duration)] to vote."))))
// And now that it's going, give everyone a voter action
for(var/client/new_voter as anything in GLOB.clients)
diff --git a/code/datums/actions/action.dm b/code/datums/actions/action.dm
index 2f297f480ae66..18525a8c04e94 100644
--- a/code/datums/actions/action.dm
+++ b/code/datums/actions/action.dm
@@ -435,5 +435,5 @@
if(source.next_click > world.time)
return
else
- source.next_click = world.time + CLICK_CD_RANGE
+ source.next_click = world.time + CLICK_CD_ACTIVATE_ABILITY
INVOKE_ASYNC(src, PROC_REF(Trigger))
diff --git a/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm b/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm
index 6cae6132d3688..4d7a3e7ad3064 100644
--- a/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm
+++ b/code/datums/ai/basic_mobs/basic_subtrees/express_happiness.dm
@@ -31,11 +31,11 @@
var/list/final_list
switch(happiness_value)
if(HIGH_HAPPINESS_THRESHOLD to INFINITY)
- final_list = happy_emotions
+ final_list = controller.blackboard[BB_HAPPY_EMOTIONS] || happy_emotions
if(MODERATE_HAPPINESS_THRESHOLD to HIGH_HAPPINESS_THRESHOLD)
- final_list = moderate_emotions
+ final_list = controller.blackboard[BB_MODERATE_EMOTIONS] || moderate_emotions
else
- final_list = depressed_emotions
+ final_list = controller.blackboard[BB_SAD_EMOTIONS] || depressed_emotions
if(!length(final_list))
return
controller.queue_behavior(/datum/ai_behavior/perform_emote, pick(final_list))
diff --git a/code/datums/ai_laws/ai_laws.dm b/code/datums/ai_laws/ai_laws.dm
index a0d1d629fc8d3..a25f7e694a9ad 100644
--- a/code/datums/ai_laws/ai_laws.dm
+++ b/code/datums/ai_laws/ai_laws.dm
@@ -442,7 +442,7 @@ GLOBAL_VAR(round_default_lawset)
/datum/ai_laws/proc/show_laws(mob/to_who)
var/list/printable_laws = get_law_list(include_zeroth = TRUE)
- to_chat(to_who, examine_block(jointext(printable_laws, "\n")))
+ to_chat(to_who, boxed_message(jointext(printable_laws, "\n")))
/datum/ai_laws/proc/associate(mob/living/silicon/M)
if(owner)
diff --git a/code/datums/browser.dm b/code/datums/browser.dm
index b9d859552389d..cf0df8dac5017 100644
--- a/code/datums/browser.dm
+++ b/code/datums/browser.dm
@@ -138,13 +138,13 @@
var/output = {"
- Stacking threeshold: Current value : [GLOB.dynamic_stacking_limit].
+ Stacking threeshold: Current value : [GLOB.dynamic_stacking_limit].
The threshold at which "round-ender" rulesets will stack. A value higher than 100 ensure this never happens.
"}
@@ -131,9 +131,9 @@ ADMIN_VERB(spawn_cargo, R_SPAWN, "Spawn Cargo", "Spawn a cargo crate.", ADMIN_CA
Change these options to forcibly enable or disable dynamic rulesets. \
Disabled rulesets will never run, even if they would otherwise be valid. \
Enabled rulesets will run even if the qualifying minimum of threat or player count is not present, this does not guarantee that they will necessarily be chosen (for example their weight may be set to 0 in config). \
- \[force enable all / \
- force disable all / \
- reset all\]"
+ \[force enable all / \
+ force disable all / \
+ reset all\]"
if (SSticker.current_state <= GAME_STATE_PREGAME) // Don't bother displaying after the round has started
var/static/list/rulesets_by_context = list()
@@ -166,9 +166,9 @@ ADMIN_VERB(spawn_cargo, R_SPAWN, "Spawn Cargo", "Spawn a cargo crate.", ADMIN_CA
if (RULESET_FORCE_DISABLED)
color = COLOR_RED
dat += "
"
var/special_statuses = get_special_statuses()
if(length(special_statuses))
@@ -138,7 +138,7 @@ GLOBAL_VAR(antag_prototypes)
continue //Let's skip subtypes of what we already shown.
else if(prototype.show_in_antagpanel)
if(prototype.can_be_owned(src))
- possible_admin_antags += "[prototype.name]"
+ possible_admin_antags += "[prototype.name]"
else
possible_admin_antags += "[prototype.name]"
else
@@ -155,8 +155,8 @@ GLOBAL_VAR(antag_prototypes)
else //Show removal and current one
priority_sections |= antag_category
antag_header_parts += span_bad("[current_antag.name]")
- antag_header_parts += "Remove"
- antag_header_parts += "Open VV"
+ antag_header_parts += "Remove"
+ antag_header_parts += "Open VV"
//We aren't antag of this category, grab first prototype to check the prefs (This is pretty vague but really not sure how else to do this)
@@ -196,19 +196,19 @@ GLOBAL_VAR(antag_prototypes)
var/datum/component/uplink/U = find_syndicate_uplink()
if(U)
if(!U.uplink_handler.has_objectives)
- uplink_info += "take"
+ uplink_info += "take"
if (check_rights(R_FUN, 0))
- uplink_info += ", [U.uplink_handler.telecrystals] TC"
+ uplink_info += ", [U.uplink_handler.telecrystals] TC"
if(U.uplink_handler.has_progression)
- uplink_info += ", [U.uplink_handler.progression_points] PR"
+ uplink_info += ", [U.uplink_handler.progression_points] PR"
if(U.uplink_handler.has_objectives)
- uplink_info += ", Force Give Objective"
+ uplink_info += ", Force Give Objective"
else
uplink_info += ", [U.uplink_handler.telecrystals] TC"
if(U.uplink_handler.has_progression)
uplink_info += ", [U.uplink_handler.progression_points] PR"
else
- uplink_info += "give"
+ uplink_info += "give"
uplink_info += "." //hiel grammar
out += uplink_info + " "
diff --git a/code/modules/admin/check_antagonists.dm b/code/modules/admin/check_antagonists.dm
index 04db519ffb50a..30071504c9199 100644
--- a/code/modules/admin/check_antagonists.dm
+++ b/code/modules/admin/check_antagonists.dm
@@ -5,9 +5,9 @@
if(!owner)
return "Unassigned"
if(owner.current)
- return "[owner.current.real_name] "
+ return "[owner.current.real_name] "
else
- return "[owner.name] "
+ return "[owner.name] "
//Whatever interesting things happened to the antag admins should know about
//Include additional information about antag in this part
@@ -28,12 +28,12 @@
if(!owner)
return
var/list/parts = list()
- parts += "PM"
+ parts += "PM"
if(owner.current) //There's body to follow
- parts += "FLW"
+ parts += "FLW"
else
parts += ""
- parts += "Show Objective"
+ parts += "Show Objective"
return parts //Better as one cell or two/three
//Builds table row for the antag
@@ -95,26 +95,26 @@
tgui_alert(usr, "The game hasn't started yet!")
return
var/list/dat = list("Round Status
Round Status
")
- dat += "Game Mode Panel "
+ dat += "Game Mode Panel "
dat += "Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)] "
dat += "Emergency shuttle "
if(EMERGENCY_IDLE_OR_RECALLED)
- dat += "Call Shuttle "
+ dat += "Call Shuttle "
else
var/timeleft = SSshuttle.emergency.timeLeft()
if(SSshuttle.emergency.mode == SHUTTLE_CALL)
- dat += "ETA: [(timeleft / 60) % 60]:[add_leading(num2text(timeleft % 60), 2, "0")] "
- dat += "Send Back "
+ dat += "ETA: [(timeleft / 60) % 60]:[add_leading(num2text(timeleft % 60), 2, "0")] "
+ dat += "Send Back "
else
- dat += "ETA: [(timeleft / 60) % 60]:[add_leading(num2text(timeleft % 60), 2, "0")] "
- dat += "End Round Now "
+ dat += "ETA: [(timeleft / 60) % 60]:[add_leading(num2text(timeleft % 60), 2, "0")] "
+ dat += "End Round Now "
if(SSticker.delay_end)
- dat += "Undelay Round End "
+ dat += "Undelay Round End "
else
- dat += "Delay Round End "
- dat += "Enable/Disable CTF "
- dat += "Reboot World "
- dat += "Check Teams"
+ dat += "Delay Round End "
+ dat += "Enable/Disable CTF "
+ dat += "Reboot World "
+ dat += "Check Teams"
var/connected_players = GLOB.clients.len
var/lobby_players = 0
var/observers = 0
diff --git a/code/modules/admin/greyscale_modify_menu.dm b/code/modules/admin/greyscale_modify_menu.dm
index 0bc1ec01f5d4f..c87c424661fd2 100644
--- a/code/modules/admin/greyscale_modify_menu.dm
+++ b/code/modules/admin/greyscale_modify_menu.dm
@@ -241,14 +241,24 @@ This is highly likely to cause massive amounts of lag as every object in the gam
config.EnableAutoRefresh(config_owner_type)
/datum/greyscale_modify_menu/proc/ReadColorsFromString(colorString)
- var/list/new_split_colors = list()
+ //length validation
var/list/colors = splittext(colorString, "#")
- for(var/index in 2 to min(length(colors), config.expected_colors + 1))
+ if(length(colors) <= 1) //doesn't even begin with a # so isn't even a color
+ return FALSE
+ colors.Cut(1, 2) //removes the white space as a consequence of the string beginning with a #
+ if(colors.len != config.expected_colors) //not the expected length
+ return FALSE
+
+ //value validation
+ var/list/new_split_colors = list()
+ for(var/index in 1 to config.expected_colors)
var/color = "#[colors[index]]"
if(!findtext(color, GLOB.is_color) && (!unlocked || !findtext(color, GLOB.is_alpha_color)))
return FALSE
new_split_colors += color
split_colors = new_split_colors
+
+ //all good
return TRUE
/datum/greyscale_modify_menu/proc/randomize_color(color_index)
diff --git a/code/modules/admin/known_alts.dm b/code/modules/admin/known_alts.dm
index 4105c7f4edc93..3c51ca68bdf1b 100644
--- a/code/modules/admin/known_alts.dm
+++ b/code/modules/admin/known_alts.dm
@@ -168,7 +168,7 @@ GLOBAL_DATUM_INIT(known_alts, /datum/known_alts, new)
var/list/known_alts_html = list()
for (var/known_alt in load_known_alts())
- known_alts_html += "\[-\] Delete[known_alt[1]] is an alt of [known_alt[2]] (added by [known_alt[3]])."
+ known_alts_html += "\[-\] Delete[known_alt[1]] is an alt of [known_alt[2]] (added by [known_alt[3]])."
var/html = {"
@@ -179,7 +179,7 @@ GLOBAL_DATUM_INIT(known_alts, /datum/known_alts, new)
Any two ckeys in this panel will not show in "banned connection history".
Sometimes players switch account, and it's customary to perma-ban the old one.