diff --git a/_maps/RandomRuins/SpaceRuins/bus.dmm b/_maps/RandomRuins/SpaceRuins/bus.dmm
index bb0156a4b7e52..1cd3d0f7ec261 100644
--- a/_maps/RandomRuins/SpaceRuins/bus.dmm
+++ b/_maps/RandomRuins/SpaceRuins/bus.dmm
@@ -19,7 +19,8 @@
"an" = (
/obj/structure/fluff/bus/passable/seat,
/obj/item/toy/plush/pkplush{
- pixel_z = 17
+ pixel_z = 17;
+ anchored = 1
},
/turf/open/floor/iron/dark/airless{
icon_state = "bus"
@@ -39,7 +40,8 @@
pixel_y = 15
},
/obj/item/toy/plush/lizard_plushie/green{
- pixel_z = 17
+ pixel_z = 17;
+ anchored = 1
},
/turf/open/floor/iron/dark/airless{
icon_state = "bus"
@@ -49,7 +51,8 @@
/obj/structure/fluff/bus/passable/seat,
/obj/effect/decal/cleanable/dirt,
/obj/item/clothing/head/helmet/knight{
- pixel_z = 16
+ pixel_z = 16;
+ anchored = 1
},
/turf/open/floor/iron/dark/airless{
icon_state = "bus"
@@ -60,11 +63,13 @@
/obj/item/grown/novaflower{
offset_at_init = 0;
pixel_z = 24;
- pixel_y = 1
+ pixel_y = 1;
+ anchored = 1
},
/obj/item/food/grown/watermelon{
offset_at_init = 0;
- pixel_z = 17
+ pixel_z = 17;
+ anchored = 1
},
/turf/open/floor/iron/dark/airless{
icon_state = "bus"
@@ -75,15 +80,18 @@
/obj/effect/decal/cleanable/dirt,
/obj/item/toy/plush/moth{
pixel_z = 26;
- pixel_y = 2
+ pixel_y = 2;
+ anchored = 1
},
/obj/item/food/grown/citrus/orange{
offset_at_init = 0;
pixel_z = 18;
- pixel_y = 1
+ pixel_y = 1;
+ anchored = 1
},
/obj/item/toy/talking/ai{
- pixel_z = 16
+ pixel_z = 16;
+ anchored = 1
},
/turf/open/floor/iron/dark/airless{
icon_state = "bus"
@@ -149,10 +157,12 @@
/obj/item/bodypart/arm/right{
pixel_z = 25;
pixel_y = 1;
- pixel_x = -4
+ pixel_x = -4;
+ anchored = 1
},
/obj/item/food/meat/slab/penguin{
- pixel_z = 13
+ pixel_z = 13;
+ anchored = 1
},
/turf/open/floor/iron/dark/airless{
icon_state = "bus"
@@ -188,12 +198,14 @@
/obj/item/food/grown/tomato{
offset_at_init = 0;
pixel_z = 23;
- pixel_y = 2
+ pixel_y = 2;
+ anchored = 1
},
/obj/item/food/donut/plain{
pixel_z = 15;
pixel_y = 1;
- pixel_x = 1
+ pixel_x = 1;
+ anchored = 1
},
/obj/effect/decal/cleanable/ants{
pixel_z = 8;
@@ -291,7 +303,8 @@
/obj/effect/decal/cleanable/dirt,
/obj/item/toy/plush/awakenedplushie{
pixel_z = 26;
- pixel_y = 1
+ pixel_y = 1;
+ anchored = 1
},
/obj/machinery/telecomms/server{
pixel_z = 12;
@@ -384,11 +397,13 @@
/obj/item/toy/singlecard{
pixel_z = 24;
pixel_y = 1;
- pixel_x = 0
+ pixel_x = 0;
+ anchored = 1
},
/obj/item/food/grown/potato{
offset_at_init = 0;
- pixel_z = 15
+ pixel_z = 15;
+ anchored = 1
},
/turf/open/floor/iron/dark/airless{
icon_state = "bus"
diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm
index 3b567283936bd..e26e63400333f 100644
--- a/_maps/map_files/Birdshot/birdshot.dmm
+++ b/_maps/map_files/Birdshot/birdshot.dmm
@@ -22386,6 +22386,12 @@
},
/turf/open/floor/engine/co2,
/area/station/engineering/atmos/space_catwalk)
+"izw" = (
+/obj/machinery/transport/tram_controller/tcomms{
+ configured_transport_id = "bird_2"
+ },
+/turf/open/floor/circuit,
+/area/station/tcommsat/server)
"izB" = (
/obj/effect/turf_decal/tile/neutral/fourcorners,
/obj/structure/sign/painting/library{
@@ -40716,6 +40722,7 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/structure/disposalpipe/segment,
+/obj/effect/mapping_helpers/airlock/access/any/engineering/general,
/turf/open/floor/catwalk_floor,
/area/station/engineering/break_room)
"oJn" = (
@@ -54321,13 +54328,14 @@
/turf/open/floor/iron,
/area/station/hallway/primary/aft)
"sKD" = (
-/obj/machinery/door/airlock/engineering{
- name = "Engine Airlock"
- },
/obj/machinery/door/firedoor,
/obj/effect/mapping_helpers/airlock/access/any/engineering/construction,
/obj/structure/cable,
/obj/effect/landmark/navigate_destination,
+/obj/effect/mapping_helpers/airlock/access/any/engineering/general,
+/obj/machinery/door/airlock/engineering{
+ name = "Main Engineering"
+ },
/turf/open/floor/catwalk_floor,
/area/station/engineering/break_room)
"sKE" = (
@@ -58360,8 +58368,10 @@
/turf/open/floor/iron/dark,
/area/station/medical/pharmacy)
"tUD" = (
-/obj/effect/spawner/structure/window/reinforced,
-/turf/open/floor/plating,
+/obj/machinery/transport/tram_controller/tcomms{
+ configured_transport_id = "bird_1"
+ },
+/turf/open/floor/circuit,
/area/station/tcommsat/server)
"tUH" = (
/obj/structure/disposalpipe/segment,
@@ -121802,7 +121812,7 @@ wos
udv
tSq
mvo
-tUD
+izw
bFw
ulK
cdn
diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm
index 229fd20cbcc5b..a1da07d798773 100644
--- a/_maps/map_files/tramstation/tramstation.dmm
+++ b/_maps/map_files/tramstation/tramstation.dmm
@@ -6765,7 +6765,10 @@
dir = 8
},
/obj/item/radio/intercom/directional/west,
-/obj/item/paper/fluff/jobs/engineering/frequencies,
+/obj/item/toy/plush/lizard_plushie/green{
+ name = "Runs-The-Rails";
+ desc = "An adorable, hard working lizard that runs in circles to keep the tram operating safely."
+ },
/turf/open/floor/iron,
/area/station/tcommsat/computer)
"boc" = (
@@ -26721,6 +26724,7 @@
},
/obj/item/folder/blue,
/obj/item/pen/blue,
+/obj/item/paper/fluff/jobs/engineering/frequencies,
/turf/open/floor/iron,
/area/station/tcommsat/computer)
"iDQ" = (
@@ -61751,6 +61755,10 @@
"uGW" = (
/turf/closed/wall,
/area/station/cargo/miningdock)
+"uGX" = (
+/obj/machinery/transport/tram_controller/tcomms,
+/turf/open/floor/iron/dark/telecomms,
+/area/station/tcommsat/server)
"uHb" = (
/obj/machinery/airalarm/directional/north,
/obj/machinery/photocopier,
@@ -98247,7 +98255,7 @@ dwR
ngp
dwR
dwR
-cXL
+ney
ney
sMr
sMr
@@ -98505,7 +98513,7 @@ gga
rBW
ffN
sMr
-sMr
+uGX
drH
ney
tms
@@ -98761,7 +98769,7 @@ ocK
ngp
dwR
dwR
-cXL
+sMr
sMr
sMr
sMr
diff --git a/_maps/shuttles/ert_bounty.dmm b/_maps/shuttles/ert_bounty.dmm
index 46c6f03f11691..03be12a36a771 100644
--- a/_maps/shuttles/ert_bounty.dmm
+++ b/_maps/shuttles/ert_bounty.dmm
@@ -21,14 +21,34 @@
shuttle_id = "huntership"
},
/obj/structure/fans/tiny,
-/turf/open/floor/plating,
+/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"d" = (
-/obj/structure/sign/warning/vacuum/external,
-/turf/closed/wall/mineral/plastitanium,
+/obj/structure/table,
+/obj/item/tape{
+ pixel_y = 17;
+ pixel_x = -12
+ },
+/obj/item/reagent_containers/cup/glass/dry_ramen{
+ pixel_x = 4;
+ pixel_y = -4
+ },
+/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"f" = (
/obj/structure/table,
+/obj/structure/sign/poster/contraband/bountyhunters/directional/north,
+/obj/item/storage/toolbox/mechanical{
+ pixel_y = 8
+ },
+/obj/item/reagent_containers/cup/glass/coffee{
+ pixel_x = 9;
+ pixel_y = -3
+ },
+/obj/effect/spawner/random/bureaucracy/pen{
+ pixel_x = -6;
+ pixel_y = -7
+ },
/turf/open/floor/pod/light,
/area/shuttle/hunter)
"h" = (
@@ -37,6 +57,7 @@
/area/shuttle/hunter)
"i" = (
/obj/structure/tank_dispenser/oxygen,
+/obj/effect/turf_decal/stripes/full,
/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"j" = (
@@ -44,11 +65,16 @@
/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"k" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 8
+/obj/structure/table/reinforced,
+/obj/item/book/manual/wiki/security_space_law{
+ pixel_y = 6;
+ pixel_x = -5
},
-/obj/machinery/light/floor,
-/turf/open/floor/pod/dark,
+/obj/item/grenade/chem_grenade/cleaner{
+ pixel_x = 8;
+ pixel_y = 14
+ },
+/turf/open/floor/pod/light,
/area/shuttle/hunter)
"l" = (
/obj/machinery/power/shuttle_engine/propulsion{
@@ -60,8 +86,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/obj/machinery/light/small/directional/west,
-/turf/open/floor/plating,
+/obj/effect/mapping_helpers/airlock/cyclelink_helper,
+/obj/machinery/door/airlock/external/ruin,
+/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"n" = (
/turf/closed/wall/mineral/plastitanium,
@@ -70,7 +97,14 @@
/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/turf/open/floor/plating,
+/turf/open/floor/pod/dark,
+/area/shuttle/hunter)
+"q" = (
+/obj/structure/closet/crate/bin,
+/obj/item/grenade/chem_grenade/glitter/pink,
+/obj/item/trash/can,
+/obj/item/cigbutt,
+/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"r" = (
/obj/structure/chair/office{
@@ -105,11 +139,11 @@
/turf/open/floor/plating/airless,
/area/shuttle/hunter)
"w" = (
-/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/obj/machinery/door/airlock/external/ruin,
-/turf/open/floor/plating,
+/obj/structure/sign/warning/vacuum/directional/west,
+/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"x" = (
/obj/structure/chair/office{
@@ -126,12 +160,15 @@
/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"z" = (
-/obj/structure/sign/poster/contraband/bountyhunters,
-/turf/closed/wall/mineral/plastitanium,
+/obj/structure/table/reinforced,
+/obj/item/storage/fancy/cigarettes/cigars/havana{
+ pixel_y = 6
+ },
+/turf/open/floor/pod/light,
/area/shuttle/hunter)
"A" = (
/obj/effect/turf_decal/stripes/line{
- dir = 9
+ dir = 8
},
/turf/open/floor/pod/dark,
/area/shuttle/hunter)
@@ -141,21 +178,30 @@
/area/shuttle/hunter)
"D" = (
/obj/machinery/power/smes,
+/obj/effect/turf_decal/stripes/full,
/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"E" = (
/obj/structure/table,
-/obj/item/phone,
+/obj/item/food/donut/plain{
+ pixel_y = -10;
+ pixel_x = -4
+ },
+/obj/item/reagent_containers/cup/glass/dry_ramen{
+ pixel_x = -4;
+ pixel_y = 15
+ },
/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"F" = (
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
/obj/machinery/door/airlock/external/ruin,
/obj/structure/fans/tiny,
-/turf/open/floor/plating,
+/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"G" = (
-/turf/open/floor/plating,
+/obj/machinery/light/small/directional/west,
+/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"H" = (
/obj/machinery/computer/camera_advanced/shuttle_docker/syndicate/hunter{
@@ -172,8 +218,11 @@
/area/shuttle/hunter)
"J" = (
/obj/effect/turf_decal/stripes/line,
-/obj/machinery/light/small/directional/west,
-/turf/open/floor/plating,
+/obj/effect/mapping_helpers/airlock/cyclelink_helper{
+ dir = 1
+ },
+/obj/machinery/door/airlock/external/ruin,
+/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"K" = (
/obj/structure/chair/office{
@@ -198,24 +247,52 @@
/area/shuttle/hunter)
"P" = (
/obj/structure/table,
+/obj/item/toy/cards/deck{
+ pixel_y = 3;
+ pixel_x = -3
+ },
+/obj/item/multitool{
+ pixel_x = 10;
+ pixel_y = 5
+ },
/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"Q" = (
-/obj/effect/mapping_helpers/airlock/cyclelink_helper,
-/obj/machinery/door/airlock/external/ruin,
-/turf/open/floor/plating,
+/obj/effect/turf_decal/stripes/line,
+/obj/structure/sign/warning/vacuum/directional/west,
+/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"R" = (
/obj/structure/table,
/obj/item/binoculars,
+/obj/item/reagent_containers/cup/glass/coffee{
+ pixel_y = 16;
+ pixel_x = -7
+ },
/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"S" = (
+/obj/structure/table/reinforced,
+/obj/item/paper{
+ pixel_y = 2;
+ pixel_x = 2
+ },
+/obj/item/paper{
+ pixel_y = 5;
+ pixel_x = -4
+ },
+/obj/item/stamp/centcom{
+ pixel_x = 6;
+ pixel_y = 5
+ },
+/obj/item/pen/fourcolor{
+ pixel_x = -4
+ },
/turf/open/floor/pod/light,
/area/shuttle/hunter)
"T" = (
/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plating,
+/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"V" = (
/obj/machinery/computer/camera_advanced{
@@ -226,30 +303,40 @@
"X" = (
/obj/structure/rack,
/obj/item/grenade/c4{
- pixel_x = -1;
- pixel_y = 1
+ pixel_x = -4;
+ pixel_y = 3
},
/obj/item/grenade/c4{
- pixel_x = -6;
- pixel_y = 7
+ pixel_x = 3;
+ pixel_y = 1
},
/obj/item/grenade/c4{
- pixel_x = 7;
- pixel_y = -5
+ pixel_x = 11;
+ pixel_y = -1
},
+/obj/effect/turf_decal/stripes/full,
/turf/open/floor/pod/dark,
/area/shuttle/hunter)
"Y" = (
/obj/structure/table,
-/obj/item/storage/toolbox/mechanical,
/obj/machinery/light/small/directional/north,
+/obj/item/phone{
+ pixel_x = 8;
+ pixel_y = 7
+ },
+/obj/item/cigbutt/cigarbutt{
+ pixel_x = 7;
+ pixel_y = -10
+ },
+/obj/item/paper_bin{
+ pixel_x = -9;
+ pixel_y = 6
+ },
/turf/open/floor/pod/light,
/area/shuttle/hunter)
"Z" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 10
- },
-/turf/open/floor/pod/dark,
+/obj/structure/bookcase/random/reference,
+/turf/open/floor/pod/light,
/area/shuttle/hunter)
(1,1,1) = {"
@@ -330,15 +417,15 @@ n
(6,1,1) = {"
n
n
-d
n
n
-O
-O
-O
+n
+A
+A
+A
+n
n
n
-d
n
n
"}
@@ -348,9 +435,9 @@ p
G
J
w
-A
-k
-Z
+O
+B
+O
Q
m
G
@@ -363,9 +450,9 @@ n
h
n
n
-j
-j
-j
+q
+O
+O
n
n
h
@@ -391,7 +478,7 @@ a
a
a
h
-z
+n
f
E
P
@@ -408,7 +495,7 @@ a
a
n
Y
-P
+d
R
O
t
@@ -436,13 +523,13 @@ a
a
a
a
-h
n
-j
-j
+n
+n
+n
j
n
-h
+n
a
a
a
@@ -452,11 +539,11 @@ a
a
a
h
-S
+Z
O
B
O
-S
+k
h
a
a
@@ -471,7 +558,7 @@ S
u
I
u
-S
+z
h
a
a
diff --git a/_maps/templates/small_shuttle_1.dmm b/_maps/templates/small_shuttle_1.dmm
index a8a7ab9b7df7e..362d17d79ac25 100644
--- a/_maps/templates/small_shuttle_1.dmm
+++ b/_maps/templates/small_shuttle_1.dmm
@@ -22,7 +22,7 @@
/turf/open/floor/mineral/titanium/blue,
/area/template_noop)
"j" = (
-/obj/machinery/door/unpowered/shuttle,
+/obj/machinery/door/airlock/titanium,
/turf/open/floor/mineral/titanium/blue,
/area/template_noop)
"l" = (
diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
index bf6e68f127c71..cf6a5a12ef7cc 100644
--- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
+++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
@@ -280,3 +280,5 @@
#define COMSIG_LIVING_THROW_MODE_TOGGLE "living_throw_mode_toggle"
///From /datum/component/happiness()
#define COMSIG_MOB_HAPPINESS_CHANGE "happiness_change"
+/// From /obj/item/melee/baton/baton_effect(): (datum/source, mob/living/user, /obj/item/melee/baton)
+#define COMSIG_MOB_BATONED "mob_batoned"
diff --git a/code/__DEFINES/projectiles.dm b/code/__DEFINES/projectiles.dm
index ae61c5e50b7f0..ed4c66b799c59 100644
--- a/code/__DEFINES/projectiles.dm
+++ b/code/__DEFINES/projectiles.dm
@@ -53,13 +53,11 @@
/// The caliber used by the harpoon gun.
#define CALIBER_HARPOON "harpoon"
/// The caliber used by the rebar crossbow.
-#define CALIBER_REBAR "sharpened iron rod"
+#define CALIBER_REBAR "sharpened rod"
/// The caliber used by the rebar crossbow when forced to hold 2 rods.
-#define CALIBER_REBAR_FORCED "sharpened iron rod"
+#define CALIBER_REBAR_FORCED "sharpened rod"
/// The caliber used by the syndicate rebar crossbow.
-#define CALIBER_REBAR_SYNDIE "jagged iron rod"
-/// The caliber used by the syndicate rebar crossbow.
-#define CALIBER_REBAR_SYNDIE_NORMAL "sharpened iron rod"
+#define CALIBER_REBAR_SYNDIE "sharpened rod"
/// The caliber used by the meat hook.
#define CALIBER_HOOK "hook"
/// The caliber used by the changeling tentacle mutation.
diff --git a/code/controllers/subsystem/transport.dm b/code/controllers/subsystem/transport.dm
index db8d19fa060a4..2f870eb674035 100644
--- a/code/controllers/subsystem/transport.dm
+++ b/code/controllers/subsystem/transport.dm
@@ -170,10 +170,6 @@ PROCESSING_SUBSYSTEM_DEF(transport)
/datum/controller/subsystem/processing/transport/proc/pre_departure(datum/transport_controller/linear/tram/transport_controller, request_flags)
log_transport("Sub: [transport_controller.specific_transport_id] start pre-departure. Info: [SUB_TS_STATUS]")
- // Tram Malfunction event
- if(transport_controller.controller_status & COMM_ERROR)
- request_flags |= BYPASS_SENSORS
-
// Lock the physical controls of the tram
transport_controller.set_status_code(PRE_DEPARTURE, TRUE)
transport_controller.set_status_code(CONTROLS_LOCKED, TRUE)
diff --git a/code/datums/brain_damage/phobia.dm b/code/datums/brain_damage/phobia.dm
index cf97c2e6e855c..9394bc98f5790 100644
--- a/code/datums/brain_damage/phobia.dm
+++ b/code/datums/brain_damage/phobia.dm
@@ -10,6 +10,9 @@
/// Cooldown for freakouts to prevent permastunning.
COOLDOWN_DECLARE(scare_cooldown)
+ ///What mood event to apply when we see the thing & freak out.
+ var/datum/mood_event/mood_event_type
+
var/regex/trigger_regex
//instead of cycling every atom, only cycle the relevant types
var/list/trigger_mobs
@@ -34,6 +37,10 @@
trigger_species = GLOB.phobia_species[phobia_type]
..()
+/datum/brain_trauma/mild/phobia/on_lose(silent)
+ owner.clear_mood_event("phobia_[phobia_type]")
+ return ..()
+
/datum/brain_trauma/mild/phobia/on_life(seconds_per_tick, times_fired)
..()
if(HAS_TRAIT(owner, TRAIT_FEARLESS))
@@ -107,6 +114,8 @@
COOLDOWN_START(src, scare_cooldown, 12 SECONDS)
if(owner.stat == DEAD)
return
+ if(mood_event_type)
+ owner.add_mood_event("phobia_[phobia_type]", mood_event_type)
var/message = pick("spooks you to the bone", "shakes you up", "terrifies you", "sends you into a panic", "sends chills down your spine")
if(reason)
to_chat(owner, span_userdanger("Seeing [span_phobia(reason.name)] [message]!"))
@@ -193,6 +202,7 @@
/datum/brain_trauma/mild/phobia/heresy
phobia_type = "heresy"
+ mood_event_type = /datum/mood_event/heresy
random_gain = FALSE
/datum/brain_trauma/mild/phobia/insects
@@ -217,6 +227,7 @@
/datum/brain_trauma/mild/phobia/skeletons
phobia_type = "skeletons"
+ mood_event_type = /datum/mood_event/spooked
random_gain = FALSE
/datum/brain_trauma/mild/phobia/snakes
diff --git a/code/datums/components/crafting/equipment.dm b/code/datums/components/crafting/equipment.dm
index e7971488d638f..7e7b7aca26f24 100644
--- a/code/datums/components/crafting/equipment.dm
+++ b/code/datums/components/crafting/equipment.dm
@@ -249,3 +249,14 @@
tool_paths = list(/obj/item/bikehorn)
time = 40 SECONDS
category = CAT_EQUIPMENT
+
+/datum/crafting_recipe/rebar_quiver
+ name = "Rebar Storage Quiver"
+ result = /obj/item/storage/bag/rebar_quiver
+ time = 10
+ reqs = list(
+ /obj/item/tank/internals/oxygen = 1,
+ /obj/item/stack/cable_coil = 15,
+ )
+ category = CAT_EQUIPMENT
+ tool_behaviors = list(TOOL_WELDER, TOOL_WIRECUTTER)
diff --git a/code/datums/components/crafting/ranged_weapon.dm b/code/datums/components/crafting/ranged_weapon.dm
index 88b721d3cb639..b646c4472ed98 100644
--- a/code/datums/components/crafting/ranged_weapon.dm
+++ b/code/datums/components/crafting/ranged_weapon.dm
@@ -225,7 +225,7 @@
/datum/crafting_recipe/rebarxbowforced
name = "Forced Rebar Crossbow"
- desc = "Get an extra shot in your crossbow... for a chance of shooting yourself when you fire it."
+ desc = "A much quicker reload... for a chance of shooting yourself when you fire it."
result = /obj/item/gun/ballistic/rifle/rebarxbow/forced
reqs = list(
/obj/item/gun/ballistic/rifle/rebarxbow = 1,
diff --git a/code/datums/components/crafting/weapon_ammo.dm b/code/datums/components/crafting/weapon_ammo.dm
index 32f34f2ae751c..f68ff58072c67 100644
--- a/code/datums/components/crafting/weapon_ammo.dm
+++ b/code/datums/components/crafting/weapon_ammo.dm
@@ -12,6 +12,15 @@
time = 0.5 SECONDS
category = CAT_WEAPON_AMMO
+/datum/crafting_recipe/paperball
+ name = "Paper Ball"
+ result = /obj/item/ammo_casing/rebar/paperball
+ reqs = list(
+ /obj/item/paper = 1,
+ )
+ time = 0.1 SECONDS
+ category = CAT_WEAPON_AMMO
+
/datum/crafting_recipe/rebarsyndie
name = "jagged iron rod"
result = /obj/item/ammo_casing/rebar/syndie
@@ -19,10 +28,20 @@
/obj/item/stack/rods = 1,
)
tool_behaviors = list(TOOL_WIRECUTTER)
- time = 0.5 SECONDS
+ time = 0.1 SECONDS
category = CAT_WEAPON_AMMO
crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
+/datum/crafting_recipe/healium_bolt
+ name = "healium crystal crossbow bolt"
+ result = /obj/item/ammo_casing/rebar/healium
+ reqs = list(
+ /obj/item/grenade/gas_crystal/healium_crystal = 1
+ )
+ time = 0.1 SECONDS
+ category = CAT_WEAPON_AMMO
+ crafting_flags = CRAFT_CHECK_DENSITY
+
/datum/crafting_recipe/pulseslug
name = "Pulse Slug Shell"
result = /obj/item/ammo_casing/shotgun/pulseslug
diff --git a/code/datums/components/fishing_spot.dm b/code/datums/components/fishing_spot.dm
index fb20588f8c5a1..414c17b6d15e3 100644
--- a/code/datums/components/fishing_spot.dm
+++ b/code/datums/components/fishing_spot.dm
@@ -84,6 +84,8 @@
if(denial_reason)
to_chat(user, span_warning(denial_reason))
return COMPONENT_NO_AFTERATTACK
+ // In case the fishing source has anything else to do before beginning to fish.
+ fish_source.on_start_fishing(rod, user, parent)
start_fishing_challenge(rod, user)
return COMPONENT_NO_AFTERATTACK
diff --git a/code/datums/elements/spooky.dm b/code/datums/elements/spooky.dm
index f80c98e2796af..30a04f6348b20 100644
--- a/code/datums/elements/spooky.dm
+++ b/code/datums/elements/spooky.dm
@@ -47,6 +47,8 @@
C.set_jitter_if_lower(30 SECONDS)
C.set_stutter(40 SECONDS)
+ C.add_mood_event("spooked", /datum/mood_event/spooked)
+
/datum/element/spooky/proc/spectral_change(mob/living/carbon/human/H, mob/user)
if((H.getStaminaLoss() > 95) && (!istype(H.dna.species, /datum/species/skeleton)) && (!istype(H.dna.species, /datum/species/golem)) && (!istype(H.dna.species, /datum/species/android)) && (!istype(H.dna.species, /datum/species/jelly)))
H.Paralyze(20)
@@ -63,12 +65,12 @@
new instrument(T)
else
to_chat(H, span_boldwarning("The spooky gods forgot to ship your instrument. Better luck next unlife."))
- to_chat(H, span_boldnotice("You are the spooky skeleton!"))
+ to_chat(H, span_boldnotice("You are a spooky skeleton!"))
to_chat(H, span_boldnotice("A new life and identity has begun. Help your fellow skeletons into bringing out the spooky-pocalypse. You haven't forgotten your past life, and are still beholden to past loyalties."))
change_name(H) //time for a new name!
/datum/element/spooky/proc/change_name(mob/living/carbon/human/spooked)
- var/skeleton_name = sanitize_name(tgui_input_text(spooked, "Enter your new skeleton name", "Spookifier", spooked.real_name, MAX_NAME_LEN))
+ var/skeleton_name = spooked.client ? sanitize_name(tgui_input_text(spooked, "Enter your new skeleton name", "Spookifier", spooked.real_name, MAX_NAME_LEN)) : null
if(!skeleton_name)
- skeleton_name = "spooky skeleton"
+ skeleton_name = "\improper spooky skeleton"
spooked.fully_replace_character_name(null, skeleton_name)
diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm
index e6cf8f2d3d80e..20a803434f40d 100644
--- a/code/datums/mood_events/generic_negative_events.dm
+++ b/code/datums/mood_events/generic_negative_events.dm
@@ -332,11 +332,16 @@
mood_change *= people_laughing_at_you
return ..()
-//These are unused so far but I want to remember them to use them later
/datum/mood_event/surgery
description = "THEY'RE CUTTING ME OPEN!!"
mood_change = -8
+/datum/mood_event/surgery/success
+ timeout = 3 MINUTES
+
+/datum/mood_event/surgery/failure
+ timeout = 10 MINUTES
+
/datum/mood_event/bald
description = "I need something to cover my head..."
mood_change = -3
diff --git a/code/datums/quirks/negative_quirks/chronic_illness.dm b/code/datums/quirks/negative_quirks/chronic_illness.dm
index 663d41381987e..f0809b55d2b0f 100644
--- a/code/datums/quirks/negative_quirks/chronic_illness.dm
+++ b/code/datums/quirks/negative_quirks/chronic_illness.dm
@@ -9,8 +9,10 @@
hardcore_value = 12
mail_goodies = list(/obj/item/storage/pill_bottle/sansufentanyl)
-/datum/quirk/item_quirk/chronic_illness/add_unique(client/client_source)
+/datum/quirk/item_quirk/chronic_illness/add(client/client_source)
var/datum/disease/chronic_illness/hms = new /datum/disease/chronic_illness()
quirk_holder.ForceContractDisease(hms)
+
+/datum/quirk/item_quirk/chronic_illness/add_unique(client/client_source)
give_item_to_holder(/obj/item/storage/pill_bottle/sansufentanyl, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK),flavour_text = "You've been provided with medication to help manage your condition. Take it regularly to avoid complications.")
give_item_to_holder(/obj/item/healthanalyzer/simple/disease, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK))
diff --git a/code/datums/quirks/negative_quirks/hemiplegic.dm b/code/datums/quirks/negative_quirks/hemiplegic.dm
index b82ad434dfbe2..ac073d4ef8865 100644
--- a/code/datums/quirks/negative_quirks/hemiplegic.dm
+++ b/code/datums/quirks/negative_quirks/hemiplegic.dm
@@ -16,7 +16,7 @@
associated_typepath = /datum/quirk/hemiplegic
customization_options = list(/datum/preference/choiced/hemiplegic)
-/datum/quirk/hemiplegic/add_unique(client/client_source)
+/datum/quirk/hemiplegic/add(client/client_source)
var/datum/brain_trauma/severe/paralysis/hemiplegic/side_choice = GLOB.side_choice_hemiplegic[client_source?.prefs?.read_preference(/datum/preference/choiced/hemiplegic)]
if(isnull(side_choice)) // Client gone or they chose a random side
side_choice = GLOB.side_choice_hemiplegic[pick(GLOB.side_choice_hemiplegic)]
diff --git a/code/datums/quirks/neutral_quirks/heretochromatic.dm b/code/datums/quirks/neutral_quirks/heretochromatic.dm
index 194262952709c..311cbf66868f0 100644
--- a/code/datums/quirks/neutral_quirks/heretochromatic.dm
+++ b/code/datums/quirks/neutral_quirks/heretochromatic.dm
@@ -7,11 +7,7 @@
value = 0
mail_goodies = list(/obj/item/clothing/glasses/eyepatch)
-// Only your first eyes are heterochromatic
-// If someone comes and says "well mr coder you can have DNA bound heterochromia so it's not unrealistic
-// to allow all inserted replacement eyes to become heterochromatic or for it to transfer between mobs"
-// Then just change this to [proc/add] I really don't care
-/datum/quirk/heterochromatic/add_unique(client/client_source)
+/datum/quirk/heterochromatic/add(client/client_source)
var/color = client_source?.prefs.read_preference(/datum/preference/color/heterochromatic)
if(!color)
return
diff --git a/code/datums/quirks/positive_quirks/bilingual.dm b/code/datums/quirks/positive_quirks/bilingual.dm
index 408a952cfe18a..20123dbe87afb 100644
--- a/code/datums/quirks/positive_quirks/bilingual.dm
+++ b/code/datums/quirks/positive_quirks/bilingual.dm
@@ -12,7 +12,7 @@
associated_typepath = /datum/quirk/bilingual
customization_options = list(/datum/preference/choiced/language)
-/datum/quirk/bilingual/add_unique(client/client_source)
+/datum/quirk/bilingual/add(client/client_source)
var/wanted_language = client_source?.prefs.read_preference(/datum/preference/choiced/language)
var/datum/language/language_type
if(wanted_language == "Random")
diff --git a/code/datums/quirks/positive_quirks/settler.dm b/code/datums/quirks/positive_quirks/settler.dm
index 81402c050cdd8..9b52403404b12 100644
--- a/code/datums/quirks/positive_quirks/settler.dm
+++ b/code/datums/quirks/positive_quirks/settler.dm
@@ -15,14 +15,16 @@
/obj/item/gps,
)
-/datum/quirk/item_quirk/settler/add_unique(client/client_source)
- give_item_to_holder(/obj/item/storage/box/papersack/wheat, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
- give_item_to_holder(/obj/item/storage/toolbox/fishing/small, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
+/datum/quirk/item_quirk/settler/add(client/client_source)
var/mob/living/carbon/human/human_quirkholder = quirk_holder
human_quirkholder.set_mob_height(HUMAN_HEIGHT_SHORTEST)
human_quirkholder.add_movespeed_modifier(/datum/movespeed_modifier/settler)
human_quirkholder.physiology.hunger_mod *= 0.5 //good for you, shortass, you don't get hungry nearly as often
+/datum/quirk/item_quirk/settler/add_unique(client/client_source)
+ give_item_to_holder(/obj/item/storage/box/papersack/wheat, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
+ give_item_to_holder(/obj/item/storage/toolbox/fishing/small, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
+
/datum/quirk/item_quirk/settler/remove()
if(QDELING(quirk_holder))
return
diff --git a/code/datums/quirks/positive_quirks/signer.dm b/code/datums/quirks/positive_quirks/signer.dm
index 8ff95d25e4a67..9e354ec71492f 100644
--- a/code/datums/quirks/positive_quirks/signer.dm
+++ b/code/datums/quirks/positive_quirks/signer.dm
@@ -7,8 +7,10 @@
medical_record_text = "Patient can communicate with sign language."
mail_goodies = list(/obj/item/clothing/gloves/radio)
-/datum/quirk/item_quirk/signer/add_unique(client/client_source)
+/datum/quirk/item_quirk/signer/add(client/client_source)
quirk_holder.AddComponent(/datum/component/sign_language)
+
+/datum/quirk/item_quirk/signer/add_unique(client/client_source)
var/obj/item/clothing/gloves/gloves_type = /obj/item/clothing/gloves/radio
if(isplasmaman(quirk_holder))
gloves_type = /obj/item/clothing/gloves/color/plasmaman/radio
diff --git a/code/datums/quirks/positive_quirks/spacer.dm b/code/datums/quirks/positive_quirks/spacer.dm
index 991c2001fbb08..4be27fe16b2e2 100644
--- a/code/datums/quirks/positive_quirks/spacer.dm
+++ b/code/datums/quirks/positive_quirks/spacer.dm
@@ -42,7 +42,6 @@
// Yes, it's assumed for planetary maps that you start at gravity sickness.
check_z(quirk_holder, skip_timers = TRUE)
-/datum/quirk/spacer_born/add_unique(client/client_source)
// drift slightly faster through zero G
quirk_holder.inertia_move_delay *= 0.8
diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm
index d9263411f7b08..8a994350be856 100644
--- a/code/game/gamemodes/objective_items.dm
+++ b/code/game/gamemodes/objective_items.dm
@@ -243,8 +243,12 @@
difficulty = 3
steal_hint = "A self-defense weapon standard-issue for all heads of staffs barring the Head of Security. Rarely found off of their person."
+/datum/objective_item/steal/traitor/telebaton/check_special_completion(obj/item/thing)
+ return thing.type == /obj/item/melee/baton/telescopic
+
/obj/item/melee/baton/telescopic/add_stealing_item_objective()
- return add_item_to_steal(src, /obj/item/melee/baton/telescopic)
+ if(type == /obj/item/melee/baton/telescopic)
+ return add_item_to_steal(src, /obj/item/melee/baton/telescopic)
/datum/objective_item/steal/traitor/cargo_budget
name = "cargo's departmental budget"
diff --git a/code/game/machinery/doors/unpowered.dm b/code/game/machinery/doors/unpowered.dm
deleted file mode 100644
index 6a9fea4741921..0000000000000
--- a/code/game/machinery/doors/unpowered.dm
+++ /dev/null
@@ -1,25 +0,0 @@
-/obj/machinery/door/unpowered
-
-/obj/machinery/door/unpowered/Bumped(atom/movable/AM)
- if(src.locked)
- return
- ..()
- return
-
-
-/obj/machinery/door/unpowered/attackby(obj/item/I, mob/user, params)
- if(locked)
- return
- else
- return ..()
-
-/obj/machinery/door/unpowered/emag_act(mob/user, obj/item/card/emag/emag_card)
- return FALSE
-
-/obj/machinery/door/unpowered/shuttle
- icon = 'icons/turf/shuttle.dmi'
- name = "door"
- icon_state = "door1"
- opacity = TRUE
- density = TRUE
- explosion_block = 1
diff --git a/code/game/objects/items/broom.dm b/code/game/objects/items/broom.dm
index 6b89ab7b7926e..4f7cb137d3009 100644
--- a/code/game/objects/items/broom.dm
+++ b/code/game/objects/items/broom.dm
@@ -68,13 +68,24 @@
* * user - The user of the pushbroom
* * A - The atom which is located at the location to push atoms from
*/
-/obj/item/pushbroom/proc/sweep(mob/user, atom/A)
+/obj/item/pushbroom/proc/sweep(mob/user, atom/atom)
SIGNAL_HANDLER
- var/turf/current_item_loc = isturf(A) ? A : A.loc
+ do_sweep(src, user, atom, user.dir)
+
+/**
+* Sweep objects in the direction we're facing towards our direction
+* Arguments
+* * broomer - The object being used for brooming
+* * user - The person who is brooming
+* * target - The object or tile that's target of a broom click or being moved into
+* * sweep_dir - The directions in which we sweep objects
+*/
+/proc/do_sweep(obj/broomer, mob/user, atom/target, sweep_dir)
+ var/turf/current_item_loc = isturf(target) ? target : target.loc
if (!isturf(current_item_loc))
return
- var/turf/new_item_loc = get_step(current_item_loc, user.dir)
+ var/turf/new_item_loc = get_step(current_item_loc, sweep_dir)
var/list/items_to_sweep = list()
var/i = 1
@@ -86,16 +97,15 @@
if(i > BROOM_PUSH_LIMIT)
break
- SEND_SIGNAL(new_item_loc, COMSIG_TURF_RECEIVE_SWEEPED_ITEMS, src, user, items_to_sweep)
+ SEND_SIGNAL(new_item_loc, COMSIG_TURF_RECEIVE_SWEEPED_ITEMS, broomer, user, items_to_sweep)
if(!length(items_to_sweep))
return
for (var/obj/item/garbage in items_to_sweep)
- garbage.Move(new_item_loc, user.dir)
-
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 30, TRUE, -1)
+ garbage.Move(new_item_loc, sweep_dir)
+ playsound(current_item_loc, 'sound/weapons/thudswoosh.ogg', 30, TRUE, -1)
/obj/item/pushbroom/cyborg
name = "cyborg push broom"
diff --git a/code/game/objects/items/granters/crafting/rebarxbowsyndie.dm b/code/game/objects/items/granters/crafting/rebarxbowsyndie.dm
index fd38d4f4ccb20..04cee4e18a792 100644
--- a/code/game/objects/items/granters/crafting/rebarxbowsyndie.dm
+++ b/code/game/objects/items/granters/crafting/rebarxbowsyndie.dm
@@ -1,5 +1,5 @@
/obj/item/book/granter/crafting_recipe/dusting/rebarxbowsyndie_ammo
- name = "SYNDICATE REBAR CROSSBOW OWNERS MANUAL"
+ name = "SYNDICATE REBAR CROSSBOW AMMO CRAFTING MANUAL"
desc = "This book will self destruct upon being read a second time."
crafting_recipe_types = list(
/datum/crafting_recipe/rebarsyndie
diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm
index 4ab568fdd4f96..ffcb5d1857cda 100644
--- a/code/game/objects/items/handcuffs.dm
+++ b/code/game/objects/items/handcuffs.dm
@@ -451,7 +451,7 @@
* Does not trigger on tiny mobs.
* If ignore_movetypes is FALSE, does not trigger on floating / flying / etc. mobs.
*/
-/obj/item/restraints/legcuffs/beartrap/proc/spring_trap(atom/movable/target, ignore_movetypes = FALSE)
+/obj/item/restraints/legcuffs/beartrap/proc/spring_trap(atom/movable/target, ignore_movetypes = FALSE, hit_prone = FALSE)
if(!armed || !isturf(loc) || !isliving(target))
return
@@ -477,7 +477,7 @@
victim.visible_message(span_danger("[victim] triggers \the [src]."), \
span_userdanger("You trigger \the [src]!"))
var/def_zone = BODY_ZONE_CHEST
- if(iscarbon(victim) && victim.body_position == STANDING_UP)
+ if(iscarbon(victim) && (victim.body_position == STANDING_UP || hit_prone))
var/mob/living/carbon/carbon_victim = victim
def_zone = pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
if(!carbon_victim.legcuffed && carbon_victim.num_legs >= 2) //beartrap can't cuff your leg if there's already a beartrap or legcuffs, or you don't have two legs.
@@ -595,7 +595,9 @@
/obj/item/restraints/legcuffs/bola/energy/ensnare(atom/hit_atom)
var/obj/item/restraints/legcuffs/beartrap/energy/cyborg/B = new (get_turf(hit_atom))
- B.spring_trap(hit_atom, ignore_movetypes = TRUE)
+ B.spring_trap(hit_atom, ignore_movetypes = TRUE, hit_prone = TRUE)
+ if(B.loc != hit_atom)
+ qdel(B)
qdel(src)
/**
diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm
index b576ef5d41c33..112c527ec28a9 100644
--- a/code/game/objects/items/melee/baton.dm
+++ b/code/game/objects/items/melee/baton.dm
@@ -212,6 +212,7 @@
if(!trait_check)
target.Knockdown((isnull(stun_override) ? knockdown_time : stun_override))
additional_effects_non_cyborg(target, user)
+ SEND_SIGNAL(target, COMSIG_MOB_BATONED, user, src)
return TRUE
/// Description for trying to stun when still on cooldown.
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index b4c12d75a30c3..2d886163a50ba 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -57,7 +57,7 @@
// Handles adding items with the module
/obj/item/borg/upgrade/proc/install_items(mob/living/silicon/robot/borg, mob/living/user = usr, list/items)
for(var/item_to_add in items)
- var/obj/item/module_item = new item_to_add(borg.model.modules)
+ var/obj/item/module_item = new item_to_add(borg.model)
borg.model.basic_modules += module_item
borg.model.add_module(module_item, FALSE, TRUE)
return TRUE
@@ -756,9 +756,11 @@
desc = "An upgrade to the service model cyborg, to help provide mobile service."
icon_state = "cyborg_upgrade3"
require_model = TRUE
- model_type = list(/obj/item/rolling_table_dock)
+ model_type = list(/obj/item/robot_model/service)
model_flags = BORG_MODEL_SERVICE
+ items_to_add = list(/obj/item/rolling_table_dock)
+
/obj/item/borg/upgrade/service_cookbook
name = "Service Cyborg Cookbook"
desc = "An upgrade to the service model cyborg, that lets them create more foods."
@@ -767,7 +769,7 @@
model_type = list(/obj/item/robot_model/service)
model_flags = BORG_MODEL_SERVICE
- model_type = list(/obj/item/borg/cookbook)
+ items_to_add = list(/obj/item/borg/cookbook)
///This isn't an upgrade or part of the same path, but I'm gonna just stick it here because it's a tool used on cyborgs.
//A reusable tool that can bring borgs back to life. They gotta be repaired first, though.
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index f6e7d797fd95c..4e4e1db1f9a1e 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -282,8 +282,9 @@ GLOBAL_LIST_INIT(bananium_recipes, list ( \
walltype = /turf/closed/wall/mineral/titanium
GLOBAL_LIST_INIT(titanium_recipes, list ( \
- new/datum/stack_recipe("Titanium tile", /obj/item/stack/tile/mineral/titanium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
- new/datum/stack_recipe("Shuttle seat", /obj/structure/chair/comfy/shuttle, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("Titanium tile", /obj/item/stack/tile/mineral/titanium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
+ new /datum/stack_recipe("Shuttle seat", /obj/structure/chair/comfy/shuttle, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("Material tram door assembly", /obj/structure/door_assembly/multi_tile/door_assembly_tram, 8, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
))
/obj/item/stack/sheet/mineral/titanium/get_main_recipes()
@@ -473,6 +474,7 @@ GLOBAL_LIST_INIT(metalhydrogen_recipes, list(
new /datum/stack_recipe("ancient armor", /obj/item/clothing/suit/armor/elder_atmosian, req_amount = 5, res_amount = 1, crafting_flags = NONE, category = CAT_CLOTHING),
new /datum/stack_recipe("ancient helmet", /obj/item/clothing/head/helmet/elder_atmosian, req_amount = 3, res_amount = 1, crafting_flags = NONE, category = CAT_CLOTHING),
new /datum/stack_recipe("metallic hydrogen axe", /obj/item/fireaxe/metal_h2_axe, req_amount = 15, res_amount = 1, crafting_flags = NONE, category = CAT_WEAPON_MELEE),
+ new /datum/stack_recipe("metallic hydrogen bolts", /obj/item/ammo_casing/rebar/hydrogen, req_amount = 1, res_amount = 1, crafting_flags = NONE, category = CAT_WEAPON_AMMO),
))
/obj/item/stack/sheet/mineral/metal_hydrogen
@@ -491,6 +493,12 @@ GLOBAL_LIST_INIT(metalhydrogen_recipes, list(
. = ..()
. += GLOB.metalhydrogen_recipes
+
+
+GLOBAL_LIST_INIT(zaukerite_recipes, list(
+ new /datum/stack_recipe("zaukerite shard", /obj/item/ammo_casing/rebar/zaukerite, req_amount=1, res_amount=1, category = CAT_WEAPON_AMMO),
+ ))
+
/obj/item/stack/sheet/mineral/zaukerite
name = "zaukerite"
icon_state = "zaukerite"
@@ -501,3 +509,7 @@ GLOBAL_LIST_INIT(metalhydrogen_recipes, list(
mats_per_unit = list(/datum/material/zaukerite = SHEET_MATERIAL_AMOUNT)
merge_type = /obj/item/stack/sheet/mineral/zaukerite
material_type = /datum/material/zaukerite
+
+/obj/item/stack/sheet/mineral/zaukerite/get_main_recipes()
+ . = ..()
+ . += GLOB.zaukerite_recipes
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index 9af23545c6f0f..28caa290a9cc1 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -573,4 +573,28 @@
for(var/i in 1 to 40)
new /obj/item/ammo_casing/harpoon(src)
+/obj/item/storage/bag/rebar_quiver
+ name = "Rebar Storage Quiver"
+ icon = 'icons/obj/weapons/bows/quivers.dmi'
+ icon_state = "rebar_quiver"
+ worn_icon_state = "rebar_quiver"
+ inhand_icon_state = "rebar_quiver"
+ desc = "A oxygen tank cut in half, used for holding sharpened rods for the rebar crossbow."
+ slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_SUITSTORE
+ resistance_flags = FLAMMABLE
+
+/obj/item/storage/bag/rebar_quiver/Initialize(mapload)
+ . = ..()
+ atom_storage.max_specific_storage = WEIGHT_CLASS_TINY
+ atom_storage.max_slots = 10
+ atom_storage.max_total_storage = 15
+ atom_storage.set_holdable(list(
+ /obj/item/ammo_casing/rebar,
+ /obj/item/ammo_casing/rebar/syndie,
+ /obj/item/ammo_casing/rebar/healium,
+ /obj/item/ammo_casing/rebar/hydrogen,
+ /obj/item/ammo_casing/rebar/zaukerite,
+ /obj/item/ammo_casing/rebar/paperball,
+ ))
+
#undef ORE_BAG_BALOON_COOLDOWN
diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm
index 7bd009016148e..3a4ce82d85e51 100644
--- a/code/game/objects/items/storage/uplink_kits.dm
+++ b/code/game/objects/items/storage/uplink_kits.dm
@@ -341,7 +341,7 @@
/obj/item/storage/box/syndie_kit/rebarxbowsyndie
name = "Boxed Rebar Crossbow"
- desc = "Now features instruction manual for making ammo."
+ desc = "A scoped weapon with low armor penetration, but devestating against flesh. Features instruction manual for making specialty ammo."
/obj/item/storage/box/syndie_kit/rebarxbowsyndie/PopulateContents()
new /obj/item/book/granter/crafting_recipe/dusting/rebarxbowsyndie_ammo(src)
diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm
index 5daf96a01b884..86d8e01f98ebe 100644
--- a/code/game/objects/structures/door_assembly.dm
+++ b/code/game/objects/structures/door_assembly.dm
@@ -44,6 +44,7 @@
multi_tile = TRUE
glass = TRUE
nomineral = TRUE
+ material_amt = 8
/obj/structure/door_assembly/Initialize(mapload)
. = ..()
diff --git a/code/game/objects/structures/door_assembly_types.dm b/code/game/objects/structures/door_assembly_types.dm
index dd06f7e42a9a4..d62fb1bec7676 100644
--- a/code/game/objects/structures/door_assembly_types.dm
+++ b/code/game/objects/structures/door_assembly_types.dm
@@ -271,6 +271,18 @@
name = "large public airlock assembly"
base_name = "large public airlock"
+/obj/structure/door_assembly/multi_tile/door_assembly_tram
+ name = "tram door assembly"
+ icon = 'icons/obj/doors/airlocks/tram/tram.dmi'
+ base_name = "tram door"
+ overlays_file = 'icons/obj/doors/airlocks/tram/tram-overlays.dmi'
+ glass_type = /obj/machinery/door/airlock/tram
+ airlock_type = /obj/machinery/door/airlock/tram
+ glass = FALSE
+ noglass = TRUE
+ mineral = "titanium"
+ material_type = /obj/item/stack/sheet/mineral/titanium
+
/obj/structure/door_assembly/door_assembly_material/atom_deconstruct(disassembled = TRUE)
var/turf/target_turf = get_turf(src)
for(var/datum/material/material_datum as anything in custom_materials)
diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm
index 8d1068baa1368..f8e679352bf78 100644
--- a/code/modules/antagonists/changeling/changeling.dm
+++ b/code/modules/antagonists/changeling/changeling.dm
@@ -260,6 +260,10 @@
*/
/datum/antagonist/changeling/proc/on_life(datum/source, seconds_per_tick, times_fired)
SIGNAL_HANDLER
+ if(isliving(owner.current))
+ var/mob/living/living_owner = owner.current
+ if(living_owner.fire_stacks && living_owner.on_fire)
+ return // No chemical regen while on fire.
var/delta_time = DELTA_WORLD_TIME(SSmobs)
diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm
index 23b4f9548c424..d5152772e51c5 100644
--- a/code/modules/antagonists/changeling/changeling_power.dm
+++ b/code/modules/antagonists/changeling/changeling_power.dm
@@ -81,6 +81,10 @@ the same goes for Remove(). if you override Remove(), call parent or else your p
/datum/action/changeling/proc/can_sting(mob/living/user, mob/living/target)
if(!can_be_used_by(user))
return FALSE
+ if(user.fire_stacks && user.on_fire)
+ user.balloon_alert(user, "on fire!")
+ to_chat(user, span_boldwarning("WE CANNOT DO THIS WHILE ENGULFED IN FLAMES!!! PUT OUT THE FIRE FIRST!!!"))
+ return FALSE
var/datum/antagonist/changeling/changeling = IS_CHANGELING(user)
if(changeling.chem_charges < chemical_cost)
user.balloon_alert(user, "needs [chemical_cost] chemicals!")
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index d82ec1d131897..167c1c697cdc2 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -173,15 +173,24 @@
\***************************************/
/datum/action/changeling/weapon/arm_blade
name = "Arm Blade"
- desc = "We reform one of our arms into a deadly blade. Costs 20 chemicals."
- helptext = "We may retract our armblade in the same manner as we form it. Cannot be used while in lesser form."
+ desc = "We reform one of our arms into a deadly blade that breaks after a number of hits, improvable by absorbing genomes. Costs 40 chemicals."
+ helptext = "We may retract our armblade in the same manner as we form it. Organic tissue is not perfect; the armblade will break after it is used too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form."
button_icon_state = "armblade"
- chemical_cost = 20
- dna_cost = 2
+ chemical_cost = 30
+ dna_cost = 3
req_human = TRUE
weapon_type = /obj/item/melee/arm_blade
weapon_name_simple = "blade"
+/datum/action/changeling/weapon/arm_blade/sting_action(mob/living/carbon/user)
+ var/datum/antagonist/changeling/changeling = IS_CHANGELING(user) //So we can read the absorbed_count.
+ if(!changeling)
+ return
+
+ var/obj/item/melee/arm_blade/blade = ..()
+ blade.remaining_uses = round(changeling.absorbed_count * 3)
+ return TRUE
+
/obj/item/melee/arm_blade
name = "arm blade"
desc = "A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter."
@@ -203,8 +212,10 @@
wound_bonus = 10
bare_wound_bonus = 10
armour_penetration = 35
+ resistance_flags = FLAMMABLE
var/can_drop = FALSE
var/fake = FALSE
+ var/remaining_uses
/obj/item/melee/arm_blade/Initialize(mapload,silent,synthetic)
. = ..()
@@ -250,6 +261,15 @@
span_hear("You hear a metal screeching sound."))
opening.open(BYPASS_DOOR_CHECKS)
+ if(remaining_uses <= 1)
+ if(ishuman(loc))
+ var/mob/living/carbon/human/changeling = loc
+ changeling.visible_message(span_warning("With a sickening crunch, [changeling] reforms [changeling.p_their()] [src] into an arm!"), span_notice("We assimilate our armblade into our body."), "You hear organic matter ripping and tearing!")
+ qdel(src)
+ else
+ remaining_uses--
+
+
/obj/item/melee/arm_blade/dropped(mob/user)
..()
if(can_drop)
@@ -297,6 +317,7 @@
throw_range = 0
throw_speed = 0
can_hold_up = FALSE
+ resistance_flags = FLAMMABLE
/obj/item/gun/magic/tentacle/Initialize(mapload, silent)
. = ..()
@@ -493,6 +514,9 @@
S.remaining_uses = round(changeling.absorbed_count * 3)
return TRUE
+/datum/armor/item_shield/changeling
+ fire = -100
+
/obj/item/shield/changeling
name = "shield-like mass"
desc = "A mass of tough, boney tissue. You can still see the fingers as a twisted pattern in the shield."
@@ -502,6 +526,8 @@
lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi'
righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi'
block_chance = 50
+ armor_type = /datum/armor/item_shield/changeling
+ resistance_flags = FLAMMABLE
var/remaining_uses //Set by the changeling ability.
@@ -512,7 +538,7 @@
loc.visible_message(span_warning("The end of [loc.name]\'s hand inflates rapidly, forming a huge shield-like mass!"), span_warning("We inflate our hand into a strong shield."), span_hear("You hear organic matter ripping and tearing!"))
/obj/item/shield/changeling/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
- if(remaining_uses < 1)
+ if(remaining_uses <= 1)
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
H.visible_message(span_warning("With a sickening crunch, [H] reforms [H.p_their()] shield into an arm!"), span_notice("We assimilate our shield into our body"), "= world.time)
+ return
+ can_move = world.time + move_delay
+
+ // ESCAPE PRISON
+ if(ismovable(loc) && prob(25))
+ var/obj/item/item = pick(loc.contents)
+ if(istype(loc, /obj/item/storage))
+ item.forceMove(loc.drop_location()) //throw stuff out of the inventory till we free ourselves!
+ playsound(src, SFX_RUSTLE, 30, TRUE)
+ return
+
+ // MOVE US
+ if(isturf(loc))
+ can_move = world.time + move_delay
+ try_step_multiz(direction)
+ SpinAnimation(move_delay, 1, direction == NORTH || direction == EAST)
+
+/obj/item/mmi/posibrain/sphere/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change)
+ . = ..()
+ if(brainmob && isturf(loc))
+ anchored = TRUE //anchor so we dont broom ourselves.
+ do_sweep(src, brainmob, loc, get_dir(old_loc, loc)) //movement dir doesnt work on objects
+ anchored = FALSE
+
+/// Punt the shit across the room
+/obj/item/mmi/posibrain/sphere/attack_hand_secondary(mob/user, list/modifiers)
+ . = ..()
+ if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
+ return .
+ throw_at(get_edge_target_turf(src, get_dir(user, src)), 7, 1, user)
+ user.do_attack_animation(src)
+ can_move = world.time + move_delay //pweeze stawp
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 6e1f9037018b6..2432888cce65d 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -796,6 +796,9 @@
if(leg_clothes)
burning_items |= leg_clothes
+ for(var/obj/item/burnable_item in held_items)
+ burning_items |= burnable_item
+
for(var/obj/item/burning in burning_items)
burning.fire_act((stacks * 25 * seconds_per_tick)) //damage taken is reduced to 2% of this value by fire_act()
diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm
index 8843a811756d7..539237fa3e801 100644
--- a/code/modules/mod/mod_types.dm
+++ b/code/modules/mod/mod_types.dm
@@ -221,6 +221,7 @@
applied_cell = /obj/item/stock_parts/cell/super
applied_modules = list(
/obj/item/mod/module/storage/syndicate,
+ /obj/item/mod/module/shock_absorber,
/obj/item/mod/module/emp_shield,
/obj/item/mod/module/magnetic_harness,
/obj/item/mod/module/jetpack,
@@ -241,6 +242,7 @@
applied_cell = /obj/item/stock_parts/cell/bluespace
applied_modules = list(
/obj/item/mod/module/storage/syndicate,
+ /obj/item/mod/module/shock_absorber,
/obj/item/mod/module/emp_shield,
/obj/item/mod/module/magnetic_harness,
/obj/item/mod/module/jetpack/advanced,
@@ -263,6 +265,7 @@
req_access = list(ACCESS_SYNDICATE)
applied_modules = list(
/obj/item/mod/module/storage/syndicate,
+ /obj/item/mod/module/shock_absorber,
/obj/item/mod/module/emp_shield,
/obj/item/mod/module/magnetic_harness,
/obj/item/mod/module/jetpack/advanced,
@@ -299,6 +302,7 @@
req_access = list(ACCESS_SYNDICATE)
applied_modules = list(
/obj/item/mod/module/storage/syndicate,
+ /obj/item/mod/module/shock_absorber,
/obj/item/mod/module/emp_shield,
/obj/item/mod/module/magnetic_harness,
/obj/item/mod/module/jetpack/advanced,
@@ -316,6 +320,7 @@
/obj/item/mod/control/pre_equipped/elite/flamethrower
applied_modules = list(
/obj/item/mod/module/storage/syndicate,
+ /obj/item/mod/module/shock_absorber,
/obj/item/mod/module/emp_shield,
/obj/item/mod/module/magnetic_harness,
/obj/item/mod/module/thermal_regulator,
diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm
index 87cab74b24f76..3ef6b9558712a 100644
--- a/code/modules/mod/modules/modules_general.dm
+++ b/code/modules/mod/modules/modules_general.dm
@@ -979,3 +979,29 @@
attempt_insert_storage(product)
balloon_alert(mod.wearer, "ammo box dispensed.")
playsound(src, 'sound/machines/microwave/microwave-end.ogg', 50, TRUE)
+
+/obj/item/mod/module/shock_absorber
+ name = "MOD shock absorption module"
+ desc = "A module that makes the user resistant to the knockdown inflicted by Stun Batons."
+ icon_state = "no_baton"
+ complexity = 1
+ use_energy_cost = DEFAULT_CHARGE_DRAIN
+ incompatible_modules = list(/obj/item/mod/module/shock_absorber)
+ required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT)
+
+/obj/item/mod/module/shock_absorber/on_suit_activation()
+ . = ..()
+ ADD_TRAIT(mod.wearer, TRAIT_BATON_RESISTANCE, REF(src))
+ RegisterSignal(mod.wearer, COMSIG_MOB_BATONED, PROC_REF(mob_batoned))
+
+/obj/item/mod/module/shock_absorber/on_suit_deactivation(deleting)
+ . = ..()
+ REMOVE_TRAIT(mod.wearer, TRAIT_BATON_RESISTANCE, REF(src))
+ UnregisterSignal(mod.wearer, COMSIG_MOB_BATONED)
+
+/obj/item/mod/module/shock_absorber/proc/mob_batoned(datum/source)
+ SIGNAL_HANDLER
+ drain_power(use_energy_cost)
+ var/datum/effect_system/lightning_spread/sparks = new /datum/effect_system/lightning_spread
+ sparks.set_up(number = 5, cardinals_only = TRUE, location = mod.wearer.loc)
+ sparks.start()
diff --git a/code/modules/projectiles/ammunition/ballistic/rifle.dm b/code/modules/projectiles/ammunition/ballistic/rifle.dm
index 8e06a0e10b5af..3a7c3fcb59d36 100644
--- a/code/modules/projectiles/ammunition/ballistic/rifle.dm
+++ b/code/modules/projectiles/ammunition/ballistic/rifle.dm
@@ -51,13 +51,61 @@
projectile_type = /obj/projectile/bullet/shotgun_beanbag/a40mm
/obj/item/ammo_casing/rebar
- name = "sharpened iron rod"
+ name = "Sharpened Iron Rod"
desc = "A Sharpened Iron rod. It's Pointy!"
caliber = CALIBER_REBAR
icon_state = "rod_sharp"
base_icon_state = "rod_sharp"
projectile_type = /obj/projectile/bullet/rebar
+/obj/item/ammo_casing/rebar/syndie
+ name = "Jagged Iron Rod"
+ desc = "An Iron rod, with notches cut into it. You really dont want this stuck in you."
+ caliber = CALIBER_REBAR
+ icon_state = "rod_jagged"
+ base_icon_state = "rod_jagged"
+ projectile_type = /obj/projectile/bullet/rebar/syndie
+
+/obj/item/ammo_casing/rebar/zaukerite
+ name = "Zaukerite Sliver"
+ desc = "A sliver of a zaukerite crystal. Due to its irregular, jagged edges, removal of an embedded zaukerite sliver should only be done by trained surgeons."
+ caliber = CALIBER_REBAR
+ icon_state = "rod_zaukerite"
+ base_icon_state = "rod_zaukerite"
+ projectile_type = /obj/projectile/bullet/rebar/zaukerite
+
+/obj/item/ammo_casing/rebar/hydrogen
+ name = "Metallic Hydrogen Bolt"
+ desc = "An ultra-sharp rod made from pure metallic hydrogen. Armor may as well not exist."
+ caliber = CALIBER_REBAR
+ icon_state = "rod_hydrogen"
+ base_icon_state = "rod_hydrogen"
+ projectile_type = /obj/projectile/bullet/rebar/hydrogen
+
+/obj/item/ammo_casing/rebar/healium
+ name = "Healium Crystal Bolt"
+ desc = "Who needs a syringe gun, anyway?"
+ caliber = CALIBER_REBAR
+ icon_state = "rod_healium"
+ base_icon_state = "rod_healium"
+ projectile_type = /obj/projectile/bullet/rebar/healium
+
+/obj/item/ammo_casing/rebar/supermatter
+ name = "Supermatter Bolt"
+ desc = "Wait, how is the bow capable of firing this without dusting?"
+ caliber = CALIBER_REBAR
+ icon_state = "rod_supermatter"
+ base_icon_state = "rod_supermatter"
+ projectile_type = /obj/projectile/bullet/rebar/supermatter
+
+/obj/item/ammo_casing/rebar/paperball
+ name = "Paper Ball"
+ desc = "Doink!"
+ caliber = CALIBER_REBAR
+ icon_state = "paperball"
+ base_icon_state = "paperball"
+ projectile_type = /obj/projectile/bullet/paperball
+
/obj/item/ammo_casing/rebar/Initialize(mapload)
. = ..()
AddElement(/datum/element/caseless, TRUE)
@@ -66,10 +114,3 @@
. = ..()
icon_state = "[base_icon_state]"
-/obj/item/ammo_casing/rebar/syndie
- name = "Jagged iron rod"
- desc = "An Iron rod, with notches cut into it. You really dont want this stuck in you."
- caliber = CALIBER_REBAR_SYNDIE
- icon_state = "rod_jagged"
- base_icon_state = "rod_jagged"
- projectile_type = /obj/projectile/bullet/rebarsyndie
diff --git a/code/modules/projectiles/boxes_magazines/internal/rifle.dm b/code/modules/projectiles/boxes_magazines/internal/rifle.dm
index 52d395725a100..8c6abaa0e7798 100644
--- a/code/modules/projectiles/boxes_magazines/internal/rifle.dm
+++ b/code/modules/projectiles/boxes_magazines/internal/rifle.dm
@@ -54,8 +54,5 @@
/obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/syndie
max_ammo = 3
caliber = CALIBER_REBAR_SYNDIE
- ammo_type = /obj/item/ammo_casing/rebar/syndie
-
-/obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/syndie/normal
- caliber = CALIBER_REBAR_SYNDIE_NORMAL
ammo_type = /obj/item/ammo_casing/rebar
+
diff --git a/code/modules/projectiles/guns/ballistic/rifle.dm b/code/modules/projectiles/guns/ballistic/rifle.dm
index e50d5ce464c89..a8161ddb39612 100644
--- a/code/modules/projectiles/guns/ballistic/rifle.dm
+++ b/code/modules/projectiles/guns/ballistic/rifle.dm
@@ -173,7 +173,8 @@
/obj/item/gun/ballistic/rifle/rebarxbow
name = "Heated Rebar Crossbow"
desc = "Made from an inducer, iron rods, and some wire, this crossbow fires sharpened iron rods, made from the plentiful iron rods found stationwide. \
- Only holds one rod in the magazine - you can craft the crossbow with a crowbar to try and force a second rod in, but risks a misfire, or worse..."
+ Additionally, can fire specialty ammo made from the materials in the atmos crystalizer - zaukerite, metallic hydrogen, and healium crytals all work. \
+ Very slow to reload - you can craft the crossbow with a crowbar to try loosen the crossbar, but risks a misfire, or worse..."
icon = 'icons/obj/weapons/guns/ballistic.dmi'
icon_state = "rebarxbow"
inhand_icon_state = "rebarxbow"
@@ -194,7 +195,7 @@
weapon_weight = WEAPON_HEAVY
initial_caliber = CALIBER_REBAR
accepted_magazine_type = /obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/normal
- fire_sound = 'sound/items/syringeproj.ogg'
+ fire_sound = 'sound/items/xbow_lock.ogg'
can_be_sawn_off = FALSE
tac_reloads = FALSE
var/draw_time = 3 SECONDS
@@ -234,24 +235,22 @@
/obj/item/gun/ballistic/rifle/rebarxbow/forced
name = "Stressed Rebar Crossbow"
- desc = "Some idiot decided that they would risk shooting themselves in the face if it meant they could have a bit more ammo in this crossbow. Hopefully, it was worth it."
+ desc = "Some idiot decided that they would risk shooting themselves in the face if it meant they could have a draw this crossbow a bit faster. Hopefully, it was worth it."
// Feel free to add a recipe to allow you to change it back if you would like, I just wasn't sure if you could have two recipes for the same thing.
can_misfire = TRUE
+ draw_time = 1.5
misfire_probability = 25
accepted_magazine_type = /obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/force
/obj/item/gun/ballistic/rifle/rebarxbow/syndie
name = "Syndicate Rebar Crossbow"
desc = "The syndicate liked the bootleg rebar crossbow NT engineers made, so they showed what it could be if properly developed. \
- Holds three shots without a chance of exploding, and features a built in scope. Normally uses special syndicate jagged iron bars, but can be wrenched to shoot inferior normal ones."
+ Holds three shots without a chance of exploding, and features a built in scope. Compatable with all known crossbow ammunition."
icon_state = "rebarxbowsyndie"
inhand_icon_state = "rebarxbowsyndie"
worn_icon_state = "rebarxbowsyndie"
w_class = WEIGHT_CLASS_NORMAL
- can_modify_ammo = TRUE
- initial_caliber = CALIBER_REBAR_SYNDIE
- alternative_caliber = CALIBER_REBAR_SYNDIE_NORMAL
- alternative_ammo_misfires = FALSE
+ initial_caliber = CALIBER_REBAR
draw_time = 1
accepted_magazine_type = /obj/item/ammo_box/magazine/internal/boltaction/rebarxbow/syndie
diff --git a/code/modules/projectiles/projectile/bullets/rifle.dm b/code/modules/projectiles/projectile/bullets/rifle.dm
index d76b2de9d6ace..e38d7f67496ee 100644
--- a/code/modules/projectiles/projectile/bullets/rifle.dm
+++ b/code/modules/projectiles/projectile/bullets/rifle.dm
@@ -58,20 +58,120 @@
armour_penetration = 10
wound_bonus = -20
bare_wound_bonus = 20
- embedding = list(embed_chance=60, fall_chance=2, jostle_chance=2, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=3, jostle_pain_mult=2, rip_time=10)
+ embedding = list("embed_chance" = 60, "fall_chance" = 2, "jostle_chance" = 2, "ignore_throwspeed_threshold" = TRUE, "pain_stam_pct" = 0.4, "pain_mult" = 4, "jostle_pain_mult" = 2, "rip_time" = 10)
embed_falloff_tile = -5
wound_falloff_tile = -2
- shrapnel_type = /obj/item/stack/rods
+ shrapnel_type = /obj/item/ammo_casing/rebar
-/obj/projectile/bullet/rebarsyndie
+/obj/projectile/bullet/rebar/proc/handle_drop(datum/source, obj/item/ammo_casing/rebar/newcasing)
+
+/obj/projectile/bullet/rebar/syndie
name = "rebar"
icon_state = "rebar"
- damage = 35
+ damage = 55
speed = 0.4
dismemberment = 2 //It's a budget sniper rifle.
armour_penetration = 20 //A bit better versus armor. Gets past anti laser armor or a vest, but doesnt wound proc on sec armor.
wound_bonus = 10
+ bare_wound_bonus = 20
+ embedding = list("embed_chance" = 80, "fall_chance" = 1, "jostle_chance" = 3, "ignore_throwspeed_threshold" = TRUE, "pain_stam_pct" = 0.4, "pain_mult" = 3, "jostle_pain_mult" = 2, "rip_time" = 14)
+ embed_falloff_tile = -3
+ shrapnel_type = /obj/item/ammo_casing/rebar/syndie
+
+/obj/projectile/bullet/rebar/zaukerite
+ name = "zaukerite shard"
+ icon_state = "rebar_zaukerite"
+ damage = 60
+ speed = 0.6
+ dismemberment = 10
+ damage_type = TOX
+ eyeblur = 5
+ armour_penetration = 20 // not nearly as good, as its not as sharp.
+ wound_bonus = 10
+ bare_wound_bonus = 40
+ embedding = list("embed_chance" =100, "fall_chance" = 0, "jostle_chance" = 5, "ignore_throwspeed_threshold" = TRUE, "pain_stam_pct" = 0.8, "pain_mult" = 6, "jostle_pain_mult" = 2, "rip_time" = 30)
+ embed_falloff_tile = 0 // very spiky.
+ shrapnel_type = /obj/item/ammo_casing/rebar/zaukerite
+
+/obj/projectile/bullet/rebar/hydrogen
+ name = "metallic hydrogen bolt"
+ icon_state = "rebar_hydrogen"
+ damage = 40
+ speed = 0.6
+ dismemberment = 0 //goes through clean.
+ damage_type = BRUTE
+ armour_penetration = 30 //very pointy.
+ projectile_piercing = PASSMOB //felt this might have been a nice compromise for the lower damage for the difficulty of getting it
+ wound_bonus = -15
bare_wound_bonus = 10
- embedding = list(embed_chance=80, fall_chance=1, jostle_chance=3, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=3, jostle_pain_mult=2, rip_time=14)
+ embedding = list("embed_chance" = 50, "fall_chance" = 2, "jostle_chance" = 3, "ignore_throwspeed_threshold" = TRUE, "pain_stam_pct" = 0.6, "pain_mult" = 4, "jostle_pain_mult" = 2, "rip_time" =18)
+ embed_falloff_tile = -3
+ shrapnel_type = /obj/item/ammo_casing/rebar/hydrogen
+
+/obj/projectile/bullet/rebar/healium
+ name = "healium bolt"
+ icon_state = "rebar_healium"
+ damage = 0
+ speed = 0.4
+ dismemberment = 0
+ damage_type = BRUTE
+ armour_penetration = 100
+ wound_bonus = -100
+ bare_wound_bonus = -100
+ embedding = list(embed_chance = 0)
embed_falloff_tile = -3
- shrapnel_type = /obj/item/stack/rods
+ shrapnel_type = /obj/item/ammo_casing/rebar/healium
+
+/obj/projectile/bullet/rebar/healium/on_hit(atom/target, blocked = 0, pierce_hit)
+ . = ..()
+ if(!isliving(target))
+ return BULLET_ACT_HIT
+ var/mob/living/breather = target
+ breather.SetSleeping(3 SECONDS)
+ breather.adjustFireLoss(-30, updating_health = TRUE, required_bodytype = BODYTYPE_ORGANIC)
+ breather.adjustToxLoss(-30, updating_health = TRUE, required_biotype = BODYTYPE_ORGANIC)
+ breather.adjustBruteLoss(-30, updating_health = TRUE, required_bodytype = BODYTYPE_ORGANIC)
+ breather.adjustOxyLoss(-30, updating_health = TRUE, required_biotype = BODYTYPE_ORGANIC, required_respiration_type = ALL)
+
+ return BULLET_ACT_HIT
+
+
+/obj/projectile/bullet/rebar/supermatter
+ name = "supermatter bolt"
+ icon_state = "rebar_supermatter"
+ damage = 0
+ speed = 0.4
+ dismemberment = 0
+ damage_type = TOX
+ armour_penetration = 100
+ shrapnel_type = /obj/item/ammo_casing/rebar/supermatter
+
+/obj/projectile/bullet/rebar/supermatter/on_hit(atom/target, blocked = 0, pierce_hit)
+ . = ..()
+ if(isliving(target))
+ var/mob/living/victim = target
+ victim.investigate_log("has been dusted by [src].", INVESTIGATE_DEATHS)
+ dust_feedback(target)
+ victim.dust()
+
+ else if(!isturf(target)&& !isliving(target))
+ dust_feedback(target)
+ qdel(target)
+
+ return BULLET_ACT_HIT
+
+
+/obj/projectile/bullet/rebar/supermatter/proc/dust_feedback(atom/target)
+ playsound(get_turf(src), 'sound/effects/supermatter.ogg', 10, TRUE)
+ visible_message(span_danger("[target] is hit by [src], turning [target.p_them()] to dust in a brilliant flash of light!"))
+
+/obj/projectile/bullet/paperball
+ desc = "Doink!"
+ damage = 1 // It's a damn toy.
+ range = 10
+ shrapnel_type = null
+ embedding = null
+ name = "paper ball"
+ desc = "doink!"
+ damage_type = BRUTE
+ icon_state = "paperball"
diff --git a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm
index 7e47586e20c3b..680cced458d91 100644
--- a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm
@@ -33,13 +33,14 @@
var/need_mob_update = FALSE
switch(affected_mob.stat)
if(CONSCIOUS) //bad
- thou_shall_heal = death_is_coming/50
+ thou_shall_heal = max(death_is_coming/20, 3)
need_mob_update += affected_mob.adjustOxyLoss(2 * REM * seconds_per_tick, TRUE, required_biotype = affected_biotype, required_respiration_type = affected_respiration_type)
if(SOFT_CRIT) //meh convert
- thou_shall_heal = round(death_is_coming/47,0.1)
+ thou_shall_heal = round(death_is_coming/13,0.1)
need_mob_update += affected_mob.adjustOxyLoss(1 * REM * seconds_per_tick, TRUE, required_biotype = affected_biotype, required_respiration_type = affected_respiration_type)
+ good_kind_of_healing = TRUE
else //no convert
- thou_shall_heal = round(death_is_coming/45, 0.1)
+ thou_shall_heal = round(death_is_coming/10, 0.1)
good_kind_of_healing = TRUE
need_mob_update += affected_mob.adjustBruteLoss(-thou_shall_heal * REM * seconds_per_tick, FALSE, required_bodytype = affected_bodytype)
if(need_mob_update)
@@ -91,6 +92,12 @@
if(helbent)
affected_mob.remove_status_effect(/datum/status_effect/necropolis_curse)
+/datum/reagent/medicine/c2/helbital/on_mob_end_metabolize(mob/living/affected_mob)
+ . = ..()
+ if(current_cycle >= 50) //greater than 10u in the system
+ affected_mob.AddComponent(/datum/component/omen, incidents_left = min(round(current_cycle/51), 3)) //no more than 3 bad incidents for dropping more than 10u
+ to_chat(affected_mob, span_hierophant_warning("You feel a sense of heavy dread and grave misfortune settle in as the substance leaves your body."))
+
/datum/reagent/medicine/c2/libital //messes with your liber
name = "Libital"
description = "A bruise reliever. Does minor liver damage."
@@ -124,7 +131,7 @@
/datum/reagent/medicine/c2/probital/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired)
. = ..()
var/need_mob_update
- need_mob_update = affected_mob.adjustBruteLoss(-2.25 * REM * normalise_creation_purity() * seconds_per_tick, updating_health = FALSE, required_bodytype = affected_bodytype)
+ need_mob_update = affected_mob.adjustBruteLoss(-3 * REM * normalise_creation_purity() * seconds_per_tick, updating_health = FALSE, required_bodytype = affected_bodytype)
var/ooo_youaregettingsleepy = 3.5
switch(round(affected_mob.getStaminaLoss()))
if(10 to 40)
@@ -177,7 +184,7 @@
/datum/reagent/medicine/c2/lenturi/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired)
. = ..()
var/need_mob_update
- need_mob_update = affected_mob.adjustFireLoss(-3 * REM * normalise_creation_purity() * seconds_per_tick, required_bodytype = affected_bodytype)
+ need_mob_update = affected_mob.adjustFireLoss(-3.75 * REM * normalise_creation_purity() * seconds_per_tick, required_bodytype = affected_bodytype)
need_mob_update += affected_mob.adjustOrganLoss(ORGAN_SLOT_STOMACH, 0.4 * REM * seconds_per_tick, required_organ_flag = affected_organ_flags)
if(need_mob_update)
return UPDATE_MOB_HEALTH
@@ -218,9 +225,9 @@
. = ..()
var/need_mob_update
if(affected_mob.getFireLoss() > 50)
- need_mob_update = affected_mob.adjustFireLoss(-2 * REM * seconds_per_tick * normalise_creation_purity(), updating_health = FALSE, required_bodytype = affected_bodytype)
+ need_mob_update = affected_mob.adjustFireLoss(-3 * REM * seconds_per_tick * normalise_creation_purity(), updating_health = FALSE, required_bodytype = affected_bodytype)
else
- need_mob_update = affected_mob.adjustFireLoss(-1.25 * REM * seconds_per_tick * normalise_creation_purity(), updating_health = FALSE, required_bodytype = affected_bodytype)
+ need_mob_update = affected_mob.adjustFireLoss(-2.25 * REM * seconds_per_tick * normalise_creation_purity(), updating_health = FALSE, required_bodytype = affected_bodytype)
affected_mob.adjust_bodytemperature(rand(-25,-5) * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, 50)
if(ishuman(affected_mob))
var/mob/living/carbon/human/humi = affected_mob
@@ -289,7 +296,7 @@
color = "#FF6464"
ph = 5.6
inverse_chem = /datum/reagent/inverse/healing/tirimol
- inverse_chem_val = 0.4
+ inverse_chem_val = 0.25
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
/// A cooldown for spacing bursts of stamina damage
@@ -298,7 +305,7 @@
/datum/reagent/medicine/c2/tirimol/on_mob_life(mob/living/carbon/human/affected_mob, seconds_per_tick, times_fired)
. = ..()
var/need_mob_update
- need_mob_update = affected_mob.adjustOxyLoss(-3 * REM * seconds_per_tick * normalise_creation_purity(), updating_health = FALSE, required_biotype = affected_biotype, required_respiration_type = affected_respiration_type)
+ need_mob_update = affected_mob.adjustOxyLoss(-4.5 * REM * seconds_per_tick * normalise_creation_purity(), updating_health = FALSE, required_biotype = affected_biotype, required_respiration_type = affected_respiration_type)
need_mob_update += affected_mob.adjustStaminaLoss(2 * REM * seconds_per_tick, updating_stamina = FALSE, required_biotype = affected_biotype)
if(drowsycd && COOLDOWN_FINISHED(src, drowsycd))
affected_mob.adjust_drowsiness(20 SECONDS)
@@ -415,8 +422,8 @@
if(!(methods & INJECT) || !iscarbon(A))
return
var/mob/living/carbon/C = A
- if(trans_volume >= 0.6) //prevents cheesing with ultralow doses.
- C.adjustToxLoss((-1.5 * min(2, trans_volume) * REM) * normalise_creation_purity(), required_biotype = affected_biotype) //This is to promote iv pole use for that chemotherapy feel.
+ if(trans_volume >= 0.4) //prevents cheesing with ultralow doses.
+ C.adjustToxLoss((-3 * min(2, trans_volume) * REM) * normalise_creation_purity(), required_biotype = affected_biotype) //This is to promote iv pole use for that chemotherapy feel.
var/obj/item/organ/internal/liver/L = C.organs_slot[ORGAN_SLOT_LIVER]
if(!L || L.organ_flags & ORGAN_FAILING)
return
@@ -429,7 +436,7 @@
. = ..()
var/need_mob_update
need_mob_update = affected_mob.adjustOrganLoss(ORGAN_SLOT_LIVER, 0.8 * REM * seconds_per_tick, required_organ_flag = affected_organ_flags)
- need_mob_update += affected_mob.adjustToxLoss(-1 * REM * seconds_per_tick, updating_health = FALSE, required_biotype = affected_biotype)
+ need_mob_update += affected_mob.adjustToxLoss(-2 * REM * seconds_per_tick, updating_health = FALSE, required_biotype = affected_biotype)
for(var/datum/reagent/R in affected_mob.reagents.reagent_list)
if(issyrinormusc(R))
continue
@@ -460,7 +467,7 @@
. = ..()
var/need_mob_update
need_mob_update = affected_mob.adjustOrganLoss(ORGAN_SLOT_LIVER, 0.1 * REM * seconds_per_tick, required_organ_flag = affected_organ_flags)
- need_mob_update += affected_mob.adjustToxLoss(-1 * REM * seconds_per_tick * normalise_creation_purity(), updating_health = FALSE, required_biotype = affected_biotype)
+ need_mob_update += affected_mob.adjustToxLoss(-1.5 * REM * seconds_per_tick * normalise_creation_purity(), updating_health = FALSE, required_biotype = affected_biotype)
for(var/datum/reagent/R in affected_mob.reagents.reagent_list)
if(issyrinormusc(R))
continue
diff --git a/code/modules/reagents/chemistry/recipes/cat2_medicines.dm b/code/modules/reagents/chemistry/recipes/cat2_medicines.dm
index 376a805e7d697..28aeb5743faaa 100644
--- a/code/modules/reagents/chemistry/recipes/cat2_medicines.dm
+++ b/code/modules/reagents/chemistry/recipes/cat2_medicines.dm
@@ -209,11 +209,11 @@
/datum/chemical_reaction/medicine/tirimol
results = list(/datum/reagent/medicine/c2/tirimol = 5)
required_reagents = list(/datum/reagent/nitrogen = 3, /datum/reagent/acetone = 2)
- required_catalysts = list(/datum/reagent/toxin/acid = 1)
+ required_catalysts = list(/datum/reagent/toxin/acid = 1, /datum/reagent/oxygen = 1)
mix_message = "The mixture turns into a tired reddish pink liquid."
optimal_temp = 900
overheat_temp = 720
- optimal_ph_min = 2
+ optimal_ph_min = 5
optimal_ph_max = 7.1
determin_ph_range = 2
temp_exponent_factor = 4
@@ -225,14 +225,6 @@
reaction_flags = REACTION_PH_VOL_CONSTANT
reaction_tags = REACTION_TAG_EASY | REACTION_TAG_HEALING | REACTION_TAG_OXY
-/datum/chemical_reaction/medicine/tirimol/reaction_step(datum/reagents/holder, datum/equilibrium/reaction, delta_t, delta_ph, step_reaction_vol)
- . = ..()
- var/datum/reagent/oxy = holder.has_reagent(/datum/reagent/oxygen)
- if(oxy)
- holder.remove_reagent(/datum/reagent/oxygen, 0.25)
- else
- holder.adjust_all_reagents_ph(-0.05*step_reaction_vol)//pH drifts faster
-
//Sleepytime for chem
/datum/chemical_reaction/medicine/tirimol/overheated(datum/reagents/holder, datum/equilibrium/equilibrium, impure = FALSE)
var/bonus = impure ? 2 : 1
diff --git a/code/modules/reagents/reagent_containers/cups/bottle.dm b/code/modules/reagents/reagent_containers/cups/bottle.dm
index 75bc79c5a6aaa..0b47a89e4b2a0 100644
--- a/code/modules/reagents/reagent_containers/cups/bottle.dm
+++ b/code/modules/reagents/reagent_containers/cups/bottle.dm
@@ -59,6 +59,11 @@
desc = "A small bottle of multiver, which removes toxins and other chemicals from the bloodstream but causes shortness of breath. All effects scale with the amount of reagents in the patient."
list_reagents = list(/datum/reagent/medicine/c2/multiver = 30)
+/obj/item/reagent_containers/cup/bottle/calomel
+ name = "calomel bottle"
+ desc = "A small bottle of calomel, a toxic drug which quickly removes chemicals from the bloodstream. Does not cause additional harm in heavily-injured people."
+ list_reagents = list(/datum/reagent/medicine/calomel = 30)
+
/obj/item/reagent_containers/cup/bottle/phlogiston
name = "Phlogiston bottle"
desc = "A small bottle of Phlogiston, that will set you on fire if used."
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index 98ba3a13ed2eb..c4c3003d768e6 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -162,7 +162,7 @@
name = "mutadone pill"
desc = "Used to treat genetic damage."
icon_state = "pill20"
- list_reagents = list(/datum/reagent/medicine/mutadone = 50)
+ list_reagents = list(/datum/reagent/medicine/mutadone = 5)
rename_with_volume = TRUE
/obj/item/reagent_containers/pill/salicylic
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 36424f22cbdf0..83f71ff69b0ab 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -173,6 +173,11 @@
desc = "Contains multiver. Diluted with granibitaluri."
list_reagents = list(/datum/reagent/medicine/c2/multiver = 6, /datum/reagent/medicine/granibitaluri = 9)
+/obj/item/reagent_containers/syringe/calomel
+ name = "syringe (calomel)"
+ desc = "Contains calomel - a toxic drug for rapidly removing chemicals from the body."
+ list_reagents = list(/datum/reagent/medicine/calomel = 15)
+
/obj/item/reagent_containers/syringe/convermol
name = "syringe (convermol)"
desc = "Contains convermol. Diluted with granibitaluri."
diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm
index f4308a8bc5408..0583269f1c6be 100644
--- a/code/modules/research/designs/mechfabricator_designs.dm
+++ b/code/modules/research/designs/mechfabricator_designs.dm
@@ -2605,3 +2605,21 @@
category = list(
RND_CATEGORY_MODSUIT_MODULES + RND_SUBCATEGORY_MODSUIT_MODULES_ENGINEERING
)
+
+/datum/design/posisphere
+ name = "Positronic Sphere"
+ desc = "The latest in Artificial Pesterance."
+ id = "posisphere"
+ build_type = MECHFAB
+ materials = list(
+ /datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT * 0.85,
+ /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT * 0.65,
+ /datum/material/gold =SMALL_MATERIAL_AMOUNT * 2.5
+ )
+ construction_time = 7.5 SECONDS
+ build_path = /obj/item/mmi/posibrain/sphere
+ category = list(
+ RND_CATEGORY_MECHFAB_CYBORG + RND_SUBCATEGORY_MECHFAB_CYBORG_CONTROL_INTERFACES
+ )
+ departmental_flags = DEPARTMENT_BITFLAG_SCIENCE
+
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index cb1ec6bb1ccc1..a8ce5f274eb14 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -2468,3 +2468,30 @@
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
hidden = TRUE
experimental = TRUE
+
+/datum/techweb_node/mod_experimental
+ id = "mod_experimental"
+ display_name = "Experimental Modular Suits"
+ description = "Applications of experimentality when creating MODsuits have created these..."
+ prereq_ids = list("base")
+ design_ids = list(
+ "mod_disposal",
+ "mod_joint_torsion",
+ "mod_recycler",
+ "mod_shooting",
+ )
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
+ hidden = TRUE
+ experimental = TRUE
+
+/datum/techweb_node/posisphere
+ id = "positronic_sphere"
+ display_name = "Experimental Spherical Positronic Brain"
+ description = "Recent developments on cost-cutting measures have allowed us to cut positronic brain cubes into twice-as-cheap spheres. Unfortunately, it also allows them to move around the lab via rolling maneuvers."
+ prereq_ids = list("base")
+ design_ids = list(
+ "posisphere",
+ )
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
+ hidden = TRUE
+ experimental = TRUE
diff --git a/code/modules/surgery/advanced/lobotomy.dm b/code/modules/surgery/advanced/lobotomy.dm
index 6c322c2d0705e..22cba90753826 100644
--- a/code/modules/surgery/advanced/lobotomy.dm
+++ b/code/modules/surgery/advanced/lobotomy.dm
@@ -48,7 +48,7 @@
span_notice("[user] begins to perform a lobotomy on [target]'s brain."),
span_notice("[user] begins to perform surgery on [target]'s brain."),
)
- display_pain(target, "Your head pounds with unimaginable pain!")
+ display_pain(target, "Your head pounds with unimaginable pain!", mood_event_type = /datum/mood_event/surgery)
/datum/surgery_step/lobotomize/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
display_results(
@@ -58,7 +58,7 @@
span_notice("[user] successfully lobotomizes [target]!"),
span_notice("[user] completes the surgery on [target]'s brain."),
)
- display_pain(target, "Your head goes totally numb for a moment, the pain is overwhelming!")
+ display_pain(target, "Your head goes totally numb for a moment, the pain is overwhelming!", mood_event_type = /datum/mood_event/surgery/success)
target.cure_all_traumas(TRAUMA_RESILIENCE_LOBOTOMY)
if(target.mind && target.mind.has_antag_datum(/datum/antagonist/brainwashed))
@@ -86,7 +86,7 @@
span_notice("[user] successfully lobotomizes [target]!"),
span_notice("[user] completes the surgery on [target]'s brain."),
)
- display_pain(target, "The pain in your head only seems to get worse!")
+ display_pain(target, "The pain in your head only seems to get worse!", mood_event_type = /datum/mood_event/surgery/failure)
target_brain.apply_organ_damage(80)
switch(rand(1,3))
if(1)
diff --git a/code/modules/surgery/amputation.dm b/code/modules/surgery/amputation.dm
index c4dc91810c14f..4b4f9aede8347 100644
--- a/code/modules/surgery/amputation.dm
+++ b/code/modules/surgery/amputation.dm
@@ -47,7 +47,7 @@
span_notice("[user] begins to sever [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
span_notice("[user] begins to sever [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
)
- display_pain(target, "You feel a gruesome pain in your [parse_zone(target_zone)]'s joint!")
+ display_pain(target, "You feel a gruesome pain in your [parse_zone(target_zone)]'s joint!", mood_event_type = /datum/mood_event/surgery)
/datum/surgery_step/sever_limb/success(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
@@ -58,7 +58,7 @@
span_notice("[user] severs [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
span_notice("[user] severs [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
)
- display_pain(target, "You can no longer feel your severed [target.parse_zone_with_bodypart(target_zone)]!")
+ display_pain(target, "You can no longer feel your severed [target.parse_zone_with_bodypart(target_zone)]!", mood_event_type = /datum/mood_event/surgery/success)
if(HAS_MIND_TRAIT(user, TRAIT_MORBID) && ishuman(user))
var/mob/living/carbon/human/morbid_weirdo = user
@@ -68,3 +68,7 @@
var/obj/item/bodypart/target_limb = surgery.operated_bodypart
target_limb.drop_limb()
return ..()
+
+/datum/surgery_step/sever_limb/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, fail_prob)
+ display_pain(target, mood_event_type = /datum/mood_event/surgery/failure)
+ return ..()
diff --git a/code/modules/surgery/burn_dressing.dm b/code/modules/surgery/burn_dressing.dm
index cde9b7b29807c..2ad5bf368d3cb 100644
--- a/code/modules/surgery/burn_dressing.dm
+++ b/code/modules/surgery/burn_dressing.dm
@@ -83,7 +83,7 @@
span_notice("[user] begins to excise infected flesh from [target]'s [target.parse_zone_with_bodypart(user.zone_selected)] with [tool]."),
span_notice("[user] begins to excise infected flesh from [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."),
)
- display_pain(target, "The infection in your [target.parse_zone_with_bodypart(user.zone_selected)] stings like hell! It feels like you're being stabbed!")
+ display_pain(target, "The infection in your [target.parse_zone_with_bodypart(user.zone_selected)] stings like hell! It feels like you're being stabbed!", mood_event_type = /datum/mood_event/surgery)
else
user.visible_message(span_notice("[user] looks for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."), span_notice("You look for [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]..."))
@@ -98,6 +98,7 @@
span_notice("[user] successfully excises some of the infected flesh from [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"),
span_notice("[user] successfully excises some of the infected flesh from [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
)
+ display_pain(target, mood_event_type = /datum/mood_event/surgery/success)
log_combat(user, target, "excised infected flesh in", addition="COMBAT MODE: [uppertext(user.combat_mode)]")
surgery.operated_bodypart.receive_damage(brute=3, wound_bonus=CANT_WOUND)
burn_wound.infestation -= infestation_removed
@@ -117,6 +118,7 @@
span_notice("[user] carves away some of the healthy flesh from [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"),
span_notice("[user] carves away some of the healthy flesh from [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
)
+ display_pain(target, mood_event_type = /datum/mood_event/surgery/failure)
surgery.operated_bodypart.receive_damage(brute=rand(4,8), sharpness=TRUE)
/datum/surgery_step/debride/initiate(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE)
diff --git a/code/modules/surgery/coronary_bypass.dm b/code/modules/surgery/coronary_bypass.dm
index af08987fd9398..19528fe6b5c81 100644
--- a/code/modules/surgery/coronary_bypass.dm
+++ b/code/modules/surgery/coronary_bypass.dm
@@ -40,7 +40,7 @@
span_notice("[user] begins to make an incision in [target]'s heart."),
span_notice("[user] begins to make an incision in [target]'s heart."),
)
- display_pain(target, "You feel a horrendous pain in your heart, it's almost enough to make you pass out!")
+ display_pain(target, "You feel a horrendous pain in your heart, it's almost enough to make you pass out!", mood_event_type = /datum/mood_event/surgery)
/datum/surgery_step/incise_heart/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
if(ishuman(target))
@@ -53,6 +53,7 @@
span_notice("Blood pools around the incision in [target_human]'s heart."),
span_notice("Blood pools around the incision in [target_human]'s heart."),
)
+ display_pain(target, mood_event_type = /datum/mood_event/surgery/success)
var/obj/item/bodypart/target_bodypart = target_human.get_bodypart(target_zone)
target_bodypart.adjustBleedStacks(10)
target_human.adjustBruteLoss(10)
@@ -68,6 +69,7 @@
span_warning("[user] screws up, causing blood to spurt out of [target_human]'s chest!"),
span_warning("[user] screws up, causing blood to spurt out of [target_human]'s chest!"),
)
+ display_pain(target, mood_event_type = /datum/mood_event/surgery/failure)
var/obj/item/bodypart/target_bodypart = target_human.get_bodypart(target_zone)
target_bodypart.adjustBleedStacks(10)
target_human.adjustOrganLoss(ORGAN_SLOT_HEART, 10)
diff --git a/code/modules/surgery/gastrectomy.dm b/code/modules/surgery/gastrectomy.dm
index a86805e3e5825..80396b04ab7e5 100644
--- a/code/modules/surgery/gastrectomy.dm
+++ b/code/modules/surgery/gastrectomy.dm
@@ -42,7 +42,7 @@
span_notice("[user] begins to make an incision in [target]."),
span_notice("[user] begins to make an incision in [target]."),
)
- display_pain(target, "You feel a horrible stab in your gut!")
+ display_pain(target, "You feel a horrible stab in your gut!", mood_event_type = /datum/mood_event/surgery)
/datum/surgery_step/gastrectomy/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
var/mob/living/carbon/human/target_human = target
@@ -57,7 +57,7 @@
span_notice("[user] successfully removes the damaged part of [target]'s stomach."),
span_notice("[user] successfully removes the damaged part of [target]'s stomach."),
)
- display_pain(target, "The pain in your gut ebbs and fades somewhat.")
+ display_pain(target, "The pain in your gut ebbs and fades somewhat.", mood_event_type = /datum/mood_event/surgery/success)
return ..()
/datum/surgery_step/gastrectomy/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery)
@@ -70,4 +70,4 @@
span_warning("[user] cuts the wrong part of [target]'s stomach!"),
span_warning("[user] cuts the wrong part of [target]'s stomach!"),
)
- display_pain(target, "Your stomach throbs with pain; it's not getting any better!")
+ display_pain(target, "Your stomach throbs with pain; it's not getting any better!", mood_event_type = /datum/mood_event/surgery/failure)
diff --git a/code/modules/surgery/hepatectomy.dm b/code/modules/surgery/hepatectomy.dm
index 934e6589e9df5..a79499627c506 100644
--- a/code/modules/surgery/hepatectomy.dm
+++ b/code/modules/surgery/hepatectomy.dm
@@ -41,7 +41,7 @@
span_notice("[user] begins to make an incision in [target]."),
span_notice("[user] begins to make an incision in [target]."),
)
- display_pain(target, "Your abdomen burns in horrific stabbing pain!")
+ display_pain(target, "Your abdomen burns in horrific stabbing pain!", mood_event_type = /datum/mood_event/surgery)
/datum/surgery_step/hepatectomy/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
var/mob/living/carbon/human/human_target = target
@@ -56,7 +56,7 @@
span_notice("[user] successfully removes the damaged part of [target]'s liver."),
span_notice("[user] successfully removes the damaged part of [target]'s liver."),
)
- display_pain(target, "The pain receeds slightly.")
+ display_pain(target, "The pain receeds slightly.", mood_event_type = /datum/mood_event/surgery/success)
return ..()
/datum/surgery_step/hepatectomy/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery)
@@ -69,4 +69,4 @@
span_warning("[user] cuts the wrong part of [target]'s liver!"),
span_warning("[user] cuts the wrong part of [target]'s liver!"),
)
- display_pain(target, "You feel a sharp stab inside your abdomen!")
+ display_pain(target, "You feel a sharp stab inside your abdomen!", mood_event_type = /datum/mood_event/surgery/failure)
diff --git a/code/modules/surgery/lipoplasty.dm b/code/modules/surgery/lipoplasty.dm
index 0e5bfb97785e8..870c53aeed7ac 100644
--- a/code/modules/surgery/lipoplasty.dm
+++ b/code/modules/surgery/lipoplasty.dm
@@ -38,7 +38,7 @@
span_notice("[user] begins to cut away [target]'s excess fat."),
span_notice("[user] begins to cut [target]'s [target_zone] with [tool]."),
)
- display_pain(target, "You feel a stabbing in your [target_zone]!")
+ display_pain(target, "You feel a stabbing in your [target_zone]!", mood_event_type = /datum/mood_event/surgery)
/datum/surgery_step/cut_fat/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results)
display_results(
@@ -48,9 +48,13 @@
span_notice("[user] cuts [target]'s excess fat loose!"),
span_notice("[user] finishes the cut on [target]'s [target_zone]."),
)
- display_pain(target, "The fat in your [target_zone] comes loose, dangling and hurting like hell!")
+ display_pain(target, "The fat in your [target_zone] comes loose, dangling and hurting like hell!", mood_event_type = /datum/mood_event/surgery/success)
return TRUE
+/datum/surgery_step/cut_fat/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, fail_prob)
+ display_pain(target, mood_event_type = /datum/mood_event/surgery/failure)
+ return ..()
+
//remove fat
/datum/surgery_step/remove_fat
name = "remove loose fat (retractor)"
diff --git a/code/modules/surgery/lobectomy.dm b/code/modules/surgery/lobectomy.dm
index 83f9279818b8d..07c96e7125a6b 100644
--- a/code/modules/surgery/lobectomy.dm
+++ b/code/modules/surgery/lobectomy.dm
@@ -39,7 +39,7 @@
span_notice("[user] begins to make an incision in [target]."),
span_notice("[user] begins to make an incision in [target]."),
)
- display_pain(target, "You feel a stabbing pain in your chest!")
+ display_pain(target, "You feel a stabbing pain in your chest!", mood_event_type = /datum/mood_event/surgery)
/datum/surgery_step/lobectomy/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
if(ishuman(target))
@@ -54,7 +54,7 @@
span_notice("Successfully removes a piece of [human_target]'s lungs."),
"",
)
- display_pain(target, "Your chest hurts like hell, but breathing becomes slightly easier.")
+ display_pain(target, "Your chest hurts like hell, but breathing becomes slightly easier.", mood_event_type = /datum/mood_event/surgery/success)
return ..()
/datum/surgery_step/lobectomy/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
@@ -67,7 +67,7 @@
span_warning("[user] screws up!"),
span_warning("[user] screws up!"),
)
- display_pain(target, "You feel a sharp stab in your chest; the wind is knocked out of you and it hurts to catch your breath!")
+ display_pain(target, "You feel a sharp stab in your chest; the wind is knocked out of you and it hurts to catch your breath!", mood_event_type = /datum/mood_event/surgery/failure)
human_target.losebreath += 4
human_target.adjustOrganLoss(ORGAN_SLOT_LUNGS, 10)
return FALSE
diff --git a/code/modules/surgery/organic_steps.dm b/code/modules/surgery/organic_steps.dm
index a307d00dbba65..299bedfc5b331 100644
--- a/code/modules/surgery/organic_steps.dm
+++ b/code/modules/surgery/organic_steps.dm
@@ -20,7 +20,7 @@
span_notice("[user] begins to make an incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]."),
span_notice("[user] begins to make an incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]."),
)
- display_pain(target, "You feel a stabbing in your [target.parse_zone_with_bodypart(target_zone)].")
+ display_pain(target, "You feel a stabbing in your [target.parse_zone_with_bodypart(target_zone)].", mood_event_type = /datum/mood_event/surgery)
/datum/surgery_step/incise/tool_check(mob/user, obj/item/tool)
if(implement_type == /obj/item && !tool.get_sharpness())
@@ -39,11 +39,16 @@
span_notice("Blood pools around the incision in [human_target]'s [target.parse_zone_with_bodypart(target_zone)]."),
span_notice("Blood pools around the incision in [human_target]'s [target.parse_zone_with_bodypart(target_zone)]."),
)
+ display_pain(target, mood_event_type = /datum/mood_event/surgery/success)
var/obj/item/bodypart/target_bodypart = target.get_bodypart(target_zone)
if(target_bodypart)
target_bodypart.adjustBleedStacks(10)
return ..()
+/datum/surgery_step/incise/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, fail_prob)
+ display_pain(target, mood_event_type = /datum/mood_event/surgery/failure)
+ return ..()
+
/datum/surgery_step/incise/nobleed/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
display_results(
user,
@@ -52,7 +57,7 @@
span_notice("[user] begins to carefully make an incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]."),
span_notice("[user] begins to carefully make an incision in [target]'s [target.parse_zone_with_bodypart(target_zone)]."),
)
- display_pain(target, "You feel a careful stabbing in your [target.parse_zone_with_bodypart(target_zone)].")
+ display_pain(target, "You feel a careful stabbing in your [target.parse_zone_with_bodypart(target_zone)].", mood_event_type = /datum/mood_event/surgery)
//clamp bleeders
/datum/surgery_step/clamp_bleeders
@@ -177,7 +182,7 @@
span_notice("[user] begins to saw through the bone in [target]'s [target.parse_zone_with_bodypart(target_zone)]."),
span_notice("[user] begins to saw through the bone in [target]'s [target.parse_zone_with_bodypart(target_zone)]."),
)
- display_pain(target, "You feel a horrid ache spread through the inside of your [target.parse_zone_with_bodypart(target_zone)]!")
+ display_pain(target, "You feel a horrid ache spread through the inside of your [target.parse_zone_with_bodypart(target_zone)]!", mood_event_type = /datum/mood_event/surgery)
/datum/surgery_step/saw/tool_check(mob/user, obj/item/tool)
if(implement_type == /obj/item && !(tool.get_sharpness() && (tool.force >= 10)))
@@ -193,7 +198,11 @@
span_notice("[user] saws [target]'s [target.parse_zone_with_bodypart(target_zone)] open!"),
span_notice("[user] saws [target]'s [target.parse_zone_with_bodypart(target_zone)] open!"),
)
- display_pain(target, "It feels like something just broke in your [target.parse_zone_with_bodypart(target_zone)]!")
+ display_pain(target, "It feels like something just broke in your [target.parse_zone_with_bodypart(target_zone)]!", mood_event_type = /datum/mood_event/surgery/success)
+ return ..()
+
+/datum/surgery_step/saw/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, fail_prob)
+ display_pain(target, mood_event_type = /datum/mood_event/surgery/failure)
return ..()
//drill bone
diff --git a/code/modules/surgery/plastic_surgery.dm b/code/modules/surgery/plastic_surgery.dm
index 90357f7b2e497..ab0d502039d53 100644
--- a/code/modules/surgery/plastic_surgery.dm
+++ b/code/modules/surgery/plastic_surgery.dm
@@ -70,7 +70,7 @@
span_notice("[user] begins to alter [target]'s appearance."),
span_notice("[user] begins to make an incision in [target]'s face."),
)
- display_pain(target, "You feel slicing pain across your face!")
+ display_pain(target, "You feel slicing pain across your face!", mood_event_type = /datum/mood_event/surgery)
/datum/surgery_step/reshape_face/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
if(HAS_TRAIT_FROM(target, TRAIT_DISFIGURED, TRAIT_GENERIC))
@@ -82,7 +82,7 @@
span_notice("[user] successfully restores [target]'s appearance!"),
span_notice("[user] finishes the operation on [target]'s face."),
)
- display_pain(target, "The pain fades, your face feels normal again!")
+ display_pain(target, "The pain fades, your face feels normal again!", mood_event_type = /datum/mood_event/surgery/success)
else
var/list/names = list()
if(!isabductor(user))
@@ -112,7 +112,7 @@
span_notice("[user] alters [oldname]'s appearance completely, [target.p_they()] is now [newname]!"),
span_notice("[user] finishes the operation on [target]'s face."),
)
- display_pain(target, "The pain fades, your face feels new and unfamiliar!")
+ display_pain(target, "The pain fades, your face feels new and unfamiliar!", mood_event_type = /datum/mood_event/surgery/failure)
if(ishuman(target))
var/mob/living/carbon/human/human_target = target
human_target.sec_hud_set_ID()
diff --git a/code/modules/surgery/repair_puncture.dm b/code/modules/surgery/repair_puncture.dm
index 31a61a8827986..601d27269eded 100644
--- a/code/modules/surgery/repair_puncture.dm
+++ b/code/modules/surgery/repair_puncture.dm
@@ -65,7 +65,7 @@
span_notice("[user] begins to realign the torn blood vessels in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)] with [tool]."),
span_notice("[user] begins to realign the torn blood vessels in [target]'s [target.parse_zone_with_bodypart(user.zone_selected)]."),
)
- display_pain(target, "You feel a horrible stabbing pain in your [target.parse_zone_with_bodypart(user.zone_selected)]!")
+ display_pain(target, "You feel a horrible stabbing pain in your [target.parse_zone_with_bodypart(user.zone_selected)]!", mood_event_type = /datum/mood_event/surgery)
/datum/surgery_step/repair_innards/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
var/datum/wound/pierce/bleed/pierce_wound = surgery.operated_wound
@@ -80,6 +80,7 @@
span_notice("[user] successfully realigns some of the blood vessels in [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"),
span_notice("[user] successfully realigns some of the blood vessels in [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
)
+ display_pain(target, mood_event_type = /datum/mood_event/surgery/success)
log_combat(user, target, "excised infected flesh in", addition="COMBAT MODE: [uppertext(user.combat_mode)]")
surgery.operated_bodypart.receive_damage(brute=3, wound_bonus=CANT_WOUND)
pierce_wound.adjust_blood_flow(-0.25)
@@ -94,6 +95,7 @@
span_notice("[user] jerks apart some of the blood vessels in [target]'s [target.parse_zone_with_bodypart(target_zone)] with [tool]!"),
span_notice("[user] jerk apart some of the blood vessels in [target]'s [target.parse_zone_with_bodypart(target_zone)]!"),
)
+ display_pain(target, mood_event_type = /datum/mood_event/surgery/failure)
surgery.operated_bodypart.receive_damage(brute=rand(4,8), sharpness=SHARP_EDGED, wound_bonus = 10)
///// Sealing the vessels back together
diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm
index 8c9782163bd00..87bc8625c7455 100644
--- a/code/modules/surgery/surgery_step.dm
+++ b/code/modules/surgery/surgery_step.dm
@@ -262,12 +262,19 @@
* * target - Who the message will be sent to
* * pain_message - The message to be displayed
* * mechanical_surgery - Boolean flag that represents if a surgery step is done on a mechanical limb (therefore does not force scream)
+ * * mood_event_type - What type of mood event the step applies if they're still conscious (ie "THEY'RE CUTTING ME OPEN!!" when being sliced open with a scalpel/saw/ect)
*/
-/datum/surgery_step/proc/display_pain(mob/living/target, pain_message, mechanical_surgery = FALSE)
+/datum/surgery_step/proc/display_pain(mob/living/target, pain_message, mechanical_surgery = FALSE, datum/mood_event/mood_event_type)
if(target.stat < UNCONSCIOUS)
if(HAS_TRAIT(target, TRAIT_ANALGESIA))
+ if(!pain_message)
+ return
to_chat(target, span_notice("You feel a dull, numb sensation as your body is surgically operated on."))
else
+ if(mood_event_type)
+ target.add_mood_event("surgery", mood_event_type)
+ if(!pain_message)
+ return
to_chat(target, span_userdanger(pain_message))
if(prob(30) && !mechanical_surgery)
target.emote("scream")
diff --git a/code/modules/transport/tram/tram_controller.dm b/code/modules/transport/tram/tram_controller.dm
index 6662cb2db9de2..a7b8a7c6a24a2 100644
--- a/code/modules/transport/tram/tram_controller.dm
+++ b/code/modules/transport/tram/tram_controller.dm
@@ -10,7 +10,10 @@
var/controller_active = FALSE
///whether all required parts of the tram are considered operational
var/controller_operational = TRUE
+ ///the controller cabinet located on the tram
var/obj/machinery/transport/tram_controller/paired_cabinet
+ ///the home controller located in telecoms
+ var/obj/machinery/transport/tram_controller/tcomms/home_controller
///if we're travelling, what direction are we going
var/travel_direction = NONE
///if we're travelling, how far do we have to go
@@ -50,16 +53,27 @@
///how many times we moved while costing less than 0.5 * SStransport.max_time milliseconds per movement
var/recovery_clear_count = 0
+ ///if the tram's next stop will be the tram malfunction event sequence
+ var/malf_active = FALSE
+
+ ///fluff information of the tram, such as ongoing kill count and age
var/datum/tram_mfg_info/tram_registration
+ ///previous trams that have been destroyed
var/list/tram_history
/datum/tram_mfg_info
+ ///serial number of this tram (what round ID it first appeared in)
var/serial_number
+ ///is it the active tram for the map
var/active = TRUE
+ ///date the tram was created
var/mfg_date
+ ///what map the tram is used on
var/install_location
+ ///lifetime distance the tram has travelled
var/distance_travelled = 0
+ ///lifetime number of players hit by the tram
var/collisions = 0
/**
@@ -245,6 +259,9 @@
playsound(paired_cabinet, 'sound/machines/synth_yes.ogg', 40, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE)
paired_cabinet.say("Controller reset.")
+ if(malf_active)
+ addtimer(CALLBACK(src, PROC_REF(announce_malf_event)), 1 SECONDS)
+
SEND_SIGNAL(src, COMSIG_TRAM_TRAVEL, idle_platform, destination_platform)
for(var/obj/structure/transport/linear/tram/transport_module as anything in transport_modules) //only thing everyone needs to know is the new location.
@@ -279,11 +296,7 @@
return PROCESS_KILL
if(!travel_remaining)
- if(!controller_operational)
- degraded_stop()
- return PROCESS_KILL
-
- if((controller_status & COMM_ERROR) && prob(5)) // malfunctioning tram has a small chance to e-stop
+ if(!controller_operational || malf_active)
degraded_stop()
else
normal_stop()
@@ -324,6 +337,9 @@
scheduled_move = world.time + speed_limiter
+/**
+ * Tram stops normally, performs post-trip actions and updates the tram registration.
+ */
/datum/transport_controller/linear/tram/proc/normal_stop()
cycle_doors(CYCLE_OPEN)
log_transport("TC: [specific_transport_id] trip completed. Info: nav_pos ([nav_beacon.x], [nav_beacon.y], [nav_beacon.z]) idle_pos ([destination_platform.x], [destination_platform.y], [destination_platform.z]).")
@@ -341,6 +357,9 @@
current_load = 0
speed_limiter = initial(speed_limiter)
+/**
+ * Tram comes to an in-station degraded stop, throwing the players. Caused by power loss or tram malfunction event.
+ */
/datum/transport_controller/linear/tram/proc/degraded_stop()
log_transport("TC: [specific_transport_id] trip completed with a degraded status. Info: [TC_TS_STATUS] nav_pos ([nav_beacon.x], [nav_beacon.y], [nav_beacon.z]) idle_pos ([destination_platform.x], [destination_platform.y], [destination_platform.z]).")
addtimer(CALLBACK(src, PROC_REF(unlock_controls)), 4 SECONDS)
@@ -350,6 +369,13 @@
paired_cabinet.say("Controller reset.")
log_transport("TC: [specific_transport_id] position data successfully reset. ")
speed_limiter = initial(speed_limiter)
+ if(malf_active)
+ set_status_code(SYSTEM_FAULT, TRUE)
+ addtimer(CALLBACK(src, PROC_REF(cycle_doors), CYCLE_OPEN), 2 SECONDS)
+ malf_active = FALSE
+ throw_chance = initial(throw_chance)
+ playsound(paired_cabinet, 'sound/machines/buzz-sigh.ogg', 60, vary = FALSE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE)
+ paired_cabinet.say("Controller error. Please contact your engineering department.")
idle_platform = destination_platform
tram_registration.distance_travelled += (travel_trip_length - travel_remaining)
travel_trip_length = 0
@@ -360,6 +386,9 @@
for(var/obj/structure/transport/linear/tram/module in transport_modules)
module.estop_throw(throw_direction)
+/**
+ * Tram comes to an emergency stop without completing its trip. Caused by emergency stop button or some catastrophic tram failure.
+ */
/datum/transport_controller/linear/tram/proc/halt_and_catch_fire()
if(controller_status & SYSTEM_FAULT)
if(!isnull(paired_cabinet))
@@ -382,6 +411,9 @@
current_speed = 0
current_load = 0
+/**
+ * Performs a reset of the tram's position data by finding a predetermined reference landmark, then driving to it.
+ */
/datum/transport_controller/linear/tram/proc/reset_position()
if(idle_platform)
if(get_turf(idle_platform) == get_turf(nav_beacon))
@@ -528,20 +560,36 @@
set_status_code(SYSTEM_FAULT, FALSE)
reset_position()
+/datum/transport_controller/linear/tram/proc/set_home_controller(obj/machinery/transport/tram_controller/tcomms/tcomms_unit)
+ home_controller = tcomms_unit
+ RegisterSignal(tcomms_unit, COMSIG_MACHINERY_POWER_LOST, PROC_REF(home_power_lost))
+ RegisterSignal(tcomms_unit, COMSIG_MACHINERY_POWER_RESTORED, PROC_REF(home_power_restored))
+ RegisterSignal(tcomms_unit, COMSIG_QDELETING, PROC_REF(on_home_qdel))
+ log_transport("TC: [specific_transport_id] is now paired with home controller [tcomms_unit].")
+ if(controller_status & COMM_ERROR)
+ set_status_code(COMM_ERROR, FALSE)
+
/datum/transport_controller/linear/tram/proc/on_cabinet_qdel()
paired_cabinet = null
log_transport("TC: [specific_transport_id] received QDEL from controller cabinet.")
set_status_code(SYSTEM_FAULT, TRUE)
- send_transport_active_signal()
+
+/datum/transport_controller/linear/tram/proc/on_home_qdel()
+ home_controller = null
+ log_transport("TC: [specific_transport_id] received QDEL from controller cabinet.")
+ set_status_code(COMM_ERROR, TRUE)
+
+/datum/transport_controller/linear/tram/proc/home_power_lost()
+ set_status_code(COMM_ERROR, TRUE)
+
+/datum/transport_controller/linear/tram/proc/home_power_restored()
+ set_status_code(COMM_ERROR, FALSE)
/**
- * Tram malfunction random event. Set comm error, increase tram lethality.
+ * Tram malfunction random event. Set comm error, requiring engineering or AI intervention.
*/
/datum/transport_controller/linear/tram/proc/start_malf_event()
- set_status_code(COMM_ERROR, TRUE)
- SEND_TRANSPORT_SIGNAL(COMSIG_COMMS_STATUS, src, FALSE)
- paired_cabinet.generate_repair_signals()
- collision_lethality *= 1.25
+ malf_active = TRUE
throw_chance *= 1.25
log_transport("TC: [specific_transport_id] starting Tram Malfunction event.")
@@ -552,15 +600,15 @@
* automagically reset it remotely.
*/
/datum/transport_controller/linear/tram/proc/end_malf_event()
- if(!(controller_status & COMM_ERROR))
+ if(!(malf_active))
return
- set_status_code(COMM_ERROR, FALSE)
- paired_cabinet.clear_repair_signals()
- collision_lethality = initial(collision_lethality)
+ malf_active = FALSE
throw_chance = initial(throw_chance)
- SEND_TRANSPORT_SIGNAL(COMSIG_COMMS_STATUS, src, TRUE)
log_transport("TC: [specific_transport_id] ending Tram Malfunction event.")
+/datum/transport_controller/linear/tram/proc/announce_malf_event()
+ priority_announce("Our automated control system has lost contact with the tram's onboard computer. Please stand by, engineering has been dispatched to the tram to perform a reset.", "[command_name()] Engineering Division")
+
/datum/transport_controller/linear/tram/proc/register_collision(points = 1)
tram_registration.collisions += points
SEND_TRANSPORT_SIGNAL(COMSIG_TRAM_COLLISION, SSpersistence.tram_hits_this_round)
@@ -689,11 +737,13 @@
name = "tram controller"
desc = "Makes the tram go, or something. Holds the tram's electronics, controls, and maintenance panel. A sticker above the card reader says 'Engineering access only.'"
icon = 'icons/obj/tram/tram_controllers.dmi'
- icon_state = "controller-panel"
+ icon_state = "tram-controller"
+ base_icon_state = "tram"
anchored = TRUE
density = FALSE
armor_type = /datum/armor/transport_module
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ interaction_flags_machine = parent_type::interaction_flags_machine | INTERACT_MACHINE_OFFLINE
max_integrity = 750
integrity_failure = 0.25
layer = SIGN_LAYER
@@ -701,6 +751,8 @@
idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.25
power_channel = AREA_USAGE_ENVIRON
var/datum/transport_controller/linear/tram/controller_datum
+ /// If this machine has a cover installed
+ var/has_cover = TRUE
/// If the cover is open
var/cover_open = FALSE
/// If the cover is locked
@@ -733,14 +785,13 @@
..()
/obj/machinery/transport/tram_controller/add_context(atom/source, list/context, obj/item/held_item, mob/user)
- if(held_item?.tool_behaviour == TOOL_SCREWDRIVER)
+ if(held_item?.tool_behaviour == TOOL_SCREWDRIVER && has_cover)
context[SCREENTIP_CONTEXT_RMB] = panel_open ? "close panel" : "open panel"
- if(!held_item)
+ if(!held_item && has_cover)
context[SCREENTIP_CONTEXT_LMB] = cover_open ? "access controls" : "open cabinet"
context[SCREENTIP_CONTEXT_RMB] = cover_open ? "close cabinet" : "toggle lock"
-
if(panel_open)
if(held_item?.tool_behaviour == TOOL_WRENCH)
context[SCREENTIP_CONTEXT_RMB] = "unscrew cabinet"
@@ -760,14 +811,15 @@
/obj/machinery/transport/tram_controller/examine(mob/user)
. = ..()
- . += span_notice("The door appears to be [cover_locked ? "locked. Swipe an ID card to unlock" : "unlocked. Swipe an ID card to lock"].")
- if(panel_open)
- . += span_notice("It is secured to the tram wall with [EXAMINE_HINT("bolts.")]")
- . += span_notice("The maintenance panel can be closed with a [EXAMINE_HINT("screwdriver.")]")
- else
- . += span_notice("The maintenance panel can be opened with a [EXAMINE_HINT("screwdriver.")]")
+ if(has_cover)
+ . += span_notice("The door appears to be [cover_locked ? "locked. Swipe an ID card to unlock" : "unlocked. Swipe an ID card to lock"].")
+ if(panel_open)
+ . += span_notice("It is secured to the tram wall with [EXAMINE_HINT("bolts.")]")
+ . += span_notice("The maintenance panel can be closed with a [EXAMINE_HINT("screwdriver.")]")
+ else
+ . += span_notice("The maintenance panel can be opened with a [EXAMINE_HINT("screwdriver.")]")
- if(cover_open)
+ if(cover_open || !has_cover)
. += span_notice("The [EXAMINE_HINT("yellow reset button")] resets the tram controller if a problem occurs or needs to be restarted.")
. += span_notice("The [EXAMINE_HINT("red stop button")] immediately stops the tram, requiring a reset afterwards.")
. += span_notice("The cabinet can be closed with a [EXAMINE_HINT("Right-click.")]")
@@ -779,16 +831,17 @@
if(user.combat_mode || cover_open)
return ..()
- var/obj/item/card/id/id_card = user.get_id_in_hand()
- if(!isnull(id_card))
- try_toggle_lock(user, id_card)
- return
+ if(has_cover)
+ var/obj/item/card/id/id_card = user.get_id_in_hand()
+ if(!isnull(id_card))
+ try_toggle_lock(user, id_card)
+ return
return ..()
/obj/machinery/transport/tram_controller/attack_hand(mob/living/user, params)
. = ..()
- if(cover_open)
+ if(cover_open || !has_cover)
return
if(cover_locked)
@@ -804,6 +857,8 @@
/obj/machinery/transport/tram_controller/attack_hand_secondary(mob/living/user, params)
. = ..()
+ if(!has_cover)
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(!cover_open)
var/obj/item/card/id/id_card = user.get_idcard(TRUE)
@@ -843,6 +898,9 @@
/obj/machinery/transport/tram_controller/wrench_act_secondary(mob/living/user, obj/item/tool)
. = ..()
+ if(!has_cover)
+ return
+
if(panel_open && cover_open)
balloon_alert(user, "unsecuring...")
tool.play_tool_sound(src)
@@ -878,53 +936,55 @@
/obj/machinery/transport/tram_controller/update_overlays()
. = ..()
- if(!cover_open)
- . += mutable_appearance(icon, "controller-closed")
- if(cover_locked)
- . += mutable_appearance(icon, "controller-locked")
+ if(has_cover)
+ if(!cover_open)
+ . += mutable_appearance(icon, "[base_icon_state]-closed")
+ if(cover_locked)
+ . += mutable_appearance(icon, "[base_icon_state]-locked")
- else
- var/mutable_appearance/controller_door = mutable_appearance(icon, "controller-open")
- controller_door.pixel_w = -3
- . += controller_door
+ else
+ var/mutable_appearance/controller_door = mutable_appearance(icon, "[base_icon_state]-open")
+ controller_door.pixel_w = -3
+ . += controller_door
if(machine_stat & NOPOWER)
- . += mutable_appearance(icon, "estop")
- . += emissive_appearance(icon, "estop", src, alpha = src.alpha)
+ . += mutable_appearance(icon, "[base_icon_state]-estop")
+ . += emissive_appearance(icon, "[base_icon_state]-estop", src, alpha = src.alpha)
return
- . += mutable_appearance(icon, "power")
- . += emissive_appearance(icon, "power", src, alpha = src.alpha)
+ . += mutable_appearance(icon, "[base_icon_state]-power")
+ . += emissive_appearance(icon, "[base_icon_state]-power", src, alpha = src.alpha)
if(!controller_datum)
- . += mutable_appearance(icon, "fatal")
- . += emissive_appearance(icon, "fatal", src, alpha = src.alpha)
+ . += mutable_appearance(icon, "[base_icon_state]-fatal")
+ . += emissive_appearance(icon, "[base_icon_state]-fatal", src, alpha = src.alpha)
return
if(controller_datum.controller_status & EMERGENCY_STOP)
- . += mutable_appearance(icon, "estop")
- . += emissive_appearance(icon, "estop", src, alpha = src.alpha)
+ . += mutable_appearance(icon, "[base_icon_state]-estop")
+ . += emissive_appearance(icon, "[base_icon_state]-estop", src, alpha = src.alpha)
+ return
+
+ if(controller_datum.controller_status & SYSTEM_FAULT || controller_datum.malf_active)
+ . += mutable_appearance(icon, "[base_icon_state]-fault")
+ . += emissive_appearance(icon, "[base_icon_state]-fault", src, alpha = src.alpha)
return
if(!(controller_datum.controller_status & DOORS_READY))
- . += mutable_appearance(icon, "doors")
- . += emissive_appearance(icon, "doors", src, alpha = src.alpha)
+ . += mutable_appearance(icon, "[base_icon_state]-doors")
+ . += emissive_appearance(icon, "[base_icon_state]-doors", src, alpha = src.alpha)
if(controller_datum.controller_active)
- . += mutable_appearance(icon, "active")
- . += emissive_appearance(icon, "active", src, alpha = src.alpha)
+ . += mutable_appearance(icon, "[base_icon_state]-active")
+ . += emissive_appearance(icon, "[base_icon_state]-active", src, alpha = src.alpha)
- if(controller_datum.controller_status & SYSTEM_FAULT)
- . += mutable_appearance(icon, "fault")
- . += emissive_appearance(icon, "fault", src, alpha = src.alpha)
-
- else if(controller_datum.controller_status & COMM_ERROR)
- . += mutable_appearance(icon, "comms")
- . += emissive_appearance(icon, "comms", src, alpha = src.alpha)
+ if(controller_datum.controller_status & COMM_ERROR)
+ . += mutable_appearance(icon, "[base_icon_state]-comms")
+ . += emissive_appearance(icon, "[base_icon_state]-comms", src, alpha = src.alpha)
else
- . += mutable_appearance(icon, "normal")
- . += emissive_appearance(icon, "normal", src, alpha = src.alpha)
+ . += mutable_appearance(icon, "[base_icon_state]-normal")
+ . += emissive_appearance(icon, "[base_icon_state]-normal", src, alpha = src.alpha)
/**
* Find the controller associated with the transport module the cabinet is sitting on.
@@ -972,24 +1032,12 @@
balloon_alert(user, "access controller shorted")
return TRUE
-/**
- * Check if the tram was malfunctioning due to the random event, and if so end the event on repair.
- */
-/obj/machinery/transport/tram_controller/try_fix_machine(obj/machinery/transport/machine, mob/living/user, obj/item/tool)
- . = ..()
-
- if(. == FALSE)
- return
-
- if(!controller_datum)
- return
+/obj/machinery/transport/tram_controller/ui_status(mob/user, datum/ui_state/state)
+ if(HAS_SILICON_ACCESS(user) && (controller_datum.controller_status & SYSTEM_FAULT || controller_datum.controller_status & COMM_ERROR || !is_operational))
+ to_chat(user, span_warning("An error code flashes: Communications fault! The [src] is not responding to remote inputs!"))
+ return UI_CLOSE
- var/datum/round_event/tram_malfunction/malfunction_event = locate(/datum/round_event/tram_malfunction) in SSevents.running
- if(malfunction_event)
- malfunction_event.end()
-
- if(controller_datum.controller_status & COMM_ERROR)
- controller_datum.set_status_code(COMM_ERROR, FALSE)
+ return ..()
/obj/machinery/transport/tram_controller/ui_interact(mob/user, datum/tgui/ui)
. = ..()
@@ -997,7 +1045,7 @@
if(!cover_open && !HAS_SILICON_ACCESS(user) && !isobserver(user))
return
- if(!is_operational)
+ if(machine_stat & BROKEN)
return
ui = SStgui.try_update_ui(user, src, ui)
@@ -1043,6 +1091,10 @@
if(!COOLDOWN_FINISHED(src, manual_command_cooldown))
return
+ if(machine_stat & NOPOWER)
+ visible_message(span_warning("The button doesn't appear to do anything, the [src]'s power failure status is flashing!"), vision_distance = COMBAT_MESSAGE_RANGE)
+ return
+
switch(action)
if("dispatch")
@@ -1078,11 +1130,53 @@
COOLDOWN_START(src, manual_command_cooldown, 2 SECONDS)
+
+/// Controller that sits in the telecoms room
+/obj/machinery/transport/tram_controller/tcomms
+ name = "tram central controller"
+ desc = "This semi-conductor is half of the brains controlling the tram and its auxillary equipment."
+ icon_state = "home-controller"
+ base_icon_state = "home"
+ density = TRUE
+ layer = BELOW_OBJ_LAYER
+ power_channel = AREA_USAGE_EQUIP
+ cover_open = TRUE
+ has_cover = FALSE
+
+/// Handles the machine being affected by an EMP, causing signal failure.
+/obj/machinery/transport/tram_controller/tcomms/emp_act(severity)
+ . = ..()
+ if(. & EMP_PROTECT_SELF)
+ return
+ if(prob(100/severity) && !(machine_stat & EMPED))
+ set_machine_stat(machine_stat | EMPED)
+ controller_datum.set_status_code(COMM_ERROR, TRUE)
+ var/duration = (300 SECONDS)/severity
+ addtimer(CALLBACK(src, PROC_REF(de_emp)), rand(duration - 2 SECONDS, duration + 2 SECONDS))
+
+/// Handles the machine stopping being affected by an EMP.
+/obj/machinery/transport/tram_controller/tcomms/proc/de_emp()
+ set_machine_stat(machine_stat & ~EMPED)
+ controller_datum.set_status_code(COMM_ERROR, FALSE)
+
+/obj/machinery/transport/tram_controller/tcomms/find_controller()
+ link_tram()
+ return
+
+/obj/machinery/transport/tram_controller/tcomms/link_tram()
+ . = ..()
+ var/datum/transport_controller/linear/tram/tram = transport_ref?.resolve()
+ controller_datum = tram
+ if(!controller_datum)
+ return
+ controller_datum.set_home_controller(src)
+ RegisterSignal(SStransport, COMSIG_TRANSPORT_ACTIVE, PROC_REF(sync_controller))
+
/obj/item/wallframe/tram/controller
name = "tram controller cabinet"
desc = "A box that contains the equipment to control a tram. Just secure to the tram wall."
icon = 'icons/obj/tram/tram_controllers.dmi'
- icon_state = "controller-panel"
+ icon_state = "tram-controller"
custom_materials = list(/datum/material/titanium = SHEET_MATERIAL_AMOUNT * 4, /datum/material/iron = SHEET_MATERIAL_AMOUNT * 2, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 2)
result_path = /obj/machinery/transport/tram_controller
pixel_shift = 32
diff --git a/code/modules/transport/tram/tram_doors.dm b/code/modules/transport/tram/tram_doors.dm
index 644f45def4aa5..653b5cbabb527 100644
--- a/code/modules/transport/tram/tram_doors.dm
+++ b/code/modules/transport/tram/tram_doors.dm
@@ -1,7 +1,7 @@
-#define TRAM_DOOR_WARNING_TIME (1.4 SECONDS)
-#define TRAM_DOOR_CYCLE_TIME (0.4 SECONDS)
+#define TRAM_DOOR_WARNING_TIME (0.9 SECONDS)
+#define TRAM_DOOR_CYCLE_TIME (0.6 SECONDS)
#define TRAM_DOOR_CRUSH_TIME (0.7 SECONDS)
-#define TRAM_DOOR_RECYCLE_TIME (3 SECONDS)
+#define TRAM_DOOR_RECYCLE_TIME (2.7 SECONDS)
/obj/machinery/door/airlock/tram
name = "tram door"
@@ -9,7 +9,7 @@
overlays_file = 'icons/obj/doors/airlocks/tram/tram-overlays.dmi'
multi_tile = TRUE
opacity = FALSE
- assemblytype = null
+ assemblytype = /obj/structure/door_assembly/multi_tile/door_assembly_tram
airlock_material = "glass"
air_tight = TRUE
req_access = list(ACCESS_TCOMMS)
@@ -55,7 +55,7 @@
update_freelook_sight()
flags_1 &= ~PREVENT_CLICK_UNDER_1
air_update_turf(TRUE, FALSE)
- sleep(TRAM_DOOR_CYCLE_TIME)
+ sleep(TRAM_DOOR_WARNING_TIME)
layer = OPEN_DOOR_LAYER
update_icon(ALL, AIRLOCK_OPEN, TRUE)
operating = FALSE
@@ -64,7 +64,7 @@
/obj/machinery/door/airlock/tram/close(forced = DEFAULT_DOOR_CHECKS, force_crush = FALSE)
retry_counter++
- if(retry_counter >= 4 || force_crush || forced == BYPASS_DOOR_CHECKS)
+ if(retry_counter >= 3 || force_crush || forced == BYPASS_DOOR_CHECKS)
try_to_close(forced = BYPASS_DOOR_CHECKS)
return
@@ -116,7 +116,7 @@
air_update_turf(TRUE, TRUE)
crush()
crushing_in_progress = FALSE
- sleep(TRAM_DOOR_CYCLE_TIME)
+ sleep(TRAM_DOOR_WARNING_TIME)
update_icon(ALL, AIRLOCK_CLOSED, 1)
operating = FALSE
retry_counter = 0
@@ -163,7 +163,7 @@
if(airlock_state == AIRLOCK_CLOSED)
return
- if(retry_counter < 3)
+ if(retry_counter < 2)
close()
return
@@ -205,6 +205,9 @@
* Tram doors can be opened with hands when unpowered
*/
/obj/machinery/door/airlock/tram/try_safety_unlock(mob/user)
+ if(DOING_INTERACTION_WITH_TARGET(user, src))
+ return
+
if(!hasPower() && density)
balloon_alert(user, "pulling emergency exit...")
if(do_after(user, 4 SECONDS, target = src))
@@ -215,10 +218,20 @@
* If you pry (bump) the doors open midtravel, open quickly so you can jump out and make a daring escape.
*/
/obj/machinery/door/airlock/tram/bumpopen(mob/user, forced = BYPASS_DOOR_CHECKS)
+ if(DOING_INTERACTION_WITH_TARGET(user, src))
+ return
+
if(operating || !density)
return
+
+ if(!hasPower())
+ try_safety_unlock(user)
+ return
+
var/datum/transport_controller/linear/tram/tram_part = transport_ref?.resolve()
add_fingerprint(user)
+ if(!tram_part.controller_active)
+ return
if((tram_part.travel_remaining < DEFAULT_TRAM_LENGTH || tram_part.travel_remaining > tram_part.travel_trip_length - DEFAULT_TRAM_LENGTH) && tram_part.controller_active)
return // we're already animating, don't reset that
open(forced = BYPASS_DOOR_CHECKS)
diff --git a/code/modules/transport/tram/tram_machinery.dm b/code/modules/transport/tram/tram_machinery.dm
index 99375bfbaf578..a60a1d658663c 100644
--- a/code/modules/transport/tram/tram_machinery.dm
+++ b/code/modules/transport/tram/tram_machinery.dm
@@ -91,6 +91,17 @@
/// The ID of the tram we're linked to
var/specific_transport_id = TRAMSTATION_LINE_1
+/// We allow borgs to use the button locally, but not the AI remotely
+/obj/machinery/button/transport/tram/attack_ai(mob/user)
+ if(isAI(user) || panel_open)
+ return
+ if(HAS_SILICON_ACCESS(user) && !issilicon(user)) //admins and remote controls can use it at a distance
+ return attack_hand(user)
+ if(in_range(user, src))
+ return attack_hand(user)
+ else
+ to_chat(user, span_warning("You are too far away to activate the button!"))
+
/obj/machinery/button/transport/tram/setup_device()
var/obj/item/assembly/control/transport/call_button/tram_device = device
tram_device.id = id
diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm
index df4f235f50cca..40e0092d434dc 100644
--- a/code/modules/uplink/uplink_items/job.dm
+++ b/code/modules/uplink/uplink_items/job.dm
@@ -151,7 +151,7 @@
desc = "A much more proffessional version of the engineer's bootleg rebar crossbow. 3 shot mag, quicker loading, and better ammo. Owners manual included."
item = /obj/item/storage/box/syndie_kit/rebarxbowsyndie
cost = 10
- restricted_roles = list(JOB_STATION_ENGINEER, JOB_CHIEF_ENGINEER)
+ restricted_roles = list(JOB_STATION_ENGINEER, JOB_CHIEF_ENGINEER, JOB_ATMOSPHERIC_TECHNICIAN)
/datum/uplink_item/role_restricted/magillitis_serum
name = "Magillitis Serum Autoinjector"
diff --git a/code/modules/uplink/uplink_items/suits.dm b/code/modules/uplink/uplink_items/suits.dm
index 8e7212744822a..5d89f80506178 100644
--- a/code/modules/uplink/uplink_items/suits.dm
+++ b/code/modules/uplink/uplink_items/suits.dm
@@ -64,6 +64,12 @@
item = /obj/item/mod/module/noslip
cost = 2
+/datum/uplink_item/suits/shock_absorber
+ name = "MODsuit Shock-Absorber Module"
+ desc = "A MODsuit module preventing the user from getting knocked down by batons."
+ item = /obj/item/mod/module/shock_absorber
+ cost = 2
+
/datum/uplink_item/suits/modsuit/elite_traitor
name = "Elite Syndicate MODsuit"
desc = "An upgraded, elite version of the Syndicate MODsuit. It features fireproofing, and also \
diff --git a/code/modules/vending/medical.dm b/code/modules/vending/medical.dm
index 71171e5783773..2209f550fce28 100644
--- a/code/modules/vending/medical.dm
+++ b/code/modules/vending/medical.dm
@@ -83,6 +83,7 @@
/obj/item/reagent_containers/pill/insulin = 5,
/obj/item/reagent_containers/cup/bottle/multiver = 2,
/obj/item/reagent_containers/cup/bottle/syriniver = 2,
+ /obj/item/reagent_containers/cup/bottle/calomel = 2,
/obj/item/reagent_containers/cup/bottle/epinephrine = 3,
/obj/item/reagent_containers/cup/bottle/morphine = 4,
/obj/item/reagent_containers/cup/bottle/potass_iodide = 1,
diff --git a/html/changelogs/AutoChangeLog-pr-83404.yml b/html/changelogs/AutoChangeLog-pr-83404.yml
deleted file mode 100644
index 91fab2e77bd2c..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83404.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "DATA-xPUNGED"
-delete-after: True
-changes:
- - rscadd: "NT reports indicate that the Syndicate have increased listening activities on Icemoon, crew is advised to watch out for possible communication interference."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83462.yml b/html/changelogs/AutoChangeLog-pr-83462.yml
deleted file mode 100644
index f6f0fffb68450..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83462.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "TheBoondock"
-delete-after: True
-changes:
- - sound: "added operating sounds for wrench, wirecutter and crowbar"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83510.yml b/html/changelogs/AutoChangeLog-pr-83510.yml
new file mode 100644
index 0000000000000..ef3af4284ec95
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83510.yml
@@ -0,0 +1,6 @@
+author: "EnterTheJake"
+delete-after: True
+changes:
+ - rscadd: "adds the MOD shock-absorption module, into the game."
+ - rscadd: "The MOD shock-absorption module into the the uplinks, costs 4 TC."
+ - balance: "Nukie modsuits come with the shock_absorption module preinstalled."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83578.yml b/html/changelogs/AutoChangeLog-pr-83578.yml
deleted file mode 100644
index 8af4ed75b545a..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83578.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "tmyqlfpir"
-delete-after: True
-changes:
- - rscadd: "Added new circuit camera components"
- - qol: "Circuit drones can now recharge at recharge stations"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83591.yml b/html/changelogs/AutoChangeLog-pr-83591.yml
deleted file mode 100644
index 5e509afdadbae..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83591.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Rhials"
-delete-after: True
-changes:
- - rscadd: "Adds some more station-trait dependent pulsar star reports. Keep an eye on that roundstart command report!"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83609.yml b/html/changelogs/AutoChangeLog-pr-83609.yml
deleted file mode 100644
index d563f3d137196..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83609.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Wayland-Smithy"
-delete-after: True
-changes:
- - bugfix: "Fixed Silicons not being able to (un)lock Air Alarms."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83621.yml b/html/changelogs/AutoChangeLog-pr-83621.yml
deleted file mode 100644
index 7e333a147b8d3..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83621.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Goat"
-delete-after: True
-changes:
- - bugfix: "mobs no longer move during cutscenes"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83630.yml b/html/changelogs/AutoChangeLog-pr-83630.yml
deleted file mode 100644
index b3008451a4046..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83630.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Watermelon914"
-delete-after: True
-changes:
- - spellcheck: "Intern announcer no longer has a weird space before the introduction message."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83636.yml b/html/changelogs/AutoChangeLog-pr-83636.yml
deleted file mode 100644
index 546c515074ae7..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83636.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Jackraxxus"
-delete-after: True
-changes:
- - admin: "The auto-mute system yells at you harder when you send a bunch of identical messages."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83657.yml b/html/changelogs/AutoChangeLog-pr-83657.yml
deleted file mode 100644
index cbc585c801079..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83657.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Time-Green"
-delete-after: True
-changes:
- - bugfix: "admins can force rulesets on background checks station trait (fucking lame)"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83661.yml b/html/changelogs/AutoChangeLog-pr-83661.yml
deleted file mode 100644
index 3689d68f7ca9a..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83661.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Ben10Omintrix"
-delete-after: True
-changes:
- - bugfix: "lobstrosities will no longer be able to fish out multiple necropolis chests"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83683.yml b/html/changelogs/AutoChangeLog-pr-83683.yml
deleted file mode 100644
index 70044676f939d..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83683.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "zxaber"
-delete-after: True
-changes:
- - qol: "Plexagon Access Management now tells you that you need an ID Trim before applying a Template, rather than silently failing."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83724.yml b/html/changelogs/AutoChangeLog-pr-83724.yml
deleted file mode 100644
index 96842a58a77fd..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83724.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "grungussuss"
-delete-after: True
-changes:
- - spellcheck: "all instances of reactive armor are now spelt the same"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83733.yml b/html/changelogs/AutoChangeLog-pr-83733.yml
deleted file mode 100644
index 33a893563f8da..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83733.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "thegrb93"
-delete-after: True
-changes:
- - bugfix: "Fixes admin borg panel upgrade functions"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83740.yml b/html/changelogs/AutoChangeLog-pr-83740.yml
deleted file mode 100644
index 8e3c56845250a..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83740.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "00-Steven"
-delete-after: True
-changes:
- - bugfix: "Latejoiners with heterochromatic eyes no longer have the wrong fingerprint in the security records."
- - bugfix: "Latejoiners actually have their quirks visible in the medical records."
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-06.yml b/html/changelogs/archive/2024-06.yml
index 60046e053bd8e..20dd1cfea33cb 100644
--- a/html/changelogs/archive/2024-06.yml
+++ b/html/changelogs/archive/2024-06.yml
@@ -374,3 +374,143 @@
zxaber:
- bugfix: Fixed borg chargers (especially unpowered ones) constantly draining a
borg's cell.
+2024-06-09:
+ 00-Steven:
+ - bugfix: Latejoiners with heterochromatic eyes no longer have the wrong fingerprint
+ in the security records.
+ - bugfix: Latejoiners actually have their quirks visible in the medical records.
+ Ben10Omintrix:
+ - bugfix: lobstrosities will no longer be able to fish out multiple necropolis chests
+ DATA-xPUNGED:
+ - rscadd: NT reports indicate that the Syndicate have increased listening activities
+ on Icemoon, crew is advised to watch out for possible communication interference.
+ DustanHache:
+ - bugfix: Lobstrosities are no longer pre-cooked through bluespace shenanigans.
+ Goat:
+ - bugfix: mobs no longer move during cutscenes
+ Jackraxxus:
+ - admin: The auto-mute system yells at you harder when you send a bunch of identical
+ messages.
+ Majkl-J:
+ - bugfix: The orbit menu clicks are accurate again
+ - bugfix: Fixes several service and item-handling borg modules not functioning
+ Melbert:
+ - balance: Coders are now locked to the coderbus
+ Rhials:
+ - rscadd: Adds some more station-trait dependent pulsar star reports. Keep an eye
+ on that roundstart command report!
+ ShizCalev:
+ - bugfix: Basic bots are now in the proper faction and will no longer be targeted
+ by turrets.
+ - bugfix: The spooky element will now apply the spooked mood event when someone
+ is spooked.
+ - bugfix: Fixed spookers getting a popup message when spooking mobs not actively
+ controlled by a player.
+ - bugfix: Seeing heretical stuff while having the heresy phobia will now apply the
+ heresy mood event.
+ - bugfix: Seeing skeletons while having the skeleton phobia will now apply the spooked
+ (by skeletons) mood event.
+ - bugfix: Getting surgically cut open while conscious will now give you the "THEY'RE
+ CUTTING ME OPEN!!" surgical mood event.
+ TheBoondock:
+ - sound: added operating sounds for wrench, wirecutter and crowbar
+ Thlumyn:
+ - bugfix: add general engineering access to birdshot engineering entrance
+ Time-Green:
+ - bugfix: admins can force rulesets on background checks station trait (fucking
+ lame)
+ Watermelon914:
+ - spellcheck: Intern announcer no longer has a weird space before the introduction
+ message.
+ Wayland-Smithy:
+ - bugfix: Fixed Silicons not being able to (un)lock Air Alarms.
+ Zenitheevee:
+ - bugfix: fish with the Anxiety gene wont die when in the same loc as any 3 items
+ carlarctg:
+ - qol: Adds a chat message for fishing in a chasm with a normal and rescue hook,
+ to clarify that only rescue hooks can drag up corpses.
+ grungussuss:
+ - spellcheck: all instances of reactive armor are now spelt the same
+ improvedname:
+ - balance: Roundstart mutadone pills now have less chems in them from 50 to 5
+ krookodilehunter:
+ - spellcheck: fixes bad raptor grammar
+ mc-oofert:
+ - code_imp: stacking machine consoles check in area instead of a tiny view range
+ on init
+ thegrb93:
+ - bugfix: Fixes admin borg panel upgrade functions
+ tmyqlfpir:
+ - rscadd: Added new circuit camera components
+ - qol: Circuit drones can now recharge at recharge stations
+ zxaber:
+ - qol: Plexagon Access Management now tells you that you need an ID Trim before
+ applying a Template, rather than silently failing.
+2024-06-10:
+ EuSouAFazer:
+ - qol: The ERT's ship has better mapping now.
+ Higgin:
+ - bugfix: energy bolas now work on prone targets and don't leave behind a fake item
+ when they whiff.
+ - balance: buffed healing values of helbital, probital, lenturi, hercuri, syriniver,
+ musiver, and tirimol for their respective damage types.
+ - balance: Tirimol now uses oxygen as a catalyst rather than consuming it over time
+ making it easier to make without babysitting. Tirimol now requires much more
+ careful management of impurity in order to make Super Melatonin.
+ - rscadd: medical chem vendors now sell bottles of calomel, a potent full-range
+ chemical purger.
+ Iamgoofball:
+ - balance: Changelings now do not like fire, as is tradition.
+ - balance: If they are on fire, they no longer generate chemicals until they put
+ the fire out.
+ - balance: If they are on fire, they no longer can use any changeling powers until
+ they put the fire out.
+ - balance: All changeling equippable items like armblades, shields, armor, spacesuits,
+ etc. are now flammable and super-duper vulnerable to flames.
+ - balance: The Armblade now costs 30 chemicals to equip, and has a DNA cost of 3,
+ compared to the previous 20 chemicals and 2 DNA cost.
+ - rscadd: The Armblade now shatters after enough uses in exactly the same way as
+ the Shield; extract genomes with Absorb to maximize your Armblade's efficiency.
+ for its' chemical cost.
+ - bugfix: Fixes items you're holding not catching on fire alongside the rest of
+ you when you light on fire.
+ - bugfix: Fixes the Changeling Shield having one more hit than it was supposed to.
+ IsaacExists:
+ - bugfix: You may no longer submit, or obtain, a spy bounty for the contractor baton.
+ LT3:
+ - rscadd: Telecoms now has a central tram controller
+ - rscadd: Tram controller is now included in communications blackout event
+ - qol: Tram malfunction event only stops tram once, requiring engineering to reset
+ (no tools required)
+ - qol: Tram malfunction event no longer sends a Central Command announcement when
+ fixed
+ - rscdel: Tram doors no longer force crush you during tram malfunction event
+ - rscdel: Silicons can no longer control the tram when communication is lost
+ - bugfix: Tram doors can now be constructed and assemblies built
+ - bugfix: Emergency opening tram doors no longer spam balloon alerts
+ - bugfix: Tram doors open faster on arrival
+ - bugfix: Tram doors correctly force close on attempt 3
+ NewyearnewmeUwu:
+ - bugfix: Fixes certain quirks being erased by slimeperson cloning.
+ Time-Green:
+ - rscadd: Adds a positronic sphere to bepis tech and roboticist mail goodies. It
+ can now wreack havoc across the robotics lab while whining for a DURAND body,
+ but you can also punt it!
+ WebcomicArtist:
+ - rscadd: Added zaukerite (high damage/embed, low AP) and metallic hydrogen (High
+ AP and piercing, but low embed) crossbow ammo for the rebar crossbows
+ - rscadd: Added healium crystal ammo for the crossbow as well, which heals whomever
+ you shoot it at.
+ - rscadd: Added admin-only supermatter crossbow bolts that dust you, because why
+ the hell not.
+ - rscadd: Added non-harmful paper balls. Can be shot from a crossbow, or thrown
+ at co-workers.
+ - rscadd: Added a quiver made from cutting an o2 tank in half, to hold it all.
+ - image: added sprites for all the above.
+ - balance: Traitor Engineer Crossbow ammo now does 55 damage instead of 45, to make
+ it compete with revolver.
+ - balance: Stressed Rebar Crossbow now has a shorter delay required to rack it,
+ but can shoot you in the face on misfire.
+ - bugfix: fixed rebar crossbow shots not dropping items on hitting walls
+ - bugfix: fixed traitor crossbow having worse wound chance than the base one
+ - sound: added new crossbow firing sound effect
diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi
index 4fc02eaa2c0fc..52be2d07923e5 100644
Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index a2347dc667abc..967968b339ba7 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index bb2a425194bd2..beb3c84860d64 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/obj/clothing/modsuit/mod_modules.dmi b/icons/obj/clothing/modsuit/mod_modules.dmi
index eb4b0c536ce3c..8b4b549eda2ae 100644
Binary files a/icons/obj/clothing/modsuit/mod_modules.dmi and b/icons/obj/clothing/modsuit/mod_modules.dmi differ
diff --git a/icons/obj/devices/assemblies.dmi b/icons/obj/devices/assemblies.dmi
index c1b0fd05f137c..95c9227ab3aa7 100644
Binary files a/icons/obj/devices/assemblies.dmi and b/icons/obj/devices/assemblies.dmi differ
diff --git a/icons/obj/tram/tram_controllers.dmi b/icons/obj/tram/tram_controllers.dmi
index aea1f691af241..251320af6b9d8 100644
Binary files a/icons/obj/tram/tram_controllers.dmi and b/icons/obj/tram/tram_controllers.dmi differ
diff --git a/icons/obj/tram/tram_display.dmi b/icons/obj/tram/tram_display.dmi
index e28beef468fef..4f64a5c8345cb 100644
Binary files a/icons/obj/tram/tram_display.dmi and b/icons/obj/tram/tram_display.dmi differ
diff --git a/icons/obj/weapons/bows/quivers.dmi b/icons/obj/weapons/bows/quivers.dmi
index 74a7b4bc8bb52..615f96ee6af6d 100644
Binary files a/icons/obj/weapons/bows/quivers.dmi and b/icons/obj/weapons/bows/quivers.dmi differ
diff --git a/icons/obj/weapons/guns/ammo.dmi b/icons/obj/weapons/guns/ammo.dmi
index 62fb2e4511451..7554749a7e4be 100644
Binary files a/icons/obj/weapons/guns/ammo.dmi and b/icons/obj/weapons/guns/ammo.dmi differ
diff --git a/icons/obj/weapons/guns/projectiles.dmi b/icons/obj/weapons/guns/projectiles.dmi
index 120a4c12cd3d9..98a2e59dbc9c3 100644
Binary files a/icons/obj/weapons/guns/projectiles.dmi and b/icons/obj/weapons/guns/projectiles.dmi differ
diff --git a/sound/items/xbow_lock.ogg b/sound/items/xbow_lock.ogg
new file mode 100644
index 0000000000000..d465a95ca056f
Binary files /dev/null and b/sound/items/xbow_lock.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index f14d18829832e..352885b35305d 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2117,7 +2117,6 @@
#include "code\game\machinery\doors\passworddoor.dm"
#include "code\game\machinery\doors\poddoor.dm"
#include "code\game\machinery\doors\shutters.dm"
-#include "code\game\machinery\doors\unpowered.dm"
#include "code\game\machinery\doors\windowdoor.dm"
#include "code\game\machinery\embedded_controller\access_controller.dm"
#include "code\game\machinery\embedded_controller\airlock_controller.dm"
diff --git a/tgui/packages/tgui/styles/interfaces/Orbit.scss b/tgui/packages/tgui/styles/interfaces/Orbit.scss
index 32a1dd59b70dd..3bed71d3f0cd7 100644
--- a/tgui/packages/tgui/styles/interfaces/Orbit.scss
+++ b/tgui/packages/tgui/styles/interfaces/Orbit.scss
@@ -1,6 +1,8 @@
.JobIcon {
+ height: 20px;
background: black;
padding: 1px 1px 0 1px;
+ overflow: hidden;
}
.OrbitItem__selected {