diff --git a/_maps/RandomRuins/StationRuins/Lavaland/Mining_Station/Mining_Station_Public_01.dmm b/_maps/RandomRuins/StationRuins/Lavaland/Mining_Station/Mining_Station_Public_01.dmm
index 9ef45ab30a..1aed2fdbb0 100644
--- a/_maps/RandomRuins/StationRuins/Lavaland/Mining_Station/Mining_Station_Public_01.dmm
+++ b/_maps/RandomRuins/StationRuins/Lavaland/Mining_Station/Mining_Station_Public_01.dmm
@@ -1552,10 +1552,14 @@
/turf/open/floor/plasteel/freezer,
/area/mine/living_quarters)
"yZ" = (
-/obj/docking_port/stationary/public_mining_dock{
+/obj/docking_port/stationary{
+ area_type = /area/lavaland/surface/outdoors;
dir = 8;
+ dwidth = 3;
+ height = 7;
id = "lavaland_common_away";
- name = "Mining Station Public Wing"
+ name = "Lavaland Mining Public Wing";
+ width = 7
},
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index f651d1df7c..4eea726f74 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -56600,10 +56600,6 @@
},
/turf/open/floor/plasteel,
/area/security/brig)
-"lxP" = (
-/mob/living/simple_animal/opossum,
-/turf/closed/wall,
-/area/science/xenobiology)
"lzt" = (
/obj/machinery/portable_atmospherics/pump,
/obj/effect/turf_decal/stripes/line,
@@ -107389,7 +107385,7 @@ bLe
bMr
bNr
bIT
-lxP
+bJN
bJN
bJN
bJN
diff --git a/_maps/shuttles/mining_common_kilo.dmm b/_maps/shuttles/mining_common_kilo.dmm
index 96208b7d4b..111944d08c 100644
--- a/_maps/shuttles/mining_common_kilo.dmm
+++ b/_maps/shuttles/mining_common_kilo.dmm
@@ -88,7 +88,7 @@
dir = 8;
dwidth = 3;
height = 5;
- id = "mining_common";
+ id = "mining_shuttle_common";
name = "lavaland shuttle";
port_direction = 4;
width = 7
diff --git a/_maps/shuttles/mining_common_meta.dmm b/_maps/shuttles/mining_common_meta.dmm
index f04f8e1a3b..c47d3b806f 100644
--- a/_maps/shuttles/mining_common_meta.dmm
+++ b/_maps/shuttles/mining_common_meta.dmm
@@ -37,7 +37,7 @@
dir = 8;
dwidth = 3;
height = 5;
- id = "mining_common";
+ id = "mining_shuttle_common";
name = "lavaland shuttle";
port_direction = 4;
width = 7
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 0704947dda..30162594d6 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -159,6 +159,7 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache)
#define BLOOD_COLOR_LIZARD "#db004D"
#define BLOOD_COLOR_UNIVERSAL "#db3300"
#define BLOOD_COLOR_BUG "#a37c0f"
+#define BLOOD_COLOR_PLANT "#3d610e"
//suit sensors: sensor_mode defines
diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm
index bc3f6cf51b..8c4fba367d 100644
--- a/code/controllers/subsystem/input.dm
+++ b/code/controllers/subsystem/input.dm
@@ -6,6 +6,12 @@ SUBSYSTEM_DEF(input)
priority = FIRE_PRIORITY_INPUT
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
+ /// KEEP THIS UP TO DATE!
+ var/static/list/all_macrosets = list(
+ SKIN_MACROSET_HOTKEYS,
+ SKIN_MACROSET_CLASSIC_HOTKEYS,
+ SKIN_MACROSET_CLASSIC_INPUT
+ )
/// Classic mode input focused macro set. Manually set because we can't define ANY or ANY+UP for classic.
var/static/list/macroset_classic_input
/// Classic mode map focused macro set. Manually set because it needs to be clientside and go to macroset_classic_input.
@@ -51,11 +57,6 @@ SUBSYSTEM_DEF(input)
// let's play the ascii game of A to Z (UPPERCASE)
for(var/i in 65 to 90)
classic_ctrl_override_keys += ascii2text(i)
- // let's play the game of clientside bind overrides!
- classic_ctrl_override_keys -= list("T", "O", "M", "L")
- macroset_classic_input["Ctrl+T"] = "say"
- macroset_classic_input["Ctrl+O"] = "ooc"
- macroset_classic_input["Ctrl+L"] = "looc"
// let's play the list iteration game x2
for(var/key in classic_ctrl_override_keys)
// make sure to double double quote to ensure things are treated as a key combo instead of addition/semicolon logic.
@@ -67,20 +68,6 @@ SUBSYSTEM_DEF(input)
// FINALLY, WE CAN DO SOMETHING MORE NORMAL FOR THE SNOWFLAKE-BUT-LESS KEYSET.
- // HAHA - SIKE. Because of BYOND weirdness (tl;dr not specifically binding this way results in potentially duplicate chatboxes when
- // conflicts occur with something like say indicator vs say), we're going to snowflake this anyways
- var/list/hard_binds = list(
- "O" = "ooc",
- "T" = "say",
- "L" = "looc",
- "M" = "me"
- )
- var/list/hard_bind_anti_collision = list()
- var/list/anti_collision_modifiers = list("Ctrl", "Alt", "Shift", "Ctrl+Alt", "Ctrl+Shift", "Alt+Shift", "Ctrl+Alt+Shift")
- for(var/key in hard_binds)
- for(var/modifier in anti_collision_modifiers)
- hard_bind_anti_collision["[modifier]+[key]"] = ".NONSENSICAL_VERB_THAT_DOES_NOTHING"
-
macroset_classic_hotkey = list(
"Any" = "\"KeyDown \[\[*\]\]\"",
"Any+UP" = "\"KeyUp \[\[*\]\]\"",
@@ -89,9 +76,6 @@ SUBSYSTEM_DEF(input)
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
)
- macroset_classic_hotkey |= hard_binds
- macroset_classic_hotkey |= hard_bind_anti_collision
-
// And finally, the modern set.
macroset_hotkey = list(
"Any" = "\"KeyDown \[\[*\]\]\"",
@@ -101,16 +85,12 @@ SUBSYSTEM_DEF(input)
"Back" = "\".winset \\\"input.text=\\\"\\\"\\\"\"",
)
- macroset_hotkey |= hard_binds
- macroset_hotkey |= hard_bind_anti_collision
-
// Badmins just wanna have fun ♪
/datum/controller/subsystem/input/proc/refresh_client_macro_sets()
var/list/clients = GLOB.clients
for(var/i in 1 to clients.len)
var/client/user = clients[i]
- user.set_macros()
- user.update_movement_keys()
+ user.full_macro_assert()
/datum/controller/subsystem/input/fire()
var/list/clients = GLOB.clients // Let's sing the list cache song
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 3cd2011334..bed006d0b5 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -55,6 +55,7 @@
icon_state = "[src.base_state]open"
/obj/machinery/door/window/update_atom_colour()
+ . = ..()
if((color && (color_hex2num(color) < 255)))
visible = TRUE
if(density)
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 32d65041bc..8526727464 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -388,6 +388,8 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
new/datum/stack_recipe("mining satchel", /obj/item/storage/bag/ore, 4), \
new/datum/stack_recipe("chemistry bag", /obj/item/storage/bag/chemistry, 4), \
new/datum/stack_recipe("bio bag", /obj/item/storage/bag/bio, 4), \
+ new/datum/stack_recipe("material bag", /obj/item/storage/bag/material, 4), \
+ new/datum/stack_recipe("construction bag", /obj/item/storage/bag/construction, 4), \
null, \
new/datum/stack_recipe("string", /obj/item/weaponcrafting/string, 1, time = 10), \
new/datum/stack_recipe("improvised gauze", /obj/item/stack/medical/gauze/improvised, 1, 2, 6), \
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index ab1aab32a0..3dd48237d6 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -457,6 +457,9 @@
STR.display_numerical_stacking = FALSE
STR.can_hold = typecacheof(list(/obj/item/ammo_box/magazine, /obj/item/ammo_casing))
+/*
+Bag for holding materials
+*/
/obj/item/storage/bag/material
name = "material pouch"
desc = "A pouch for sheets and RCD ammunition that manages to hang where you would normally put things in your pocket."
@@ -474,3 +477,24 @@
STR.max_items = 2
STR.display_numerical_stacking = TRUE
STR.can_hold = typecacheof(list(/obj/item/rcd_ammo, /obj/item/stack/sheet))
+
+/*
+ * Construction bag (for engineering, holds stock parts and electronics)
+ */
+
+/obj/item/storage/bag/construction
+ name = "construction bag"
+ icon = 'icons/obj/tools.dmi'
+ icon_state = "construction_bag"
+ desc = "A bag for storing small construction components."
+ w_class = WEIGHT_CLASS_TINY
+ resistance_flags = FLAMMABLE
+
+/obj/item/storage/bag/construction/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_combined_w_class = 100
+ STR.max_items = 50
+ STR.max_w_class = WEIGHT_CLASS_SMALL
+ STR.insert_preposition = "in"
+ STR.can_hold = typecacheof(list(/obj/item/stack/ore/bluespace_crystal, /obj/item/assembly, /obj/item/stock_parts, /obj/item/reagent_containers/glass/beaker, /obj/item/stack/cable_coil, /obj/item/circuitboard, /obj/item/electronics,/obj/item/wallframe/camera))
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
index 05798df953..3cbeae1ce8 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
@@ -30,6 +30,8 @@
new /obj/item/construction/rcd/loaded/upgraded(src)
new /obj/item/clothing/suit/hooded/wintercoat/ce(src)
new /obj/item/clothing/head/beret/ce/white(src)
+ new /obj/item/storage/bag/construction(src)
+ new /obj/item/storage/bag/material(src)
/obj/structure/closet/secure_closet/engineering_electrical
name = "electrical supplies locker"
@@ -78,6 +80,8 @@
new /obj/item/clothing/glasses/meson/engine(src)
new /obj/item/storage/box/emptysandbags(src)
new /obj/item/cartridge/engineering(src)
+ new /obj/item/storage/bag/construction(src)
+ new /obj/item/storage/bag/material(src)
/obj/structure/closet/secure_closet/atmospherics
name = "\proper atmospheric technician's locker"
@@ -99,6 +103,8 @@
new /obj/item/clothing/glasses/meson/engine/tray(src)
new /obj/item/extinguisher/advanced(src)
new /obj/item/cartridge/atmos(src)
+ new /obj/item/storage/bag/construction(src)
+ new /obj/item/storage/bag/material(src)
/*
* Empty lockers
diff --git a/code/modules/admin/permissionedit.dm b/code/modules/admin/permissionedit.dm
index 346f0e9790..05f7465b03 100644
--- a/code/modules/admin/permissionedit.dm
+++ b/code/modules/admin/permissionedit.dm
@@ -287,7 +287,7 @@
R = rank_names[new_rank]
if(!R) //rank with that name doesn't exist yet - make it
if(D)
- R = new(new_rank, D.rank.rights) //duplicate our previous admin_rank but with a new name
+ R = new(new_rank, D.rank.rights, D.rank.exclude_rights, D.rank.can_edit_rights) //duplicate our previous admin_rank but with a new name
else
R = new(new_rank) //blank new admin_rank
GLOB.admin_ranks += R
diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm
index 8f4e7ef3d6..dacd568993 100644
--- a/code/modules/antagonists/changeling/changeling.dm
+++ b/code/modules/antagonists/changeling/changeling.dm
@@ -18,7 +18,6 @@
var/list/stored_profiles = list() //list of datum/changelingprofile
var/datum/changelingprofile/first_prof = null
- var/dna_max = 6 //How many extra DNA strands the changeling can store for transformation.
var/absorbedcount = 0
/// did we get succed by another changeling
var/hostile_absorbed = FALSE
@@ -252,12 +251,6 @@
var/mob/living/carbon/user = owner.current
if(!istype(user))
return
- if(stored_profiles.len)
- var/datum/changelingprofile/prof = stored_profiles[1]
- if(prof.dna == user.dna && stored_profiles.len >= dna_max)//If our current DNA is the stalest, we gotta ditch it.
- if(verbose)
- to_chat(user, "We have reached our capacity to store genetic information! We must transform before absorbing more.")
- return
if(!target)
return
if(NO_DNA_COPY in target.dna.species.species_traits)
@@ -317,9 +310,6 @@
return prof
/datum/antagonist/changeling/proc/add_profile(datum/changelingprofile/prof)
- if(stored_profiles.len > dna_max)
- if(!push_out_profile())
- return
if(!first_prof)
first_prof = prof
@@ -340,19 +330,6 @@
stored_profiles -= prof
qdel(prof)
-/datum/antagonist/changeling/proc/get_profile_to_remove()
- for(var/datum/changelingprofile/prof in stored_profiles)
- if(!prof.protected)
- return prof
-
-/datum/antagonist/changeling/proc/push_out_profile()
- var/datum/changelingprofile/removeprofile = get_profile_to_remove()
- if(removeprofile)
- stored_profiles -= removeprofile
- return 1
- return 0
-
-
/datum/antagonist/changeling/proc/create_initial_profile()
var/mob/living/carbon/C = owner.current //only carbons have dna now, so we have to typecaste
if(ishuman(C))
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_items.dm b/code/modules/antagonists/eldritch_cult/eldritch_items.dm
index 2052a2fbb3..739304e822 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_items.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_items.dm
@@ -136,6 +136,7 @@
hoodtype = /obj/item/clothing/head/hooded/cult_hoodie/eldritch
// slightly better than normal cult robes
armor = list("melee" = 50, "bullet" = 50, "laser" = 50,"energy" = 50, "bomb" = 35, "bio" = 20, "rad" = 0, "fire" = 20, "acid" = 20)
+ mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON
/obj/item/reagent_containers/glass/beaker/eldritch
name = "flask of eldritch essence"
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index 53ab7f7abb..b71521121b 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -89,6 +89,8 @@
var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen.
+ /// Last time they used fix macros
+ var/last_macro_fix = 0
/// Keys currently held
var/list/keys_held = list()
/// These next two vars are to apply movement for keypresses and releases made while move delayed.
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index c581e402a6..267ee3a5e1 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -269,7 +269,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
prefs = new /datum/preferences(src)
GLOB.preferences_datums[ckey] = prefs
- addtimer(CALLBACK(src, .proc/ensure_keys_set), 10) //prevents possible race conditions
+ addtimer(CALLBACK(src, .proc/ensure_keys_set, prefs), 10) //prevents possible race conditions
prefs.last_ip = address //these are gonna be used for banning
prefs.last_id = computer_id //these are gonna be used for banning
@@ -443,7 +443,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them.
to_chat(src, "Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you.")
-
//This is down here because of the browse() calls in tooltip/New()
if(!tooltips)
tooltips = new /datum/tooltip(src)
@@ -475,11 +474,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
fit_viewport()
Master.UpdateTickRate()
-/client/proc/ensure_keys_set()
- if(SSinput.initialized)
- set_macros()
- update_movement_keys(prefs)
-
//////////////
//DISCONNECT//
//////////////
@@ -937,23 +931,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
y = clamp(y+change, min,max)
view_size.setDefault("[x]x[y]")
-/client/proc/update_movement_keys(datum/preferences/direct_prefs)
- var/datum/preferences/D = prefs || direct_prefs
- if(!D?.key_bindings)
- return
- movement_keys = list()
- for(var/key in D.key_bindings)
- for(var/kb_name in D.key_bindings[key])
- switch(kb_name)
- if("North")
- movement_keys[key] = NORTH
- if("East")
- movement_keys[key] = EAST
- if("West")
- movement_keys[key] = WEST
- if("South")
- movement_keys[key] = SOUTH
-
/client/proc/change_view(new_size)
if (isnull(new_size))
CRASH("change_view called without argument.")
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 0d01c4c343..80f3a8365c 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -53,7 +53,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
/// List with a key string associated to a list of keybindings. Unlike key_bindings, this one operates on raw key, allowing for binding a key that triggers regardless of if a modifier is depressed as long as the raw key is sent.
var/list/modless_key_bindings = list()
-
var/tgui_fancy = TRUE
var/tgui_lock = TRUE
var/windowflashing = TRUE
@@ -219,7 +218,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
//we couldn't load character data so just randomize the character appearance + name
random_character() //let's create a random character then - rather than a fat, bald and naked man.
key_bindings = deepCopyList(GLOB.hotkey_keybinding_list_by_key) // give them default keybinds and update their movement keys
- C?.update_movement_keys(src)
+ C?.ensure_keys_set(src)
real_name = pref_species.random_name(gender,1)
if(!loaded_preferences_successfully)
save_preferences()
@@ -952,7 +951,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/list/default_keys = hotkeys ? kb.hotkey_keys : kb.classic_keys
if(LAZYLEN(default_keys))
dat += "| Default: [default_keys.Join(", ")]"
- dat += "Independent Binding: [current_independent_binding]"
+ dat += ""
+ if(!kb.special && !kb.clientside)
+ dat += "Independent Binding: [current_independent_binding]"
dat += "
"
else
var/bound_key = user_binds[kb.name][1]
@@ -965,7 +966,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/list/default_keys = hotkeys ? kb.classic_keys : kb.hotkey_keys
if(LAZYLEN(default_keys))
dat += "| Default: [default_keys.Join(", ")]"
- dat += "Independent Binding: [current_independent_binding]"
+ dat += ""
+ if(!kb.special && !kb.clientside)
+ dat += "Independent Binding: [current_independent_binding]"
dat += "
"
dat += "
"
@@ -991,7 +994,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
#undef APPEARANCE_CATEGORY_COLUMN
#undef MAX_MUTANT_ROWS
-/datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, old_key, independent = FALSE)
+/datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, old_key, independent = FALSE, special = FALSE)
var/HTML = {"