diff --git a/_maps/RandomRuins/StationRuins/Box/Engine/engine_am.dmm b/_maps/RandomRuins/StationRuins/Box/Engine/engine_am.dmm
index db2a4f6cd7..f7fa98fcf7 100644
--- a/_maps/RandomRuins/StationRuins/Box/Engine/engine_am.dmm
+++ b/_maps/RandomRuins/StationRuins/Box/Engine/engine_am.dmm
@@ -1367,7 +1367,7 @@ JZ
kK
Ch
Ch
-MJ
+Ch
MJ
MJ
MJ
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 0f41cd3b1a..57a4831073 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -36739,14 +36739,12 @@
dir = 1
},
/turf/open/floor/plasteel,
-/area/science/misc_lab)
+/area/science/mixing)
"cAJ" = (
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 8
- },
/obj/structure/cable/yellow{
icon_state = "1-2"
},
+/obj/machinery/atmospherics/pipe/manifold4w/supplymain/hidden,
/turf/open/floor/plasteel,
/area/science/mixing)
"cAK" = (
@@ -36755,7 +36753,7 @@
dir = 4
},
/turf/open/floor/plasteel,
-/area/science/misc_lab)
+/area/science/mixing)
"cAL" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -37139,7 +37137,7 @@
dir = 8
},
/turf/open/floor/plasteel,
-/area/science/misc_lab)
+/area/science/mixing)
"cBE" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/structure/cable/yellow{
@@ -37149,7 +37147,7 @@
dir = 4
},
/turf/open/floor/plasteel,
-/area/science/misc_lab)
+/area/science/mixing)
"cBF" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 4
@@ -37158,7 +37156,7 @@
pixel_x = 32
},
/turf/open/floor/plasteel,
-/area/science/misc_lab)
+/area/science/mixing)
"cBG" = (
/obj/machinery/door/airlock/research{
name = "Toxins Launch Room";
@@ -37556,6 +37554,9 @@
/obj/machinery/light{
dir = 8
},
+/obj/machinery/atmospherics/components/unary/vent_pump/on{
+ dir = 4
+ },
/turf/open/floor/plasteel,
/area/science/mixing)
"cCE" = (
@@ -54495,7 +54496,7 @@
"gLC" = (
/obj/structure/reagent_dispensers/water_cooler,
/turf/open/floor/plasteel,
-/area/science/misc_lab)
+/area/science/mixing)
"gLD" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -70548,11 +70549,11 @@
/turf/open/floor/grass,
/area/service/hydroponics/garden)
"qqg" = (
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
- dir = 6
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
+ dir = 1
},
/turf/open/floor/plasteel,
-/area/science/misc_lab)
+/area/science/mixing)
"qqK" = (
/obj/structure/cable/yellow{
icon_state = "1-2"
@@ -78267,7 +78268,7 @@
dir = 4
},
/turf/open/floor/plasteel,
-/area/science/misc_lab)
+/area/science/mixing)
"vhM" = (
/obj/machinery/teleport/hub,
/turf/open/floor/plating,
@@ -81108,7 +81109,7 @@
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel,
-/area/science/misc_lab)
+/area/science/mixing)
"wRz" = (
/obj/effect/landmark/xeno_spawn,
/obj/machinery/atmospherics/components/unary/vent_pump/on{
@@ -82282,8 +82283,12 @@
/area/service/library)
"xAp" = (
/obj/structure/chair/comfy,
+/obj/machinery/airalarm{
+ dir = 4;
+ pixel_x = -22
+ },
/turf/open/floor/plasteel,
-/area/science/misc_lab)
+/area/science/mixing)
"xAs" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/grunge{
@@ -82583,6 +82588,16 @@
/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/plasteel,
/area/commons/dorms)
+"xHe" = (
+/obj/structure/cable/yellow{
+ icon_state = "1-2"
+ },
+/obj/machinery/atmospherics/pipe/simple/supply/hidden,
+/obj/machinery/atmospherics/components/unary/vent_scrubber/on{
+ dir = 4
+ },
+/turf/open/floor/plasteel,
+/area/science/mixing)
"xHm" = (
/obj/machinery/holopad,
/obj/structure/cable/yellow{
@@ -118574,7 +118589,7 @@ cJa
cJa
gHh
wRy
-wRy
+xHe
wRy
cBE
cAJ
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index d749c51798..3f07daecc2 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -9531,6 +9531,9 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
+/obj/structure/mirror{
+ pixel_y = 30
+ },
/turf/open/floor/plasteel/freezer,
/area/command/heads_quarters/captain)
"avJ" = (
@@ -16873,10 +16876,10 @@
dir = 4
},
/obj/effect/landmark/start/assistant,
+/obj/machinery/light/small,
/turf/open/floor/plasteel/freezer,
/area/commons/toilet/auxiliary)
"aNd" = (
-/obj/machinery/light/small,
/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 1
},
@@ -24652,12 +24655,6 @@
},
/turf/open/space,
/area/solars/starboard)
-"beW" = (
-/obj/machinery/atmospherics/pipe/simple/general/visible{
- dir = 5
- },
-/turf/open/floor/plasteel,
-/area/engineering/atmos)
"beY" = (
/obj/machinery/camera{
c_tag = "Arrivals Central";
@@ -34476,7 +34473,7 @@
dir = 8
},
/obj/structure/cable{
- icon_state = "4-8"
+ icon_state = "0-4"
},
/turf/open/floor/plasteel/dark,
/area/command/heads_quarters/rd)
@@ -40389,8 +40386,8 @@
icon_state = "1-2"
},
/obj/machinery/atmospherics/components/binary/pump/on{
- dir = 8;
- name = "Unfiltered to Mix"
+ dir = 4;
+ name = "Ports to Mix"
},
/turf/open/floor/plasteel,
/area/engineering/atmos)
@@ -41430,6 +41427,9 @@
/obj/structure/cable{
icon_state = "1-2"
},
+/obj/machinery/atmospherics/pipe/simple/general/visible{
+ dir = 10
+ },
/turf/open/floor/plasteel,
/area/engineering/atmos)
"bPW" = (
@@ -42132,7 +42132,9 @@
/turf/open/floor/plasteel,
/area/engineering/atmos)
"bRw" = (
-/obj/machinery/atmospherics/pipe/simple/general/visible,
+/obj/machinery/atmospherics/pipe/simple/general/visible{
+ dir = 5
+ },
/turf/open/floor/plasteel,
/area/engineering/atmos)
"bRx" = (
@@ -55286,15 +55288,6 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/plasteel,
/area/construction/mining/aux_base)
-"hEi" = (
-/obj/structure/cable{
- icon_state = "1-2"
- },
-/obj/machinery/atmospherics/pipe/simple/general/visible{
- dir = 10
- },
-/turf/open/floor/plasteel,
-/area/engineering/atmos)
"hEX" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 6
@@ -61354,12 +61347,6 @@
},
/turf/open/floor/engine,
/area/engineering/main)
-"uST" = (
-/obj/machinery/atmospherics/components/binary/pump{
- name = "Mix to Ports"
- },
-/turf/open/floor/plasteel,
-/area/engineering/atmos)
"uUQ" = (
/obj/machinery/door/airlock/maintenance{
name = "Engineering Maintenance";
@@ -100505,7 +100492,7 @@ bOr
bPU
kWG
bRw
-beW
+bMf
bMf
bMf
bMf
@@ -100761,9 +100748,9 @@ bKV
bOX
eEd
bQL
-uST
pEM
bMf
+bMf
qQu
qQu
bSU
@@ -101019,7 +101006,7 @@ bMg
bNj
bOp
bPV
-hEi
+sGJ
sGJ
bUw
bUw
diff --git a/_maps/templates/shelter_5.dmm b/_maps/templates/shelter_5.dmm
index 60066dc0c0..643f744fb9 100644
--- a/_maps/templates/shelter_5.dmm
+++ b/_maps/templates/shelter_5.dmm
@@ -253,6 +253,10 @@
/obj/machinery/dish_drive,
/turf/open/floor/pod/dark,
/area/survivalpod/nonpowered)
+"Vv" = (
+/obj/machinery/biogenerator,
+/turf/open/floor/pod/dark,
+/area/survivalpod/nonpowered)
"Ws" = (
/obj/structure/dresser,
/turf/open/floor/pod/dark,
@@ -274,12 +278,8 @@
/obj/structure/table/survival_pod,
/obj/item/shovel,
/obj/item/pickaxe,
-/obj/item/clothing/gloves/chameleon/insulated,
/obj/item/storage/toolbox/electrical,
-/turf/open/floor/pod/dark,
-/area/survivalpod/nonpowered)
-"Zd" = (
-/obj/machinery/seed_extractor,
+/obj/item/clothing/gloves/color/yellow,
/turf/open/floor/pod/dark,
/area/survivalpod/nonpowered)
@@ -453,8 +453,8 @@ FZ
Ng
wI
Ng
-FZ
-Zd
+Vv
+Lv
xC
td
FZ
diff --git a/code/controllers/subsystem/acid.dm b/code/controllers/subsystem/acid.dm
deleted file mode 100644
index 25d080a1b1..0000000000
--- a/code/controllers/subsystem/acid.dm
+++ /dev/null
@@ -1,37 +0,0 @@
-SUBSYSTEM_DEF(acid)
- name = "Acid"
- priority = FIRE_PRIORITY_ACID
- flags = SS_NO_INIT|SS_BACKGROUND
- runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
-
- var/list/currentrun = list()
- var/list/processing = list()
-
-/datum/controller/subsystem/acid/stat_entry(msg)
- msg = "P:[length(processing)]"
- return ..()
-
-
-/datum/controller/subsystem/acid/fire(resumed = 0)
- if (!resumed)
- src.currentrun = processing.Copy()
-
- //cache for sanic speed (lists are references anyways)
- var/list/currentrun = src.currentrun
-
- while (currentrun.len)
- var/obj/O = currentrun[currentrun.len]
- currentrun.len--
- if (!O || QDELETED(O))
- processing -= O
- if (MC_TICK_CHECK)
- return
- continue
-
- if(O.acid_level && O.acid_processing())
- else
- O.update_icon()
- processing -= O
-
- if (MC_TICK_CHECK)
- return
diff --git a/code/datums/components/acid.dm b/code/datums/components/acid.dm
new file mode 100644
index 0000000000..2e3784dc97
--- /dev/null
+++ b/code/datums/components/acid.dm
@@ -0,0 +1,65 @@
+/datum/component/acid
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
+ var/level = 0
+
+/datum/component/acid/Initialize(acidpwr, acid_volume)
+ if(!isobj(parent))
+ return COMPONENT_INCOMPATIBLE
+ var/obj/O = parent
+ var/acid_cap = acidpwr * 300
+ level = min(acidpwr * acid_volume, acid_cap)
+ START_PROCESSING(SSprocessing, src)
+ RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/add_acid_overlay)
+ if(isitem(parent))
+ RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/on_attack_hand)
+ O.update_icon()
+
+/datum/component/acid/proc/on_attack_hand(datum/source, mob/user)
+ var/obj/item/I = parent
+ if(istype(I) && level > 20 && !ismob(I.loc))// so we can still remove the clothes on us that have acid.
+ var/mob/living/carbon/C = user
+ if(istype(C))
+ if(!C.gloves || (!(C.gloves.resistance_flags & (UNACIDABLE|ACID_PROOF))))
+ to_chat(user, "The acid on [I] burns your hand!")
+ var/obj/item/bodypart/affecting = C.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm")
+ if(affecting && affecting.receive_damage( 0, 5 )) // 5 burn damage
+ C.update_damage_overlays()
+
+/datum/component/acid/InheritComponent(datum/component/C, i_am_original, acidpwr, acid_volume)
+ if(!i_am_original)
+ return
+ var/acid_cap = acidpwr * 300
+ if(level < acid_cap)
+ if(C)
+ var/datum/component/acid/other = C
+ level = min(level + other.level, acid_cap)
+ else
+ level = min(level + acidpwr * acid_volume, acid_cap)
+
+/datum/component/acid/Destroy()
+ STOP_PROCESSING(SSprocessing, src)
+ var/obj/O = parent
+ level = 0
+ O.update_overlays()
+ return ..()
+
+/datum/component/acid/process()
+ var/obj/O = parent
+ if(!istype(O))
+ qdel(src)
+ return PROCESS_KILL
+ if(!(O.resistance_flags & ACID_PROOF))
+ if(prob(33))
+ playsound(O.loc, 'sound/items/welder.ogg', 150, 1)
+ O.take_damage(min(1 + round(sqrt(level)*0.3), 300), BURN, "acid", 0)
+
+ level = max(level - (5 + 3*round(sqrt(level))), 0)
+ if(level <= 0)
+ qdel(src)
+ return PROCESS_KILL
+ else
+ O.update_icon()
+ return TRUE
+
+/datum/component/acid/proc/add_acid_overlay(atom/source, list/overlay_list)
+ overlay_list += GLOB.acid_overlay
diff --git a/code/datums/components/activity.dm b/code/datums/components/activity.dm
index ae18ca01a2..7c4c758d49 100644
--- a/code/datums/components/activity.dm
+++ b/code/datums/components/activity.dm
@@ -16,7 +16,7 @@
RegisterSignal(L, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_MOVABLE_TELEPORTED, COMSIG_LIVING_GUN_PROCESS_FIRE, COMSIG_MOB_APPLY_DAMAGE), .proc/minor_activity)
/datum/component/activity/proc/log_activity()
- historical_activity_levels[world.time] = activity_level
+ historical_activity_levels["[world.time]"] = activity_level
/datum/component/activity/proc/minor_activity(datum/source)
activity_level += 1
diff --git a/code/datums/components/crafting/recipes/recipes_misc.dm b/code/datums/components/crafting/recipes/recipes_misc.dm
index 032dd0ea90..625e850212 100644
--- a/code/datums/components/crafting/recipes/recipes_misc.dm
+++ b/code/datums/components/crafting/recipes/recipes_misc.dm
@@ -374,6 +374,20 @@
subcategory = CAT_MISCELLANEOUS
category = CAT_MISC
+/datum/crafting_recipe/motorized_wheelchair
+ name = "Hoverchair"
+ result = /obj/vehicle/ridden/wheelchair/motorized
+ reqs = list(/obj/item/stack/sheet/plasteel = 10,
+ /obj/item/stack/rods = 8,
+ /obj/item/stock_parts/manipulator = 2,
+ /obj/item/stock_parts/capacitor = 1)
+ parts = list(/obj/item/stock_parts/manipulator = 2,
+ /obj/item/stock_parts/capacitor = 1)
+ tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WRENCH)
+ time = 200
+ subcategory = CAT_MISCELLANEOUS
+ category = CAT_MISC
+
/datum/crafting_recipe/skateboard
name = "Skateboard"
result = /obj/vehicle/ridden/scooter/skateboard
diff --git a/code/game/objects/effects/alien_acid.dm b/code/game/objects/effects/alien_acid.dm
index 6496b392c3..40d950332c 100644
--- a/code/game/objects/effects/alien_acid.dm
+++ b/code/game/objects/effects/alien_acid.dm
@@ -9,6 +9,7 @@
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF
layer = ABOVE_NORMAL_TURF_LAYER
var/turf/target
+ var/acid_level = 0 // Removed from obj, so it goes here now
/obj/effect/acid/Initialize(mapload, acid_pwr, acid_amt)
@@ -42,7 +43,7 @@
for(var/obj/O in target)
if(prob(20) && !(resistance_flags & UNACIDABLE))
- if(O.acid_level < acid_level*0.3)
+ if(O.acid_level() < acid_level*0.3)
var/acid_used = min(acid_level*0.05, 20)
O.acid_act(10, acid_used)
acid_level = max(0, acid_level - acid_used*10)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index cbfd5ef5a0..cd486ccf6b 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -352,15 +352,6 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
C.update_damage_overlays()
return
- if(acid_level > 20 && ismob(loc))// so we can still remove the clothes on us that have acid.
- var/mob/living/carbon/C = user
- if(istype(C))
- if(!C.gloves || (!(C.gloves.resistance_flags & (UNACIDABLE|ACID_PROOF))))
- to_chat(user, "The acid on [src] burns your hand!")
- var/obj/item/bodypart/affecting = C.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm")
- if(affecting && affecting.receive_damage( 0, 5 )) // 5 burn damage
- C.update_damage_overlays()
-
if(!(interaction_flags_item & INTERACT_ITEM_ATTACK_HAND_PICKUP)) //See if we're supposed to auto pickup.
return
diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm
index 9ae8fb80db..60538b479b 100644
--- a/code/game/objects/items/handcuffs.dm
+++ b/code/game/objects/items/handcuffs.dm
@@ -1,6 +1,8 @@
/obj/item/restraints
breakouttime = 600
var/demoralize_criminals = TRUE // checked on carbon/carbon.dm to decide wheter to apply the handcuffed negative moodlet or not.
+ /// allow movement at all during breakout
+ var/allow_breakout_movement = FALSE
/obj/item/restraints/suicide_act(mob/living/carbon/user)
user.visible_message("[user] is strangling [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -243,6 +245,7 @@
throwforce = 0
w_class = WEIGHT_CLASS_NORMAL
slowdown = 7
+ allow_breakout_movement = TRUE
breakouttime = 300 //Deciseconds = 30s = 0.5 minute
/obj/item/restraints/legcuffs/proc/on_removed()
@@ -312,7 +315,7 @@
trap_damage = 0
item_flags = DROPDEL
flags_1 = NONE
- breakouttime = 25
+ breakouttime = 50
/obj/item/restraints/legcuffs/beartrap/energy/New()
..()
@@ -328,7 +331,7 @@
. = ..()
/obj/item/restraints/legcuffs/beartrap/energy/cyborg
- breakouttime = 20 // Cyborgs shouldn't have a strong restraint
+ breakouttime = 40 // Cyborgs shouldn't have a strong restraint
/obj/item/restraints/legcuffs/bola
name = "bola"
@@ -379,7 +382,7 @@
icon_state = "ebola"
hitsound = 'sound/weapons/taserhit.ogg'
w_class = WEIGHT_CLASS_SMALL
- breakouttime = 25
+ breakouttime = 50
/obj/item/restraints/legcuffs/bola/energy/on_removed()
do_sparks(1, TRUE, src)
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index 02f2009667..cc2e6412eb 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -204,32 +204,23 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
//the obj's reaction when touched by acid
/obj/acid_act(acidpwr, acid_volume)
if(!(resistance_flags & UNACIDABLE) && acid_volume)
-
- if(!acid_level)
- SSacid.processing[src] = src
- update_icon()
- var/acid_cap = acidpwr * 300 //so we cannot use huge amounts of weak acids to do as well as strong acids.
- if(acid_level < acid_cap)
- acid_level = min(acid_level + acidpwr * acid_volume, acid_cap)
+ AddComponent(/datum/component/acid, acidpwr, acid_volume)
return 1
-//the proc called by the acid subsystem to process the acid that's on the obj
-/obj/proc/acid_processing()
- . = 1
- if(!(resistance_flags & ACID_PROOF))
- if(prob(33))
- playsound(loc, 'sound/items/welder.ogg', 150, 1)
- take_damage(min(1 + round(sqrt(acid_level)*0.3), 300), BURN, "acid", 0)
-
- acid_level = max(acid_level - (5 + 3*round(sqrt(acid_level))), 0)
- if(!acid_level)
- return 0
-
//called when the obj is destroyed by acid.
/obj/proc/acid_melt()
- SSacid.processing -= src
+ var/datum/component/acid/acid = GetComponent(/datum/component/acid)
+ if(acid)
+ acid.RemoveComponent()
deconstruct(FALSE)
+/obj/proc/acid_level()
+ var/datum/component/acid/acid = GetComponent(/datum/component/acid)
+ if(acid)
+ return acid.level
+ else
+ return 0
+
//// FIRE
/obj/fire_act(exposed_temperature, exposed_volume)
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index a9a891464b..ca4428db57 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -22,8 +22,6 @@
var/resistance_flags = NONE // INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ON_FIRE | UNACIDABLE | ACID_PROOF
- var/acid_level = 0 //how much acid is on that obj
-
var/persistence_replacement //have something WAY too amazing to live to the next round? Set a new path here. Overuse of this var will make me upset.
var/current_skin //the item reskin
var/list/unique_reskin //List of options to reskin.
@@ -369,8 +367,6 @@
/obj/update_overlays()
. = ..()
- if(acid_level)
- . += GLOB.acid_overlay
if(resistance_flags & ON_FIRE)
. += GLOB.fire_overlay
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 01c62a7901..9a2b4aab1a 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -354,10 +354,10 @@
. = SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
. = O.clean_blood()
O.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
- if(isitem(O))
- var/obj/item/I = O
- I.acid_level = 0
- I.extinguish()
+ var/datum/component/acid/acid = O.GetComponent(/datum/component/acid)
+ if(acid)
+ acid.level = 0
+ O.extinguish()
/obj/machinery/shower/proc/wash_turf()
if(isturf(loc))
@@ -601,7 +601,9 @@
busy = FALSE
SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
O.clean_blood()
- O.acid_level = 0
+ var/datum/component/acid/acid = O.GetComponent(/datum/component/acid)
+ if(acid)
+ acid.level = 0
create_reagents(5)
reagents.add_reagent(dispensedreagent, 5)
reagents.reaction(O, TOUCH)
diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm
index c25e74fc5c..cfa3e7eb14 100644
--- a/code/modules/atmospherics/environmental/LINDA_fire.dm
+++ b/code/modules/atmospherics/environmental/LINDA_fire.dm
@@ -13,7 +13,7 @@
if(!air)
return
- if (air.get_oxidation_power(exposed_temperature) < 0.5)
+ if (air.get_oxidation_power(exposed_temperature) < 0.5 || air.get_moles(GAS_HYPERNOB) > 5)
return
var/has_fuel = air.get_moles(GAS_PLASMA) > 0.5 || air.get_moles(GAS_TRITIUM) > 0.5 || air.get_fuel_amount(exposed_temperature) > 0.5
if(active_hotspot)
@@ -152,7 +152,7 @@
if((temperature < FIRE_MINIMUM_TEMPERATURE_TO_EXIST) || (volume <= 1))
qdel(src)
return
- if(!location.air || location.air.get_oxidation_power() < 0.5 || (INSUFFICIENT(GAS_PLASMA) && INSUFFICIENT(GAS_TRITIUM) && location.air.get_fuel_amount() < 0.5))
+ if(!location.air || location.air.get_moles(GAS_HYPERNOB) > 5 || location.air.get_oxidation_power() < 0.5 || (INSUFFICIENT(GAS_PLASMA) && INSUFFICIENT(GAS_TRITIUM) && location.air.get_fuel_amount() < 0.5))
qdel(src)
return
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index e4d6f5253e..44379660b6 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -358,7 +358,7 @@
return
I.item_flags |= BEING_REMOVED
breakouttime = I.breakouttime
- var/datum/cuffbreak_checker/cuffbreak_checker = new(get_turf(src))
+ var/datum/cuffbreak_checker/cuffbreak_checker = new(get_turf(src), istype(I, /obj/item/restraints)? I : null)
if(!cuff_break)
visible_message("[src] attempts to remove [I]!")
to_chat(src, "You attempt to remove [I]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)")
@@ -384,16 +384,22 @@
/datum/cuffbreak_checker
var/turf/last
+ var/obj/item/restraints/cuffs
-/datum/cuffbreak_checker/New(turf/initial_turf)
+/datum/cuffbreak_checker/New(turf/initial_turf, obj/item/restraints/R)
last = initial_turf
+ if(R)
+ cuffs = R
/datum/cuffbreak_checker/proc/check_movement(atom/user, delay, atom/target, time_left, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool, list/passed_in)
if(get_turf(user) != last)
last = get_turf(user)
passed_in[1] = 0.5
+ if(cuffs && !cuffs.allow_breakout_movement)
+ return DO_AFTER_STOP
else
passed_in[1] = 1
+ return DO_AFTER_CONTINUE
/mob/living/carbon/proc/uncuff()
if (handcuffed)
@@ -961,7 +967,9 @@
/mob/living/carbon/ExtinguishMob()
for(var/X in get_equipped_items())
var/obj/item/I = X
- I.acid_level = 0 //washes off the acid on our clothes
+ var/datum/component/acid/acid = I.GetComponent(/datum/component/acid)
+ if(acid)
+ acid.level = 0
I.extinguish() //extinguishes our clothes
..()
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 6f1fe57df3..ac456ead3f 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -15,7 +15,6 @@
block_parry_data = /datum/block_parry_data/unarmed/human
default_block_parry_data = /datum/block_parry_data/unarmed/human
- causes_dirt_buildup_on_floor = TRUE
//Hair colour and style
var/hair_color = "000"
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index 1619d0f6de..54d6771c6c 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -90,13 +90,31 @@
//End bloody footprints
S.step_action()
+ if(movement_type & GROUND)
+ dirt_buildup()
/mob/living/carbon/human/Process_Spacemove(movement_dir = 0) //Temporary laziness thing. Will change to handles by species reee.
if(dna.species.space_move(src))
return TRUE
return ..()
-/mob/living/carbon/human/dirt_buildup(strength)
+/mob/living/carbon/human/proc/dirt_buildup(strength = 1)
if(!shoes || !(shoes.body_parts_covered & FEET))
return // barefoot advantage
- return ..()
+ var/turf/open/T = loc
+ if(!istype(T) || !T.dirt_buildup_allowed)
+ return
+ var/area/A = T.loc
+ if(!A.dirt_buildup_allowed)
+ return
+ var/multiplier = CONFIG_GET(number/turf_dirty_multiplier)
+ strength *= multiplier
+ var/obj/effect/decal/cleanable/dirt/D = locate() in T
+ if(D)
+ D.dirty(strength)
+ else
+ T.dirtyness += strength
+ if(T.dirtyness >= (isnull(T.dirt_spawn_threshold)? CONFIG_GET(number/turf_dirt_threshold) : T.dirt_spawn_threshold))
+ D = new /obj/effect/decal/cleanable/dirt(T)
+ D.dirty(T.dirt_spawn_threshold - T.dirtyness)
+ T.dirtyness = 0 // reset.
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 3b53eec64f..a76fbe4c4e 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -67,8 +67,6 @@
//Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects.
var/incorporeal_move = FALSE //FALSE is off, INCORPOREAL_MOVE_BASIC is normal, INCORPOREAL_MOVE_SHADOW is for ninjas
//and INCORPOREAL_MOVE_JAUNT is blocked by holy water/salt
- /// Do we make floors dirty as we move?
- var/causes_dirt_buildup_on_floor = FALSE
var/list/roundstart_quirks = list()
diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm
index bafa38ec5e..07b40b3ab1 100644
--- a/code/modules/mob/living/living_movement.dm
+++ b/code/modules/mob/living/living_movement.dm
@@ -102,31 +102,6 @@
if(lying && !buckled && prob(getBruteLoss()*200/maxHealth))
makeTrail(newloc, T, old_direction)
- if(causes_dirt_buildup_on_floor && (movement_type & GROUND))
- dirt_buildup()
-
-/**
- * Attempts to make the floor dirty.
- */
-/mob/living/proc/dirt_buildup(strength = 1)
- var/turf/open/T = loc
- if(!istype(T) || !T.dirt_buildup_allowed)
- return
- var/area/A = T.loc
- if(!A.dirt_buildup_allowed)
- return
- var/multiplier = CONFIG_GET(number/turf_dirty_multiplier)
- strength *= multiplier
- var/obj/effect/decal/cleanable/dirt/D = locate() in T
- if(D)
- D.dirty(strength)
- else
- T.dirtyness += strength
- if(T.dirtyness >= (isnull(T.dirt_spawn_threshold)? CONFIG_GET(number/turf_dirt_threshold) : T.dirt_spawn_threshold))
- D = new /obj/effect/decal/cleanable/dirt(T)
- D.dirty(T.dirt_spawn_threshold - T.dirtyness)
- T.dirtyness = 0 // reset.
-
/mob/living/Move_Pulled(atom/A)
. = ..()
if(!. || !isliving(A))
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 593d77f959..0c70f47c53 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -287,7 +287,9 @@
/datum/reagent/water/reaction_obj(obj/O, reac_volume)
O.extinguish()
- O.acid_level = 0
+ var/datum/component/acid/acid = O.GetComponent(/datum/component/acid)
+ if(acid)
+ acid.level = 0
// cubes
if(istype(O, /obj/item/reagent_containers/food/snacks/cube))
var/obj/item/reagent_containers/food/snacks/cube/cube = O
diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
index f3e14993ed..62e68e5b0e 100644
--- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
@@ -622,7 +622,9 @@
var/obj/O = owner.get_active_held_item()
if(O)
O.extinguish() //All shamelessly copied from water's reaction_obj, since I didn't seem to be able to get it here for some reason.
- O.acid_level = 0
+ var/datum/component/acid/acid = O.GetComponent(/datum/component/acid)
+ if(acid)
+ acid.level = 0
// Monkey cube
if(istype(O, /obj/item/reagent_containers/food/snacks/cube))
to_chat(owner, "[linked_extract] kept your hands wet! It makes [O] expand!")
diff --git a/code/modules/tooltip/tooltip.dm b/code/modules/tooltip/tooltip.dm
index fd45ea37d9..f9efd7d9c1 100644
--- a/code/modules/tooltip/tooltip.dm
+++ b/code/modules/tooltip/tooltip.dm
@@ -138,12 +138,10 @@ Notes:
. = ..()
if(tooltips)
if(!QDELETED(src))
- var/list/examine_list = examine(src)
- var/get_tooltip_data = get_tooltip_data()
- if(length(get_tooltip_data))
- examine_list = get_tooltip_data
- var/examine_data = examine_list.Join("
")
- openToolTip(usr, src, params, title = name, content = examine_data)
+ var/list/tooltip_data = get_tooltip_data()
+ if(length(tooltip_data))
+ var/examine_data = tooltip_data.Join("
")
+ openToolTip(usr, src, params, title = name, content = examine_data)
/atom/movable/MouseExited(location, control, params)
. = ..()
diff --git a/code/modules/vehicles/motorized_wheelchair.dm b/code/modules/vehicles/motorized_wheelchair.dm
new file mode 100644
index 0000000000..8e2d838066
--- /dev/null
+++ b/code/modules/vehicles/motorized_wheelchair.dm
@@ -0,0 +1,155 @@
+/obj/vehicle/ridden/wheelchair/motorized
+ name = "Hoverchair"
+ desc = "A chair with thrusters. It seems to have a motor in it."
+ icon = 'icons/obj/vehicles.dmi'
+ icon_state = "wheelchair_motorized"
+ max_integrity = 150
+ var/speed = 2
+ var/power_efficiency = 1
+ var/power_usage = 25
+ var/panel_open = FALSE
+ var/list/required_parts = list(/obj/item/stock_parts/manipulator,
+ /obj/item/stock_parts/manipulator,
+ /obj/item/stock_parts/capacitor)
+ var/obj/item/stock_parts/cell/power_cell
+
+/obj/vehicle/ridden/wheelchair/motorized/CheckParts(list/parts_list)
+ ..()
+ refresh_parts()
+
+/obj/vehicle/ridden/wheelchair/motorized/proc/refresh_parts()
+ speed = 1 // Should never be under 1
+ for(var/obj/item/stock_parts/manipulator/M in contents)
+ speed += M.rating
+ for(var/obj/item/stock_parts/capacitor/C in contents)
+ power_efficiency = C.rating
+ var/datum/component/riding/D = GetComponent(/datum/component/riding)
+ D.vehicle_move_delay = round((CONFIG_GET(number/movedelay/run_delay) * 2) / speed, world.tick_lag)
+
+/obj/vehicle/ridden/wheelchair/motorized/obj_destruction(damage_flag)
+ var/turf/T = get_turf(src)
+ for(var/atom/movable/A in contents)
+ A.forceMove(T)
+ if(isliving(A))
+ var/mob/living/L = A
+ L.update_mobility()
+ ..()
+
+/obj/vehicle/ridden/wheelchair/motorized/driver_move(mob/living/user, direction)
+ if(istype(user))
+ if(!canmove)
+ return FALSE
+ if(!power_cell)
+ to_chat(user, "There seems to be no cell installed in [src].")
+ canmove = FALSE
+ addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20)
+ return FALSE
+ if(power_cell.charge < power_usage / max(power_efficiency, 1))
+ to_chat(user, "The display on [src] blinks 'Out of Power'.")
+ canmove = FALSE
+ addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20)
+ return FALSE
+ if(user.get_num_arms() < arms_required)
+ to_chat(user, "You don't have enough arms to operate the motor controller!")
+ canmove = FALSE
+ addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20)
+ return FALSE
+ power_cell.use(power_usage / max(power_efficiency, 1))
+ return ..()
+
+/obj/vehicle/ridden/wheelchair/motorized/post_buckle_mob(mob/living/user)
+ . = ..()
+ density = TRUE
+
+/obj/vehicle/ridden/wheelchair/motorized/post_unbuckle_mob()
+ . = ..()
+ density = FALSE
+
+/obj/vehicle/ridden/wheelchair/motorized/attack_hand(mob/living/user)
+ if(power_cell && panel_open)
+ power_cell.update_icon()
+ user.put_in_hands(power_cell)
+ power_cell = null
+ to_chat(user, "You remove the power cell from [src].")
+ return
+ return ..()
+
+/obj/vehicle/ridden/wheelchair/motorized/attackby(obj/item/I, mob/user, params)
+ if(I.tool_behaviour == TOOL_SCREWDRIVER)
+ I.play_tool_sound(src)
+ panel_open = !panel_open
+ user.visible_message("[user] [panel_open ? "opens" : "closes"] the maintenance panel on [src].", "You [panel_open ? "open" : "close"] the maintenance panel.")
+ return
+ if(panel_open)
+ if(istype(I, /obj/item/stock_parts/cell))
+ if(power_cell)
+ to_chat(user, "There is a power cell already installed.")
+ else
+ I.forceMove(src)
+ power_cell = I
+ to_chat(user, "You install the [I].")
+ refresh_parts()
+ return
+ if(istype(I, /obj/item/stock_parts))
+ var/obj/item/stock_parts/B = I
+ var/P
+ for(var/obj/item/stock_parts/A in contents)
+ for(var/D in required_parts)
+ if(ispath(A.type, D))
+ P = D
+ break
+ if(istype(B, P) && istype(A, P))
+ if(B.get_part_rating() > A.get_part_rating())
+ B.forceMove(src)
+ user.put_in_hands(A)
+ user.visible_message("[user] replaces [A] with [B] in [src].", "You replace [A] with [B].")
+ break
+ refresh_parts()
+ return
+ return ..()
+
+/obj/vehicle/ridden/wheelchair/motorized/wrench_act(mob/living/user, obj/item/I)
+ to_chat(user, "You begin to detach the thrusters...")
+ if(I.use_tool(src, user, 40, volume=50))
+ to_chat(user, "You detach the thrusters and deconstruct the chair.")
+ new /obj/item/stack/rods(drop_location(), 8)
+ new /obj/item/stack/sheet/plasteel(drop_location(), 10)
+ var/turf/T = get_turf(src)
+ for(var/atom/movable/A in contents)
+ A.forceMove(T)
+ if(isliving(A))
+ var/mob/living/L = A
+ L.update_mobility()
+ qdel(src)
+ return TRUE
+
+/obj/vehicle/ridden/wheelchair/motorized/examine(mob/user)
+ . = ..()
+ if(panel_open)
+ . += "There is a small screen on it, [(in_range(user, src) || isobserver(user)) ? "[power_cell ? "it reads:" : "but it is dark."]" : "but you can't see it from here."]"
+ if(!power_cell || (!in_range(user, src) && !isobserver(user)))
+ return
+ . += "Speed: [speed]"
+ . += "Energy efficiency: [power_efficiency]"
+ . += "Power: [power_cell.charge] out of [power_cell.maxcharge]"
+
+/obj/vehicle/ridden/wheelchair/motorized/Bump(atom/movable/M)
+ . = ..()
+ // If the speed is higher than delay_multiplier throw the person on the wheelchair away
+ if(M.density && speed > 2 && has_buckled_mobs())
+ var/mob/living/H = buckled_mobs[1]
+ var/atom/throw_target = get_edge_target_turf(H, pick(GLOB.cardinals))
+ unbuckle_mob(H)
+ H.throw_at(throw_target, 2, 3)
+ H.Knockdown(100)
+ H.adjustStaminaLoss(40)
+ if(isliving(M))
+ var/mob/living/D = M
+ throw_target = get_edge_target_turf(D, pick(GLOB.cardinals))
+ D.throw_at(throw_target, 2, 3)
+ D.Knockdown(80)
+ D.adjustStaminaLoss(35)
+ visible_message("[src] crashes into [M], sending [H] and [D] flying!")
+ else
+ visible_message("[src] crashes into [M], sending [H] flying!")
+ playsound(src, 'sound/effects/bang.ogg', 50, 1)
diff --git a/code/modules/vehicles/wheelchair.dm b/code/modules/vehicles/wheelchair.dm
index a81dff37ad..28145ba8e1 100644
--- a/code/modules/vehicles/wheelchair.dm
+++ b/code/modules/vehicles/wheelchair.dm
@@ -26,8 +26,8 @@
AddComponent(/datum/component/simple_rotation,ROTATION_ALTCLICK | ROTATION_CLOCKWISE, CALLBACK(src, .proc/can_user_rotate),CALLBACK(src, .proc/can_be_rotated),null)
/obj/vehicle/ridden/wheelchair/obj_destruction(damage_flag)
- new /obj/item/stack/rods(drop_location(), 1)
- new /obj/item/stack/sheet/metal(drop_location(), 1)
+ new /obj/item/stack/rods(drop_location(), 8)
+ new /obj/item/stack/sheet/metal(drop_location(), 2)
..()
/obj/vehicle/ridden/wheelchair/Destroy()
@@ -53,7 +53,10 @@
/obj/vehicle/ridden/wheelchair/Moved()
. = ..()
cut_overlays()
- playsound(src, 'sound/effects/roll.ogg', 75, 1)
+ if(istype(src, /obj/vehicle/ridden/wheelchair/motorized))
+ playsound(src, 'sound/effects/chairwhoosh.ogg', 75, 1)
+ else
+ playsound(src, 'sound/effects/roll.ogg', 75, 1)
if(has_buckled_mobs())
handle_rotation_overlayed()
@@ -88,8 +91,12 @@
/obj/vehicle/ridden/wheelchair/proc/handle_rotation_overlayed()
cut_overlays()
- var/image/V = image(icon = icon, icon_state = "wheelchair_overlay", layer = FLY_LAYER, dir = src.dir)
- add_overlay(V)
+ if(istype(src, /obj/vehicle/ridden/wheelchair/motorized))
+ var/image/V = image(icon = icon, icon_state = "wheelchair_noverlay", layer = FLY_LAYER, dir = src.dir)
+ add_overlay(V)
+ else
+ var/image/V = image(icon = icon, icon_state = "wheelchair_overlay", layer = FLY_LAYER, dir = src.dir)
+ add_overlay(V)
diff --git a/html/changelog.html b/html/changelog.html
index 9af663a1f7..b1e5e2aa59 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -50,6 +50,52 @@
-->