From aed3013410a511c4a384bbb7f0cdb9990c25136e Mon Sep 17 00:00:00 2001
From: silicons <2003111+silicons@users.noreply.github.com>
Date: Fri, 10 Jan 2025 11:34:32 -0500
Subject: [PATCH] bugfix / tweaks (#6959)
---
citadel.dme | 14 ++-
code/__DEFINES/mapping/multiz.dm | 22 +++-
code/__HELPERS/lists/associations.dm | 1 +
code/controllers/repository/flooring.dm | 12 +-
code/datums/components/_component.dm | 9 +-
.../components/mobs/mob_feign_impairment.dm | 62 +++++++++++
.../mobs/mob_self_horizontal_inversion.dm | 6 +
.../mobs/mob_self_vertical_inversion.dm | 40 +++++++
.../nanotrasen/nanotrasen-supply/costumes.dm | 4 +-
.../game/objects/items-inventory-rendering.dm | 2 +-
code/game/objects/items/gifts.dm | 1 -
.../melee/types/transforming/energy/saber.dm | 1 +
code/game/objects/items/stacks/rods.dm | 3 +-
code/game/objects/items/stacks/stack.dm | 41 +++++--
.../objects/items/stacks/tiles/tile_types.dm | 12 +-
code/game/objects/random/maintenance.dm | 2 +-
code/game/objects/structures/loot_piles.dm | 2 +-
code/game/objects/structures/trash_pile.dm | 2 +-
code/game/objects/systems/storage/storage.dm | 12 +-
code/game/rendering/legacy/radial.dm | 4 +
code/game/rendering/mob.dm | 2 +
.../simulated/floor/floor-construction.dm | 21 +++-
.../game/turfs/simulated/flooring/flooring.dm | 12 ++
.../simulated/flooring/flooring_types.dm | 3 -
code/modules/artwork/crayon_decal_meta.dm | 10 +-
code/modules/artwork/items/crayon.dm | 2 +
code/modules/clothing/accessories/halo.dm | 4 +-
code/modules/clothing/clothing.dm | 27 +++--
code/modules/clothing/under/_under.dm | 4 +-
code/modules/clothing/under/gear_harness.dm | 25 +++++
code/modules/clothing/under/miscellaneous.dm | 6 -
code/modules/frames/frame_step.dm | 10 +-
code/modules/frames/types/fire_alarm.dm | 2 +-
code/modules/loadout/loadout_xeno.dm | 2 +-
code/modules/materials/material_sheets.dm | 2 +-
code/modules/materials/material_synth.dm | 6 +
code/modules/mining/tools/vertibore.dm | 2 +-
code/modules/mob/animations.dm | 11 +-
.../mob/living/carbon/human/examine.dm | 7 +-
.../mob/living/carbon/human/human-defense.dm | 2 +-
.../mob/living/carbon/human/update_icons.dm | 2 +-
code/modules/mob/living/living.dm | 2 +-
code/modules/mob/living/say.dm | 4 +-
code/modules/mob/mob-status_procs.dm | 36 ++++++
code/modules/mob/mob.dm | 5 +
code/modules/mob/verbs/feign_impairment.dm | 105 ++++++++++++++++++
.../mob/verbs/horizontal_invert_self.dm | 1 +
.../modules/mob/verbs/vertical_invert_self.dm | 24 ++++
code/modules/multiz/atom-z_fall.dm | 29 +++++
.../multiz/{atoms.dm => atom-z_move.dm} | 2 +-
code/modules/multiz/core.dm | 2 +-
code/modules/multiz/falling.dm | 15 ---
code/modules/multiz/movement.dm | 36 +++---
code/modules/multiz/turf-multiz_misc.dm | 52 +++++++++
code/modules/multiz/turf-z_fall.dm | 38 +++++++
.../multiz/{turf.dm => turf-z_move.dm} | 100 ++---------------
code/modules/power/cable.dm | 45 ++++----
.../preferences/preferences_toggle_procs.dm | 50 ---------
.../micro/mecha_construction_paths_vr.dm | 2 -
maps/templates/archive/tradeship.dmm | 2 +-
60 files changed, 677 insertions(+), 287 deletions(-)
create mode 100644 code/datums/components/mobs/mob_feign_impairment.dm
create mode 100644 code/datums/components/mobs/mob_self_vertical_inversion.dm
create mode 100644 code/modules/clothing/under/gear_harness.dm
create mode 100644 code/modules/mob/mob-status_procs.dm
create mode 100644 code/modules/mob/verbs/feign_impairment.dm
create mode 100644 code/modules/mob/verbs/vertical_invert_self.dm
create mode 100644 code/modules/multiz/atom-z_fall.dm
rename code/modules/multiz/{atoms.dm => atom-z_move.dm} (92%)
delete mode 100644 code/modules/multiz/falling.dm
create mode 100644 code/modules/multiz/turf-multiz_misc.dm
create mode 100644 code/modules/multiz/turf-z_fall.dm
rename code/modules/multiz/{turf.dm => turf-z_move.dm} (52%)
diff --git a/citadel.dme b/citadel.dme
index c1999fd4477..674277a855b 100644
--- a/citadel.dme
+++ b/citadel.dme
@@ -811,7 +811,9 @@
#include "code\datums\components\items\passive_parry.dm"
#include "code\datums\components\items\wielding.dm"
#include "code\datums\components\mobs\block_frame.dm"
+#include "code\datums\components\mobs\mob_feign_impairment.dm"
#include "code\datums\components\mobs\mob_self_horizontal_inversion.dm"
+#include "code\datums\components\mobs\mob_self_vertical_inversion.dm"
#include "code\datums\components\mobs\parry_frame.dm"
#include "code\datums\components\movable\aquarium.dm"
#include "code\datums\components\movable\spatial_grid.dm"
@@ -2668,6 +2670,7 @@
#include "code\modules\clothing\suits\aliens\vox.dm"
#include "code\modules\clothing\under\_under.dm"
#include "code\modules\clothing\under\color.dm"
+#include "code\modules\clothing\under\gear_harness.dm"
#include "code\modules\clothing\under\imperial_vr.dm"
#include "code\modules\clothing\under\misc.dm"
#include "code\modules\clothing\under\miscellaneous.dm"
@@ -3615,6 +3618,7 @@
#include "code\modules\mob\mob-keybind-triggers.dm"
#include "code\modules\mob\mob-login.dm"
#include "code\modules\mob\mob-logout.dm"
+#include "code\modules\mob\mob-status_procs.dm"
#include "code\modules\mob\mob.dm"
#include "code\modules\mob\mob_defines.dm"
#include "code\modules\mob\mob_helpers.dm"
@@ -4146,7 +4150,9 @@
#include "code\modules\mob\observer\dead\orbit.dm"
#include "code\modules\mob\observer\dead\perspective.dm"
#include "code\modules\mob\observer\dead\say.dm"
+#include "code\modules\mob\verbs\feign_impairment.dm"
#include "code\modules\mob\verbs\horizontal_invert_self.dm"
+#include "code\modules\mob\verbs\vertical_invert_self.dm"
#include "code\modules\modular_computers\laptop_vendor.dm"
#include "code\modules\modular_computers\computers\modular_computer\core.dm"
#include "code\modules\modular_computers\computers\modular_computer\damage.dm"
@@ -4211,12 +4217,14 @@
#include "code\modules\movespeed\movespeed_modifier.dm"
#include "code\modules\movespeed\modifiers\misc.dm"
#include "code\modules\movespeed\modifiers\mob.dm"
-#include "code\modules\multiz\atoms.dm"
+#include "code\modules\multiz\atom-z_fall.dm"
+#include "code\modules\multiz\atom-z_move.dm"
#include "code\modules\multiz\basic_legacy.dm"
#include "code\modules\multiz\core.dm"
-#include "code\modules\multiz\falling.dm"
#include "code\modules\multiz\movement.dm"
-#include "code\modules\multiz\turf.dm"
+#include "code\modules\multiz\turf-multiz_misc.dm"
+#include "code\modules\multiz\turf-z_fall.dm"
+#include "code\modules\multiz\turf-z_move.dm"
#include "code\modules\multiz\structures\hoist.dm"
#include "code\modules\multiz\structures\ladder.dm"
#include "code\modules\multiz\structures\pipes.dm"
diff --git a/code/__DEFINES/mapping/multiz.dm b/code/__DEFINES/mapping/multiz.dm
index b43bdd839d7..51636b09d27 100644
--- a/code/__DEFINES/mapping/multiz.dm
+++ b/code/__DEFINES/mapping/multiz.dm
@@ -1,4 +1,8 @@
-// fall_flags
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2025 Citadel Station Developers *//
+
+//* fall_Flags *//
+
/// Falling should ignore anchored status
#define FALL_IGNORE_ANCHORED (1<<0)
/// this fall shouldn't incur any sort of self-damage for hitting the ground
@@ -20,17 +24,25 @@
#define FALL_FLAGS_STOP (FALL_BLOCKED | FALL_RECOVERED | FALL_TERMINATED)
/// there's a level above
+/// * This works as long as SSmapping has its rebuild proc called after a load; given this is enforced
+/// by SSmapping most of the time, this is usually fine.
#define Z_HAS_ABOVE(z) (!isnull(SSmapping.cached_level_up[z]))
/// there's a level below
+/// * This works as long as SSmapping has its rebuild proc called after a load; given this is enforced
+/// by SSmapping most of the time, this is usually fine.
#define Z_HAS_BELOW(z) (!isnull(SSmapping.cached_level_down[z]))
/// get turf below this turf, if any
-/// we are at the mercy of zmimic when we do this. do not use in critical maploader code.
+/// * this is a guesstimation
+/// * we are at the mercy of zmimic when we do this. do not use in critical maploader code.
#define TURF_BELOW_ISH(T) (T.below || T.below())
/// get turf above this turf, if any
-/// we are at the mercy of zmimic when we do this. do not use in critical maploader code.
+/// * this is a guesstimation
+/// * we are at the mercy of zmimic when we do this. do not use in critical maploader code.
#define TURF_ABOVE_ISH(T) (T.above || T.above())
-/// we should use get virtual step due to our x/y being border
-/// we do not get step this, so use it on something **on** game world. (aka turf or on turf).
+/// Checks if we're right next to the map transition border.
+/// * Only valid for something on a turf.
+///
+/// todo: support multi-tile objects
#define AT_MAP_BORDER(A) (A.x == 2 || A.y == 2 || A.x == world.maxx - 1 || A.y == world.maxy - 1)
diff --git a/code/__HELPERS/lists/associations.dm b/code/__HELPERS/lists/associations.dm
index 7e2610cb0ba..243906b6dba 100644
--- a/code/__HELPERS/lists/associations.dm
+++ b/code/__HELPERS/lists/associations.dm
@@ -32,6 +32,7 @@
flat_list[flat_list[i]] = TRUE
return flat_list
+//! WARNING: this no longer works; byond will NEVER de-assoc a list for json_encode purposes even if this is called!
/proc/assoc_list_strip_value_inplace(list/input)
for(var/i in 1 to length(input))
input[input[i]] = null
diff --git a/code/controllers/repository/flooring.dm b/code/controllers/repository/flooring.dm
index 8b7bd2ba2e3..ed8190c1253 100644
--- a/code/controllers/repository/flooring.dm
+++ b/code/controllers/repository/flooring.dm
@@ -20,17 +20,21 @@ REPOSITORY_DEF(flooring)
if(!.)
return
if(ispath(instance.build_type, /obj/item/stack))
- LAZYADD(build_item_lookup[instance.build_type], instance)
+ if(build_item_lookup?[instance.build_type])
+ stack_trace("attempted to load [instance.id], but build type [instance.build_type] collides with [build_item_lookup?[instance.build_type]:id]. suppressing [instance.id]'s build_type.")
+ LAZYSET(build_item_lookup, instance.build_type, instance)
else if(ispath(instance.build_type, /datum/prototype/material))
var/datum/prototype/material/casted_material = instance.build_type
- LAZYADD(build_material_lookup[initial(casted_material.id)], instance)
+ if(build_material_lookup?[casted_material.id])
+ stack_trace("attempted to load [instance.id], but material [casted_material.id] collides with [build_material_lookup?[casted_material.id]:id]. suppressing [instance.id]'s build_type.")
+ LAZYSET(build_material_lookup, initial(casted_material.id), instance)
/datum/controller/repository/flooring/unload(datum/prototype/flooring/instance)
. = ..()
if(!.)
return
if(ispath(instance.build_type, /obj/item/stack))
- LAZYREMOVE(build_item_lookup[instance.build_type], instance)
+ LAZYREMOVE(build_item_lookup, instance.build_type)
else if(ispath(instance.build_type, /datum/prototype/material))
var/datum/prototype/material/casted_material = instance.build_type
- LAZYREMOVE(build_material_lookup[initial(casted_material.id)], instance)
+ LAZYREMOVE(build_material_lookup, initial(casted_material.id))
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index e9fb0a5caa0..ec9b3e6a4a3 100644
--- a/code/datums/components/_component.dm
+++ b/code/datums/components/_component.dm
@@ -345,11 +345,10 @@
for(var/datum/listening_datum as anything in queued_calls)
. |= call(listening_datum, queued_calls[listening_datum])(arglist(arguments))
-// The type arg is casted so initial works, you shouldn't be passing a real instance into this
/**
- * Return any component assigned to this datum of the given type
+ * Return any component assigned to this datum of the given registered component type
*
- * If it has a registered type, that'll be used instead!
+ * * `registered_type` must be set on the component for this to work.
*
* Arguments:
* * datum/component/c_type The type of the component you want to get a reference to. It will be overridden with the type of its [registered_type] if it's set.
@@ -360,7 +359,9 @@
return . && (length(.) ? .[1] : .)
/**
- * Get all components of a given type that are attached to this datum
+ * Get all components of a given registered component type that are attached to this datum
+ *
+ * * `registered_type` must be set on the component for this to work.
*
* Arguments:
* * c_type The component type path
diff --git a/code/datums/components/mobs/mob_feign_impairment.dm b/code/datums/components/mobs/mob_feign_impairment.dm
new file mode 100644
index 00000000000..0c9d897dad0
--- /dev/null
+++ b/code/datums/components/mobs/mob_feign_impairment.dm
@@ -0,0 +1,62 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2025 Citadel Station Developers *//
+
+// todo: datumize impairments; the way this works right now is pretty stupid
+// it's because we're using different components since i was too
+// lazy to do a single tracking component
+
+/**
+ * Component added to a mob by the mob themselves to feign an impairment
+ */
+/datum/component/mob_feign_impairment
+ var/power
+ var/feign_impairment_type
+
+/datum/component/mob_feign_impairment/Initialize(power)
+ if(!ismob(parent))
+ return COMPONENT_INCOMPATIBLE
+ . = ..()
+ if(. == COMPONENT_INCOMPATIBLE)
+ return
+ src.power = power
+
+/datum/component/mob_feign_impairment/RegisterWithParent()
+ . = ..()
+ // todo: on update stat
+ RegisterSignal(parent, COMSIG_MOB_ON_UPDATE_MOBILITY, PROC_REF(recheck_stat))
+ var/mob/mob_parent = parent
+ LAZYSET(mob_parent.impairments_feigned, feign_impairment_type, src)
+
+/datum/component/mob_feign_impairment/UnregisterFromParent()
+ . = ..()
+ // todo: on update stat
+ UnregisterSignal(parent, COMSIG_MOB_ON_UPDATE_MOBILITY)
+ var/mob/mob_parent = parent
+ LAZYREMOVE(mob_parent.impairments_feigned, feign_impairment_type)
+
+/datum/component/mob_feign_impairment/proc/recheck_stat(mob/source)
+ SIGNAL_HANDLER
+ if(IS_CONSCIOUS(source))
+ return
+ qdel(src)
+
+/datum/component/mob_feign_impairment/slurring
+ // this must be set
+ registered_type = /datum/component/mob_feign_impairment/slurring
+ feign_impairment_type = /datum/feign_impairment/slurring
+
+/datum/component/mob_feign_impairment/stutter
+ // this must be set
+ registered_type = /datum/component/mob_feign_impairment/stutter
+ feign_impairment_type = /datum/feign_impairment/stutter
+
+/datum/component/mob_feign_impairment/jitter
+ // this must be set
+ registered_type = /datum/component/mob_feign_impairment/jitter
+ feign_impairment_type = /datum/feign_impairment/jitter
+
+/datum/component/mob_feign_impairment/jitter/RegisterWithParent()
+ . = ..()
+ // shitcode but whatever
+ var/mob/mob_parent = parent
+ mob_parent.make_jittery(0)
diff --git a/code/datums/components/mobs/mob_self_horizontal_inversion.dm b/code/datums/components/mobs/mob_self_horizontal_inversion.dm
index 79df9ca7c29..fc85738cf3e 100644
--- a/code/datums/components/mobs/mob_self_horizontal_inversion.dm
+++ b/code/datums/components/mobs/mob_self_horizontal_inversion.dm
@@ -15,6 +15,7 @@
/datum/component/mob_self_horizontal_inversion/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_MOVABLE_BASE_TRANSFORM, PROC_REF(alter_base_transform))
+ RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
var/mob/target = parent
var/matrix/to_apply = target.transform
to_apply.Scale(-1, 1)
@@ -23,6 +24,7 @@
/datum/component/mob_self_horizontal_inversion/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, COMSIG_MOVABLE_BASE_TRANSFORM)
+ UnregisterSignal(parent, COMSIG_MOVABLE_MOVED)
var/mob/target = parent
var/matrix/to_apply = target.transform
to_apply.Scale(-1, 1)
@@ -31,3 +33,7 @@
/datum/component/mob_self_horizontal_inversion/proc/alter_base_transform(datum/source, matrix/applying)
SIGNAL_HANDLER
applying.Scale(-1, 1)
+
+/datum/component/mob_self_horizontal_inversion/proc/on_move(datum/source)
+ SIGNAL_HANDLER
+ qdel(src)
diff --git a/code/datums/components/mobs/mob_self_vertical_inversion.dm b/code/datums/components/mobs/mob_self_vertical_inversion.dm
new file mode 100644
index 00000000000..8bdec05ff5f
--- /dev/null
+++ b/code/datums/components/mobs/mob_self_vertical_inversion.dm
@@ -0,0 +1,40 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2024 Citadel Station Developers *//
+
+/**
+ * Component added to a mob by the mob themselves to invert themselves vertically.
+ */
+/datum/component/mob_self_vertical_inversion
+ registered_type = /datum/component/mob_self_vertical_inversion
+
+/datum/component/mob_self_vertical_inversion/Initialize()
+ if(!ismob(parent))
+ return COMPONENT_INCOMPATIBLE
+ return ..()
+
+/datum/component/mob_self_vertical_inversion/RegisterWithParent()
+ . = ..()
+ // todo: allow it if they're being moved by an external source; MOB_SLEFMOVE?
+ RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
+ RegisterSignal(parent, COMSIG_MOVABLE_BASE_TRANSFORM, PROC_REF(alter_base_transform))
+ var/mob/target = parent
+ var/matrix/to_apply = target.transform
+ to_apply.Scale(1, -1)
+ target.set_transform(to_apply)
+
+/datum/component/mob_self_vertical_inversion/UnregisterFromParent()
+ . = ..()
+ UnregisterSignal(parent, COMSIG_MOVABLE_BASE_TRANSFORM)
+ UnregisterSignal(parent, COMSIG_MOVABLE_MOVED)
+ var/mob/target = parent
+ var/matrix/to_apply = target.transform
+ to_apply.Scale(1, -1)
+ target.set_transform(to_apply)
+
+/datum/component/mob_self_vertical_inversion/proc/alter_base_transform(datum/source, matrix/applying)
+ SIGNAL_HANDLER
+ applying.Scale(1, -1)
+
+/datum/component/mob_self_vertical_inversion/proc/on_move(datum/source)
+ SIGNAL_HANDLER
+ qdel(src)
diff --git a/code/game/content/factions/corporations/nanotrasen/nanotrasen-supply/costumes.dm b/code/game/content/factions/corporations/nanotrasen/nanotrasen-supply/costumes.dm
index 782a2e66f39..25ab2126413 100644
--- a/code/game/content/factions/corporations/nanotrasen/nanotrasen-supply/costumes.dm
+++ b/code/game/content/factions/corporations/nanotrasen/nanotrasen-supply/costumes.dm
@@ -187,7 +187,7 @@
/obj/item/clothing/under/permit,
/obj/item/clothing/under/vox/vox_casual,
/obj/item/clothing/under/vox/vox_robes,
- /obj/item/clothing/under/harness,
+ /obj/item/clothing/under/gear_harness,
/obj/item/clothing/under/skirt/loincloth,
/obj/item/clothing/gloves/vox,
)
@@ -345,7 +345,7 @@
/obj/item/clothing/suit/storage/toggle/leather_jacket/nanotrasen/sleeveless,
/obj/item/clothing/under/pants/chaps,
/obj/item/clothing/under/pants/chaps/black,
- /obj/item/clothing/under/harness,
+ /obj/item/clothing/under/gear_harness,
/obj/item/clothing/shoes/laceup/brown,
/obj/item/clothing/shoes/boots/jungle,
/obj/item/clothing/shoes/boots/jackboots,
diff --git a/code/game/objects/items-inventory-rendering.dm b/code/game/objects/items-inventory-rendering.dm
index d28e70515cc..a0e8fc2d44f 100644
--- a/code/game/objects/items-inventory-rendering.dm
+++ b/code/game/objects/items-inventory-rendering.dm
@@ -472,7 +472,7 @@
var/mob/living/carbon/human/H = ishuman(M)? M : null
var/datum/inventory_slot/slot_meta
if(isnull(slot_or_id))
- slot_or_id = worn_slot
+ slot_or_id = inv_slot_or_index
if(isnum(slot_or_id))
slot_meta = resolve_inventory_slot((slot_or_id % 2)? /datum/inventory_slot/abstract/hand/left : /datum/inventory_slot/abstract/hand/right)
else
diff --git a/code/game/objects/items/gifts.dm b/code/game/objects/items/gifts.dm
index 2c762e45b57..af41f9f6049 100644
--- a/code/game/objects/items/gifts.dm
+++ b/code/game/objects/items/gifts.dm
@@ -77,7 +77,6 @@ GLOBAL_LIST_EMPTY(possible_gifts)
return gift_type
-
/obj/item/a_gift/anything
name = "christmas gift"
desc = "It could be anything!"
diff --git a/code/game/objects/items/melee/types/transforming/energy/saber.dm b/code/game/objects/items/melee/types/transforming/energy/saber.dm
index 48e1eb49140..60f6d1a5fad 100644
--- a/code/game/objects/items/melee/types/transforming/energy/saber.dm
+++ b/code/game/objects/items/melee/types/transforming/energy/saber.dm
@@ -83,6 +83,7 @@
armor_penetration = 35
colorable = TRUE
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+ worn_render_flags = WORN_RENDER_SLOT_NO_RENDER | WORN_RENDER_INHAND_ONE_FOR_ALL
passive_parry = /datum/passive_parry{
parry_chance_default = 60;
diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm
index 13af5cc22f9..b36e4520505 100644
--- a/code/game/objects/items/stacks/rods.dm
+++ b/code/game/objects/items/stacks/rods.dm
@@ -64,5 +64,6 @@
gender = NEUTER
uses_charge = 1
charge_costs = list(500)
- stacktype = /obj/item/stack/rods
+ stack_type = /obj/item/stack/rods
+ stacktype_legacy = /obj/item/stack/rods
no_variants = TRUE
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 4d4b4b51135..6aa51a10242 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -36,16 +36,19 @@
origin_tech = list(TECH_MATERIAL = 1)
icon = 'icons/obj/stacks.dmi'
item_flags = ITEM_CAREFUL_BLUDGEON | ITEM_ENCUMBERS_WHILE_HELD
+
+ /// Always create this type when splitting, instead of our own type.
+ var/split_type
+ /// The type we actually are. This is what is used when things try to consume an amount of us.
+ /// * null = this current type
+ var/stack_type
+
var/singular_name
var/amount = 1
/// See stack recipes initialisation, param "max_res_amount" must be equal to this max_amount.
var/max_amount = 50
/// Determines whether different stack types can merge.
- var/stacktype
- /// enforce a certain type when splitting; useful if you have an infinite stack you don't want to be split into another one
- var/split_type
- /// Used when directly applied to a turf.
- var/build_type = null
+ var/stacktype_legacy
var/uses_charge = 0
var/list/charge_costs = null
var/list/datum/matter_synth/synths = null
@@ -70,8 +73,8 @@
explicit_recipes = typelist(NAMEOF(src, explicit_recipes), generate_explicit_recipes())
if(new_amount != null)
amount = new_amount
- if(!stacktype)
- stacktype = type
+ if(!stacktype_legacy)
+ stacktype_legacy = type
. = ..()
if(merge)
for(var/obj/item/stack/S in loc)
@@ -189,7 +192,7 @@
return FALSE
if((strict_color_stacking || other.strict_color_stacking) && (color != other.color))
return FALSE
- return other.stacktype == stacktype
+ return other.stacktype_legacy == stacktype_legacy
/obj/item/stack/proc/use(used)
if (!can_use(used))
@@ -424,3 +427,25 @@
return FALSE
update_icon()
return TRUE
+
+//* Types *//
+
+/**
+ * Get our 'use as type'.
+ */
+/obj/item/stack/proc/get_use_as_type()
+ return stack_type || type
+
+/**
+ * We can be used as a specific stack type.
+ */
+/obj/item/stack/proc/can_use_as_type(path)
+ return stack_type == path || type == path
+
+/**
+ * Can merge into a type
+ *
+ * todo: use this instead of raw stacktype_legacy checks
+ */
+/obj/item/stack/proc/can_merge_into_type(path)
+ CRASH("Not implemented.")
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index 3f0955fd54b..b0b1e5db320 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -87,8 +87,8 @@
desc = "A device that makes wood floor tiles."
uses_charge = 1
charge_costs = list(250)
- stacktype = /obj/item/stack/tile/wood
- build_type = /obj/item/stack/tile/wood
+ stack_type = /obj/item/stack/tile/wood
+ stacktype_legacy = /obj/item/stack/tile/wood
/*
* Carpets
@@ -298,8 +298,8 @@
materials_base = null
uses_charge = 1
charge_costs = list(250)
- stacktype = /obj/item/stack/tile/floor
- build_type = /obj/item/stack/tile/floor
+ stack_type = /obj/item/stack/tile/floor
+ stacktype_legacy = /obj/item/stack/tile/floor
/obj/item/stack/tile/floor/sandstone
name = "sandstone tile"
@@ -353,8 +353,8 @@
desc = "A device that makes roofing tiles."
uses_charge = 1
charge_costs = list(250)
- stacktype = /obj/item/stack/tile/roofing
- build_type = /obj/item/stack/tile/roofing
+ stack_type = /obj/item/stack/tile/roofing
+ stacktype_legacy = /obj/item/stack/tile/roofing
/obj/item/stack/tile/roofing/wood
name = "wood roofing"
diff --git a/code/game/objects/random/maintenance.dm b/code/game/objects/random/maintenance.dm
index a2613ba2563..244aa5293f5 100644
--- a/code/game/objects/random/maintenance.dm
+++ b/code/game/objects/random/maintenance.dm
@@ -97,7 +97,7 @@ something, make sure it's not in one of the other lists.*/
prob(4);/obj/item/clothing/under/color/grey,
prob(2);/obj/item/clothing/under/syndicate/tacticool,
prob(2);/obj/item/clothing/under/pants/camo,
- prob(1);/obj/item/clothing/under/harness,
+ prob(1);/obj/item/clothing/under/gear_harness,
prob(1);/obj/item/clothing/under/tactical,
prob(3);/obj/item/clothing/accessory/storage/webbing,
prob(3);/obj/item/camera_assembly,
diff --git a/code/game/objects/structures/loot_piles.dm b/code/game/objects/structures/loot_piles.dm
index bde9d888de8..981c8140a1f 100644
--- a/code/game/objects/structures/loot_piles.dm
+++ b/code/game/objects/structures/loot_piles.dm
@@ -192,7 +192,7 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
/obj/item/clothing/under/color/grey,
/obj/item/clothing/under/syndicate/tacticool,
/obj/item/clothing/under/pants/camo,
- /obj/item/clothing/under/harness,
+ /obj/item/clothing/under/gear_harness,
/obj/item/clothing/accessory/storage/webbing,
/obj/item/spacecash/c1,
/obj/item/spacecash/c10,
diff --git a/code/game/objects/structures/trash_pile.dm b/code/game/objects/structures/trash_pile.dm
index 7532fc01b19..eab27406c2c 100644
--- a/code/game/objects/structures/trash_pile.dm
+++ b/code/game/objects/structures/trash_pile.dm
@@ -202,7 +202,7 @@
prob(1);/obj/item/clothing/shoes/syndigaloshes,
prob(1);/obj/item/clothing/suit/bio_suit/general,
prob(1);/obj/item/clothing/suit/space/emergency,
- prob(1);/obj/item/clothing/under/harness,
+ prob(1);/obj/item/clothing/under/gear_harness,
prob(1);/obj/item/clothing/under/tactical,
prob(1);/obj/item/clothing/suit/armor/material/makeshift,
prob(1);/obj/item/flashlight/glowstick/orange,
diff --git a/code/game/objects/systems/storage/storage.dm b/code/game/objects/systems/storage/storage.dm
index 32f9799907d..204b0f90876 100644
--- a/code/game/objects/systems/storage/storage.dm
+++ b/code/game/objects/systems/storage/storage.dm
@@ -284,7 +284,6 @@
return
action_mode_switch = new(src)
action_mode_switch.button_additional_only = TRUE
- action_mode_switch.button_additional_overlay = parent
/datum/object_system/storage/proc/grant_buttons(mob/wearer)
ensure_buttons()
@@ -1145,6 +1144,17 @@
/datum/action/storage_gather_mode
name = "Switch Gather Mode"
+/datum/action/storage_gather_mode/pre_render_hook()
+ if(istype(target, /datum/object_system/storage))
+ var/datum/object_system/storage/storage_datum = target
+ var/obj/storage_target = storage_datum.parent
+ var/image/generated = new
+ generated.appearance = storage_target
+ generated.layer = FLOAT_LAYER
+ generated.plane = FLOAT_PLANE
+ button_additional_overlay = generated
+ return ..()
+
//? Hooks
/obj/proc/object_storage_opened(mob/user)
diff --git a/code/game/rendering/legacy/radial.dm b/code/game/rendering/legacy/radial.dm
index 0cb587ad865..6d37d8f09e0 100644
--- a/code/game/rendering/legacy/radial.dm
+++ b/code/game/rendering/legacy/radial.dm
@@ -252,6 +252,10 @@ GLOBAL_LIST_EMPTY(radial_menus)
//! perform fixup
I.plane = FLOAT_PLANE
I.layer = FLOAT_LAYER
+ I.maptext = MAPTEXT(I.maptext)
+ I.maptext_width = 64
+ I.maptext_height = 32
+ I.maptext_y = 32
//! end
choices_icons[id] = I
else
diff --git a/code/game/rendering/mob.dm b/code/game/rendering/mob.dm
index bfcd07a224d..b49319562e2 100644
--- a/code/game/rendering/mob.dm
+++ b/code/game/rendering/mob.dm
@@ -24,6 +24,8 @@
client.global_planes.apply(client)
client.update_clickcatcher()
client.using_perspective?.reload(client, TRUE)
+ client.actor_huds.reassert_onto_owner()
+ client.action_drawer.reassert_screen()
INVOKE_ASYNC(client, TYPE_PROC_REF(/client, init_viewport_blocking))
reload_fullscreen()
hud_used?.reorganize_alerts()
diff --git a/code/game/turfs/simulated/floor/floor-construction.dm b/code/game/turfs/simulated/floor/floor-construction.dm
index 319c589de13..d0a37d37eac 100644
--- a/code/game/turfs/simulated/floor/floor-construction.dm
+++ b/code/game/turfs/simulated/floor/floor-construction.dm
@@ -22,12 +22,17 @@
using_stack = with_mat_stack
else
var/obj/item/stack/with_stack = with_item
- possible = RSflooring.build_item_lookup[with_stack.type]
+ possible = RSflooring.build_item_lookup[with_stack.get_use_as_type()]
has_amount = with_stack.amount
using_stack = with_stack
- if(!length(possible))
+ if(!possible)
return FALSE
- var/datum/prototype/flooring/trying_to_make
+ var/datum/prototype/flooring/trying_to_make = possible
+ if(force_flooring && !(trying_to_make.id == force_flooring || trying_to_make.type == force_flooring))
+ return FALSE
+ // todo: multiple possible floorings are disabled for UI/UX reasons. put the selector on the stack
+ // with client-local-state sometime, and re-enable it.
+ /*
if(force_flooring)
for(var/datum/prototype/flooring/potential as anything in possible)
if(potential.type == force_flooring || potential.id == force_flooring)
@@ -42,16 +47,24 @@
else
var/list/built_choices = list()
var/list/pick_choices = list()
+ var/matrix/three_fourths_size = matrix()
+ three_fourths_size.Scale(3 / 4, 3 / 4)
for(var/datum/prototype/flooring/potential as anything in possible)
built_choices[potential.name] = potential
var/image/preview = image(potential.icon, potential.icon_base)
+ preview.transform = three_fourths_size
preview.maptext = MAPTEXT_CENTER(potential.name)
preview.maptext_width = 64
- pick_choices[potential.name] = preview
+ var/use_name = potential.name
+ var/notch = 1
+ while(pick_choices[use_name])
+ use_name = "[potential.name] ([notch++])"
+ pick_choices[use_name] = preview
var/choice_name = show_radial_menu(e_args.initiator, src, pick_choices)
trying_to_make = built_choices[choice_name]
if(!trying_to_make)
return FALSE
+ */
if(trying_to_make.build_cost > has_amount)
e_args.chat_feedback(SPAN_WARNING("You require at least [trying_to_make.build_cost] [with_item.name] to lay down those [trying_to_make.descriptor]"))
return FALSE
diff --git a/code/game/turfs/simulated/flooring/flooring.dm b/code/game/turfs/simulated/flooring/flooring.dm
index 2e846cbf714..b8e70f205cf 100644
--- a/code/game/turfs/simulated/flooring/flooring.dm
+++ b/code/game/turfs/simulated/flooring/flooring.dm
@@ -71,6 +71,11 @@
///
/// * Supports /obj/item/stack
/// * Supports /datum/material
+ ///
+ /// todo: as of right now, only a single floor can ever be allowed to be built in this way
+ /// for a given stack or material id.
+ /// at some point, we need to investigate having multiple possibilities
+ /// todo: remove 'subtype build_type suppression' from New()
var/build_type
/// Amount of material needed to build.
var/build_cost = 1
@@ -162,6 +167,13 @@
dismantle_tool = dismantle_tool ? list(dismantle_tool) : list()
if(!islist(destroy_tool))
destroy_tool = destroy_tool ? list(destroy_tool) : list()
+ // subtype build suppression
+ // erase our build_type if our parent type defaults to it
+ // this way only the first declaration on the tree of a certain build type applies
+ if(ispath(parent_type, /datum/prototype/flooring))
+ var/datum/prototype/flooring/parent = parent_type
+ if(initial(parent.build_type) == build_type)
+ build_type = null
/datum/prototype/flooring/proc/get_flooring_overlay(cache_key, base_state, icon_dir = 0, layer = FLOOR_DECAL_LAYER)
if(!flooring_cache[cache_key])
diff --git a/code/game/turfs/simulated/flooring/flooring_types.dm b/code/game/turfs/simulated/flooring/flooring_types.dm
index 5fa2358958e..e92d3e9be39 100644
--- a/code/game/turfs/simulated/flooring/flooring_types.dm
+++ b/code/game/turfs/simulated/flooring/flooring_types.dm
@@ -250,7 +250,6 @@
icon_base = "asteroidfloor"
has_damage_range = null
flooring_flags = TURF_REMOVE_CROWBAR
- build_type = /obj/item/stack/tile/floor/steel
/datum/prototype/flooring/tiling/white
name = "floor"
@@ -276,12 +275,10 @@
/datum/prototype/flooring/tiling/hydro
name = "floor"
icon_base = "hydrofloor"
- build_type = /obj/item/stack/tile/floor/steel
/datum/prototype/flooring/tiling/neutral
name = "floor"
icon_base = "neutral"
- build_type = /obj/item/stack/tile/floor/steel
/datum/prototype/flooring/tiling/freezer
name = "floor"
diff --git a/code/modules/artwork/crayon_decal_meta.dm b/code/modules/artwork/crayon_decal_meta.dm
index fc1051634f7..3b9227a8eb1 100644
--- a/code/modules/artwork/crayon_decal_meta.dm
+++ b/code/modules/artwork/crayon_decal_meta.dm
@@ -74,11 +74,17 @@ GLOBAL_LIST_EMPTY(crayon_data_lookup_by_string_icon_path)
var/centering_pixel_y
/datum/crayon_decal_meta/proc/tgui_crayon_data()
+ //! uh oh! byond alert! !//
+ //! associative lists are contagious and we really need a flat list or tgui crashes! !//
+ //! manually flatten it. !//
+ var/list/i_really_dislike_byond = list()
+ for(var/key in states)
+ i_really_dislike_byond += key
+
return list(
"name" = name,
- "states" = states,
+ "states" = i_really_dislike_byond,
"width" = width,
"height" = height,
"id" = id,
)
-
diff --git a/code/modules/artwork/items/crayon.dm b/code/modules/artwork/items/crayon.dm
index 30acd4e54bc..9cc2db19343 100644
--- a/code/modules/artwork/items/crayon.dm
+++ b/code/modules/artwork/items/crayon.dm
@@ -10,6 +10,7 @@
pen_color = "#FF0000" //RGB
clickable = FALSE
+ // todo: reorganize vars
/// color name
var/crayon_color_name = "red"
/// what we show as; e.g. 'crayon', 'marker'
@@ -35,6 +36,7 @@
/// can eat
var/crayon_edible = TRUE
+ // todo: per user this so you can't see what someone else was about to do lmao
/// currently picked datapack string path
var/current_graffiti_icon_string_path
/// currently picked datapack icon state
diff --git a/code/modules/clothing/accessories/halo.dm b/code/modules/clothing/accessories/halo.dm
index de07cf47854..6ea632337d7 100644
--- a/code/modules/clothing/accessories/halo.dm
+++ b/code/modules/clothing/accessories/halo.dm
@@ -16,12 +16,12 @@
generate_styles()
AddElement(/datum/element/clothing/dynamic_recolor)
-/obj/item/clothing/accessory/halo_projector/available_styles(mob/user)
+/obj/item/clothing/accessory/halo_projector/style_repick_query(mob/user)
. = ..()
for(var/halo_name in global_halo_styles)
.[halo_name] = global_halo_styles[halo_name]
-/obj/item/clothing/accessory/halo_projector/set_style(style, mob/user)
+/obj/item/clothing/accessory/halo_projector/style_repick_set(style, mob/user)
. = ..()
if(.)
return
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 8d2de2bcc9d..e76f2ed187b 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -231,25 +231,29 @@
else
icon = initial(icon)
-//? styles
+//* Style Repicking *//
/**
* returns available styles as name = state or image or mutable_appearance
*/
-/obj/item/clothing/proc/available_styles(mob/user)
+/obj/item/clothing/proc/style_repick_query(mob/user)
+ SHOULD_NOT_SLEEP(TRUE)
. = list()
/**
* sets us to a specific style
+ *
+ * * do not update_icon() or update_worn_icon() in here, we do that automatically.
*/
-/obj/item/clothing/proc/set_style(style, mob/user)
+/obj/item/clothing/proc/style_repick_set(style, mob/user)
+ SHOULD_NOT_SLEEP(TRUE)
return FALSE
/**
* prompts a user to pick style
*/
-/obj/item/clothing/proc/pick_style(mob/user)
- var/list/available = available_styles(user)
+/obj/item/clothing/proc/style_repick_open(mob/user)
+ var/list/available = style_repick_query(user)
var/list/assembled = list()
for(var/name in available)
var/using = available[name]
@@ -272,9 +276,16 @@
var/choice = show_radial_menu(user, loc == user ? user : src, assembled, radius = 48)
if(isnull(choice))
return
- set_style(choice, user)
+ if(!style_repick_set(choice, user))
+ return
+ // todo: logging API
+ to_chat(user, SPAN_NOTICE("You set [src]'s style to [choice]."))
+ log_game("[key_name(user)] set [src]'s style to [choice]")
+ update_icon()
+ update_worn_icon()
-/obj/item/clothing/verb/pick_style_verb()
+// todo: context menu this instead
+/obj/item/clothing/verb/style_repick_verb()
set name = "Set Worn Style"
set category = VERB_CATEGORY_IC
set desc = "Wear this piece of clothing in a different style."
@@ -284,4 +295,4 @@
usr.action_feedback(SPAN_WARNING("You can't do that right now!"), src)
return
- pick_style(usr)
+ style_repick_open(usr)
diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm
index f7ce6de2bdf..1110856226e 100644
--- a/code/modules/clothing/under/_under.dm
+++ b/code/modules/clothing/under/_under.dm
@@ -96,7 +96,7 @@
//? Styles
-/obj/item/clothing/under/available_styles(mob/user)
+/obj/item/clothing/under/style_repick_query(mob/user)
. = list()
var/old_roll = worn_rolled_down
var/old_sleeves = worn_rolled_sleeves
@@ -114,7 +114,7 @@
worn_rolled_down = old_roll
worn_rolled_sleeves = old_sleeves
-/obj/item/clothing/under/set_style(style, mob/user)
+/obj/item/clothing/under/style_repick_set(style, mob/user)
. = ..()
if(.)
return
diff --git a/code/modules/clothing/under/gear_harness.dm b/code/modules/clothing/under/gear_harness.dm
new file mode 100644
index 00000000000..1b47733b5d5
--- /dev/null
+++ b/code/modules/clothing/under/gear_harness.dm
@@ -0,0 +1,25 @@
+/obj/item/clothing/under/gear_harness
+ name = "gear harness"
+ desc = "How... minimalist."
+ icon_state = "gear_harness"
+ body_cover_flags = NONE
+
+/obj/item/clothing/under/gear_harness/style_repick_query(mob/user)
+ . = ..()
+ var/image/normal_image = image(icon, "gear_harness")
+ normal_image.maptext = "normal"
+ .["normal"] = normal_image
+ var/image/invisible_image = image('icons/system/blank_32x32.dmi', "")
+ invisible_image.maptext = "invisible"
+ .["invisible"] = invisible_image
+
+/obj/item/clothing/under/gear_harness/style_repick_set(style, mob/user)
+ switch(style)
+ if("normal")
+ worn_render_flags = initial(worn_render_flags)
+ return TRUE
+ if("invisible")
+ worn_render_flags |= WORN_RENDER_SLOT_NO_RENDER
+ return TRUE
+ else
+ return FALSE
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index 88fc5e8f779..ab14cd390f5 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -724,12 +724,6 @@
icon_state = "cuttop_red"
item_state_slots = list(SLOT_ID_RIGHT_HAND = "red", SLOT_ID_LEFT_HAND = "red")
-/obj/item/clothing/under/harness
- name = "gear harness"
- desc = "How... minimalist."
- icon_state = "gear_harness"
- body_cover_flags = 0
-
/obj/item/clothing/under/dress/white
name = "white wedding dress"
desc = "A fancy white dress with a blue underdress."
diff --git a/code/modules/frames/frame_step.dm b/code/modules/frames/frame_step.dm
index 0c3c6c35119..5b40f8dc3cb 100644
--- a/code/modules/frames/frame_step.dm
+++ b/code/modules/frames/frame_step.dm
@@ -30,6 +30,11 @@
var/request_type
/// ergo: stack type, item type, tool function, etc. what this is depends on [step_type]
/// limited autodetection is allowed.
+ ///
+ /// allowed:
+ /// * /datum/prototype/material path
+ /// * /obj/item/stack path
+ /// * /obj/item path
var/request
/// * stacks: amount
/// * items: amount; if 0, we just apply the item to it
@@ -157,11 +162,12 @@
/datum/frame_step/proc/valid_interaction(datum/event_args/actor/actor, obj/item/using_tool, datum/frame2/frame_datum, obj/structure/frame2/frame)
switch(request_type)
if(FRAME_REQUEST_TYPE_INTERACT)
- return TRUE
+ return isnull(using_tool)
if(FRAME_REQUEST_TYPE_ITEM)
return using_tool?.type == request
if(FRAME_REQUEST_TYPE_STACK)
- return using_tool?.type == request
+ var/obj/item/stack/using_stack = using_tool
+ return using_stack.can_use_as_type(request)
if(FRAME_REQUEST_TYPE_PROC)
return FALSE // override this proc
if(FRAME_REQUEST_TYPE_TOOL)
diff --git a/code/modules/frames/types/fire_alarm.dm b/code/modules/frames/types/fire_alarm.dm
index 03f5797e8e8..c35f319481f 100644
--- a/code/modules/frames/types/fire_alarm.dm
+++ b/code/modules/frames/types/fire_alarm.dm
@@ -46,7 +46,7 @@ AUTO_FRAME_DATUM(/datum/frame2/fire_alarm, fire_alarm, 'icons/machinery/fire_ala
steps = list(
/datum/frame_step{
request = /obj/item/stack/cable_coil;
- name = "unsecure circuit";
+ name = "wire circuit";
request_amount = 1;
stage = "wired";
direction = TOOL_DIRECTION_FORWARDS;
diff --git a/code/modules/loadout/loadout_xeno.dm b/code/modules/loadout/loadout_xeno.dm
index 3e961c1bb9d..94105322a1b 100644
--- a/code/modules/loadout/loadout_xeno.dm
+++ b/code/modules/loadout/loadout_xeno.dm
@@ -1044,4 +1044,4 @@
/datum/loadout_entry/xeno/uniform
name = "Generic - Gear Harness"
- path = /obj/item/clothing/under/harness
+ path = /obj/item/clothing/under/gear_harness
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
index 8fea3c15a16..2684f9c1c40 100644
--- a/code/modules/materials/material_sheets.dm
+++ b/code/modules/materials/material_sheets.dm
@@ -51,7 +51,7 @@
pixel_x = rand(0,4)-4
pixel_y = rand(0,4)-4
- stacktype = src.material.stack_type
+ stacktype_legacy = src.material.stack_type
if(islist(src.material.stack_origin_tech))
origin_tech = src.material.stack_origin_tech.Copy()
diff --git a/code/modules/materials/material_synth.dm b/code/modules/materials/material_synth.dm
index ad5b16c35ec..8acd60ee9c2 100644
--- a/code/modules/materials/material_synth.dm
+++ b/code/modules/materials/material_synth.dm
@@ -15,25 +15,31 @@
/obj/item/stack/material/cyborg/plastic
icon_state = "sheet-plastic"
+ stack_type = /obj/item/stack/material/plastic
material = /datum/prototype/material/plastic
/obj/item/stack/material/cyborg/steel
icon_state = "sheet-metal"
+ stack_type = /obj/item/stack/material/steel
material = /datum/prototype/material/steel
/obj/item/stack/material/cyborg/plasteel
icon_state = "sheet-plasteel"
+ stack_type = /obj/item/stack/material/plasteel
material = /datum/prototype/material/plasteel
/obj/item/stack/material/cyborg/wood
icon_state = "sheet-wood"
+ stack_type = /obj/item/stack/material/wood
material = /datum/prototype/material/wood_plank
/obj/item/stack/material/cyborg/glass
icon_state = "sheet-glass"
+ stack_type = /obj/item/stack/material/glass
material = /datum/prototype/material/glass
/obj/item/stack/material/cyborg/glass/reinforced
icon_state = "sheet-rglass"
+ stack_type = /obj/item/stack/material/glass/reinforced
material = /datum/prototype/material/glass/reinforced
charge_costs = list(500, 1000)
diff --git a/code/modules/mining/tools/vertibore.dm b/code/modules/mining/tools/vertibore.dm
index eb2319b9171..692b1ed1d89 100644
--- a/code/modules/mining/tools/vertibore.dm
+++ b/code/modules/mining/tools/vertibore.dm
@@ -27,7 +27,7 @@
if(cell)
to_chat(user, "\The [src] already has \a [cell] installed.")
return
- if(!user.attempt_insert_item_for_installation(cell, src))
+ if(!user.attempt_insert_item_for_installation(thing, src))
return
cell = thing
playsound(loc, 'sound/machines/click.ogg', 10, 1)
diff --git a/code/modules/mob/animations.dm b/code/modules/mob/animations.dm
index 24ea11d5c45..e9facbae81f 100644
--- a/code/modules/mob/animations.dm
+++ b/code/modules/mob/animations.dm
@@ -46,18 +46,21 @@ note dizziness decrements automatically in the mob's Life() proc.
jitteriness = min(1000, jitteriness + amount) // store what will be new value
// clamped to max 1000
- if(jitteriness > 100 && !is_jittery)
+
+ var/effective_jitteriness = get_effective_impairment_power_jitter()
+ if(effective_jitteriness > 100 && !is_jittery)
spawn(0)
jittery_process()
-
/mob/proc/jittery_process()
if(IS_DEAD(src))//Dead people dont twitch around
return
is_jittery = 1
- while(jitteriness > 100)
- var/amplitude = min(4, jitteriness / 100)
+ var/effective_jitteriness = get_effective_impairment_power_jitter()
+ while(effective_jitteriness > 100)
+ effective_jitteriness = get_effective_impairment_power_jitter()
+ var/amplitude = min(4, effective_jitteriness / 100)
pixel_x = get_managed_pixel_x() + rand(-amplitude, amplitude)
pixel_y = get_managed_pixel_y() + rand(-amplitude/3, amplitude/3)
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 8d423b44b08..9a5244888f5 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -273,11 +273,12 @@
//Jitters
if(is_jittery)
- if(jitteriness >= 300)
+ var/effective_jitteriness = get_effective_impairment_power_jitter()
+ if(effective_jitteriness >= 300)
. += SPAN_DANGER("[T.He] [T.is] convulsing violently!")
- else if(jitteriness >= 200)
+ else if(effective_jitteriness >= 200)
. += SPAN_WARNING("[T.He] [T.is] extremely jittery.")
- else if(jitteriness >= 100)
+ else if(effective_jitteriness >= 100)
. += SPAN_WARNING("[T.He] [T.is] twitching ever so slightly.")
//splints
diff --git a/code/modules/mob/living/carbon/human/human-defense.dm b/code/modules/mob/living/carbon/human/human-defense.dm
index dd8ec528930..20dcc1ab071 100644
--- a/code/modules/mob/living/carbon/human/human-defense.dm
+++ b/code/modules/mob/living/carbon/human/human-defense.dm
@@ -33,7 +33,7 @@
/mob/living/carbon/human/slip_act(slip_class, source, hard_strength, soft_strength, suppressed)
var/footcoverage_check = length(inventory.query_coverage(FEET))
- var/obj/item/shoes = inventory.get_slot(/datum/inventory_slot/inventory/shoes)
+ var/obj/item/shoes = inventory.get_slot_single(/datum/inventory_slot/inventory/shoes)
if(((species.species_flags & NO_SLIP) && !footcoverage_check) || (shoes && (shoes.clothing_flags & NOSLIP))) //Footwear negates a species' natural traction.
return 0
return ..()
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 251cfc5f004..d5e89635d87 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -66,7 +66,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
/mob/living/carbon/human/apply_transform(matrix/to_apply)
var/anim_time = CHECK_MOBILITY(src, MOBILITY_CAN_STAND)? 3 : 1
- animate(src, transform = to_apply, time = anim_time, flags = ANIMATION_PARALLEL)
+ animate(src, transform = to_apply, time = anim_time, flags = ANIMATION_PARALLEL | ANIMATION_LINEAR_TRANSFORM)
update_icon_special() //May contain transform-altering things
update_ssd_overlay()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 62cc2e737e8..069d93070ef 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -605,7 +605,7 @@ default behaviour is:
return applying
/mob/living/apply_transform(matrix/to_apply)
- animate(src, transform = to_apply, time = 1 SECONDS)
+ animate(src, transform = to_apply, time = 1 SECONDS, flags = ANIMATION_LINEAR_TRANSFORM | ANIMATION_PARALLEL)
update_ssd_overlay()
// This handles setting the client's color variable, which makes everything look a specific color.
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 16d78b94b22..71ebc1b8723 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -109,11 +109,11 @@ var/list/channel_to_radio_key = new
verb = pick("yells","roars","hollers")
whispering = 0
. = 1
- if(slurring)
+ if(get_effective_impairment_power_slurring())
message = slur(message)
verb = pick("slobbers","slurs")
. = 1
- if(stuttering)
+ if(get_effective_impairment_power_stutter())
message = stutter(message)
verb = pick("stammers","stutters")
. = 1
diff --git a/code/modules/mob/mob-status_procs.dm b/code/modules/mob/mob-status_procs.dm
new file mode 100644
index 00000000000..83935e06c82
--- /dev/null
+++ b/code/modules/mob/mob-status_procs.dm
@@ -0,0 +1,36 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2025 Citadel Station Developers *//
+
+//* Impairments *//
+
+// hey! listen
+// if you're thinking about find-replacing checks for the var with this
+// well fucking don't
+//
+// the reason this is separate from main vars for these things
+// is because people keep abusing vars to implement features that have a
+// ton of unintended side effects
+//
+// these should only be used for the actual effects; it is **not**
+// allowed to use for any other effects like xenochimera feral,
+// traumatic shock, etc
+
+// todo: /datum/mob_impairment ?
+
+/mob/proc/get_effective_impairment_power_slurring()
+ . = slurring
+ var/datum/component/mob_feign_impairment/slurring/feigned = GetComponent(/datum/component/mob_feign_impairment/slurring)
+ if(feigned)
+ . = max(., feigned.power)
+
+/mob/proc/get_effective_impairment_power_jitter()
+ . = jitteriness
+ var/datum/component/mob_feign_impairment/jitter/feigned = GetComponent(/datum/component/mob_feign_impairment/jitter)
+ if(feigned)
+ . = max(., feigned.power)
+
+/mob/proc/get_effective_impairment_power_stutter()
+ . = stuttering
+ var/datum/component/mob_feign_impairment/stutter/feigned = GetComponent(/datum/component/mob_feign_impairment/stutter)
+ if(feigned)
+ . = max(., feigned.power)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 9e30f2992a7..c2021320c78 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1,3 +1,8 @@
+/mob
+ //* Impairments *//
+ /// active feign_impairment types
+ /// * lazy list
+ var/list/impairments_feigned
/**
* Intialize a mob
diff --git a/code/modules/mob/verbs/feign_impairment.dm b/code/modules/mob/verbs/feign_impairment.dm
new file mode 100644
index 00000000000..dd7a3ab8ff4
--- /dev/null
+++ b/code/modules/mob/verbs/feign_impairment.dm
@@ -0,0 +1,105 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2025 Citadel Station Developers *//
+
+GLOBAL_LIST_INIT(feign_impairment_types, init_feign_impairment_types())
+
+/proc/init_feign_impairment_types()
+ . = list()
+ var/list/component_collision_check = list()
+ for(var/datum/feign_impairment/path as anything in subtypesof(/datum/feign_impairment))
+ if(initial(path.abstract_type) == path)
+ continue
+ var/datum/feign_impairment/instance = new path
+ if(component_collision_check[instance.component_type])
+ stack_trace("collision between [component_collision_check[instance.component_type]:type] and [instance.type] on component type [instance.component_type]")
+ continue
+ component_collision_check[instance.component_type] = instance
+ .[path] = instance
+
+// todo: this is better than the old, but still a dumpster fire. impairments
+// need to be datums so we can have a single tracking system
+// and a single /datum/component/mob_feign_impairment
+// to track everything, instead of this crap.
+
+/datum/feign_impairment
+ abstract_type = /datum/feign_impairment
+ var/name
+ var/adjective
+ var/component_type
+ var/power_min = 0
+ var/power_max = 0
+
+/datum/feign_impairment/slurring
+ name = "Slurring"
+ adjective = "slurring"
+ component_type = /datum/component/mob_feign_impairment/slurring
+ power_min = 10
+ power_max = 500
+
+/datum/feign_impairment/stutter
+ name = "Stuttering"
+ adjective = "stuttering"
+ component_type = /datum/component/mob_feign_impairment/stutter
+ power_min = 10
+ power_max = 500
+
+/datum/feign_impairment/jitter
+ name = "Jittering"
+ adjective = "jittering"
+ component_type = /datum/component/mob_feign_impairment/jitter
+ power_min = 10
+ power_max = 2000
+
+// todo: DECLARE_MOB_VERB
+/mob/verb/feign_impairment()
+ set name = "Feign Impairment"
+ set category = VERB_CATEGORY_IC
+ set desc = "Pretend like you're slurring, stuttering, jittering, and more."
+
+ var/list/name_to_type = list()
+ for(var/datum/feign_impairment/path as anything in subtypesof(/datum/feign_impairment))
+ if(initial(path.abstract_type) == path)
+ continue
+ var/is_active = impairments_feigned?[path]
+ name_to_type["[initial(path.name)] (Currently: [is_active ? "Active" : "Inactive"])"] = path
+
+ var/choice = tgui_input_list(src, "Choose an impairment to toggle.", "Feign Impairment", name_to_type)
+ if(!choice)
+ return
+
+ var/path = name_to_type[choice]
+ var/new_active = !impairments_feigned?[path]
+ var/datum/feign_impairment/impairment = GLOB.feign_impairment_types[path]
+
+ var/power
+
+ if(new_active)
+ if(GetComponent(impairment.component_type))
+ to_chat(src, SPAN_WARNING("You are already pretending to be [impairment.adjective]."))
+ return
+ power = tgui_input_number(
+ src,
+ "What power? ([impairment.power_min] - [impairment.power_max])",
+ "Feign Impairment",
+ impairment.power_min,
+ impairment.power_max,
+ impairment.power_min,
+ round_value = TRUE,
+ )
+ else
+ if(!GetComponent(impairment.component_type))
+ return
+
+ // todo: better logging
+ log_game("[key_name(src)] toggled [impairment] to [new_active ?"on, with power [power]" : "off"]")
+
+ if(new_active)
+ AddComponent(impairment.component_type, power)
+ else
+ qdel(GetComponent(impairment.component_type))
+
+ to_chat(src, SPAN_NOTICE("You are now [new_active ? "pretending" : "no longer pretending"] to be [impairment.adjective]. This will be automatically reset should you lose consciousness."))
+
+/mob/proc/clear_feign_impairment()
+ QDEL_LIST_ASSOC_VAL(impairments_feigned)
+ impairments_feigned = null
diff --git a/code/modules/mob/verbs/horizontal_invert_self.dm b/code/modules/mob/verbs/horizontal_invert_self.dm
index 09adab8dbc5..57b55fd188f 100644
--- a/code/modules/mob/verbs/horizontal_invert_self.dm
+++ b/code/modules/mob/verbs/horizontal_invert_self.dm
@@ -1,6 +1,7 @@
//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2024 Citadel Station Developers *//
+// todo: DECLARE_MOB_VERB
/mob/verb/horizontal_invert_self()
set name = "Invert Yourself (Horizontal)"
set desc = "Mirror your sprite across the N-S axis."
diff --git a/code/modules/mob/verbs/vertical_invert_self.dm b/code/modules/mob/verbs/vertical_invert_self.dm
new file mode 100644
index 00000000000..9b179d98fe0
--- /dev/null
+++ b/code/modules/mob/verbs/vertical_invert_self.dm
@@ -0,0 +1,24 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2025 Citadel Station Developers *//
+
+// todo: DECLARE_MOB_VERB
+/mob/verb/vertical_invert_self()
+ set name = "Invert Yourself (Vertical)"
+ set desc = "Mirror your sprite across the N-S axis."
+ set category = VERB_CATEGORY_IC
+
+ // todo: remote control? mobs that don't allow it?
+
+ if(TIMER_COOLDOWN_CHECK(src, CD_INDEX_MOB_VERB_INVERT_SELF))
+ // todo: don't usr lol
+ to_chat(usr, SPAN_WARNING("You can't do that yet!"))
+ return
+ TIMER_COOLDOWN_START(src, CD_INDEX_MOB_VERB_INVERT_SELF, 0.5 SECONDS)
+
+ log_game("[key_name(usr)] invoked vertical_invert_self on [key_name(src)].")
+
+ var/datum/component/mob_self_vertical_inversion/inversion = GetComponent(/datum/component/mob_self_vertical_inversion)
+ if(inversion)
+ qdel(inversion)
+ else
+ AddComponent(/datum/component/mob_self_vertical_inversion)
diff --git a/code/modules/multiz/atom-z_fall.dm b/code/modules/multiz/atom-z_fall.dm
new file mode 100644
index 00000000000..6f06a7b9eb4
--- /dev/null
+++ b/code/modules/multiz/atom-z_fall.dm
@@ -0,0 +1,29 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2025 Citadel Station Developers *//
+
+/**
+ * Stops a thing from falling through this
+ *
+ * * If said thing is asking while falling, the first thing to return this will be what gets on_z_impacted'd.
+ *
+ * @params
+ * * victim - thing trying to fall through us
+ * * levels - levels fallen so far, preventing a fall in the first place has this at 0, breaking a falling object from z2 to z1's floor would be 1, etc.
+ * * fall_flags - see __DEFINES/mapping/multiz.dm
+ */
+/atom/proc/prevent_z_fall(atom/movable/victim, levels = 0, fall_flags)
+ return fall_flags
+
+/**
+ * Called when a thing falls onto us.
+ *
+ * * Only called if something is falling; if we prevent the fall in the first place, this never gets called
+ *
+ * @params
+ * * victim - thing trying to fall through us
+ * * levels - levels fallen so far, preventing a fall in the first place has this at 0, breaking a falling object from z2 to z1's floor would be 1, etc.
+ * * fall_flags - see __DEFINES/mapping/multiz.dm
+ * * direct_hit - we're the thing actually landed on.
+ */
+/atom/proc/on_z_impacted(atom/movable/victim, levels, fall_flags, direct_hit)
+ return fall_flags
diff --git a/code/modules/multiz/atoms.dm b/code/modules/multiz/atom-z_move.dm
similarity index 92%
rename from code/modules/multiz/atoms.dm
rename to code/modules/multiz/atom-z_move.dm
index 5abbda59d9a..bfafd6552c3 100644
--- a/code/modules/multiz/atoms.dm
+++ b/code/modules/multiz/atom-z_move.dm
@@ -1,5 +1,5 @@
//* This file is explicitly licensed under the MIT license. *//
-//* Copyright (c) 2023 Citadel Station developers. *//
+//* Copyright (c) 2025 Citadel Station Developers *//
/**
* returns if an atom can enter our tile from a multiz move
diff --git a/code/modules/multiz/core.dm b/code/modules/multiz/core.dm
index 5d16359cd4b..fd8ce02a737 100644
--- a/code/modules/multiz/core.dm
+++ b/code/modules/multiz/core.dm
@@ -1,5 +1,5 @@
//* This file is explicitly licensed under the MIT license. *//
-//* Copyright (c) 2023 Citadel Station developers. *//
+//* Copyright (c) 2025 Citadel Station Developers *//
/**
* This is the basic get multiz step.
diff --git a/code/modules/multiz/falling.dm b/code/modules/multiz/falling.dm
deleted file mode 100644
index 7e671e085d1..00000000000
--- a/code/modules/multiz/falling.dm
+++ /dev/null
@@ -1,15 +0,0 @@
-//* This file is explicitly licensed under the MIT license. *//
-//* Copyright (c) 2023 Citadel Station developers. *//
-
-/**
- * Stops a thing from falling through this
- *
- * If said thing is asking while falling, the first thing to return this will be what gets ZImpact'd.
- *
- * @params
- * - victim - thing trying to fall through us
- * - levels - levels fallen so far, preventing a fall in the first place has this at 0, breaking a falling object from z2 to z1's floor would be 1, etc.
- * - fall_flags - see __DEFINES/mapping/multiz.dm
- */
-/atom/proc/prevent_z_fall(atom/movable/victim, levels = 0, fall_flags)
- return fall_flags
diff --git a/code/modules/multiz/movement.dm b/code/modules/multiz/movement.dm
index 907f3d5a410..85479fe8b69 100644
--- a/code/modules/multiz/movement.dm
+++ b/code/modules/multiz/movement.dm
@@ -309,18 +309,12 @@
var/obj/structure/stairs/stairs = locate() in landing
if(!stairs)
// Now lets move there!
- // todo: this should not use Move
- if(!Move(landing))
+ if(!forceMove(landing))
return 1
var/atom/A = find_fall_target(oldloc, landing)
if(special_fall_handle(A) || !A || !A.check_z_impact(src))
return
- var/mob/drop_mob = locate(/mob, landing)
- if(drop_mob && !(drop_mob == src) && ismob(drop_mob) && isliving(drop_mob)) //Shitload of checks. This is because the game finds various ways to screw me over.
- var/mob/living/drop_living = drop_mob
- if(drop_living.dropped_onto(src))
- return
fall_impact(A)
else
locationTransitForceMove(landing)
@@ -343,6 +337,8 @@
// First hit objects in the turf!
for(var/atom/movable/A in landing)
+ if(A.atom_flags & (ATOM_NONWORLD | ATOM_ABSTRACT))
+ continue
if(A != src && A.CheckFall(src))
return A
@@ -360,7 +356,7 @@
// CheckFall landing.fall_impact(src)
//! ## THE FALLING PROCS ###
-
+// todo: rework falling :/
/**
* Called on everything that falling_atom might hit.
@@ -375,6 +371,8 @@
* If you are hit: how is it handled.
* Return TRUE if the generic fall_impact should be called.
* Return FALSE if you handled it yourself or if there's no effect from hitting you.
+ *
+ * todo: this is a legacy proc
*/
/atom/proc/check_z_impact(atom/movable/falling_atom)
return TRUE
@@ -386,16 +384,19 @@
* damage_max is the largest amount of damage a thing (currently only mobs and mechs) will take from falling.
* If silent is True, the proc won't play sound or give a message.
* If planetary is True, it's harder to stop the fall damage.
+ *
+ * todo: rework everything lmao
*/
/atom/movable/proc/fall_impact(atom/hit_atom, damage_min = 0, damage_max = 10, silent = FALSE, planetary = FALSE)
if(!silent)
visible_message("\The [src] falls from above and slams into \the [hit_atom]!", "You hear something slam into \the [hit_atom].")
for(var/atom/movable/A in src.contents)
+ if(A.atom_flags & (ATOM_NONWORLD | ATOM_ABSTRACT))
+ continue
A.fall_impact(hit_atom, damage_min, damage_max, silent = TRUE)
for(var/mob/M in buckled_mobs)
M.fall_impact(hit_atom, damage_min, damage_max, silent, planetary)
-
/// Take damage from falling and hitting the ground.
/mob/living/fall_impact(atom/hit_atom, damage_min = 0, damage_max = 5, silent = FALSE, planetary = FALSE)
var/turf/landing = get_turf(hit_atom)
@@ -419,15 +420,15 @@
if(!silent)
if(planetary)
visible_message(
- SPAN_USERDANGER("\A [src] falls out of the sky and crashes into \the [landing]!"),
- SPAN_USERDANGER("You fall out of the sky and crash into \the [landing]!"),
+ SPAN_USERDANGER("\A [src] falls out of the sky and crashes into [landing]!"),
+ SPAN_USERDANGER("You fall out of the sky and crash into [landing]!"),
SPAN_HEAR("You hear something slam into \the [landing]."),
)
var/turf/T = get_turf(landing)
explosion(T, 0, 1, 2)
else
visible_message(
- SPAN_WARNING("\The [src] falls from above and slams into \the [landing]!"),
+ SPAN_WARNING("\The [src] falls from above and slams into [landing]!"),
SPAN_DANGER("You fall off and hit \the [landing]!"),
SPAN_HEAR("You hear something slam into \the [landing]."),
)
@@ -437,7 +438,7 @@
// Hits 10 times, because apparently targeting individual limbs lets certain species survive the fall from atmosphere
for(var/i = 1 to 10)
adjustBruteLoss(rand(damage_min, damage_max))
- afflict_paralyze(20 * 4)
+ afflict_paralyze(8 SECONDS)
update_health()
/mob/living/carbon/human/fall_impact(atom/hit_atom, damage_min, damage_max, silent, planetary)
@@ -563,12 +564,9 @@
var/turf/simulated/floor/ground = hit_atom
ground.break_tile()
-
+// todo: rewrite this entire file
/mob/CheckFall(atom/movable/falling_atom)
return falling_atom.fall_impact(src)
-//! I didn't feel like removing @silicons' check in handle_fall(). @Zandario
-/mob/living/proc/dropped_onto(atom/hit_atom)
- if(!isliving(hit_atom))
- return FALSE
- return TRUE
+/mob/observer/CheckFall(atom/movable/falling_atom)
+ return FALSE
diff --git a/code/modules/multiz/turf-multiz_misc.dm b/code/modules/multiz/turf-multiz_misc.dm
new file mode 100644
index 00000000000..6cfecc5af46
--- /dev/null
+++ b/code/modules/multiz/turf-multiz_misc.dm
@@ -0,0 +1,52 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2025 Citadel Station Developers *//
+
+// todo: redo
+/turf/CheckFall(atom/movable/falling_atom)
+ if(!(mz_flags & MZ_OPEN_DOWN))
+ return TRUE // impact!
+ return ..()
+
+//* lookups
+
+/turf/proc/above()
+ RETURN_TYPE(/turf)
+ return locate(x, y, SSmapping.cached_level_up[z])
+
+/turf/proc/below()
+ RETURN_TYPE(/turf)
+ return locate(x, y, SSmapping.cached_level_down[z])
+
+/**
+ * This is the basic get multiz step.
+ * It will not look across lateral transitions, only up/down.
+ */
+/turf/proc/vertical_step(dir)
+ RETURN_TYPE(/turf)
+ if((dir & (UP|DOWN)) == 0)
+ return get_step(src, dir)
+ else if(dir & UP)
+ return get_step(locate(x, y, SSmapping.cached_level_up[z]), dir & ~(UP))
+ else if(dir & DOWN)
+ return get_step(locate(x, y, SSmapping.cached_level_down[z]), dir & ~(DOWN))
+ CRASH("how did we get here?")
+
+/**
+ * Basic multiz get dir
+ * Will not look across lateral transitions, only directly up/down.
+ */
+/turf/proc/vertical_dir(turf/other)
+ if(other.z == z)
+ return get_dir(src, other)
+ else if(other.z == SSmapping.cached_level_up[z])
+ return get_dir(src, other) | UP
+ else if(other.z == SSmapping.cached_level_down[z])
+ return get_dir(src, other) | DOWN
+
+/**
+ * This is the full get multiz step.
+ * It will look across lateral transitions and other struct magic.
+ */
+/turf/proc/virtual_step(dir)
+ RETURN_TYPE(/turf)
+ return SSmapping.get_virtual_step(src, dir)
diff --git a/code/modules/multiz/turf-z_fall.dm b/code/modules/multiz/turf-z_fall.dm
new file mode 100644
index 00000000000..6e501a85323
--- /dev/null
+++ b/code/modules/multiz/turf-z_fall.dm
@@ -0,0 +1,38 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2025 Citadel Station Developers *//
+
+/**
+ * simple boolean check to see if something's physically blocked from leaving us via up/down
+ *
+ * @params
+ * - mover - atom that needs to move
+ * - dir - are they going UP abov eus or DOWN below us?
+ */
+/turf/proc/z_exit_check(atom/movable/mover, dir)
+ // we assume dir is up/down because why wouldn't it be
+ var/turf/dest
+ if(dir == UP)
+ dest = above()
+ return dest && !z_pass_out_obstruction(mover, UP, dest) && !dest.z_pass_in_obstruction(mover, DOWN, src)
+ else if(dir == DOWN)
+ dest = below()
+ return dest && !z_pass_out_obstruction(mover, DOWN, dest) && !dest.z_pass_in_obstruction(mover, UP, src)
+ CRASH("Non-vertical direction '[dir]' passed in.")
+
+/**
+ * checks what is going to block something from falling through us
+ */
+/turf/proc/z_fall_obstruction(atom/movable/mover, levels, fall_flags)
+ for(var/atom/movable/AM as anything in contents)
+ if(AM.prevent_z_fall(mover, levels, fall_flags))
+ return AM
+
+/**
+ * simple boolean check to see if something's physically blocked from falling through us
+ *
+ * * checked in addition to z_exit_check.
+ */
+/turf/proc/z_fall_check(atom/movable/mover, levels, fall_flags)
+ if(!(mz_flags & MZ_OPEN_DOWN))
+ return FALSE
+ return isnull(z_fall_obstruction(mover, levels, fall_flags))
diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf-z_move.dm
similarity index 52%
rename from code/modules/multiz/turf.dm
rename to code/modules/multiz/turf-z_move.dm
index e35652e4e2b..239c2f06357 100644
--- a/code/modules/multiz/turf.dm
+++ b/code/modules/multiz/turf-z_move.dm
@@ -1,5 +1,11 @@
//* This file is explicitly licensed under the MIT license. *//
-//* Copyright (c) 2023 Citadel Station developers. *//
+//* Copyright (c) 2025 Citadel Station Developers *//
+
+/turf/z_pass_in(atom/movable/AM, dir, turf/old_loc)
+ return isnull(z_pass_in_obstruction(AM, dir, old_loc))
+
+/turf/z_pass_out(atom/movable/AM, dir, turf/new_loc)
+ return isnull(z_pass_out_obstruction(AM, dir, new_loc))
/**
* WARNING: This proc is unique. Read the doc here, especially the return value.
@@ -65,94 +71,4 @@
else if(dir == DOWN)
dest = below()
return dest && (z_pass_out_obstruction(mover, DOWN, dest) || dest.z_pass_in_obstruction(mover, UP, src))
- CRASH("What?")
-
-/**
- * simple boolean check to see if something's physically blocked from leaving us via up/down
- *
- * @params
- * - mover - atom that needs to move
- * - dir - are they going UP abov eus or DOWN below us?
- */
-/turf/proc/z_exit_check(atom/movable/mover, dir)
- // we assume dir is up/down because why wouldn't it be
- var/turf/dest
- if(dir == UP)
- dest = above()
- return dest && !z_pass_out_obstruction(mover, UP, dest) && !dest.z_pass_in_obstruction(mover, DOWN, src)
- else if(dir == DOWN)
- dest = below()
- return dest && !z_pass_out_obstruction(mover, DOWN, dest) && !dest.z_pass_in_obstruction(mover, UP, src)
- CRASH("What?")
-
-/**
- * checks what is going to block something from falling through us
- */
-/turf/proc/z_fall_obstruction(atom/movable/mover, levels, fall_flags)
- for(var/atom/movable/AM as anything in contents)
- if(AM.prevent_z_fall(mover, levels, fall_flags))
- return AM
-
-/**
- * simple boolean check to see if something's physically blocked from falling through us
- */
-/turf/proc/z_fall_check(atom/movable/mover, levels, fall_flags)
- if(!(mz_flags & MZ_OPEN_DOWN))
- return FALSE
- return isnull(z_fall_obstruction(mover, levels, fall_flags))
-
-/turf/z_pass_in(atom/movable/AM, dir, turf/old_loc)
- return isnull(z_pass_in_obstruction(AM, dir, old_loc))
-
-/turf/z_pass_out(atom/movable/AM, dir, turf/new_loc)
- return isnull(z_pass_out_obstruction(AM, dir, new_loc))
-
-// todo: redo
-/turf/CheckFall(atom/movable/falling_atom)
- if(!(mz_flags & MZ_OPEN_DOWN))
- return TRUE // impact!
- return ..()
-
-//* lookups
-
-/turf/proc/above()
- RETURN_TYPE(/turf)
- return locate(x, y, SSmapping.cached_level_up[z])
-
-/turf/proc/below()
- RETURN_TYPE(/turf)
- return locate(x, y, SSmapping.cached_level_down[z])
-
-/**
- * This is the basic get multiz step.
- * It will not look across lateral transitions, only up/down.
- */
-/turf/proc/vertical_step(dir)
- RETURN_TYPE(/turf)
- if((dir & (UP|DOWN)) == 0)
- return get_step(src, dir)
- else if(dir & UP)
- return get_step(locate(x, y, SSmapping.cached_level_up[z]), dir & ~(UP))
- else if(dir & DOWN)
- return get_step(locate(x, y, SSmapping.cached_level_down[z]), dir & ~(DOWN))
- CRASH("how did we get here?")
-
-/**
- * Basic multiz get dir
- * Will not look across lateral transitions, only directly up/down.
- */
-/turf/proc/vertical_dir(turf/other)
- if(other.z == z)
- return get_dir(src, other)
- else if(other.z == SSmapping.cached_level_up[z])
- return get_dir(src, other) | UP
- else if(other.z == SSmapping.cached_level_down[z])
- return get_dir(src, other) | DOWN
-
-/**
- * This is the full get multiz step.
- * It will look across lateral transitions and other struct magic.
- */
-/turf/proc/virtual_step(dir)
- RETURN_TYPE(/turf)
- return SSmapping.get_virtual_step(src, dir)
+ CRASH("Non-vertical direction '[dir]' passed in.")
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 0a6fd8c9ffc..ba987430fd4 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -542,9 +542,10 @@ GLOBAL_LIST_INIT(possible_cable_coil_colours, list(
slot_flags = SLOT_BELT
item_state = "coil"
attack_verb = list("whipped", "lashed", "disciplined", "flogged")
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
drop_sound = 'sound/items/drop/accessory.ogg'
pickup_sound = 'sound/items/pickup/accessory.ogg'
+ stack_type = /obj/item/stack/cable_coil
/obj/item/stack/cable_coil/cyborg
name = "cable coil synthesizer"
@@ -856,85 +857,85 @@ GLOBAL_LIST_INIT(possible_cable_coil_colours, list(
update_wclass()
/obj/item/stack/cable_coil/yellow
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_YELLOW
/obj/item/stack/cable_coil/blue
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_BLUE
/obj/item/stack/cable_coil/green
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_LIME
/obj/item/stack/cable_coil/pink
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_PINK
/obj/item/stack/cable_coil/orange
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_ORANGE
/obj/item/stack/cable_coil/cyan
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_CYAN
/obj/item/stack/cable_coil/white
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_WHITE
/obj/item/stack/cable_coil/silver
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_SILVER
/obj/item/stack/cable_coil/gray
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_GRAY
/obj/item/stack/cable_coil/black
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_BLACK
/obj/item/stack/cable_coil/maroon
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_MAROON
/obj/item/stack/cable_coil/olive
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_OLIVE
/obj/item/stack/cable_coil/lime
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_LIME
/obj/item/stack/cable_coil/teal
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_TEAL
/obj/item/stack/cable_coil/navy
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_NAVY
/obj/item/stack/cable_coil/purple
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_PURPLE
/obj/item/stack/cable_coil/beige
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_BEIGE
/obj/item/stack/cable_coil/brown
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = COLOR_BROWN
/obj/item/stack/cable_coil/random/Initialize(mapload, new_amount, merge)
. = ..()
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = pick(COLOR_RED, COLOR_BLUE, COLOR_LIME, COLOR_WHITE, COLOR_PINK, COLOR_YELLOW, COLOR_CYAN, COLOR_SILVER, COLOR_GRAY, COLOR_BLACK, COLOR_MAROON, COLOR_OLIVE, COLOR_LIME, COLOR_TEAL, COLOR_NAVY, COLOR_PURPLE, COLOR_BEIGE, COLOR_BROWN)
/obj/item/stack/cable_coil/random_belt/Initialize(mapload, new_amount, merge)
. = ..()
- stacktype = /obj/item/stack/cable_coil
+ stacktype_legacy = /obj/item/stack/cable_coil
color = pick(COLOR_RED, COLOR_YELLOW, COLOR_ORANGE)
amount = 30
@@ -972,7 +973,7 @@ GLOBAL_LIST_INIT(possible_cable_coil_colours, list(
materials_base = list(MAT_STEEL = 50, MAT_GLASS = 20)
slot_flags = SLOT_BELT
attack_verb = list("whipped", "lashed", "disciplined", "flogged")
- stacktype = null
+ stacktype_legacy = null
split_type = /obj/item/stack/cable_coil
tool_speed = 0.25
diff --git a/code/modules/preferences/preferences_toggle_procs.dm b/code/modules/preferences/preferences_toggle_procs.dm
index 3337c1d9dd0..185314f2924 100644
--- a/code/modules/preferences/preferences_toggle_procs.dm
+++ b/code/modules/preferences/preferences_toggle_procs.dm
@@ -12,53 +12,3 @@
else
src.painmsg = 1
to_chat(src,"You will [ (painmsg) ? "now" : "no longer"] see your own pain messages.")
-
-/mob/living/carbon/human/verb/acting()
- set name = "Feign Impairment"
- set category = VERB_CATEGORY_IC
- set desc = "Allows user to manually enable drunkenness, stutter, jitter, etc."
- set src = usr
-
- if(!IS_CONSCIOUS(src))
- to_chat(src, "You need to be conscious to do that")
- return
-
- var/list/choices = list("Drunkenness", "Stuttering", "Jittering")
- if(src.slurring >= 10 || src.stuttering >= 10 || src.jitteriness >= 100)
- var/disable = alert(src, "Stop performing impairment? (Do NOT abuse this)", "Impairments", "Yes", "No")
- if(disable == "Yes")
- acting_expiry()
- return
-
- var/impairment = input(src, "Select an impairment to perform:", "Impairments") as null|anything in choices
- if(!impairment)
- return
- var/duration = input(src,"Choose a duration to perform [impairment]. (1 - 60 seconds)","Duration in seconds",25) as num|null
- if(!isnum(duration))
- return
- if(duration > 60 && !check_rights(R_EVENT, 0)) // admins can do as they please
- to_chat(src, "Please choose a duration in seconds between 1 to 60.")
- return
- if(duration >= 1000) // unreachable code for anyone but admins who have set the number very high, logging for my sanity
- message_admins("[src] has set their [impairment] to [duration] via Feign Impairment.")
- if(duration >= 2000)
- to_chat(src, "Please choose a duration less than 2000.")
- return
- if(impairment == "Drunkenness")
- slurring = duration
- if(impairment == "Stuttering")
- stuttering = duration
- if(impairment == "Jittering")
- make_jittery(duration + 100)
-
- if(duration)
- addtimer(CALLBACK(src, PROC_REF(acting_expiry)), duration SECONDS)
- var/aduration = duration SECONDS / 10
- to_chat(src,"You will now performatively act as if you were experiencing [impairment] for [aduration] seconds. (Do NOT abuse this)")
- feedback_add_details("admin_verb","actimpaired") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/mob/living/carbon/human/proc/acting_expiry()
- to_chat(src,"You are no longer acting impaired.") // tick down from 1 to allow the effects to end 'naturally'
- slurring = 1
- stuttering = 1
- jitteriness = 1
diff --git a/code/modules/vehicles/sealed/mecha/subtypes/micro/mecha_construction_paths_vr.dm b/code/modules/vehicles/sealed/mecha/subtypes/micro/mecha_construction_paths_vr.dm
index 36d682829ff..36606784333 100644
--- a/code/modules/vehicles/sealed/mecha/subtypes/micro/mecha_construction_paths_vr.dm
+++ b/code/modules/vehicles/sealed/mecha/subtypes/micro/mecha_construction_paths_vr.dm
@@ -306,8 +306,6 @@
const_holder.cut_overlays()
spawn()
qdel(src)
- return
-
/datum/construction/reversible/mecha/gopher
result = "/obj/vehicle/sealed/mecha/micro/utility/gopher"
diff --git a/maps/templates/archive/tradeship.dmm b/maps/templates/archive/tradeship.dmm
index ed1a4ce9f4c..dcad551d9a7 100644
--- a/maps/templates/archive/tradeship.dmm
+++ b/maps/templates/archive/tradeship.dmm
@@ -1537,7 +1537,7 @@
/obj/item/clothing/under/cheongsam,
/obj/item/clothing/under/hosformalmale,
/obj/item/clothing/under/hosformalfem,
-/obj/item/clothing/under/harness,
+/obj/item/clothing/under/gear_harness,
/obj/item/clothing/under/gladiator,
/obj/item/clothing/under/ert,
/obj/item/clothing/under/schoolgirl,