diff --git a/_maps/RandomRuins/JungleRuins/jungle_paradise.dmm b/_maps/RandomRuins/JungleRuins/jungle_paradise.dmm
index 0e19890e63c7..47455933ec16 100644
--- a/_maps/RandomRuins/JungleRuins/jungle_paradise.dmm
+++ b/_maps/RandomRuins/JungleRuins/jungle_paradise.dmm
@@ -5181,7 +5181,7 @@
pixel_x = 7;
pixel_y = 6
},
-/obj/structure/fireaxecabinet{
+/obj/structure/cabinet/fireaxe{
pixel_y = 28
},
/turf/open/floor/mineral/titanium,
diff --git a/_maps/RandomRuins/SpaceRuins/singularity_lab.dmm b/_maps/RandomRuins/SpaceRuins/singularity_lab.dmm
index 99ccda138d00..7dd57c637f35 100644
--- a/_maps/RandomRuins/SpaceRuins/singularity_lab.dmm
+++ b/_maps/RandomRuins/SpaceRuins/singularity_lab.dmm
@@ -8625,13 +8625,13 @@
/turf/open/floor/plasteel/grimy,
/area/ruin/space/has_grav/singularitylab/lab)
"HU" = (
-/obj/structure/fireaxecabinet{
- pixel_y = 32
- },
/obj/structure/sign/warning/incident{
pixel_x = -32
},
/obj/effect/decal/cleanable/cobweb,
+/obj/structure/cabinet/fireaxe{
+ pixel_y = 28
+ },
/turf/open/floor/plasteel/dark,
/area/ruin/space/has_grav/singularitylab/engineering)
"HW" = (
diff --git a/_maps/shuttles/independent/independent_lagoon.dmm b/_maps/shuttles/independent/independent_lagoon.dmm
index 3615828fa9d2..1c8c2307a7e8 100644
--- a/_maps/shuttles/independent/independent_lagoon.dmm
+++ b/_maps/shuttles/independent/independent_lagoon.dmm
@@ -2347,7 +2347,7 @@
},
/obj/item/clothing/suit/hooded/wintercoat/engineering/atmos,
/obj/item/clothing/gloves/color/black,
-/obj/structure/fireaxecabinet{
+/obj/structure/cabinet/fireaxe{
dir = 8;
pixel_x = 28
},
diff --git a/_maps/shuttles/inteq/inteq_talos.dmm b/_maps/shuttles/inteq/inteq_talos.dmm
index 195852c9fd5c..6b05aa78caaa 100644
--- a/_maps/shuttles/inteq/inteq_talos.dmm
+++ b/_maps/shuttles/inteq/inteq_talos.dmm
@@ -2090,7 +2090,7 @@
dir = 1
},
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4,
-/obj/structure/fireaxecabinet{
+/obj/structure/cabinet/fireaxe{
dir = 1;
pixel_y = -32
},
diff --git a/_maps/shuttles/nanotrasen/nanotrasen_heron.dmm b/_maps/shuttles/nanotrasen/nanotrasen_heron.dmm
index 3dda0b36dd63..7d8db3ebb68b 100644
--- a/_maps/shuttles/nanotrasen/nanotrasen_heron.dmm
+++ b/_maps/shuttles/nanotrasen/nanotrasen_heron.dmm
@@ -13621,7 +13621,7 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 6
},
-/obj/structure/fireaxecabinet{
+/obj/structure/cabinet/fireaxe{
pixel_y = 27
},
/obj/structure/closet/secure_closet/engineering_electrical,
diff --git a/_maps/shuttles/nanotrasen/nanotrasen_osprey.dmm b/_maps/shuttles/nanotrasen/nanotrasen_osprey.dmm
index fb1d6e3c1f12..e99a4cd360a8 100644
--- a/_maps/shuttles/nanotrasen/nanotrasen_osprey.dmm
+++ b/_maps/shuttles/nanotrasen/nanotrasen_osprey.dmm
@@ -5632,7 +5632,7 @@
/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer2{
dir = 1
},
-/obj/structure/fireaxecabinet{
+/obj/structure/cabinet/fireaxe{
pixel_y = 32
},
/obj/structure/cable{
diff --git a/_maps/shuttles/nanotrasen/nanotrasen_skipper.dmm b/_maps/shuttles/nanotrasen/nanotrasen_skipper.dmm
index d875a024d07f..a8f5bc22c7f4 100644
--- a/_maps/shuttles/nanotrasen/nanotrasen_skipper.dmm
+++ b/_maps/shuttles/nanotrasen/nanotrasen_skipper.dmm
@@ -472,7 +472,7 @@
/turf/open/floor/plasteel/white,
/area/ship/medical)
"dZ" = (
-/obj/structure/fireaxecabinet{
+/obj/structure/cabinet/fireaxe{
pixel_y = -29
},
/obj/structure/catwalk/over/plated_catwalk/dark,
diff --git a/_maps/shuttles/pirate/pirate_libertatia.dmm b/_maps/shuttles/pirate/pirate_libertatia.dmm
index b1bf098571c0..46d00806edd7 100644
--- a/_maps/shuttles/pirate/pirate_libertatia.dmm
+++ b/_maps/shuttles/pirate/pirate_libertatia.dmm
@@ -299,7 +299,7 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 4
},
-/obj/structure/fireaxecabinet{
+/obj/structure/cabinet/fireaxe{
pixel_y = 32
},
/turf/open/floor/pod/light,
diff --git a/_maps/shuttles/syndicate/syndicate_gorlex_komodo.dmm b/_maps/shuttles/syndicate/syndicate_gorlex_komodo.dmm
index 2b4cfd484e98..c466f5351f9c 100644
--- a/_maps/shuttles/syndicate/syndicate_gorlex_komodo.dmm
+++ b/_maps/shuttles/syndicate/syndicate_gorlex_komodo.dmm
@@ -2048,7 +2048,7 @@
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
-/obj/structure/fireaxecabinet{
+/obj/structure/cabinet/fireaxe{
dir = 8;
pixel_x = 27
},
diff --git a/_maps/shuttles/syndicate/syndicate_twinkleshine.dmm b/_maps/shuttles/syndicate/syndicate_twinkleshine.dmm
index 6c690286b2ac..29f4bc28922b 100644
--- a/_maps/shuttles/syndicate/syndicate_twinkleshine.dmm
+++ b/_maps/shuttles/syndicate/syndicate_twinkleshine.dmm
@@ -3500,7 +3500,7 @@
pixel_y = 4
},
/obj/item/storage/toolbox/electrical,
-/obj/structure/fireaxecabinet{
+/obj/structure/cabinet/fireaxe{
pixel_y = -32;
dir = 1
},
diff --git a/code/__DEFINES/dcs/signals/signals.dm b/code/__DEFINES/dcs/signals/signals.dm
index f3295b737904..fd56e61f003b 100644
--- a/code/__DEFINES/dcs/signals/signals.dm
+++ b/code/__DEFINES/dcs/signals/signals.dm
@@ -671,6 +671,7 @@
#define COMPONENT_TWOHANDED_BLOCK_WIELD 1
#define COMSIG_TWOHANDED_UNWIELD "twohanded_unwield" //from base of datum/component/two_handed/proc/unwield(mob/living/carbon/user): (/mob/user)
+
// /datum/action signals
#define COMSIG_ACTION_TRIGGER "action_trigger" //from base of datum/action/proc/Trigger(): (datum/action)
#define COMPONENT_ACTION_BLOCK_TRIGGER 1
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index c97fa62ffc5d..4925981b2a91 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -301,6 +301,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_NO_STORAGE_INSERT "no_storage_insert" //cannot be inserted in a storage.
#define TRAIT_T_RAY_VISIBLE "t-ray-visible" // Visible on t-ray scanners if the atom/var/level == 1
#define TRAIT_NO_TELEPORT "no-teleport" //you just can't
+#define TRAIT_WIELDED "wielded" //The item is currently being wielded
//quirk traits
#define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance"
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index d831296dbb62..7bd6f72771cc 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -680,7 +680,7 @@ GLOBAL_LIST_INIT(WALLITEMS, typecacheof(list(
/obj/machinery/newscaster, /obj/machinery/firealarm, /obj/structure/noticeboard, /obj/machinery/button,
/obj/machinery/computer/security/telescreen, /obj/machinery/embedded_controller/radio/simple_vent_controller,
/obj/item/storage/secure/safe, /obj/machinery/door_timer, /obj/machinery/flasher, /obj/machinery/keycard_auth,
- /obj/structure/mirror, /obj/structure/fireaxecabinet, /obj/machinery/computer/security/telescreen/entertainment,
+ /obj/structure/mirror, /obj/structure/cabinet, /obj/machinery/computer/security/telescreen/entertainment,
/obj/structure/sign/picture_frame, /obj/machinery/bounty_board
)))
diff --git a/code/datums/components/twohanded.dm b/code/datums/components/twohanded.dm
index 51c9268d13ab..5ba0a368c637 100644
--- a/code/datums/components/twohanded.dm
+++ b/code/datums/components/twohanded.dm
@@ -4,6 +4,7 @@
* When applied to an item it will make it two handed
*
*/
+
/datum/component/two_handed
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS // Only one of the component can exist on an item
var/wielded = FALSE /// Are we holding the two handed item properly
@@ -145,6 +146,7 @@
if(SEND_SIGNAL(parent, COMSIG_TWOHANDED_WIELD, user) & COMPONENT_TWOHANDED_BLOCK_WIELD)
return // blocked wield from item
wielded = TRUE
+ ADD_TRAIT(parent, TRAIT_WIELDED, REF(src))
RegisterSignal(user, COMSIG_MOB_SWAP_HANDS, PROC_REF(on_swap_hands))
// update item stats and name
@@ -188,6 +190,7 @@
// wield update status
wielded = FALSE
+ REMOVE_TRAIT(parent, TRAIT_WIELDED, REF(src))
UnregisterSignal(user, COMSIG_MOB_SWAP_HANDS)
SEND_SIGNAL(parent, COMSIG_TWOHANDED_UNWIELD, user)
@@ -303,7 +306,7 @@
sharpened_increase = min(amount, (max_amount - wielded_val))
return COMPONENT_BLOCK_SHARPEN_APPLIED
-/**
+/*
* The offhand dummy item for two handed items
*
*/
diff --git a/code/datums/elements/bed_tucking.dm b/code/datums/elements/bed_tucking.dm
index c094e5a5b108..e505e6efdb5a 100644
--- a/code/datums/elements/bed_tucking.dm
+++ b/code/datums/elements/bed_tucking.dm
@@ -8,8 +8,13 @@
var/y_offset = 0
/// our rotation degree - how much the item turns when in bed (+degrees turns it more parallel)
var/rotation_degree = 0
+ /// Whether the item changes its dir to match the desired lying direction of the bed that it's tucked into.
+ var/change_dir = FALSE
+ /// Whether the item changes its layer to the layer suggested by the bed for tucked-in item.
+ /// When the item is untucked, it is returned to its initial() layer.
+ var/change_layer = FALSE
-/datum/element/bed_tuckable/Attach(obj/target, x = 0, y = 0, rotation = 0)
+/datum/element/bed_tuckable/Attach(obj/target, x = 0, y = 0, rotation = 0, _change_dir = FALSE, _change_layer = FALSE)
. = ..()
if(!isitem(target))
return ELEMENT_INCOMPATIBLE
@@ -17,6 +22,8 @@
x_offset = x
y_offset = y
rotation_degree = rotation
+ change_dir = _change_dir
+ change_layer = _change_layer
RegisterSignal(target, COMSIG_ITEM_ATTACK_OBJ, PROC_REF(tuck_into_bed))
/datum/element/bed_tuckable/Detach(obj/target)
@@ -40,11 +47,20 @@
return
to_chat(tucker, "You lay [tucked] out on [target_bed].")
- tucked.pixel_x = x_offset
- tucked.pixel_y = y_offset
+ tucked.pixel_x = x_offset + target_bed.tucked_x_shift
+ tucked.pixel_y = y_offset + target_bed.tucked_y_shift
if(rotation_degree)
tucked.transform = turn(tucked.transform, rotation_degree)
RegisterSignal(tucked, COMSIG_ITEM_PICKUP, PROC_REF(untuck))
+ // the buckle_lying value on the bed controls the direction that mobs lay down in when they're buckled into bed.
+ // some items (bedsheets) have different states to reflect those directions.
+ if(change_dir)
+ if(target_bed.buckle_lying == 270)
+ tucked.setDir(NORTH)
+ else
+ tucked.setDir(SOUTH)
+ if(target_bed.suggested_tuck_layer != null)
+ tucked.layer = target_bed.suggested_tuck_layer
return COMPONENT_NO_AFTERATTACK
@@ -57,4 +73,5 @@
SIGNAL_HANDLER
tucked.transform = turn(tucked.transform, -rotation_degree)
+ tucked.layer = initial(tucked.layer)
UnregisterSignal(tucked, COMSIG_ITEM_PICKUP)
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index e70edb721788..4c27a08e64a7 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -1238,7 +1238,7 @@
if(!operating)
if(istype(I, /obj/item/melee/axe/fire)) //being fireaxe'd
var/obj/item/melee/axe/fire/axe = I
- if(axe && !axe.wielded)
+ if(axe && !HAS_TRAIT(axe, TRAIT_WIELDED))
to_chat(user, "You need to be wielding \the [axe] to do that!")
return
INVOKE_ASYNC(src, (density ? PROC_REF(open) : PROC_REF(close)), 2)
diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm
index 4161403fefd9..3ec6f58aa7b1 100644
--- a/code/game/objects/effects/decals/cleanable.dm
+++ b/code/game/objects/effects/decals/cleanable.dm
@@ -89,8 +89,9 @@
/obj/effect/decal/cleanable/wash(clean_types)
..()
if(!(flags_1 & INITIALIZED_1))
- return FALSE
- qdel(src)
+ return
+ if(clean_types in list(CLEAN_WASH, CLEAN_SCRUB))
+ qdel(src)
return TRUE
/obj/effect/decal/cleanable/proc/can_bloodcrawl_in()
diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm
index 51020d8f60dc..5fedeb47e455 100644
--- a/code/game/objects/effects/effect_system/effects_foam.dm
+++ b/code/game/objects/effects/effect_system/effects_foam.dm
@@ -48,13 +48,11 @@
/obj/effect/particle_effect/foam/firefighting/kill_foam()
STOP_PROCESSING(SSfastprocess, src)
-
if(absorbed_plasma)
var/obj/effect/decal/cleanable/plasma/P = (locate(/obj/effect/decal/cleanable/plasma) in get_turf(src))
if(!P)
P = new(loc)
P.reagents.add_reagent(/datum/reagent/stable_plasma, absorbed_plasma)
-
flick("[icon_state]-disolve", src)
QDEL_IN(src, 5)
@@ -67,6 +65,33 @@
/obj/effect/particle_effect/foam/firefighting/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
return
+
+/obj/effect/particle_effect/foam/antirad
+ name = "antiradiation foam"
+ lifetime = 80
+ amount = 0 //no spread
+ slippery_foam = FALSE
+ color = "#A6FAFF55"
+
+
+/obj/effect/particle_effect/foam/antirad/process()
+ ..()
+
+ var/turf/open/T = get_turf(src)
+ var/obj/effect/radiation/rads = (locate(/obj/effect/radiation) in T)
+ if(rads && istype(T))
+ rads.rad_power = rads.rad_power * rand(0.8, 0.95)
+ if (rads.rad_power <= RAD_BACKGROUND_RADIATION)
+ new /obj/effect/decal/cleanable/greenglow/filled(loc)
+ qdel(rads)
+ for(var/obj/things in get_turf(src))
+ things.wash(CLEAN_TYPE_RADIATION)
+
+/obj/effect/particle_effect/foam/antirad/kill_foam()
+ STOP_PROCESSING(SSfastprocess, src)
+ flick("[icon_state]-disolve", src)
+ QDEL_IN(src, 5)
+
/obj/effect/particle_effect/foam/metal
name = "aluminium foam"
metal = ALUMINIUM_FOAM
diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm
index 32a62880d69c..517bc9922786 100644
--- a/code/game/objects/items/defib.dm
+++ b/code/game/objects/items/defib.dm
@@ -309,17 +309,6 @@
AddElement(/datum/element/update_icon_updates_onmob)
AddComponent(/datum/component/two_handed, force_unwielded=8, force_wielded=12)
-/// triggered on wield of two handed item
-/obj/item/shockpaddles/proc/on_wield(obj/item/source, mob/user)
- SIGNAL_HANDLER
-
- wielded = TRUE
-
-/// triggered on unwield of two handed item
-/obj/item/shockpaddles/proc/on_unwield(obj/item/source, mob/user)
- SIGNAL_HANDLER
-
- wielded = FALSE
/obj/item/shockpaddles/Destroy()
defib = null
@@ -369,8 +358,6 @@
/obj/item/shockpaddles/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_NO_STORAGE_INSERT, GENERIC_ITEM_TRAIT) //stops shockpaddles from being inserted in BoH
- RegisterSignal(src, COMSIG_TWOHANDED_WIELD, PROC_REF(on_wield))
- RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, PROC_REF(on_unwield))
if(!req_defib)
return //If it doesn't need a defib, just say it exists
if (!loc || !istype(loc, /obj/item/defibrillator)) //To avoid weird issues from admin spawns
diff --git a/code/game/objects/items/melee/chainsaw.dm b/code/game/objects/items/melee/chainsaw.dm
index 494ec65cdb5a..d179237f8559 100644
--- a/code/game/objects/items/melee/chainsaw.dm
+++ b/code/game/objects/items/melee/chainsaw.dm
@@ -22,30 +22,12 @@
tool_behaviour = TOOL_SAW
toolspeed = 0.5
var/on = FALSE
- var/wielded = FALSE // track wielded status on item
-
-/obj/item/chainsaw/Initialize()
- . = ..()
- RegisterSignal(src, COMSIG_TWOHANDED_WIELD, PROC_REF(on_wield))
- RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, PROC_REF(on_unwield))
/obj/item/chainsaw/ComponentInitialize()
. = ..()
AddComponent(/datum/component/butchering, 30, 100, 0, 'sound/weapons/chainsawhit.ogg', TRUE)
AddComponent(/datum/component/two_handed, require_twohands=TRUE)
-/// triggered on wield of two handed item
-/obj/item/chainsaw/proc/on_wield(obj/item/source, mob/user)
- SIGNAL_HANDLER
-
- wielded = TRUE
-
-/// triggered on unwield of two handed item
-/obj/item/chainsaw/proc/on_unwield(obj/item/source, mob/user)
- SIGNAL_HANDLER
-
- wielded = FALSE
-
/obj/item/chainsaw/attack_self(mob/user)
on = !on
to_chat(user, "As you pull the starting cord dangling from [src], [on ? "it begins to whirr." : "the chain stops moving."]")
@@ -67,7 +49,7 @@
A.UpdateButtonIcon()
/obj/item/chainsaw/get_dismemberment_chance()
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
. = ..()
/obj/item/chainsaw/doomslayer
diff --git a/code/game/objects/items/melee/dualsaber.dm b/code/game/objects/items/melee/dualsaber.dm
index 965979db215a..28242c1006a1 100644
--- a/code/game/objects/items/melee/dualsaber.dm
+++ b/code/game/objects/items/melee/dualsaber.dm
@@ -28,7 +28,6 @@
var/two_hand_force = 34
var/hacked = FALSE
var/list/possible_colors = list("red", "blue", "green", "purple", "yellow")
- var/wielded = FALSE // track wielded status on item
/obj/item/dualsaber/ComponentInitialize()
. = ..()
@@ -43,7 +42,6 @@
if(user.dna.check_mutation(HULK))
to_chat(user, "You lack the grace to wield this!")
return COMPONENT_TWOHANDED_BLOCK_WIELD
- wielded = TRUE
sharpness = IS_SHARP
w_class = w_class_on
hitsound = 'sound/weapons/blade1.ogg'
@@ -56,16 +54,14 @@
/obj/item/dualsaber/proc/on_unwield(obj/item/source, mob/living/carbon/user)
SIGNAL_HANDLER
- wielded = FALSE
sharpness = initial(sharpness)
w_class = initial(w_class)
hitsound = "swing_hit"
STOP_PROCESSING(SSobj, src)
set_light_on(FALSE)
-
/obj/item/dualsaber/update_icon_state()
- icon_state = wielded ? "dualsaber[saber_color]" : "dualsaber"
+ icon_state = HAS_TRAIT(src, TRAIT_WIELDED) ? "dualsaber[saber_color]" : "dualsaber"
return ..()
/obj/item/dualsaber/Initialize()
@@ -94,14 +90,14 @@
if(user.has_dna())
if(user.dna.check_mutation(HULK))
to_chat(user, "You grip the blade too hard and accidentally drop it!")
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
user.dropItemToGround(src, force=TRUE)
return
..()
- if(wielded && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(40))
+ if(HAS_TRAIT(src, TRAIT_WIELDED) && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(40))
impale(user)
return
- if(wielded && prob(50))
+ if(HAS_TRAIT(src, TRAIT_WIELDED) && prob(50))
INVOKE_ASYNC(src, PROC_REF(jedi_spin), user)
/obj/item/dualsaber/proc/jedi_spin(mob/living/user)
@@ -109,18 +105,18 @@
/obj/item/dualsaber/proc/impale(mob/living/user)
to_chat(user, "You twirl around a bit before losing your balance and impaling yourself on [src].")
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
user.take_bodypart_damage(20,25,check_armor = TRUE)
else
user.adjustStaminaLoss(25)
/obj/item/dualsaber/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
return ..()
return 0
/obj/item/dualsaber/process()
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
if(hacked)
set_light_color(pick(COLOR_SOFT_RED, LIGHT_COLOR_GREEN, LIGHT_COLOR_LIGHT_CYAN, LIGHT_COLOR_LAVENDER))
open_flame()
@@ -128,12 +124,12 @@
STOP_PROCESSING(SSobj, src)
/obj/item/dualsaber/IsReflect()
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
return 1
/obj/item/dualsaber/ignition_effect(atom/A, mob/user)
// same as /obj/item/melee/transforming/energy, mostly
- if(!wielded)
+ if(!HAS_TRAIT(src, TRAIT_WIELDED))
return ""
var/in_mouth = ""
if(iscarbon(user))
diff --git a/code/game/objects/items/melee/energyhalberd.dm b/code/game/objects/items/melee/energyhalberd.dm
index 62c6f5de6020..8ae5cdd96f36 100644
--- a/code/game/objects/items/melee/energyhalberd.dm
+++ b/code/game/objects/items/melee/energyhalberd.dm
@@ -31,13 +31,12 @@
var/two_hand_force = 34
var/hacked = FALSE
var/list/possible_colors = list("red", "blue", "green", "purple", "yellow")
- var/wielded = FALSE // track wielded status on item
/obj/item/energyhalberd/ComponentInitialize()
. = ..()
AddComponent(/datum/component/two_handed, force_unwielded=force, force_wielded=two_hand_force, wieldsound='sound/weapons/saberon.ogg', unwieldsound='sound/weapons/saberoff.ogg')
-/// Triggered on wield of two handed item
+
/// Specific hulk checks due to reflection chance for balance issues and switches hitsounds.
/obj/item/energyhalberd/proc/on_halberdwield(obj/item/source, mob/living/carbon/user)
SIGNAL_HANDLER
@@ -46,7 +45,6 @@
if(user.dna.check_mutation(HULK))
to_chat(user, "You lack the grace to wield this!")
return COMPONENT_TWOHANDED_BLOCK_WIELD
- wielded = TRUE
sharpness = IS_SHARP
w_class = w_class_on
hitsound = 'sound/weapons/blade1.ogg'
@@ -54,12 +52,9 @@
set_light_on(TRUE)
-/// Triggered on unwield of two handed item
/// switch hitsounds
/obj/item/energyhalberd/proc/on_halberdunwield(obj/item/source, mob/living/carbon/user)
SIGNAL_HANDLER
-
- wielded = FALSE
sharpness = initial(sharpness)
w_class = initial(w_class)
hitsound = "swing_hit"
@@ -68,7 +63,7 @@
/obj/item/energyhalberd/update_icon_state()
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
icon_state = "halberd[halberd_color]"
return ..()
else
@@ -101,28 +96,28 @@
if(user.has_dna())
if(user.dna.check_mutation(HULK))
to_chat(user, "You grip the blade too hard and accidentally drop it!")
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
user.dropItemToGround(src, force=TRUE)
return
..()
- if(wielded && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(40))
+ if(HAS_TRAIT(src, TRAIT_WIELDED) && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(40))
impale(user)
return
/obj/item/energyhalberd/proc/impale(mob/living/user)
to_chat(user, "You swing around a bit before losing your balance and impaling yourself on [src].")
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
user.take_bodypart_damage(20,25,check_armor = TRUE)
else
user.adjustStaminaLoss(25)
/obj/item/energyhalberd/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
return ..()
return 0
/obj/item/energyhalberd/process()
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
if(hacked)
set_light_color(pick(COLOR_SOFT_RED, LIGHT_COLOR_GREEN, LIGHT_COLOR_LIGHT_CYAN, LIGHT_COLOR_LAVENDER))
open_flame()
@@ -130,12 +125,12 @@
STOP_PROCESSING(SSobj, src)
/obj/item/energyhalberd/IsReflect()
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
return 1
/obj/item/energyhalberd/ignition_effect(atom/A, mob/user)
// same as /obj/item/melee/transforming/energy, mostly
- if(!wielded)
+ if(!HAS_TRAIT(src, TRAIT_WIELDED))
return ""
var/in_mouth = ""
if(iscarbon(user))
diff --git a/code/game/objects/items/melee/fireaxe.dm b/code/game/objects/items/melee/fireaxe.dm
index bfbed0fe361b..b3e04ac1bc3c 100644
--- a/code/game/objects/items/melee/fireaxe.dm
+++ b/code/game/objects/items/melee/fireaxe.dm
@@ -13,31 +13,13 @@
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 30)
resistance_flags = FIRE_PROOF
species_exception = list(/datum/species/kepori)
- var/wielded = FALSE // track wielded status on item
-
-/obj/item/melee/axe/Initialize()
- . = ..()
- RegisterSignal(src, COMSIG_TWOHANDED_WIELD, PROC_REF(on_wield))
- RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, PROC_REF(on_unwield))
/obj/item/melee/axe/ComponentInitialize()
. = ..()
AddComponent(/datum/component/butchering, 100, 80, 0 , hitsound) //axes are not known for being precision butchering tools
AddComponent(/datum/component/two_handed, force_unwielded=5, force_wielded=24, icon_wielded="[base_icon_state]1")
-/// triggered on wield of two handed item
-/obj/item/melee/axe/proc/on_wield(obj/item/source, mob/user)
- SIGNAL_HANDLER
-
- wielded = TRUE
-
-/// triggered on unwield of two handed item
-/obj/item/melee/axe/proc/on_unwield(obj/item/source, mob/user)
- SIGNAL_HANDLER
-
- wielded = FALSE
-
-/obj/item/melee/axe/update_icon_state()
+/obj/item/fireaxe/update_icon_state()
icon_state = "[base_icon_state]0"
return ..()
@@ -45,7 +27,7 @@
. = ..()
if(!proximity)
return
- if(wielded) //destroys windows and grilles in one hit
+ if(HAS_TRAIT(src, TRAIT_WIELDED)) //destroys windows and grilles in one hit
if(istype(A, /obj/structure/window) || istype(A, /obj/structure/grille))
var/obj/structure/W = A
W.obj_destruction("axe")
diff --git a/code/game/objects/items/melee/spear.dm b/code/game/objects/items/melee/spear.dm
index 42717117fd8e..218638882bfb 100644
--- a/code/game/objects/items/melee/spear.dm
+++ b/code/game/objects/items/melee/spear.dm
@@ -66,30 +66,15 @@
icon_prefix = "spearbomb"
var/obj/item/grenade/explosive = null
var/war_cry = "AAAAARGH!!!"
- var/wielded = FALSE // track wielded status on item
/obj/item/melee/spear/explosive/Initialize(mapload)
. = ..()
- RegisterSignal(src, COMSIG_TWOHANDED_WIELD, PROC_REF(on_wield))
- RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, PROC_REF(on_unwield))
set_explosive(new /obj/item/grenade/iedcasing/spawned()) //For admin-spawned explosive lances
/obj/item/melee/spear/explosive/ComponentInitialize()
. = ..()
AddComponent(/datum/component/two_handed, force_unwielded=10, force_wielded=18, icon_wielded="[icon_prefix]1")
-/// triggered on wield of two handed item
-/obj/item/melee/spear/explosive/proc/on_wield(obj/item/source, mob/user)
- SIGNAL_HANDLER
-
- wielded = TRUE
-
-/// triggered on unwield of two handed item
-/obj/item/melee/spear/explosive/proc/on_unwield(obj/item/source, mob/user)
- SIGNAL_HANDLER
-
- wielded = FALSE
-
/obj/item/melee/spear/explosive/proc/set_explosive(obj/item/grenade/G)
if(explosive)
QDEL_NULL(explosive)
@@ -130,7 +115,7 @@
. = ..()
if(!proximity)
return
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
user.say("[war_cry]", forced="spear warcry")
explosive.forceMove(AM)
explosive.prime()
diff --git a/code/game/objects/items/melee/sword.dm b/code/game/objects/items/melee/sword.dm
index 21bde05c0dd3..ff384770a318 100644
--- a/code/game/objects/items/melee/sword.dm
+++ b/code/game/objects/items/melee/sword.dm
@@ -332,38 +332,20 @@
attack_verb = list("cut", "sliced", "diced")
slot_flags = ITEM_SLOT_BACK
hitsound = 'sound/weapons/bladeslice.ogg'
- var/wielded = FALSE // track wielded status on item
-
-/obj/item/melee/sword/vibro/Initialize()
- . = ..()
- RegisterSignal(src, COMSIG_TWOHANDED_WIELD, PROC_REF(on_wield))
- RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, PROC_REF(on_unwield))
/obj/item/melee/sword/vibro/ComponentInitialize()
. = ..()
AddComponent(/datum/component/butchering, 20, 105)
AddComponent(/datum/component/two_handed, force_multiplier=2, icon_wielded="[base_icon_state]1")
-/// triggered on wield of two handed item
-/obj/item/melee/sword/vibro/proc/on_wield(obj/item/source, mob/user)
- SIGNAL_HANDLER
-
- wielded = TRUE
-
-/// triggered on unwield of two handed item
-/obj/item/melee/sword/vibro/proc/on_unwield(obj/item/source, mob/user)
- SIGNAL_HANDLER
-
- wielded = FALSE
-
/obj/item/melee/sword/vibro/update_icon_state()
icon_state = "[base_icon_state]0"
return ..()
/obj/item/melee/sword/vibro/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
final_block_chance *= 2
- if(wielded || attack_type != PROJECTILE_ATTACK)
+ if(HAS_TRAIT(src, TRAIT_WIELDED) || attack_type != PROJECTILE_ATTACK)
if(prob(final_block_chance))
if(attack_type == PROJECTILE_ATTACK)
owner.visible_message("[owner] deflects [attack_text] with [src]!")
diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm
index 63e4ffc5e6c3..4b16ee60942d 100644
--- a/code/game/objects/items/plushes.dm
+++ b/code/game/objects/items/plushes.dm
@@ -38,7 +38,7 @@
. = ..()
if(should_squeak)
AddComponent(/datum/component/squeak, squeak_override)
- AddElement(/datum/element/bed_tuckable, 6, -5, 90)
+ AddElement(/datum/element/bed_tuckable, 6, -5, 90, FALSE, FALSE)
//have we decided if Pinocchio goes in the blue or pink aisle yet?
if(gender == NEUTER)
diff --git a/code/game/objects/items/stacks/sheets/recipes/recipes_metal.dm b/code/game/objects/items/stacks/sheets/recipes/recipes_metal.dm
index 6860f34be5c7..9819a941e5f8 100644
--- a/code/game/objects/items/stacks/sheets/recipes/recipes_metal.dm
+++ b/code/game/objects/items/stacks/sheets/recipes/recipes_metal.dm
@@ -1,9 +1,13 @@
GLOBAL_LIST_INIT(metal_recipes, list ( \
new/datum/stack_recipe("stool", /obj/structure/chair/stool, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("bar stool", /obj/structure/chair/stool/bar, one_per_turf = TRUE, on_floor = TRUE), \
- new/datum/stack_recipe("bed", /obj/structure/bed, 2, one_per_turf = TRUE, on_floor = TRUE), \
- new/datum/stack_recipe("double bed", /obj/structure/bed/double, 4, one_per_turf = TRUE, on_floor = TRUE), \
null, \
+ new/datum/stack_recipe_list("beds", list( \
+ new/datum/stack_recipe("bed", /obj/structure/bed, 2, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("double bed", /obj/structure/bed/double, 4, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("bottom bunk", /obj/structure/bed/bunk, 2, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("top bunk", /obj/structure/bed/bunk/top, 2, one_per_turf = TRUE, on_floor = TRUE), \
+ )), \
new/datum/stack_recipe_list("office chairs", list( \
new/datum/stack_recipe("gray office chair", /obj/structure/chair/office, 5, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("light office chair", /obj/structure/chair/office/light, 5, one_per_turf = TRUE, on_floor = TRUE), \
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 5653b641c99d..f34836de156f 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -305,7 +305,7 @@
if(!window_structure.fulltile)
continue
if(object.density)
- to_chat(usr, "There is \a [object.name] here. You cant make \a [recipe.title] here!")
+ to_chat(usr, "There is \a [object.name] here. You can't make \a [recipe.title] here!")
return FALSE
if(recipe.placement_checks)
switch(recipe.placement_checks)
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index c2679adf8ae9..52a6fdf8738e 100644
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -275,6 +275,7 @@
STR.set_holdable(list(
/obj/item/melee/baton,
/obj/item/melee/classic_baton,
+ /obj/item/melee/knife,
/obj/item/grenade,
/obj/item/reagent_containers/spray/pepper,
/obj/item/restraints/handcuffs,
@@ -367,7 +368,7 @@
/obj/item/storage/fancy/cigarettes,
/obj/item/reagent_containers/food/drinks/bottle,
/obj/item/stack/medical,
- /obj/item/melee/knife/kitchen,
+ /obj/item/melee/knife,
/obj/item/reagent_containers/hypospray,
/obj/item/gps,
/obj/item/storage/bag/ore,
diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm
index 422ff52b15b0..f918a3b883fb 100644
--- a/code/game/objects/items/storage/secure.dm
+++ b/code/game/objects/items/storage/secure.dm
@@ -173,7 +173,7 @@
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.set_holdable(null, list(/obj/item/storage/secure/briefcase))
- STR.max_w_class = 8 //??
+ STR.max_w_class = 8
/obj/item/storage/secure/safe/PopulateContents()
new /obj/item/paper(src)
diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm
index 50f709dcd65f..23fe0852c353 100644
--- a/code/game/objects/items/tanks/watertank.dm
+++ b/code/game/objects/items/tanks/watertank.dm
@@ -175,6 +175,39 @@
amount_per_transfer_from_this = (amount_per_transfer_from_this == 10 ? 5 : 10)
to_chat(user, "You [amount_per_transfer_from_this == 10 ? "remove" : "fix"] the nozzle. You'll now use [amount_per_transfer_from_this] units per spray.")
+//radiation cleanup pack
+
+/obj/item/watertank/anti_rad
+ name = "radiation foam pack"
+ desc = "A pressurized backpack tank with sprayer nozzle, intended to clean up radioactive hazards."
+ item_state = "waterbackpackatmos"
+ icon_state = "waterbackpackatmos"
+ volume = 200
+ slowdown = 0.3
+
+/obj/item/watertank/anti_rad/Initialize()
+ . = ..()
+ reagents.add_reagent(/datum/reagent/anti_radiation_foam, 200)
+
+
+/obj/item/reagent_containers/spray/mister/anti_rad
+ name = "spray nozzle"
+ desc = "A heavy duty nozzle attached to a radiation foam tank."
+ icon_state = "atmos_nozzle"
+ item_state = "nozzleatmos"
+ amount_per_transfer_from_this = 5
+ possible_transfer_amounts = list()
+ current_range = 6
+ spray_range = 6
+
+
+/obj/item/watertank/anti_rad/make_noz()
+ return new /obj/item/reagent_containers/spray/mister/anti_rad(src)
+
+/obj/item/reagent_containers/spray/mister/anti_rad/attack_self(mob/user)
+ amount_per_transfer_from_this = (amount_per_transfer_from_this == 10 ? 5 : 10)
+ to_chat(user, "You [amount_per_transfer_from_this == 10 ? "tigten" : "loosen"] the nozzle. You'll now use [amount_per_transfer_from_this] units per spray.")
+
//ATMOS FIRE FIGHTING BACKPACK
#define EXTINGUISHER 0
diff --git a/code/game/objects/structures/beds_chairs/alien_nest.dm b/code/game/objects/structures/beds_chairs/alien_nest.dm
index 4f132b11af99..ecc050aa8f77 100644
--- a/code/game/objects/structures/beds_chairs/alien_nest.dm
+++ b/code/game/objects/structures/beds_chairs/alien_nest.dm
@@ -14,6 +14,7 @@
buildstacktype = null
flags_1 = NODECONSTRUCT_1
bolts = FALSE
+ swap_lying_with_dir = FALSE
var/static/mutable_appearance/nest_overlay = mutable_appearance('icons/mob/alien.dmi', "nestoverlay", LYING_MOB_LAYER)
/obj/structure/bed/nest/user_unbuckle_mob(mob/living/buckled_mob, mob/living/user)
diff --git a/code/game/objects/structures/beds_chairs/bed.dm b/code/game/objects/structures/beds_chairs/bed.dm
index 6c5f46e94a3b..ec7132a67cdd 100644
--- a/code/game/objects/structures/beds_chairs/bed.dm
+++ b/code/game/objects/structures/beds_chairs/bed.dm
@@ -18,10 +18,44 @@
resistance_flags = FLAMMABLE
max_integrity = 100
integrity_failure = 0.35
+
var/buildstacktype = /obj/item/stack/sheet/metal
var/buildstackamount = 2
var/bolts = TRUE
+ /// Whether the bed changes its buckle_lying direction
+ /// (and accordingly the direction in which mobs lie down) based on its current direction.
+ var/swap_lying_with_dir = TRUE
+ /// If non-null, some items (bedsheets) which can be tucked into beds
+ /// will set their layer to this value when they are tucked in, until they are picked up again.
+ var/suggested_tuck_layer = null
+ /// The amount added to the pixel_x value of a tucked-in item.
+ var/tucked_x_shift = 0
+ /// The amount added to the pixel_y value of a tucked-in item.
+ var/tucked_y_shift = 0
+
+/obj/structure/bed/Initialize(...)
+ . = ..()
+ if(swap_lying_with_dir)
+ buckle_lying = get_buckle_angle_from_dir(dir)
+
+/obj/structure/bed/setDir(newdir)
+ . = ..()
+ if(swap_lying_with_dir)
+ buckle_lying = get_buckle_angle_from_dir(newdir)
+ // shuttle rotation etc... ugh.
+ if(has_buckled_mobs())
+ for(var/mob/living/M as anything in buckled_mobs)
+ // this proc already checks to see if the new angle is different from the old one,
+ // so this shouldn't cause any duplicate work or unnecessary animations.
+ M.set_lying_angle(buckle_lying)
+
+/obj/structure/bed/proc/get_buckle_angle_from_dir(some_dir)
+ if(some_dir & (SOUTH|WEST))
+ return 90
+ else
+ return 270
+
/obj/structure/bed/examine(mob/user)
. = ..()
if(bolts)
@@ -52,6 +86,9 @@
icon_state = "down"
anchored = FALSE
resistance_flags = NONE
+
+ // no dir states
+ swap_lying_with_dir = FALSE
var/foldabletype = /obj/item/roller
/obj/structure/bed/roller/attackby(obj/item/W, mob/user, params)
@@ -161,8 +198,9 @@
else
to_chat(user, "The dock is empty!")
-//Dog bed
-
+/*
+ * "Dog" beds
+ */
/obj/structure/bed/dogbed
name = "dog bed"
icon_state = "dogbed"
@@ -170,6 +208,9 @@
anchored = TRUE
buildstacktype = /obj/item/stack/sheet/mineral/wood
buildstackamount = 10
+
+ // no dir states
+ swap_lying_with_dir = FALSE
var/mob/living/owner = null
/obj/structure/bed/dogbed/ian
@@ -206,7 +247,9 @@
. = ..()
update_owner(M)
-//Double Beds, for luxurious sleeping, i.e. the captain and maybe heads - no quirky refrence here. Move along
+/*
+ * Double beds, for luxurious sleeping, i.e. the captain and maybe heads - no quirky refrence here. Move along
+ */
/obj/structure/bed/double
name = "double bed"
desc = "A luxurious double bed, for those too important for small dreams."
@@ -232,3 +275,84 @@
name = "double dirty mattress"
desc = "An old grubby king sized mattress. You really try to not think about what could be the cause of those stains."
icon_state = "dirty_mattress_double"
+
+/*
+ * Bunk beds. Comes with an /obj/effect spawner that lets mappers place them down easily.
+ * The base type is the bottom bunk, with the top bunk as a derived type.
+ * Like other beds, the pillow may be on the left or right depending on the direction.
+ */
+/obj/structure/bed/bunk
+ name = "bottom bunk"
+ desc = "The oft-maligned bottom bunk of a compact bunk bed. Heavy sleepers only."
+ icon_state = "bottom_bunk"
+ // just below the top bunk's main layer
+ suggested_tuck_layer = LYING_MOB_LAYER + 0.005
+ /// The amount added to the pixel_y value of mobs lying down, relative to the default shift for that position.
+ var/mob_y_shift = -1
+ // i think it looks best without shifting the bedsheet down, even though the mob gets shifted down some
+
+// alter their pixel offset when they lie down...
+/obj/structure/bed/bunk/post_buckle_mob(mob/living/M)
+ // we shift the lying mob a little so that they line up better with the pillow, but the shift direction changes
+ // depending on the direction they lie down in, controlled by buckle_lying
+ // (which is in turn based on our direction, but we don't need to worry about that directly)
+ var/horz_offset
+ if(buckle_lying == 90)
+ horz_offset = 2
+ else
+ horz_offset = -2
+
+ M.pixel_x = M.get_standard_pixel_x_offset(M.body_position == LYING_DOWN) + horz_offset
+ M.pixel_y = M.get_standard_pixel_y_offset(M.body_position == LYING_DOWN) + mob_y_shift
+
+// ...and reset it when they get off
+/obj/structure/bed/bunk/post_unbuckle_mob(mob/living/M)
+ M.pixel_x = M.get_standard_pixel_x_offset(M.body_position == LYING_DOWN)
+ M.pixel_y = M.get_standard_pixel_y_offset(M.body_position == LYING_DOWN)
+
+
+/obj/structure/bed/bunk/top
+ name = "top bunk"
+ desc = "The top bunk of a compact bunk bed. Few other sleeping accommodations can match its luxury."
+ icon_state = "top_bunk"
+
+ // higher layer, so that it renders on top of people on the bottom bunk
+ layer = LYING_MOB_LAYER + 0.01
+ mob_y_shift = 13
+
+ // above the lying mob, but below the ladder
+ suggested_tuck_layer = LYING_MOB_LAYER + 0.025
+ tucked_y_shift = 14
+
+/obj/structure/bed/bunk/top/Initialize(...)
+ . = ..()
+ // the ladder needs to render above the mob
+ overlays += image(icon = 'icons/obj/objects.dmi', icon_state = "top_bunk_ladder", layer = LYING_MOB_LAYER + 0.03)
+ // and the posts need to render below the bottom bunk
+ overlays += image(icon = 'icons/obj/objects.dmi', icon_state = "top_bunk_posts", layer = TABLE_LAYER)
+
+/obj/structure/bed/bunk/top/post_buckle_mob(mob/living/M)
+ . = ..()
+ M.layer = LYING_MOB_LAYER + 0.02
+
+/obj/structure/bed/bunk/top/post_unbuckle_mob(mob/living/M)
+ . = ..()
+ // honestly not really confident in this, but since standing up takes a do_after
+ // (and thus happens afterwards, resetting the layer), it should be fine...
+ // i'm more worried about altering layers via + and -, since if you figured out ways
+ // of stacking those you could layer yourself under, like, the floor.
+ M.layer = LYING_MOB_LAYER
+
+
+// the spawner
+/obj/effect/spawner/bunk_bed
+ name = "bunk bed spawner"
+ icon_state = "bunk_bed_spawner"
+
+/obj/effect/spawner/bunk_bed/Initialize(...)
+ . = ..()
+ var/obj/structure/bed/bunk/bottom_bunk = new(loc)
+ var/obj/structure/bed/bunk/top/top_bunk = new(loc)
+
+ bottom_bunk.setDir(dir)
+ top_bunk.setDir(dir)
diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm
index 1a89195c646a..31e9d9a0b8fc 100644
--- a/code/game/objects/structures/bedsheet_bin.dm
+++ b/code/game/objects/structures/bedsheet_bin.dm
@@ -28,7 +28,7 @@ LINEN BINS
/obj/item/bedsheet/Initialize(mapload)
. = ..()
- AddElement(/datum/element/bed_tuckable, 0, 0, 0)
+ AddElement(/datum/element/bed_tuckable, 0, 0, 0, TRUE, TRUE)
/obj/item/bedsheet/attack_self(mob/user)
if(!user.CanReach(src)) //No telekenetic grabbing.
diff --git a/code/game/objects/structures/cabinet.dm b/code/game/objects/structures/cabinet.dm
new file mode 100644
index 000000000000..bc89cf1d0bbe
--- /dev/null
+++ b/code/game/objects/structures/cabinet.dm
@@ -0,0 +1,214 @@
+/obj/structure/cabinet
+ name = "\improper cabinet"
+ desc = "There is a small label that reads \"For Emergency use only\". Yeah right."
+ icon = 'icons/obj/wallmounts.dmi'
+ icon_state = "fireaxe"
+ anchored = TRUE
+ density = FALSE
+ armor = list("melee" = 50, "bullet" = 20, "laser" = 0, "energy" = 100, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 50)
+ max_integrity = 150
+ integrity_failure = 0.33
+ req_one_access_txt = "0"
+ var/locked = TRUE
+ var/open = FALSE
+ var/start_empty = FALSE
+ var/obj/item/stored
+ var/allowed_type
+ var/stored_sprite = "axe"
+
+/obj/structure/cabinet/Initialize()
+ . = ..()
+ if(allowed_type && !start_empty)
+ stored = new allowed_type(src)
+ update_appearance()
+
+/obj/structure/cabinet/Destroy()
+ if(istype(stored))
+ qdel(stored)
+ stored = null
+ return ..()
+
+/obj/structure/cabinet/examine(mob/user)
+ . = ..()
+ if(!open)
+ . += span_notice("Alt-click to [locked ? "unlock" : "lock"] [src]")
+ if(stored)
+ . += span_notice("[stored] is sitting inside, ripe for the taking.")
+
+/obj/structure/cabinet/attackby(obj/item/I, mob/user, params)
+ if(iscyborg(user) || I.tool_behaviour == TOOL_MULTITOOL)
+ hack_lock(user)
+ else if(I.tool_behaviour == TOOL_WELDER && user.a_intent == INTENT_HELP && !broken)
+ if(obj_integrity < max_integrity)
+ if(!I.tool_start_check(user, amount=2))
+ return
+ to_chat(user, span_notice("You begin repairing [src]"))
+ if(I.use_tool(src, user, 40, volume=50, amount=2))
+ obj_integrity = max_integrity
+ update_appearance()
+ to_chat(user, span_notice("You repair [src]"))
+ else
+ to_chat(user, span_warning("[src] is already in good condition!"))
+ return
+ else if(istype(I, /obj/item/stack/sheet/glass) && broken)
+ var/obj/item/stack/sheet/glass/G = I
+ if(G.get_amount() < 2)
+ to_chat(user, span_warning("You need two [G.singular_name] to fix [src]!"))
+ return
+ to_chat(user, span_notice("You start fixing [src]..."))
+ if(do_after(user, 20, target = src) && G.use(2))
+ broken = 0
+ obj_integrity = max_integrity
+ update_appearance()
+ else if(open || broken)
+ if(istype(I, allowed_type) && !stored)
+ var/obj/item/storee = I
+ SIGNAL_HANDLER
+ if(storee && HAS_TRAIT(storee, TRAIT_WIELDED))
+ to_chat(user, span_warning("Unwield the [storee.name] first."))
+ return
+ if(!user.transferItemToLoc(I, src))
+ return
+ stored = storee
+ to_chat(user, span_notice("You place the [storee.name] back in the [name]."))
+ update_appearance()
+ return
+ else if(!broken)
+ toggle_open()
+ else
+ return ..()
+
+/obj/structure/cabinet/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
+ switch(damage_type)
+ if(BRUTE)
+ if(broken)
+ playsound(loc, 'sound/effects/hit_on_shattered_glass.ogg', 90, TRUE)
+ else
+ playsound(loc, 'sound/effects/glasshit.ogg', 90, TRUE)
+ if(BURN)
+ playsound(src.loc, 'sound/items/welder.ogg', 100, TRUE)
+
+/obj/structure/cabinet/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
+ if(open)
+ return
+ . = ..()
+ if(.)
+ update_appearance()
+
+/obj/structure/cabinet/obj_break(damage_flag)
+ if(!broken && !(flags_1 & NODECONSTRUCT_1))
+ update_appearance()
+ broken = TRUE
+ playsound(src, 'sound/effects/glassbr3.ogg', 100, TRUE)
+ new /obj/item/shard(loc)
+ new /obj/item/shard(loc)
+
+/obj/structure/cabinet/deconstruct(disassembled = TRUE)
+ if(!(flags_1 & NODECONSTRUCT_1))
+ if(stored && loc)
+ stored.forceMove(loc)
+ stored = null
+ new /obj/item/stack/sheet/metal(loc, 2)
+ qdel(src)
+
+/obj/structure/cabinet/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
+ if(open || broken)
+ if(stored)
+ to_chat(user, span_notice("You take [stored] from [name]."))
+ user.put_in_hands(stored)
+ stored = null
+ src.add_fingerprint(user)
+ update_appearance()
+ return
+ if(locked)
+ to_chat(user, span_warning("[name] won't budge!"))
+ return
+ else
+ open = !open
+ update_appearance()
+ return
+
+/obj/structure/cabinet/attack_paw(mob/living/user)
+ return attack_hand(user)
+
+/obj/structure/cabinet/attack_ai(mob/user)
+ toggle_lock(user)
+ return
+
+/obj/structure/cabinet/attack_tk(mob/user)
+ if(locked)
+ to_chat(user, span_warning("[name] won't budge!"))
+ return
+ else
+ open = !open
+ update_appearance()
+ return
+
+/obj/structure/cabinet/update_overlays()
+ . = ..()
+ if(stored)
+ . += "[stored_sprite]"
+ if(open)
+ . += "glass_raised"
+ return
+ var/hp_percent = obj_integrity/max_integrity * 100
+ if(broken)
+ . += "glass4"
+ else
+ switch(hp_percent)
+ if(-INFINITY to 40)
+ . += "glass3"
+ if(40 to 60)
+ . += "glass2"
+ if(60 to 80)
+ . += "glass1"
+ if(80 to INFINITY)
+ . += "glass"
+
+ . += locked ? "locked" : "unlocked"
+
+/obj/structure/cabinet/proc/toggle_lock(mob/user)
+ if(!broken)
+ if(allowed(user))
+ if(iscarbon(user))
+ add_fingerprint(user)
+ locked = !locked
+ user.visible_message(
+ span_notice("[user] [locked ? "locks" : "unlocks"][src]."),
+ span_notice("You [locked ? "lock" : "unlock"] [src]."))
+ update_appearance()
+ else
+ to_chat(user, span_warning("Access denied!"))
+ else if(broken)
+ to_chat(user, span_warning("\The [src] is broken!"))
+
+/obj/structure/cabinet/AltClick(mob/user)
+ ..()
+ if(!user.canUseTopic(src, BE_CLOSE) || !isturf(loc) || open)
+ return
+ else
+ toggle_lock(user)
+
+/obj/structure/cabinet/proc/hack_lock(mob/user)
+ to_chat(user, span_notice("Resetting circuitry..."))
+ playsound(src, 'sound/machines/locktoggle.ogg', 50, TRUE)
+ if(do_after(user, 20, target = src))
+ to_chat(user, span_notice("You [locked ? "disable" : "re-enable"] the locking modules."))
+ locked = !locked
+ update_appearance()
+
+/obj/structure/cabinet/verb/toggle_open()
+ set name = "Open/Close"
+ set category = "Object"
+ set src in oview(1)
+
+ if(locked)
+ visible_message(span_warning("[name] won't budge!"))
+ return
+ else
+ open = !open
+ update_appearance()
+ return
diff --git a/code/game/objects/structures/cabinet_types.dm b/code/game/objects/structures/cabinet_types.dm
new file mode 100644
index 000000000000..347e1954ded4
--- /dev/null
+++ b/code/game/objects/structures/cabinet_types.dm
@@ -0,0 +1,10 @@
+/obj/structure/cabinet/fireaxe
+ name = "\improper fire axe cabinet"
+ desc = "There is a small label that reads \"For Emergency use only\" along with details for safe use of the axe. As if."
+ icon = 'icons/obj/wallmounts.dmi'
+ icon_state = "fireaxe"
+ anchored = TRUE
+ density = FALSE
+ stored_sprite = "axe"
+ allowed_type = /obj/item/melee/axe/fire
+ req_one_access_txt = "24"
diff --git a/code/game/objects/structures/fireaxe.dm b/code/game/objects/structures/fireaxe.dm
deleted file mode 100644
index a164248a2bdd..000000000000
--- a/code/game/objects/structures/fireaxe.dm
+++ /dev/null
@@ -1,179 +0,0 @@
-/obj/structure/fireaxecabinet
- name = "fire axe cabinet"
- desc = "There is a small label that reads \"For Emergency use only\" along with details for safe use of the axe. As if."
- icon = 'icons/obj/wallmounts.dmi'
- icon_state = "fireaxe"
- anchored = TRUE
- density = FALSE
- armor = list("melee" = 50, "bullet" = 20, "laser" = 0, "energy" = 100, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 50)
- max_integrity = 150
- integrity_failure = 0.33
- var/locked = TRUE
- var/open = FALSE
- var/obj/item/melee/axe/fire/fireaxe
-
-/obj/structure/fireaxecabinet/Initialize()
- . = ..()
- fireaxe = new
- update_appearance()
-
-/obj/structure/fireaxecabinet/Destroy()
- if(fireaxe)
- QDEL_NULL(fireaxe)
- return ..()
-
-/obj/structure/fireaxecabinet/attackby(obj/item/I, mob/user, params)
- if(iscyborg(user) || I.tool_behaviour == TOOL_MULTITOOL)
- toggle_lock(user)
- else if(I.tool_behaviour == TOOL_WELDER && user.a_intent == INTENT_HELP && !broken)
- if(obj_integrity < max_integrity)
- if(!I.tool_start_check(user, amount=2))
- return
-
- to_chat(user, "You begin repairing [src].")
- if(I.use_tool(src, user, 40, volume=50, amount=2))
- obj_integrity = max_integrity
- update_appearance()
- to_chat(user, "You repair [src].")
- else
- to_chat(user, "[src] is already in good condition!")
- return
- else if(istype(I, /obj/item/stack/sheet/glass) && broken)
- var/obj/item/stack/sheet/glass/G = I
- if(G.get_amount() < 2)
- to_chat(user, "You need two glass sheets to fix [src]!")
- return
- to_chat(user, "You start fixing [src]...")
- if(do_after(user, 20, target = src) && G.use(2))
- broken = 0
- obj_integrity = max_integrity
- update_appearance()
- else if(open || broken)
- if(istype(I, /obj/item/melee/axe/fire) && !fireaxe)
- var/obj/item/melee/axe/fire/F = I
- if(F && F.wielded)
- to_chat(user, "Unwield the [F.name] first.")
- return
- if(!user.transferItemToLoc(F, src))
- return
- fireaxe = F
- to_chat(user, "You place the [F.name] back in the [name].")
- update_appearance()
- return
- else if(!broken)
- toggle_open()
- else
- return ..()
-
-/obj/structure/fireaxecabinet/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
- switch(damage_type)
- if(BRUTE)
- if(broken)
- playsound(loc, 'sound/effects/hit_on_shattered_glass.ogg', 90, TRUE)
- else
- playsound(loc, 'sound/effects/glasshit.ogg', 90, TRUE)
- if(BURN)
- playsound(src.loc, 'sound/items/welder.ogg', 100, TRUE)
-
-/obj/structure/fireaxecabinet/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
- if(open)
- return
- . = ..()
- if(.)
- update_appearance()
-
-/obj/structure/fireaxecabinet/obj_break(damage_flag)
- if(!broken && !(flags_1 & NODECONSTRUCT_1))
- update_appearance()
- broken = TRUE
- playsound(src, 'sound/effects/glassbr3.ogg', 100, TRUE)
- new /obj/item/shard(loc)
- new /obj/item/shard(loc)
-
-/obj/structure/fireaxecabinet/deconstruct(disassembled = TRUE)
- if(!(flags_1 & NODECONSTRUCT_1))
- if(fireaxe && loc)
- fireaxe.forceMove(loc)
- fireaxe = null
- new /obj/item/stack/sheet/metal(loc, 2)
- qdel(src)
-
-/obj/structure/fireaxecabinet/attack_hand(mob/user)
- . = ..()
- if(.)
- return
- if(open || broken)
- if(fireaxe)
- user.put_in_hands(fireaxe)
- fireaxe = null
- to_chat(user, "You take the fire axe from the [name].")
- src.add_fingerprint(user)
- update_appearance()
- return
- if(locked)
- to_chat(user, "The [name] won't budge!")
- return
- else
- open = !open
- update_appearance()
- return
-
-/obj/structure/fireaxecabinet/attack_paw(mob/living/user)
- return attack_hand(user)
-
-/obj/structure/fireaxecabinet/attack_ai(mob/user)
- toggle_lock(user)
- return
-
-/obj/structure/fireaxecabinet/attack_tk(mob/user)
- if(locked)
- to_chat(user, "The [name] won't budge!")
- return
- else
- open = !open
- update_appearance()
- return
-
-/obj/structure/fireaxecabinet/update_overlays()
- . = ..()
- if(fireaxe)
- . += "axe"
- if(open)
- . += "glass_raised"
- return
- var/hp_percent = obj_integrity/max_integrity * 100
- if(broken)
- . += "glass4"
- else
- switch(hp_percent)
- if(-INFINITY to 40)
- . += "glass3"
- if(40 to 60)
- . += "glass2"
- if(60 to 80)
- . += "glass1"
- if(80 to INFINITY)
- . += "glass"
-
- . += locked ? "locked" : "unlocked"
-
-/obj/structure/fireaxecabinet/proc/toggle_lock(mob/user)
- to_chat(user, "Resetting circuitry...")
- playsound(src, 'sound/machines/locktoggle.ogg', 50, TRUE)
- if(do_after(user, 20, target = src))
- to_chat(user, "You [locked ? "disable" : "re-enable"] the locking modules.")
- locked = !locked
- update_appearance()
-
-/obj/structure/fireaxecabinet/verb/toggle_open()
- set name = "Open/Close"
- set category = "Object"
- set src in oview(1)
-
- if(locked)
- to_chat(usr, "The [name] won't budge!")
- return
- else
- open = !open
- update_appearance()
- return
diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm
index 1be5f857e155..c0604dd5e09b 100644
--- a/code/game/objects/structures/tank_dispenser.dm
+++ b/code/game/objects/structures/tank_dispenser.dm
@@ -28,10 +28,10 @@
/obj/structure/tank_dispenser/update_overlays()
. = ..()
switch(oxygentanks)
- if(1 to 3)
+ if(1 to 4)
. += "oxygen-[oxygentanks]"
- if(4 to TANK_DISPENSER_CAPACITY)
- . += "oxygen-4"
+ if(5 to TANK_DISPENSER_CAPACITY)
+ . += "oxygen-5"
switch(plasmatanks)
if(1 to 4)
. += "plasma-[plasmatanks]"
diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
index 5bce8014babe..abc69300c9c6 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
@@ -761,6 +761,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
icon = 'icons/obj/abductor.dmi'
buildstacktype = /obj/item/stack/sheet/mineral/abductor
icon_state = "bed"
+ swap_lying_with_dir = FALSE
/obj/structure/table_frame/abductor
name = "alien table frame"
diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
index 9c65e50130cf..c073a7c3521c 100644
--- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
+++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
@@ -608,7 +608,7 @@ This is here to make the tiles around the station mininuke change when it's arme
/obj/item/disk/nuclear/Initialize()
. = ..()
- AddElement(/datum/element/bed_tuckable, 6, -6, 0)
+ AddElement(/datum/element/bed_tuckable, 6, -6, 0, FALSE, FALSE)
if(!fake)
SSpoints_of_interest.make_point_of_interest(src)
diff --git a/code/modules/cargo/packs/tools.dm b/code/modules/cargo/packs/tools.dm
index 25ed4aaab554..e4081a448e0b 100644
--- a/code/modules/cargo/packs/tools.dm
+++ b/code/modules/cargo/packs/tools.dm
@@ -146,3 +146,14 @@
contains = list(/obj/structure/reagent_dispensers/foamtank)
crate_name = "foam tank crate"
crate_type = /obj/structure/closet/crate/large
+
+/datum/supply_pack/tools/radfoamtank
+ name = "Radiation Foam Tank Crate"
+ desc = "Contains a tank of anti-radiation foam. Pressurized sprayer included!"
+ cost = 1500
+ contains = list(
+ /obj/item/watertank/anti_rad,
+ /obj/structure/reagent_dispensers/foamtank/antirad
+ )
+ crate_name = "foam tank crate"
+ crate_type = /obj/structure/closet/crate/large
diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm
index 69c15b1e3494..8f8e532577c0 100644
--- a/code/modules/flufftext/Hallucination.dm
+++ b/code/modules/flufftext/Hallucination.dm
@@ -29,7 +29,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
if(!hallucination)
return
- hallucination--
+ hallucination = max(hallucination - 1, 0)
if(world.time < next_hallucination)
return
diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm
index 3e0bed238bec..05e81421ac4f 100644
--- a/code/modules/mining/equipment/kinetic_crusher.dm
+++ b/code/modules/mining/equipment/kinetic_crusher.dm
@@ -8,7 +8,7 @@
name = "proto-magnetic crusher"
desc = "A multipurpose disembarkation and self-defense tool designed by EXOCOM using an incomplete Nanotrasen prototype. \
Found in the grime-stained hands of wannabee explorers across the frontier, it cuts rock and hews flora using magnetic osscilation and a heavy cleaving edge."
- force = 0 //You can't hit stuff unless wielded
+ force = 0 //You can't hit stuff unless it's wielded
w_class = WEIGHT_CLASS_BULKY
slot_flags = ITEM_SLOT_BACK
throwforce = 5
@@ -28,33 +28,19 @@
var/charge_time = 15
var/detonation_damage = 20
var/backstab_bonus = 10
- var/wielded = FALSE // track wielded status on item
-
-/obj/item/kinetic_crusher/Initialize()
- . = ..()
- RegisterSignal(src, COMSIG_TWOHANDED_WIELD, PROC_REF(on_wield))
- RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, PROC_REF(on_unwield))
/obj/item/kinetic_crusher/ComponentInitialize()
. = ..()
AddComponent(/datum/component/butchering, 60, 110) //technically it's huge and bulky, but this provides an incentive to use it
AddComponent(/datum/component/two_handed, force_unwielded=0, force_wielded=15)
-/// triggered on wield of two handed item
-/obj/item/kinetic_crusher/proc/on_wield(obj/item/source, mob/user)
- wielded = TRUE
-
-/// triggered on unwield of two handed item
-/obj/item/kinetic_crusher/proc/on_unwield(obj/item/source, mob/user)
- wielded = FALSE
-
/obj/item/kinetic_crusher/examine(mob/living/user)
. = ..()
. += "Induce magnetism in an enemy by striking them with a magnetospheric wave, then hit them in melee to force a waveform collapse for [force + detonation_damage] damage."
. += "Does [force + detonation_damage + backstab_bonus] damage if the target is backstabbed, instead of [force + detonation_damage]."
/obj/item/kinetic_crusher/attack(mob/living/target, mob/living/carbon/user)
- if(!wielded)
+ if(!HAS_TRAIT(src, TRAIT_WIELDED))
to_chat(user, "[src] is too heavy to use with one hand! You fumble and drop everything.")
user.drop_all_held_items()
return
@@ -66,7 +52,7 @@
/obj/item/kinetic_crusher/afterattack(atom/target, mob/living/user, proximity_flag, clickparams)
. = ..()
- if(!wielded)
+ if(!HAS_TRAIT(src, TRAIT_WIELDED))
return
if(!proximity_flag && charged)//Mark a target, or mine a tile.
var/turf/proj_turf = user.loc
@@ -118,7 +104,7 @@
/obj/item/kinetic_crusher/update_icon_state()
- item_state = "crusher[wielded]" // this is not icon_state and not supported by 2hcomponent
+ item_state = "crusher[HAS_TRAIT(src, TRAIT_WIELDED)]" // this is not icon_state and not supported by 2hcomponent
return ..()
/obj/item/kinetic_crusher/update_overlays()
@@ -182,7 +168,7 @@
user.changeNext_move(CLICK_CD_MELEE * 2.0)//...slow swinga.
/obj/item/kinetic_crusher/old/update_icon_state()
- item_state = "crusherold[wielded]" // still not supported by 2hcomponent
+ item_state = "crusherold[HAS_TRAIT(src, TRAIT_WIELDED)]" // still not supported by 2hcomponent
return ..()
//100% original syndicate oc, plz do not steal. More effective against human targets then the typical crusher, with a bit of block chance.
@@ -195,7 +181,7 @@
name = "magnetic cleaver"
desc = "Designed by Syndicate Research and Development for their resource-gathering operations on hostile worlds. Syndicate Legal Ops would like to stress that you've never seen anything like this before. Ever."
armour_penetration = 69//nice cut
- force = 0 //You can't hit stuff unless wielded
+ force = 0 //You can't hit stuff unless HAS_TRAIT(src, TRAIT_WIELDED)
w_class = WEIGHT_CLASS_BULKY
slot_flags = ITEM_SLOT_BACK
throwforce = 5
@@ -216,35 +202,40 @@
charge_time = 15
detonation_damage = 35
backstab_bonus = 15
- wielded = FALSE // track wielded status on item
actions_types = list()
+
+/obj/item/kinetic_crusher/syndie_crusher/Initialize()
+ . = ..()
+ RegisterSignal(src, COMSIG_TWOHANDED_WIELD, PROC_REF(on_wield))
+ RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, PROC_REF(on_unwield))
+
/obj/item/kinetic_crusher/syndie_crusher/ComponentInitialize()
. = ..()
AddComponent(/datum/component/butchering, 60, 150)
AddComponent(/datum/component/two_handed, force_unwielded=0, force_wielded=10)
/// triggered on wield of two handed item
-/obj/item/kinetic_crusher/syndie_crusher/on_wield(obj/item/source, mob/user)
- . = ..()
- wielded = TRUE
+/obj/item/kinetic_crusher/syndie_crusher/proc/on_wield(obj/item/source, mob/user)
+ SIGNAL_HANDLER
+
icon_state = "crushersyndie1"
playsound(user, 'sound/weapons/saberon.ogg', 35, TRUE)
- set_light_on(wielded)
+ set_light_on(HAS_TRAIT(src, TRAIT_WIELDED))
/// triggered on unwield of two handed item
-/obj/item/kinetic_crusher/syndie_crusher/on_unwield(obj/item/source, mob/user)
- . = ..()
- wielded = FALSE
+/obj/item/kinetic_crusher/syndie_crusher/proc/on_unwield(obj/item/source, mob/user)
+ SIGNAL_HANDLER
+
icon_state = "crushersyndie"
playsound(user, 'sound/weapons/saberoff.ogg', 35, TRUE)
- set_light_on(wielded)
+ set_light_on(HAS_TRAIT(src, TRAIT_WIELDED))
/obj/item/kinetic_crusher/syndie_crusher/update_icon_state()
- item_state = "crushersyndie[wielded]" // this is not icon_state and not supported by 2hcomponent
+ item_state = "crushersyndie[HAS_TRAIT(src, TRAIT_WIELDED)]" // this is not icon_state and not supported by 2hcomponent
return ..()
/obj/item/kinetic_crusher/syndie_crusher/update_overlays()
. = ..()
- if(wielded)
+ if(HAS_TRAIT(src, TRAIT_WIELDED))
. += "[icon_state]_lit"
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 3ed2b86816ac..9a19e198a555 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -386,7 +386,7 @@
/mob/living/carbon/get_standard_pixel_y_offset(lying = 0)
if(lying)
- return -6
+ return PIXEL_Y_OFFSET_LYING
else
return initial(pixel_y)
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 94cc4f6f1e38..7fe0a5b07c3a 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -364,9 +364,6 @@
wielded_fully = TRUE
return TRUE
-/obj/item/gun/proc/is_wielded()
- return wielded
-
/// triggered on unwield of two handed item
/obj/item/gun/proc/on_unwield(obj/item/source, mob/user)
wielded = FALSE
@@ -374,6 +371,9 @@
zoom(user, forced_zoom = FALSE)
user.remove_movespeed_modifier(/datum/movespeed_modifier/gun)
+/obj/item/gun/proc/is_wielded()
+ return wielded
+
/obj/item/gun/Destroy()
if(chambered) //Not all guns are chambered (EMP'ed energy guns etc)
QDEL_NULL(chambered)
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 11306b441f1e..e0d4e2a86606 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -2526,3 +2526,38 @@
description = "Bacteria native to the Saint-Roumain Militia home planet."
color = "#5a4f42"
taste_description = "sour"
+
+//anti rad foam
+/datum/reagent/anti_radiation_foam
+ name = "Anti-Radiation Foam"
+ description = "A tried and tested foam, used for decontaminating nuclear disasters."
+ reagent_state = LIQUID
+ color = "#A6FAFF55"
+ taste_description = "bitter, foamy awfulness."
+
+/datum/reagent/anti_radiation_foam/expose_turf(turf/open/T, reac_volume)
+ if (!istype(T))
+ return
+
+ if(reac_volume >= 1)
+ var/obj/effect/particle_effect/foam/antirad/F = (locate(/obj/effect/particle_effect/foam/antirad) in T)
+ if(!F)
+ F = new(T)
+ else if(istype(F))
+ F.lifetime = initial(F.lifetime) //the foam is what does the cleaning here
+
+/datum/reagent/anti_radiation_foam/expose_obj(obj/O, reac_volume)
+ O.wash(CLEAN_RAD)
+
+/datum/reagent/anti_radiation_foam/expose_mob(mob/living/M, method=TOUCH, reac_volume)
+ if(method in list(TOUCH, VAPOR))
+ M.radiation = M.radiation - rand(max(M.radiation * 0.95, M.radiation)) //get the hose
+ M.ExtinguishMob()
+ ..()
+
+
+/datum/reagent/anti_radiation_foam/on_mob_life(mob/living/carbon/M)
+ M.adjustToxLoss(0.5, 200)
+ M.adjust_disgust(4)
+ ..()
+ . = 1
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index fafd67305c9c..54d2fc182398 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -58,6 +58,12 @@
reagent_id = /datum/reagent/firefighting_foam
tank_volume = 500
+/obj/structure/reagent_dispensers/foamtank/antirad
+ name = "anti-radiation foam tank"
+ desc = "A tank full of decontamination foam"
+ reagent_id = /datum/reagent/anti_radiation_foam
+ tank_volume = 1000
+
/obj/structure/reagent_dispensers/fueltank
name = "fuel tank"
desc = "A tank full of industrial welding fuel. Do not consume."
diff --git a/html/changelogs/AutoChangeLog-pr-3136.yml b/html/changelogs/AutoChangeLog-pr-3136.yml
deleted file mode 100644
index 1c06ebef6c3e..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3136.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: Thera-Pissed
-changes:
- - {rscadd: 'New wasteplanet ruin, the abandoned Miskilamo shipbreaking yard!'}
-delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3345.yml b/html/changelogs/AutoChangeLog-pr-3345.yml
new file mode 100644
index 000000000000..3da650007188
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3345.yml
@@ -0,0 +1,6 @@
+author: tmtmtl30, Thgvr
+changes:
+ - {rscadd: 'Added bunkbeds, which can now be crafted with metal or placed by mappers.'}
+ - {bugfix: Beds facing alternate directions now correctly support people buckling
+ to them and bedsheets being placed on top of them.}
+delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3350.yml b/html/changelogs/AutoChangeLog-pr-3350.yml
deleted file mode 100644
index 8869478b429b..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3350.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: FalloutFalcon
-changes:
- - {bugfix: condiment packs are no longer invisible and missing names}
-delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3364.yml b/html/changelogs/AutoChangeLog-pr-3364.yml
deleted file mode 100644
index 7c6b1f04c8a7..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3364.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: MassiveMen
-changes:
- - {rscadd: Added the fire axe to the black market uplink}
-delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3422.yml b/html/changelogs/AutoChangeLog-pr-3422.yml
deleted file mode 100644
index 6bb9c3e4e60d..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3422.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: Bjarl
-changes:
- - {rscdel: The Elephant Graveyard ruin has been taken out back}
-delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3428.yml b/html/changelogs/AutoChangeLog-pr-3428.yml
deleted file mode 100644
index ecad99d43c1d..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3428.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: FalloutFalcon
-changes:
- - {bugfix: sawnoff weapons made from init now function correctly}
-delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3454.yml b/html/changelogs/AutoChangeLog-pr-3454.yml
deleted file mode 100644
index 9e1b731951c9..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3454.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: Bjarl
-changes:
- - {bugfix: m90 posters are real again}
-delete-after: true
diff --git a/html/changelogs/archive/2024-09.yml b/html/changelogs/archive/2024-09.yml
index 0beabb6bcc8b..52b3cbfbf679 100644
--- a/html/changelogs/archive/2024-09.yml
+++ b/html/changelogs/archive/2024-09.yml
@@ -207,3 +207,14 @@
2024-09-29:
fighterslam:
- balance: Modernizes and slightly buffs the Ranger.
+2024-09-30:
+ Bjarl:
+ - rscdel: The Elephant Graveyard ruin has been taken out back
+ - bugfix: m90 posters are real again
+ FalloutFalcon:
+ - bugfix: sawnoff weapons made from init now function correctly
+ - bugfix: condiment packs are no longer invisible and missing names
+ MassiveMen:
+ - rscadd: Added the fire axe to the black market uplink
+ Thera-Pissed:
+ - rscadd: New wasteplanet ruin, the abandoned Miskilamo shipbreaking yard!
diff --git a/html/changelogs/archive/2024-10.yml b/html/changelogs/archive/2024-10.yml
new file mode 100644
index 000000000000..546d4d7ab402
--- /dev/null
+++ b/html/changelogs/archive/2024-10.yml
@@ -0,0 +1,10 @@
+2024-10-01:
+ Erika Fox:
+ - rscadd: Anti-Radiation Foam is now available at the outpost
+ - code_imp: Fireaxe cabinets have been repathed, and now function as a more general
+ cabinet object. please report any inconsistencies with behavior
+ Sadhorizon:
+ - tweak: You can now put knives in secbelts and the subtypes of secbelts.
+ - bugfix: You can now fit all knives in mining webbings.
+ SomeguyManperson:
+ - bugfix: hallucinations can no longer be permanent unless treated
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 0aa256c631e4..bb63eb2b7f0e 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/obj/objects.dmi b/icons/obj/objects.dmi
index 1b156b9294f9..8479c100f1b0 100644
Binary files a/icons/obj/objects.dmi and b/icons/obj/objects.dmi differ
diff --git a/shiptest.dme b/shiptest.dme
index 0bff452a9161..53b8c061b5fa 100644
--- a/shiptest.dme
+++ b/shiptest.dme
@@ -1387,6 +1387,8 @@
#include "code\game\objects\structures\artstuff.dm"
#include "code\game\objects\structures\barsigns.dm"
#include "code\game\objects\structures\bedsheet_bin.dm"
+#include "code\game\objects\structures\cabinet.dm"
+#include "code\game\objects\structures\cabinet_types.dm"
#include "code\game\objects\structures\catwalk.dm"
#include "code\game\objects\structures\crateshelf.dm"
#include "code\game\objects\structures\curtains.dm"
@@ -1400,7 +1402,6 @@
#include "code\game\objects\structures\extinguisher.dm"
#include "code\game\objects\structures\false_walls.dm"
#include "code\game\objects\structures\fence.dm"
-#include "code\game\objects\structures\fireaxe.dm"
#include "code\game\objects\structures\fireplace.dm"
#include "code\game\objects\structures\flora.dm"
#include "code\game\objects\structures\fluff.dm"