You insert the power cell into \the [src].")
SStgui.update_uis(src)
@@ -270,11 +269,13 @@
settable_temperature_median + settable_temperature_range)
if("eject")
if(panel_open && cell)
- cell.forceMove(drop_location())
cell = null
+ for(var/obj/item/stock_parts/cell/M in component_parts)
+ M.forceMove(drop_location())
+ component_parts.Remove(M)
. = TRUE
-//Space Heaters without cel
+//Space Heaters without a cell
/obj/machinery/space_heater/no_cell
cell = null
@@ -287,7 +288,10 @@
/obj/machinery/space_heater/atmos
/obj/machinery/space_heater/atmos/Initialize(mapload)
- cell = /obj/item/stock_parts/cell/hyper
+ for(var/obj/item/stock_parts/cell/M in component_parts)
+ QDEL_NULL(M)
+ component_parts.Add(/obj/item/stock_parts/cell/hyper)
+ RefreshParts()
. = ..()
#undef HEATER_MODE_STANDBY
diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm
index 38dc7cc00b3a8..3c0e11ff55ac8 100644
--- a/code/game/machinery/status_display.dm
+++ b/code/game/machinery/status_display.dm
@@ -288,6 +288,8 @@
var/friendc = FALSE // track if Friend Computer mode
var/last_picture // For when Friend Computer mode is undone
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/evac, 32)
+
/obj/machinery/status_display/evac/Initialize(mapload)
. = ..()
// register for radio system
@@ -437,6 +439,8 @@
AI_EMOTION_RED_GLOW = "ai_hal",
)
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/ai, 32)
+
/obj/machinery/status_display/ai/Initialize(mapload)
. = ..()
GLOB.ai_status_displays.Add(src)
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index feba69aafc738..c0e616567412b 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -366,7 +366,7 @@
return
if(isliving(user))
var/mob/living/L = user
- if(!(L.mobility_flags & MOBILITY_STAND))
+ if(L.body_position == LYING_DOWN)
return
var/mob/living/target = A
if(!state_open)
@@ -466,6 +466,18 @@
if(mob_occupant)
dump_inventory_contents()
+/obj/machinery/suit_storage_unit/process()
+ if(!suit)
+ return
+ if(!istype(suit, /obj/item/clothing/suit/space))
+ return
+ if(!suit.cell)
+ return
+
+ var/obj/item/stock_parts/cell/C = suit.cell
+ use_power(charge_rate)
+ C.give(charge_rate)
+
/obj/machinery/suit_storage_unit/proc/shock(mob/user, prb)
if(!prob(prb))
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
@@ -474,7 +486,7 @@
if(electrocute_mob(user, src, src, 1, TRUE))
return 1
-/obj/machinery/suit_storage_unit/relaymove(mob/user)
+/obj/machinery/suit_storage_unit/relaymove(mob/living/user, direction)
if(locked)
if(message_cooldown <= world.time)
message_cooldown = world.time + 50
diff --git a/code/game/machinery/telecomms/machines/message_server.dm b/code/game/machinery/telecomms/machines/message_server.dm
index 5f7003e346d4d..3f093e9ab9b60 100644
--- a/code/game/machinery/telecomms/machines/message_server.dm
+++ b/code/game/machinery/telecomms/machines/message_server.dm
@@ -14,7 +14,7 @@
use_power = IDLE_POWER_USE
idle_power_usage = 10
active_power_usage = 100
- armor = list(MELEE = 25, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 70, STAMINA = 0)
+ armor = list(MELEE = 25, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 70, STAMINA = 0, BLEED = 0)
var/obj/item/stored
investigate_flags = ADMIN_INVESTIGATE_TARGET
diff --git a/code/game/machinery/transformer.dm b/code/game/machinery/transformer.dm
index e9884d629b4e9..737a712d92544 100644
--- a/code/game/machinery/transformer.dm
+++ b/code/game/machinery/transformer.dm
@@ -50,10 +50,11 @@
// Only humans can enter from the west side, while lying down.
var/move_dir = get_dir(loc, AM.loc)
var/mob/living/carbon/human/H = AM
- if((transform_standing || !(H.mobility_flags & MOBILITY_STAND)) && move_dir == EAST)// || move_dir == WEST)
+ if((transform_standing || H.body_position == LYING_DOWN) && move_dir == EAST)// || move_dir == WEST)
AM.forceMove(drop_location())
do_transform(AM)
+
/obj/machinery/transformer/CanAllowThrough(atom/movable/mover, border_dir)
. = ..()
// Allows items to go through,
diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm
index 601f1e68a95a1..d1520a6ad6f47 100644
--- a/code/game/machinery/washing_machine.dm
+++ b/code/game/machinery/washing_machine.dm
@@ -365,7 +365,7 @@ GLOBAL_LIST_INIT(dye_registry, list(
new /obj/item/restraints/handcuffs(loc)
..()
-/obj/machinery/washing_machine/relaymove(mob/user)
+/obj/machinery/washing_machine/relaymove(mob/living/user, direction)
container_resist(user)
/obj/machinery/washing_machine/container_resist(mob/living/user)
diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm
index 3ef541ccb225a..bde20b4ddb8b8 100644
--- a/code/game/objects/buckling.dm
+++ b/code/game/objects/buckling.dm
@@ -1,11 +1,15 @@
/atom/movable
+ /// Whether the atom allows mobs to be buckled to it. Can be ignored in [/atom/movable/proc/buckle_mob()] if force = TRUE
var/can_buckle = FALSE
- /// Bed-like behaviour, forces mob.lying = buckle_lying if != -1
- var/buckle_lying = -1
+ /// Bed-like behaviour, forces mob.lying = buckle_lying if not set to [NO_BUCKLE_LYING].
+ var/buckle_lying = NO_BUCKLE_LYING
/// Require people to be handcuffed before being able to buckle. eg: pipes
var/buckle_requires_restraints = FALSE
+ // The mobs currently buckled to this atom
var/list/mob/living/buckled_mobs = null //list()
+ /// The maximum number of mob/livings allowed to be buckled to this atom at once
var/max_buckled_mobs = 1
+ /// Whether things buckled to this atom can be pulled while they're buckled
var/buckle_prevents_pull = FALSE
var/can_be_unanchored = FALSE
@@ -15,7 +19,7 @@
if(.)
return
if(can_buckle && has_buckled_mobs())
- if(buckled_mobs.len > 1)
+ if(length(buckled_mobs) > 1)
var/mob/living/unbuckled = tgui_input_list(user, "Who do you wish to unbuckle?", "Unbuckle", sort_names(buckled_mobs))
if(isnull(unbuckled))
return
@@ -25,11 +29,11 @@
if(user_unbuckle_mob(buckled_mobs[1],user))
return TRUE
-/atom/movable/attackby(obj/item/W, mob/user, params)
- if(!can_buckle || !istype(W, /obj/item/riding_offhand) || !user.Adjacent(src))
+/atom/movable/attackby(obj/item/attacking_item, mob/user, params)
+ if(!can_buckle || !istype(attacking_item, /obj/item/riding_offhand) || !user.Adjacent(src))
return ..()
- var/obj/item/riding_offhand/riding_item = W
+ var/obj/item/riding_offhand/riding_item = attacking_item
var/mob/living/carried_mob = riding_item.rider
if(carried_mob == user) //Piggyback user.
return
@@ -43,32 +47,47 @@
if(.)
return
if(Adjacent(user) && can_buckle && has_buckled_mobs())
- if(buckled_mobs.len > 1)
+ if(length(buckled_mobs) > 1)
var/mob/living/unbuckled = tgui_input_list(user, "Who do you wish to unbuckle?", "Unbuckle", sort_names(buckled_mobs))
if(isnull(unbuckled))
return
- if(user_unbuckle_mob(unbuckled,user))
- return TRUE
+ return user_unbuckle_mob(unbuckled,user)
else
- if(user_unbuckle_mob(buckled_mobs[1],user))
- return TRUE
+ return user_unbuckle_mob(buckled_mobs[1], user)
/atom/movable/MouseDrop_T(mob/living/M, mob/living/user)
. = ..()
return mouse_buckle_handling(M, user)
+/**
+ * Does some typechecks and then calls user_buckle_mob
+ *
+ * Arguments:
+ * M - The mob being buckled to src
+ * user - The mob buckling M to src
+ */
/atom/movable/proc/mouse_buckle_handling(mob/living/M, mob/living/user)
if(can_buckle && istype(M) && istype(user))
- if(user_buckle_mob(M, user, check_loc = FALSE))
- return TRUE
+ return user_buckle_mob(M, user)
+/**
+ * Returns TRUE if there are mobs buckled to this atom and FALSE otherwise
+ */
/atom/movable/proc/has_buckled_mobs()
if(!buckled_mobs)
return FALSE
if(buckled_mobs.len)
return TRUE
-//procs that handle the actual buckling and unbuckling
+/**
+ * Set a mob as buckled to src
+ *
+ * If you want to have a mob buckling another mob to something, or you want a chat message sent, use user_buckle_mob instead.
+ * Arguments:
+ * M - The mob to be buckled to src
+ * force - Set to TRUE to ignore src's can_buckle and M's can_buckle_to
+ * check_loc - Set to FALSE to allow buckling from adjacent turfs, or TRUE if buckling is only allowed with src and M on the same turf.
+ */
/atom/movable/proc/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
if(!buckled_mobs)
buckled_mobs = list()
@@ -76,15 +95,6 @@
if(!is_buckle_possible(M, force, check_loc))
return FALSE
- M.buckling = src
- if(!M.can_buckle() && !force)
- if(M == usr)
- to_chat(M, "You are unable to buckle yourself to [src]! ")
- else
- to_chat(usr, "You are unable to buckle [M] to [src]! ")
- M.buckling = null
- return FALSE
-
if(M.pulledby)
if(buckle_prevents_pull)
M.pulledby.stop_pulling()
@@ -98,11 +108,9 @@
if (!check_loc && M.loc != loc)
M.forceMove(loc)
- M.buckling = null
M.set_buckled(src)
M.setDir(dir)
buckled_mobs |= M
- M.update_mobility()
M.throw_alert("buckled", /atom/movable/screen/alert/restrained/buckled)
/*
M.set_glide_size(glide_size)
@@ -124,17 +132,31 @@
M.adjust_fire_stacks(1)
M.IgniteMob()
-/atom/movable/proc/unbuckle_mob(mob/living/buckled_mob, force=FALSE)
- if(istype(buckled_mob) && buckled_mob.buckled == src && (buckled_mob.can_unbuckle() || force))
- . = buckled_mob
- buckled_mob.set_buckled(null)
- buckled_mob.set_anchored(initial(buckled_mob.anchored))
- buckled_mob.update_mobility()
- buckled_mob.clear_alert("buckled")
- buckled_mobs -= buckled_mob
- SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, buckled_mob, force)
+/**
+ * Set a mob as unbuckled from src
+ *
+ * The mob must actually be buckled to src or else bad things will happen.
+ * Arguments:
+ * buckled_mob - The mob to be unbuckled
+ * force - TRUE if we should ignore buckled_mob.can_buckle_to
+ */
+/atom/movable/proc/unbuckle_mob(mob/living/buckled_mob, force = FALSE)
+ if(!isliving(buckled_mob))
+ CRASH("Non-living [buckled_mob] thing called unbuckle_mob() for source.")
+ if(buckled_mob.buckled != src)
+ CRASH("[buckled_mob] called unbuckle_mob() for source while having buckled as [buckled_mob.buckled].")
+ if(!force && !buckled_mob.can_buckle_to)
+ return
+ . = buckled_mob
+ buckled_mob.set_buckled(null)
+ buckled_mob.set_anchored(initial(buckled_mob.anchored))
+ buckled_mob.clear_alert("buckled")
+ //buckled_mob.set_glide_size(DELAY_TO_GLIDE_SIZE(buckled_mob.total_multiplicative_slowdown()))
+ buckled_mobs -= buckled_mob
+ SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, buckled_mob, force)
+
+ post_unbuckle_mob(.)
- post_unbuckle_mob(.)
/atom/movable/proc/unbuckle_all_mobs(force=FALSE)
if(!has_buckled_mobs())
@@ -154,9 +176,11 @@
* Simple helper proc that runs a suite of checks to test whether it is possible or not to buckle the target mob to src.
*
* Returns FALSE if any conditions that should prevent buckling are satisfied. Returns TRUE otherwise.
+ * Called from [/atom/movable/proc/buckle_mob] and [/atom/movable/proc/is_user_buckle_possible].
* Arguments:
* * target - Target mob to check against buckling to src.
- * * force - Whether or not the buckle should be forced. If TRUE, ignores src's can_buckle var.
+ * * force - Whether or not the buckle should be forced. If TRUE, ignores src's can_buckle var and target's can_buckle_to
+ * * check_loc - TRUE if target and src have to be on the same tile, FALSE if they are allowed to just be adjacent
* * check_loc - Whether to do a proximity check or not. The proximity check looks for target.loc == src.loc.
*/
/atom/movable/proc/is_buckle_possible(mob/living/target, force = FALSE, check_loc = TRUE)
@@ -172,10 +196,6 @@
if(!can_buckle && !force)
return FALSE
- // Check if this atom can buckle, proc wise.
- if(!target.can_buckle() && !force)
- return FALSE
-
// If we're checking the loc, make sure the target is on the thing we're bucking them to.
if(check_loc && target.loc != loc)
return FALSE
@@ -192,16 +212,21 @@
if(buckle_requires_restraints && !HAS_TRAIT(target, TRAIT_RESTRAINED))
return FALSE
+ //If buckling is forbidden for the target, cancel
+ if(!target.can_buckle_to && !force)
+ return FALSE
+
return TRUE
/**
* Simple helper proc that runs a suite of checks to test whether it is possible or not for user to buckle target mob to src.
*
* Returns FALSE if any conditions that should prevent buckling are satisfied. Returns TRUE otherwise.
+ * Called from [/atom/movable/proc/user_buckle_mob].
* Arguments:
* * target - Target mob to check against buckling to src.
* * user - The mob who is attempting to buckle the target to src.
- * * check_loc - Whether to do a proximity check or not when calling is_buckle_possible().
+ * * check_loc - TRUE if target and src have to be on the same tile, FALSE if buckling is allowed from adjacent tiles
*/
/atom/movable/proc/is_user_buckle_possible(mob/living/target, mob/user, check_loc = TRUE)
// Standard adjacency and other checks.
@@ -212,15 +237,20 @@
if(!is_buckle_possible(target, FALSE, check_loc))
return FALSE
- // If the person attempting to buckle is stood on this atom's turf and they're not buckling themselves,
- // buckling shouldn't be possible as they're blocking it.
- if((target != user) && (get_turf(user) == get_turf(src)))
- to_chat(target, "You are unable to buckle [target] to [src] while it is blocked! ")
- return FALSE
-
return TRUE
-//Wrapper procs that handle sanity and user feedback
+/**
+ * Handles a mob buckling another mob to src and sends a visible_message
+ *
+ * Basically exists to do some checks on the user and then call buckle_mob where the real buckling happens.
+ * First, checks if the buckle is valid and cancels if it isn't.
+ * Second, checks if src is on a different turf from the target; if it is, does a do_after and another check for sanity
+ * Finally, calls [/atom/movable/proc/buckle_mob] to buckle the target to src then gives chat feedback
+ * Arguments:
+ * * M - The target mob/living being buckled to src
+ * * user - The other mob that's buckling M to src
+ * * check_loc - TRUE if src and M have to be on the same turf, false otherwise
+ */
/atom/movable/proc/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE)
// Is buckling even possible? Do a full suite of checks.
if(!is_user_buckle_possible(M, user, check_loc))
@@ -248,12 +278,21 @@
M.visible_message(\
"[M] buckles [M.p_them()]self to [src]. ",\
"You buckle yourself to [src]. ",\
- "You hear metal clanking. ")
+ "You hear metal clanking. ")
else
M.visible_message("[user] buckles [M] to [src]! ",\
"[user] buckles you to [src]! ",\
"You hear metal clanking. ")
+/**
+ * Handles a user unbuckling a mob from src and sends a visible_message
+ *
+ * Basically just calls unbuckle_mob, sets fingerprint, and sends a visible_message
+ * about the user unbuckling the mob
+ * Arguments:
+ * buckled_mob - The mob/living to unbuckle
+ * user - The mob unbuckling buckled_mob
+ */
/atom/movable/proc/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
var/mob/living/M = unbuckle_mob(buckled_mob)
if(M)
@@ -261,12 +300,12 @@
M.visible_message(\
"[user] unbuckles [M] from [src]. ",\
"[user] unbuckles you from [src]. ",\
- "You hear metal clanking. ")
+ "You hear metal clanking. ")
else
M.visible_message(\
"[M] unbuckles [M.p_them()]self from [src]. ",\
"You unbuckle yourself from [src]. ",\
- "You hear metal clanking. ")
+ "You hear metal clanking. ")
add_fingerprint(user)
if(isliving(M.pulledby))
var/mob/living/L = M.pulledby
diff --git a/code/game/objects/effects/anomalies/anomaly_bleed.dm b/code/game/objects/effects/anomalies/anomaly_bleed.dm
new file mode 100644
index 0000000000000..81cab90bc4972
--- /dev/null
+++ b/code/game/objects/effects/anomalies/anomaly_bleed.dm
@@ -0,0 +1,61 @@
+/obj/effect/anomaly/blood
+ name = "blood anomaly"
+ icon_state = "blood_anomaly"
+ density = TRUE
+ aSignal = /obj/item/assembly/signaler/anomaly/blood
+ var/sucking = FALSE
+
+/obj/effect/anomaly/blood/anomalyEffect(delta_time)
+ if (sucking)
+ return
+ ..()
+ if (DT_PROB(20, delta_time))
+ AddComponent(/datum/component/pellet_cloud, projectile_type=/obj/projectile/bullet/shrapnel/bleed, magnitude=3)
+ playsound(src, 'sound/weapons/shrapnel.ogg', 70, TRUE)
+ if (DT_PROB(10, delta_time))
+ for (var/mob/living/carbon/bleed_target in view(6, src))
+ if (!bleed_target.resting)
+ continue
+ if (do_teleport(src, get_turf(bleed_target), channel = TELEPORT_CHANNEL_BLUESPACE))
+ bleed_target.Stun(3 SECONDS)
+ INVOKE_ASYNC(src, PROC_REF(suck_blood))
+ break
+
+/obj/effect/anomaly/blood/detonate()
+ // Stop processing here since we don't want to keep moving while doing the detonation action
+ STOP_PROCESSING(SSobj, src)
+ // Needs to sleep since this gets instantly deleted as soon as the proc ends
+ for (var/mob/living/carbon/human/player in shuffle(GLOB.player_list))
+ if (!is_station_level(player.z))
+ continue
+ var/turf/player_loc = get_turf(player)
+ var/list/nearby_turfs = RANGE_TURFS(4, player_loc)
+ shuffle_inplace(nearby_turfs)
+ var/turf/target = locate(/turf/open) in nearby_turfs
+ if (!target)
+ continue
+ // Blocked by the bluespace anchor
+ if (!do_teleport(src, target, channel = TELEPORT_CHANNEL_BLUESPACE))
+ return
+ sleep(40)
+ if (QDELETED(src))
+ return
+ AddComponent(/datum/component/pellet_cloud, projectile_type=/obj/projectile/bullet/shrapnel/bleed, magnitude=3)
+ playsound(src, 'sound/weapons/shrapnel.ogg', 70, TRUE)
+ sleep(20)
+ if (QDELETED(src))
+ return
+
+/obj/effect/anomaly/blood/proc/suck_blood()
+ sucking = FALSE
+ for (var/mob/living/carbon/bleed_target in loc)
+ bleed_target.add_bleeding(BLEED_SURFACE)
+ bleed_target.emote("scream")
+ sucking = TRUE
+ if (sucking)
+ new /obj/effect/temp_visual/cult/sparks(loc)
+ addtimer(CALLBACK(src, PROC_REF(suck_blood)), 0.5 SECONDS)
+
+/obj/projectile/bullet/shrapnel/bleed
+ damage = 4
+ bleed_force = BLEED_DEEP_WOUND
diff --git a/code/game/objects/effects/contraband.dm b/code/game/objects/effects/contraband.dm
index 55f9515d880e5..07c0d3f0c5d3b 100644
--- a/code/game/objects/effects/contraband.dm
+++ b/code/game/objects/effects/contraband.dm
@@ -603,7 +603,7 @@
/obj/structure/sign/poster/official/no_erp
name = "No ERP"
- desc = "This poster reminds the crew that Eroticism, Rape and Pornography are banned on Nanotrasen stations."
+ desc = "This poster reminds the crew that Eroticism, Reproduction and Pornography are banned on Nanotrasen stations."
icon_state = "poster34_legit"
/obj/structure/sign/poster/official/wtf_is_co2
diff --git a/code/game/objects/effects/decals/misc.dm b/code/game/objects/effects/decals/misc.dm
index 59481d74d49bb..dc132da8e1b06 100644
--- a/code/game/objects/effects/decals/misc.dm
+++ b/code/game/objects/effects/decals/misc.dm
@@ -55,7 +55,7 @@
if(!turf_mob.can_inject())
continue
- if(!(turf_mob.mobility_flags & MOBILITY_STAND) && !travelled_max_distance)
+ if(turf_mob.body_position != STANDING_UP && !travelled_max_distance)
continue
lifetime--
@@ -76,4 +76,4 @@
desc = "A lightweight support lattice."
icon = 'icons/obj/smooth_structures/catwalks/lattice.dmi'
icon_state = "lattice-255"
- density = TRUE
+ density = FALSE
diff --git a/code/game/objects/effects/decals/turfdecal/markings.dm b/code/game/objects/effects/decals/turfdecal/markings.dm
index 83caefda4b508..5581acdeb62c9 100644
--- a/code/game/objects/effects/decals/turfdecal/markings.dm
+++ b/code/game/objects/effects/decals/turfdecal/markings.dm
@@ -464,23 +464,84 @@
/obj/effect/turf_decal/numbers/two_nine
icon_state = "number_2-9"
-/obj/effect/turf_decal/techfloor
+///Borderfloors
+
+//Plain
+/obj/effect/turf_decal/edges/borderfloor
+ icon_state = "borderfloor"
+
+/obj/effect/turf_decal/edges/borderfloor/corner1
+ icon_state = "borderfloorcorner"
+
+/obj/effect/turf_decal/edges/borderfloor/corner2
+ icon_state = "borderfloorcorner2"
+
+/obj/effect/turf_decal/edges/borderfloor/full
+ icon_state = "borderfloorfull"
+
+/obj/effect/turf_decal/edges/borderfloor/cee
+ icon_state = "borderfloorcee"
+
+//Black
+/obj/effect/turf_decal/edges/borderfloor/black
+ icon_state = "borderfloor_black"
+
+/obj/effect/turf_decal/edges/borderfloor/black/corner1
+ icon_state = "borderfloorcorner_black"
+
+/obj/effect/turf_decal/edges/borderfloor/black/corner2
+ icon_state = "borderfloorcorner2_black"
+
+/obj/effect/turf_decal/edges/borderfloor/black/full
+ icon_state = "borderfloorfull_black"
+
+/obj/effect/turf_decal/edges/borderfloor/black/cee
+ icon_state = "borderfloorcee_black"
+
+//White
+/obj/effect/turf_decal/edges/borderfloor/white
+ icon_state = "borderfloor_white"
+
+/obj/effect/turf_decal/edges/borderfloor/white/corner1
+ icon_state = "borderfloorcorner_white"
+
+/obj/effect/turf_decal/edges/borderfloor/white/corner2
+ icon_state = "borderfloorcorner2_white"
+
+/obj/effect/turf_decal/edges/borderfloor/white/full
+ icon_state = "borderfloorfull_white"
+
+/obj/effect/turf_decal/edges/borderfloor/white/cee
+ icon_state = "borderfloorcee_white"
+
+/obj/effect/turf_decal/edges/borderfloor/edge
+ icon_state = "edge"
+
+//Techfloors
+
+/obj/effect/turf_decal/edges/techfloor
icon_state = "techfloor_edges"
-/obj/effect/turf_decal/techfloor/corners
+/obj/effect/turf_decal/edges/techfloor/corners
icon_state = "techfloor_corners"
+/obj/effect/turf_decal/edges/techfloor_orange
+ icon_state = "techfloororange_edges"
+
+/obj/effect/turf_decal/edges/techfloor_orange/corners
+ icon_state = "techfloororange_corners"
+
/obj/effect/turf_decal/evac
icon_state = "evac"
-
+
/obj/effect/turf_decal/evac/evac_big
icon_state = "evac_big"
-
+
/obj/effect/turf_decal/evac/evac_massive_left
icon_state = "evac_massive_left"
-
+
/obj/effect/turf_decal/evac/evac_massive_middle
icon_state = "evac_massive_middle"
-
+
/obj/effect/turf_decal/evac/evac_massive_right
icon_state = "evac_massive_right"
diff --git a/code/game/objects/effects/decals/turfdecal/tilecoloring.dm b/code/game/objects/effects/decals/turfdecal/tilecoloring.dm
index 62e36d0324d5d..805681dd7ee4e 100644
--- a/code/game/objects/effects/decals/turfdecal/tilecoloring.dm
+++ b/code/game/objects/effects/decals/turfdecal/tilecoloring.dm
@@ -944,6 +944,77 @@
color = "#[random_short_color()]"
return ..()
+
+
+///SPECIAL
+
+//Steelgrid
+/obj/effect/turf_decal/tile/steelgrid
+ icon_state = "steelgrid_corner"
+
+/obj/effect/turf_decal/tile/steelgrid/diagonal
+ icon_state = "steelgrid_diagonal"
+
+/obj/effect/turf_decal/tile/steelgrid/anticorner
+ icon_state = "steelgrid_anticorner"
+
+
+//techfloor
+/obj/effect/turf_decal/tile/techfloor
+ icon_state = "techfloor_corner"
+
+/obj/effect/turf_decal/tile/techfloor/diagonal
+ icon_state = "techfloor_diagonal"
+
+/obj/effect/turf_decal/tile/techfloor/anticorner
+ icon_state = "techfloor_anticorner"
+
+
+//techfloorgrid
+/obj/effect/turf_decal/tile/techfloorgrid
+ icon_state = "techfloorgrid_corner"
+
+/obj/effect/turf_decal/tile/techfloorgrid/diagonal
+ icon_state = "techfloorgrid_diagonal"
+
+/obj/effect/turf_decal/tile/techfloorgrid/anticorner
+ icon_state = "techfloorgrid_anticorner"
+
+
+//"Rust"
+
+/obj/effect/turf_decal/tile/monorust
+ icon_state = "mono_rusted1"
+
+/obj/effect/turf_decal/tile/monorust/intensity2
+ icon_state = "mono_rusted2"
+
+/obj/effect/turf_decal/tile/monorust/intensity3
+ icon_state = "mono_rusted3"
+
+
+/obj/effect/turf_decal/tile/cornerrust
+ icon_state = "part_rusted1"
+
+/obj/effect/turf_decal/tile/cornerrust/intensity2
+ icon_state = "part_rusted2"
+
+/obj/effect/turf_decal/tile/cornerrust/intensity3
+ icon_state = "part_rusted3"
+
+
+/obj/effect/turf_decal/tile/colorrust
+ icon_state = "color_rusted"
+
+/obj/effect/turf_decal/tile/colorrust/corner
+ icon_state = "color_rustedcorner"
+
+/obj/effect/turf_decal/tile/colorrust/full
+ icon_state = "color_rustedfull"
+
+/obj/effect/turf_decal/tile/colorrust/cee
+ icon_state = "color_rustedcee"
+
/// Trimlines
/obj/effect/turf_decal/trimline
diff --git a/code/game/objects/effects/lighting.dm b/code/game/objects/effects/lighting.dm
new file mode 100644
index 0000000000000..a0838f6e840fa
--- /dev/null
+++ b/code/game/objects/effects/lighting.dm
@@ -0,0 +1,42 @@
+/**
+ * Basically, a fake object that emits light.
+ *
+ * Why is this used sometimes instead of giving atoms light values directly?
+ * Because using these, you can have multiple light sources in a single object.
+ */
+/obj/effect/dummy/lighting_obj
+ name = "lighting"
+ desc = "Tell a coder if you're seeing this."
+ icon_state = "nothing"
+ light_system = MOVABLE_LIGHT
+ light_range = MINIMUM_USEFUL_LIGHT_RANGE
+ light_color = COLOR_WHITE
+ //blocks_emissive = EMISSIVE_BLOCK_NONE
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+
+/obj/effect/dummy/lighting_obj/Initialize(mapload, range, power, color, duration)
+ . = ..()
+ if(!isnull(range))
+ set_light_range(range)
+ if(!isnull(power))
+ set_light_power(power)
+ if(!isnull(color))
+ set_light_color(color)
+ if(duration)
+ QDEL_IN(src, duration)
+
+/obj/effect/dummy/lighting_obj/moblight
+ name = "mob"
+
+/obj/effect/dummy/lighting_obj/moblight/Initialize(mapload, range, power, color, duration)
+ . = ..()
+ if(!ismob(loc))
+ return INITIALIZE_HINT_QDEL
+
+/obj/effect/dummy/lighting_obj/moblight/fire
+ name = "fire"
+ light_color = LIGHT_COLOR_FIRE
+ light_range = LIGHT_RANGE_FIRE
+
+/obj/effect/dummy/lighting_obj/moblight/species
+ name = "species lighting"
diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm
index fcc05faa8dec1..46e723f021783 100644
--- a/code/game/objects/effects/misc.dm
+++ b/code/game/objects/effects/misc.dm
@@ -100,31 +100,5 @@
/obj/effect/abstract/marker/at
name = "active turf marker"
-
-/obj/effect/dummy/lighting_obj
- name = "lighting fx obj"
- desc = "Tell a coder if you're seeing this."
- icon_state = "nothing"
- light_color = "#FFFFFF"
- light_system = MOVABLE_LIGHT
- light_range = MINIMUM_USEFUL_LIGHT_RANGE
+/obj/effect/abstract/directional_lighting
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
-
-/obj/effect/dummy/lighting_obj/Initialize(mapload, _range, _power, _color, _duration)
- . = ..()
- if(!isnull(_range))
- set_light_range(_range)
- if(!isnull(_power))
- set_light_power(_power)
- if(!isnull(_color))
- set_light_color(_color)
- if(_duration)
- QDEL_IN(src, _duration)
-
-/obj/effect/dummy/lighting_obj/moblight
- name = "mob lighting fx"
-
-/obj/effect/dummy/lighting_obj/moblight/Initialize(mapload, _color, _range, _power, _duration)
- . = ..()
- if(!ismob(loc))
- return INITIALIZE_HINT_QDEL
diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm
index 85c8babc56308..b398597382f38 100644
--- a/code/game/objects/effects/overlays.dm
+++ b/code/game/objects/effects/overlays.dm
@@ -83,3 +83,14 @@
layer = FLOAT_LAYER
vis_flags = VIS_INHERIT_ID
appearance_flags = KEEP_TOGETHER | LONG_GLIDE | PIXEL_SCALE
+
+/obj/effect/overlay/light_cone
+ name = ""
+ icon = 'icons/effects/light_overlays/light_cone.dmi'
+ icon_state = "light"
+ layer = O_LIGHTING_VISUAL_LAYER
+ plane = O_LIGHTING_VISUAL_PLANE
+ appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ vis_flags = NONE
+ alpha = 110
diff --git a/code/game/objects/effects/spawners/roomspawner.dm b/code/game/objects/effects/spawners/roomspawner.dm
index 01f3e47265ad3..2444e6cf3aca1 100644
--- a/code/game/objects/effects/spawners/roomspawner.dm
+++ b/code/game/objects/effects/spawners/roomspawner.dm
@@ -42,13 +42,61 @@
room_width = 10
room_height = 5
icon_state = "random_room_alternative"
- rooms = list("sk_rdm011_barbershop","sk_rdm031_deltarobotics","sk_rdm039_deltaclutter1","sk_rdm040_deltabotnis","sk_rdm045_deltacafeteria","sk_rdm046_deltaarcade","sk_rdm082_maintmedical","sk_rdm091_skidrow","sk_rdm100_meetingroom","sk_rdm105_phage","sk_rdm125_courtroom","sk_rdm126_gaschamber","sk_rdm127_oldaichamber","sk_rdm128_radiationtherapy","sk_rdm150_smallmedlobby","sk_rdm151_ratburger","sk_rdm152_geneticsoffice","sk_rdm153_hobowithpeter","sk_rdm154_butchersden","sk_rdm155_punjiconveyor","sk_rdm156_oldairlock_interchange","sk_rdm161_kilovault")
+ rooms = list(
+ "sk_rdm011_barbershop",
+ "sk_rdm031_deltarobotics",
+ "sk_rdm039_deltaclutter1",
+ "sk_rdm040_deltabotnis",
+ "sk_rdm045_deltacafeteria",
+ "sk_rdm046_deltaarcade",
+ "sk_rdm082_maintmedical",
+ "sk_rdm091_skidrow",
+ "sk_rdm100_meetingroom",
+ "sk_rdm105_phage",
+ "sk_rdm125_courtroom",
+ "sk_rdm126_gaschamber",
+ "sk_rdm127_oldaichamber",
+ "sk_rdm128_radiationtherapy",
+ "sk_rdm150_smallmedlobby",
+ "sk_rdm151_ratburger",
+ "sk_rdm152_geneticsoffice",
+ "sk_rdm153_hobowithpeter",
+ "sk_rdm154_butchersden",
+ "sk_rdm155_punjiconveyor",
+ "sk_rdm156_oldairlock_interchange",
+ "sk_rdm161_kilovault")
/obj/effect/spawner/room/special/tenxten_terrestrial
name = "10x10 terrestrial room"
room_width = 10
room_height = 10
icon_state = "random_room_alternative"
- rooms = list("sk_rdm033_deltalibrary","sk_rdm060_snakefighter","sk_rdm062_roosterdome","sk_rdm070_pubbybar","sk_rdm083_bigtheatre","sk_rdm098_graffitiroom","sk_rdm102_podrepairbay","sk_rdm106_sanitarium","sk_rdm129_beach","sk_rdm130_benoegg","sk_rdm131_confinementroom","sk_rdm132_conveyorroom","sk_rdm133_oldoffice","sk_rdm134_snowforest","sk_rdm141_6sectorsdown","sk_rdm142_olddiner","sk_rdm143_gamercave","sk_rdm144_smallmagician","sk_rdm145_ladytesla_altar","sk_rdm146_blastdoor_interchange","sk_rdm147_advbotany","sk_rdm148_botany_apiary","sk_rdm157_chess","sk_rdm159_kilosnakepit","sk_rdm167_library_ritual")
+ rooms = list(
+ "sk_rdm033_deltalibrary",
+ "sk_rdm060_snakefighter",
+ "sk_rdm062_roosterdome",
+ "sk_rdm070_pubbybar",
+ "sk_rdm083_bigtheatre",
+ "sk_rdm098_graffitiroom",
+ "sk_rdm102_podrepairbay",
+ "sk_rdm106_sanitarium",
+ "sk_rdm129_beach",
+ "sk_rdm130_benoegg",
+ "sk_rdm131_confinementroom",
+ "sk_rdm132_conveyorroom",
+ "sk_rdm133_oldoffice",
+ "sk_rdm134_snowforest",
+ "sk_rdm141_6sectorsdown",
+ "sk_rdm142_olddiner",
+ "sk_rdm143_gamercave",
+ "sk_rdm144_smallmagician",
+ "sk_rdm145_ladytesla_altar",
+ "sk_rdm146_blastdoor_interchange",
+ "sk_rdm147_advbotany",
+ "sk_rdm148_botany_apiary",
+ "sk_rdm157_chess",
+ "sk_rdm159_kilosnakepit",
+ "sk_rdm167_library_ritual",
+ "sk_rdm176_spacewindowroom")
/obj/effect/spawner/room/fivexfour
name = "5x4 room spawner"
room_width = 5
diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm
index cb85c98cc456b..ffd84411841df 100644
--- a/code/game/objects/effects/step_triggers.dm
+++ b/code/game/objects/effects/step_triggers.dm
@@ -68,10 +68,8 @@
if(AM in T.affecting)
return
- if(isliving(AM))
- var/mob/living/M = AM
- if(immobilize)
- M.mobility_flags &= ~MOBILITY_MOVE
+ if(immobilize)
+ ADD_TRAIT(AM, TRAIT_IMMOBILIZED, src)
affecting[AM] = AM.dir
var/datum/move_loop/loop = SSmove_manager.move(AM, direction, speed, tiles ? tiles * speed : INFINITY)
@@ -107,11 +105,8 @@
SIGNAL_HANDLER
var/atom/movable/being_moved = source.moving
affecting -= being_moved
- if(isliving(being_moved))
- var/mob/living/M = being_moved
- if(immobilize)
- M.mobility_flags |= MOBILITY_MOVE
- M.update_mobility()
+ REMOVE_TRAIT(being_moved, TRAIT_IMMOBILIZED, REF(src))
+
/* Stops things thrown by a thrower, doesn't do anything */
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index b024a12a7e6ad..2b826a39dd931 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -571,7 +571,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
blockhand = (locate(/obj/item/bodypart/l_arm) in owner.bodyparts)
if(!blockhand)
return 0
- if(blockhand.is_disabled())
+ if(blockhand?.bodypart_disabled)
to_chat(owner, "You're too exausted to block the attack! ")
return 0
else if(HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE) && owner.getStaminaLoss() >= 30)
diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm
index 06be746ccd785..d899c38641ee2 100644
--- a/code/game/objects/items/RCD.dm
+++ b/code/game/objects/items/RCD.dm
@@ -24,7 +24,7 @@ RLD
w_class = WEIGHT_CLASS_LARGE
custom_materials = list(/datum/material/iron=100000)
req_access_txt = "11"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
var/datum/effect_system/spark_spread/spark_system
var/matter = 0
@@ -932,7 +932,8 @@ RLD
/obj/machinery/plumbing/disposer = 10,
/obj/machinery/plumbing/filter = 5,
/obj/machinery/plumbing/grinder_chemical = 30,
- /obj/machinery/plumbing/splitter = 5
+ /obj/machinery/plumbing/splitter = 5,
+ /obj/machinery/plumbing/bottle_dispenser = 20,
)
/obj/item/construction/plumbing/attack_self(mob/user)
diff --git a/code/game/objects/items/RPD.dm b/code/game/objects/items/RPD.dm
index b701a0509ba5d..96be0b40ffc06 100644
--- a/code/game/objects/items/RPD.dm
+++ b/code/game/objects/items/RPD.dm
@@ -213,7 +213,7 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
w_class = WEIGHT_CLASS_LARGE
slot_flags = ITEM_SLOT_BELT
custom_materials = list(/datum/material/iron=75000, /datum/material/glass=37500)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
var/datum/effect_system/spark_spread/spark_system
var/working = 0
diff --git a/code/game/objects/items/RSF.dm b/code/game/objects/items/RSF.dm
index 3f676294af26c..b29a67d9a7b2b 100644
--- a/code/game/objects/items/RSF.dm
+++ b/code/game/objects/items/RSF.dm
@@ -14,7 +14,7 @@ RSF
density = FALSE
anchored = FALSE
item_flags = NOBLUDGEON
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
var/matter = 0
var/mode = 1
w_class = WEIGHT_CLASS_NORMAL
diff --git a/code/game/objects/items/apc_frame.dm b/code/game/objects/items/apc_frame.dm
index 1c93bfcd08531..66f3e8c6eac62 100644
--- a/code/game/objects/items/apc_frame.dm
+++ b/code/game/objects/items/apc_frame.dm
@@ -1,92 +1,9 @@
-/obj/item/wallframe
- icon = 'icons/obj/wallframe.dmi'
- custom_materials = list(/datum/material/iron=MINERAL_MATERIAL_AMOUNT*2)
- flags_1 = CONDUCT_1
- item_state = "syringe_kit"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- w_class = WEIGHT_CLASS_SMALL
- var/result_path
- var/inverse = 0 // For inverse dir frames like light fixtures.
- var/pixel_shift //The amount of pixels
-
-/obj/item/wallframe/proc/try_build(turf/on_wall, mob/user)
- if(get_dist(on_wall,user)>1)
- return
- var/ndir = get_dir(on_wall, user)
- if(!(ndir in GLOB.cardinals))
- return
- var/turf/T = get_turf(user)
- var/area/A = get_area(T)
- if(!isfloorturf(T))
- to_chat(user, "You cannot place [src] on this spot! ")
- return
- if(A.always_unpowered)
- to_chat(user, "You cannot place [src] in this area! ")
- return
- if(check_wall_item(T, ndir, inverse*2))
- to_chat(user, "There's already an item on this wall! ")
- return
-
- return TRUE
-
-/obj/item/wallframe/proc/attach(turf/on_wall, mob/user)
- if(result_path)
- playsound(src.loc, 'sound/machines/click.ogg', 75, 1)
- user.visible_message("[user.name] attaches [src] to the wall.",
- "You attach [src] to the wall. ",
- "You hear clicking. ")
- var/ndir = get_dir(on_wall,user)
- if(inverse)
- ndir = turn(ndir, 180)
-
- var/obj/O = new result_path(get_turf(user), ndir, TRUE)
- if(pixel_shift)
- switch(ndir)
- if(NORTH)
- O.pixel_y = pixel_shift
- if(SOUTH)
- O.pixel_y = -pixel_shift
- if(EAST)
- O.pixel_x = pixel_shift
- if(WEST)
- O.pixel_x = -pixel_shift
- after_attach(O)
-
- qdel(src)
-
-/obj/item/wallframe/proc/after_attach(var/obj/O)
- transfer_fingerprints_to(O)
-
-/obj/item/wallframe/attackby(obj/item/W, mob/user, params)
- ..()
- if(W.tool_behaviour == TOOL_SCREWDRIVER)
- // For camera-building borgs
- var/turf/T = get_step(get_turf(user), user.dir)
- if(iswallturf(T))
- T.attackby(src, user, params)
-
- var/iron_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]/MINERAL_MATERIAL_AMOUNT) //Replace this shit later
- var/glass_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)]/MINERAL_MATERIAL_AMOUNT) //Replace this shit later
-
- if(W.tool_behaviour == TOOL_WRENCH && (iron_amt || glass_amt))
- to_chat(user, "You dismantle [src]. ")
- if(iron_amt)
- new /obj/item/stack/sheet/iron(get_turf(src), iron_amt)
- if(glass_amt)
- new /obj/item/stack/sheet/glass(get_turf(src), glass_amt)
- qdel(src)
-
-
-
// APC HULL
/obj/item/wallframe/apc
name = "\improper APC frame"
desc = "Used for repairing or building APCs."
icon_state = "apc"
result_path = /obj/machinery/power/apc
- inverse = 1
-
/obj/item/wallframe/apc/try_build(turf/on_wall, user)
if(!..())
@@ -108,16 +25,3 @@
to_chat(user, "You cut the cables and disassemble the unused power terminal. ")
qdel(E)
return TRUE
-
-
-/obj/item/electronics
- desc = "Looks like a circuit. Probably is."
- icon = 'icons/obj/module.dmi'
- icon_state = "door_electronics"
- item_state = "electronic"
- lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
- flags_1 = CONDUCT_1
- w_class = WEIGHT_CLASS_SMALL
- custom_materials = list(/datum/material/iron=50, /datum/material/glass=50)
- grind_results = list(/datum/reagent/iron = 10, /datum/reagent/silicon = 10)
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index 87115edd19379..a743677e5141e 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -164,7 +164,7 @@
lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
slot_flags = ITEM_SLOT_ID
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF | ACID_PROOF
var/list/access = list()
var/registered_name// The name registered_name on the card
@@ -849,7 +849,7 @@ update_label("John Doe", "Clowny")
name = "paper nametag"
desc = "Some spare papers taped into a vague card shape, with a name scribbled on it. Seems trustworthy."
icon_state = "paper"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 50, STAMINA = 0, BLEED = 0)
resistance_flags = null // removes all resistance because its a piece of paper
access = list()
assignment = "Unknown"
diff --git a/code/game/objects/items/chainsaw.dm b/code/game/objects/items/chainsaw.dm
index 913e7337f6889..5d84cdcfcccb6 100644
--- a/code/game/objects/items/chainsaw.dm
+++ b/code/game/objects/items/chainsaw.dm
@@ -20,6 +20,7 @@
attack_verb = list("sawed", "tore", "cut", "chopped", "diced")
hitsound = "swing_hit"
sharpness = IS_SHARP
+ bleed_force = BLEED_DEEP_WOUND
actions_types = list(/datum/action/item_action/startchainsaw)
var/on = FALSE
tool_behaviour = TOOL_SAW
diff --git a/code/game/objects/items/chrono_eraser.dm b/code/game/objects/items/chrono_eraser.dm
index 3a58d75db273e..e835909745a4f 100644
--- a/code/game/objects/items/chrono_eraser.dm
+++ b/code/game/objects/items/chrono_eraser.dm
@@ -111,7 +111,7 @@
if(field == F)
var/turf/currentpos = get_turf(src)
var/mob/living/user = loc
- if(currentpos == startpos && isliving(user) && (user.mobility_flags & MOBILITY_STAND) && (user.stat == CONSCIOUS) && (field in view(CHRONO_BEAM_RANGE, currentpos)))
+ if(currentpos == startpos && isliving(user) && user.body_position == STANDING_UP && !HAS_TRAIT(user, TRAIT_INCAPACITATED) && (field in view(CHRONO_BEAM_RANGE, currentpos)))
return TRUE
field_disconnect(F)
return FALSE
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index fce19cc26baec..f536623565e43 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -175,8 +175,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
else
return ..()
-/obj/item/clothing/mask/cigarette/afterattack(obj/item/reagent_containers/glass/glass, mob/user, proximity)
- . = ..()
+/obj/item/clothing/mask/cigarette/proc/dip(obj/item/reagent_containers/glass/glass, mob/user, proximity)
if(!proximity || lit) //can't dip if cigarette is lit (it will heat the reagents in the glass instead)
return
if(istype(glass)) //you can dip cigarettes into beakers
@@ -190,6 +189,38 @@ CIGARETTE PACKETS ARE IN FANCY.DM
else
to_chat(user, "[src] is full. ")
+/obj/item/clothing/mask/cigarette/proc/butt(mob/living/M, mob/living/user, proximity)
+ if(!istype(M))
+ return
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ return
+ if(lit && user.a_intent == INTENT_HARM)
+ force = 4
+ var/target_zone = user.get_combat_bodyzone()
+ M.apply_damage(force, BURN, target_zone)
+ qdel(src)
+ var/cig_butt = new type_butt()
+ user.put_in_hands(cig_butt)
+ new /obj/effect/decal/cleanable/ash(M.loc)
+ playsound(user, 'sound/surgery/cautery2.ogg', 25, 1)
+ return
+ if(lit && user.a_intent != INTENT_HARM)
+ smoketime -= 120
+ if(prob(40))
+ src.extinguish()
+ if(src.smoketime <= 0)
+ qdel(src)
+ var/cig_butt = new type_butt()
+ user.put_in_hands(cig_butt)
+ playsound(user, 'sound/items/cig_snuff.ogg', 25, 1)
+
+/obj/item/clothing/mask/cigarette/afterattack(var/target, mob/living/user, proximity)
+ if (istype(target, /mob/living))
+ butt(target, user, proximity)
+ . = ..()
+ else
+ . = ..()
+ dip(target, user, proximity)
/obj/item/clothing/mask/cigarette/proc/light(flavor_text = null)
if(lit)
@@ -675,15 +706,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM
user.visible_message("Without even breaking stride, [user] flips open and lights [src] in one smooth movement.", "Without even breaking stride, you flip open and light [src] in one smooth movement. ")
playsound(src.loc, 'sound/items/zippo_on.ogg', 100, 1)
else
- var/prot = FALSE
var/mob/living/carbon/human/H = user
- if(istype(H) && H.gloves)
- var/obj/item/clothing/gloves/G = H.gloves
- if(G.max_heat_protection_temperature)
- prot = (G.max_heat_protection_temperature > 360)
- else
- prot = TRUE
+ var/prot = !istype(H) || H.gloves
if(prot || prob(75))
user.visible_message("After a few attempts, [user] manages to light [src].", "After a few attempts, you manage to light [src]. ")
@@ -987,7 +1012,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
if(prob(5))//small chance for the vape to break and deal damage if it's emagged
playsound(get_turf(src), 'sound/effects/pop_expl.ogg', 50, 0)
M.apply_damage(20, BURN, BODY_ZONE_HEAD)
- M.Paralyze(300, 1, 0)
+ M.Paralyze(300)
var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread
sp.set_up(5, 1, src)
sp.start()
diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm
index 7e70e7d6740e3..be38d3ff63d34 100644
--- a/code/game/objects/items/circuitboards/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm
@@ -506,6 +506,7 @@
req_components = list(
/obj/item/stock_parts/micro_laser = 1,
/obj/item/stock_parts/capacitor = 1,
+ /obj/item/stock_parts/cell = 1,
/obj/item/stack/cable_coil = 3)
needs_anchored = FALSE
@@ -860,14 +861,6 @@
/obj/item/stock_parts/manipulator = 1,
/obj/item/stock_parts/micro_laser = 1)
-/obj/item/circuitboard/machine/experimentor
- name = "E.X.P.E.R.I-MENTOR (Machine Board)"
- icon_state = "science"
- build_path = /obj/machinery/rnd/experimentor
- req_components = list(
- /obj/item/stock_parts/scanning_module = 1,
- /obj/item/stock_parts/manipulator = 2,
- /obj/item/stock_parts/micro_laser = 2)
/obj/item/circuitboard/machine/mech_recharger
name = "mechbay recharger (Machine Board)"
diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm
index 69d133edb6a44..d53776dd14bd3 100644
--- a/code/game/objects/items/cosmetics.dm
+++ b/code/game/objects/items/cosmetics.dm
@@ -265,15 +265,6 @@
user.visible_message("[user] is slitting [user.p_their()] own throat with [src]! It looks like [user.p_theyre()] trying to commit suicide! ")
return BRUTELOSS
-/obj/item/razor/attack(mob/M, mob/user)
- . = ..()
- if(ishuman(M) && extended == 1 && (user.a_intent == INTENT_HARM))
- var/mob/living/carbon/human/H = M
- var/def_check = H.getarmor(MELEE)
- H.bleed_rate += ((force * 10) - def_check)/30 //sharp blade causes a shitload of blood loss if on harm intent
- if(H.bleed_rate >= 10)
- to_chat(M, "You're losing blood fast! ")
-
/obj/item/razor/straightrazor/attack_self(mob/user)
extended = !extended
playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1)
@@ -285,6 +276,7 @@
attack_verb = list("slashed", "stabbed", "sliced", "slit", "shaved", "diced", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ bleed_force = BLEED_SURFACE
tool_behaviour = TOOL_SCALPEL
else
force = initial(force)
@@ -294,6 +286,7 @@
attack_verb = list("stubbed", "poked")
hitsound = 'sound/weapons/genhit.ogg'
sharpness = IS_BLUNT
+ bleed_force = 0
tool_behaviour = null
/obj/item/handmirror
diff --git a/code/game/objects/items/crab17.dm b/code/game/objects/items/crab17.dm
index 659b808765829..5b4b0946fea3e 100644
--- a/code/game/objects/items/crab17.dm
+++ b/code/game/objects/items/crab17.dm
@@ -33,7 +33,7 @@
icon = 'icons/obj/money_machine.dmi'
icon_state = "bogdanoff"
layer = TABLE_LAYER //So that the crate inside doesn't appear underneath
- armor = list(MELEE = 30, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 100, BIO = 0, RAD = 0, FIRE = 100, ACID = 80, STAMINA = 0)
+ armor = list(MELEE = 30, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 100, BIO = 0, RAD = 0, FIRE = 100, ACID = 80, STAMINA = 0, BLEED = 0)
density = TRUE
pixel_z = -8
layer = LARGE_MOB_LAYER
diff --git a/code/game/objects/items/debug_items.dm b/code/game/objects/items/debug_items.dm
index 14032b526c10b..dd9f63ee12241 100644
--- a/code/game/objects/items/debug_items.dm
+++ b/code/game/objects/items/debug_items.dm
@@ -235,7 +235,7 @@
item_state = "holdingpack"
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
item_flags = NO_MAT_REDEMPTION
- armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
/obj/item/storage/backpack/debug/ComponentInitialize()
. = ..()
@@ -328,6 +328,7 @@
TRAIT_SURGEON,
TRAIT_METALANGUAGE_KEY_ALLOWED
)
+ var/spacewalk_initial
/obj/item/debug/orb_of_power/pickup(mob/user)
. = ..()
@@ -350,12 +351,17 @@
picker.see_override = SEE_INVISIBLE_OBSERVER
picker.update_sight()
+ spacewalk_initial = user.spacewalk
+ user.spacewalk = TRUE
/obj/item/debug/orb_of_power/dropped(mob/living/carbon/human/user)
. = ..()
var/obj/item/debug/orb_of_power/orb = locate() in user.get_contents()
if(orb)
return
+
+ user.spacewalk = spacewalk_initial
+
for(var/each in traits_to_give)
REMOVE_TRAIT(user, each, "debug")
user.remove_all_languages("debug")
@@ -371,3 +377,67 @@
if(!HAS_TRAIT(user, TRAIT_SECURITY_HUD))
hud = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
hud.remove_hud_from(user)
+
+// kinda works like hilbert, but not really
+/obj/item/map_template_diver
+ name = "Pseudo-world diver"
+ desc = "A globe that you can dive into a pseudo-world, but there's no way back."
+ icon_state = "hilbertshotel"
+ w_class = WEIGHT_CLASS_TINY
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+
+ var/datum/map_template/map_template = /datum/map_template/debug_target
+ var/working
+ var/turf/turf_to_dive
+
+ var/live_server_warning
+
+/datum/map_template/debug_target
+ name = "Debug map to test"
+ mappath = '_maps/map_files/debug/multidir_sprite_debug.dmm'
+
+// friendly warning setter
+/obj/item/map_template_diver/Initialize()
+ . = ..()
+#ifndef DEBUG
+ live_server_warning = TRUE
+#endif
+
+/obj/item/map_template_diver/attack_self(mob/user)
+ . = ..()
+
+ if(turf_to_dive)
+ dive_into(user)
+ return
+
+ if(!check_rights_for(user.client, R_ADMIN | R_DEBUG))
+ client_alert(user.client, "Players are not allowed to use this debug item, even for fun.", "No permission, no fun")
+ return
+ if(live_server_warning)
+ client_alert(user.client, "It looks the server is actually live. Using this may cost the performance of the server. Use this again if you're sure.", "Warning")
+ live_server_warning = FALSE
+ return
+
+ if(working)
+ to_chat(user, "We're creating a map yet. ")
+ return
+
+ if(ispath(map_template))
+ create_map(user)
+ return
+
+/obj/item/map_template_diver/proc/create_map(mob/user)
+ set waitfor = FALSE
+
+ to_chat(user, "Creates a map template... ")
+ working = TRUE
+ map_template = new map_template()
+ var/datum/space_level/space_level = map_template.load_new_z(null, ZTRAITS_DEBUG)
+ turf_to_dive = locate(round((world.maxx - map_template.width)/2), round((world.maxy - map_template.height)/2), space_level.z_value)
+ to_chat(user, "Creation is completed. ")
+ working = FALSE
+ dive_into(user)
+
+/obj/item/map_template_diver/proc/dive_into(mob/user)
+ to_chat(user, "Teleports to the test area. ")
+ user.forceMove(turf_to_dive)
diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm
index 4675d451aa906..ad4d2dccb00e1 100644
--- a/code/game/objects/items/defib.dm
+++ b/code/game/objects/items/defib.dm
@@ -14,7 +14,7 @@
throwforce = 6
w_class = WEIGHT_CLASS_BULKY
actions_types = list(/datum/action/item_action/toggle_paddles)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0, BLEED = 0)
var/obj/item/shockpaddles/paddle_type = /obj/item/shockpaddles
var/on = FALSE //if the paddles are equipped (1) or on the defib (0)
diff --git a/code/game/objects/items/deployable/barricade.dm b/code/game/objects/items/deployable/barricade.dm
index ee8c46727a671..38688c4cc8eed 100644
--- a/code/game/objects/items/deployable/barricade.dm
+++ b/code/game/objects/items/deployable/barricade.dm
@@ -194,7 +194,7 @@
icon_state = "barrier1"
max_integrity = 180
proj_pass_rate = 20
- armor = list(MELEE = 10, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 10, BIO = 100, RAD = 100, FIRE = 10, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 10, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 10, BIO = 100, RAD = 100, FIRE = 10, ACID = 0, STAMINA = 0, BLEED = 0)
req_access = list(ACCESS_SECURITY)
pickup_damaged = FALSE
locked_down = TRUE
diff --git a/code/game/objects/items/devices/camera_bug.dm b/code/game/objects/items/devices/camera_bug.dm
index e3ba5227963ef..b97e1707c6159 100644
--- a/code/game/objects/items/devices/camera_bug.dm
+++ b/code/game/objects/items/devices/camera_bug.dm
@@ -187,7 +187,7 @@
else
names[M.name] = 1
dat += "[M.name]"
- if(!(M.mobility_flags & MOBILITY_STAND))
+ if(M.body_position == LYING_DOWN)
if(M.buckled)
dat += " (Sitting)"
else
diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm
index c55f91eca42f0..ed801cfa5e9c0 100644
--- a/code/game/objects/items/devices/chameleonproj.dm
+++ b/code/game/objects/items/devices/chameleonproj.dm
@@ -161,7 +161,7 @@
. = ..()
master.disrupt()
-/obj/effect/dummy/chameleon/relaymove(mob/user, direction)
+/obj/effect/dummy/chameleon/relaymove(mob/living/user, direction)
if(isspaceturf(loc) || !direction)
return //No magical space movement!
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 1c5446cf371b4..6aa2ee923e4d4 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -13,14 +13,16 @@
slot_flags = ITEM_SLOT_BELT
custom_materials = list(/datum/material/iron=50, /datum/material/glass=20)
actions_types = list(/datum/action/item_action/toggle_light)
- light_system = MOVABLE_LIGHT
+ light_system = MOVABLE_LIGHT_DIRECTIONAL
light_range = 4
light_power = 1
light_on = FALSE
- var/on = FALSE
+ /// The sound the light makes when it's turned on
var/sound_on = 'sound/items/flashlight_on.ogg'
+ /// The sound the light makes when it's turned off
var/sound_off = 'sound/items/flashlight_off.ogg'
-
+ /// Is the light turned on or off currently
+ var/on = FALSE
/obj/item/flashlight/Initialize(mapload)
. = ..()
@@ -41,16 +43,18 @@
if(light_system == STATIC_LIGHT)
update_light()
-
-/obj/item/flashlight/attack_self(mob/user)
+/obj/item/flashlight/proc/toggle_lights(mob/user)
on = !on
+ playsound(user, on ? sound_on : sound_off, 40, TRUE)
update_brightness(user)
update_action_buttons()
- return 1
+
+/obj/item/flashlight/attack_self(mob/user)
+ toggle_lights(user)
/obj/item/flashlight/suicide_act(mob/living/carbon/human/user)
if (user.is_blind())
- user.visible_message("[user] is putting [src] close to [user.p_their()] eyes and turning it on... but [user.p_theyre()] blind! ")
+ user.visible_message("[user] is putting [src] close to [user.p_their()] eyes and turning it on... but [user.p_theyre()] blind! ")
return SHAME
user.visible_message("[user] is putting [src] close to [user.p_their()] eyes and turning it on! It looks like [user.p_theyre()] trying to commit suicide! ")
return FIRELOSS
@@ -178,6 +182,7 @@
icon_state = "penlight"
item_state = ""
worn_icon_state = "pen"
+ w_class = WEIGHT_CLASS_TINY
flags_1 = CONDUCT_1
light_range = 2
var/holo_cooldown = 0
@@ -191,7 +196,7 @@
var/T = get_turf(target)
if(locate(/mob/living) in T)
new /obj/effect/temp_visual/medical_holosign(T,user) //produce a holographic glow
- holo_cooldown = world.time + 100
+ holo_cooldown = world.time + 10 SECONDS
return
/obj/effect/temp_visual/medical_holosign
@@ -202,7 +207,7 @@
/obj/effect/temp_visual/medical_holosign/Initialize(mapload, creator)
. = ..()
- playsound(loc, 'sound/machines/ping.ogg', 50, 0) //make some noise!
+ playsound(loc, 'sound/machines/ping.ogg', 50, FALSE) //make some noise!
if(creator)
visible_message("[creator] created a medical hologram! ")
@@ -229,6 +234,7 @@
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
force = 10
light_range = 5
+ light_system = STATIC_LIGHT
w_class = WEIGHT_CLASS_BULKY
flags_1 = CONDUCT_1
custom_materials = null
@@ -274,6 +280,7 @@
var/produce_heat = 1500
heat = 1000
light_color = LIGHT_COLOR_FLARE
+ light_system = MOVABLE_LIGHT
grind_results = list(/datum/reagent/sulfur = 15)
sound_on = 'sound/items/matchstick_lit.ogg'
sound_off = null
@@ -358,6 +365,7 @@
righthand_file = 'icons/mob/inhands/equipment/mining_righthand.dmi'
desc = "A mining lantern."
light_range = 6 // luminosity when on
+ light_system = MOVABLE_LIGHT
/obj/item/flashlight/lantern/heirloom_moth
name = "old lantern"
@@ -445,8 +453,10 @@
custom_price = 10
w_class = WEIGHT_CLASS_SMALL
light_range = 4
+ light_system = MOVABLE_LIGHT
color = LIGHT_COLOR_GREEN
icon_state = "glowstick"
+ base_icon_state = "glowstick"
item_state = "glowstick"
grind_results = list(/datum/reagent/phenol = 15, /datum/reagent/hydrogen = 10, /datum/reagent/oxygen = 5) //Meth-in-a-stick
var/burn_pickup = FALSE //If true, fuel will only decrease after being picked up or used in hand (Useful for mapping)
@@ -472,24 +482,30 @@
/obj/item/flashlight/glowstick/proc/turn_off()
on = FALSE
- update_icon()
+ update_appearance()
-/obj/item/flashlight/glowstick/update_icon()
- item_state = "glowstick"
- cut_overlays()
+/obj/item/flashlight/glowstick/update_appearance(updates=ALL)
+ . = ..()
if(fuel <= 0)
- icon_state = "glowstick-empty"
- cut_overlays()
set_light_on(FALSE)
- else if(on)
- var/mutable_appearance/glowstick_overlay = mutable_appearance(icon, "glowstick-glow")
- glowstick_overlay.color = color
- add_overlay(glowstick_overlay)
- item_state = "glowstick-on"
+ return
+ if(on)
set_light_on(TRUE)
- else
- icon_state = "glowstick"
- cut_overlays()
+ return
+
+/obj/item/flashlight/glowstick/update_icon_state()
+ icon_state = "[base_icon_state][(fuel <= 0) ? "-empty" : ""]"
+ item_state = "[base_icon_state][((fuel > 0) && on) ? "-on" : ""]"
+ return ..()
+
+/obj/item/flashlight/glowstick/update_overlays()
+ . = ..()
+ if(fuel <= 0 && !on)
+ return
+
+ var/mutable_appearance/glowstick_overlay = mutable_appearance(icon, "glowstick-glow")
+ glowstick_overlay.color = color
+ . += glowstick_overlay
/obj/item/flashlight/glowstick/pickup(mob/user)
..()
@@ -574,7 +590,7 @@
name = "disco light"
desc = "Groovy..."
icon_state = null
- light_system = STATIC_LIGHT
+ light_system = MOVABLE_LIGHT
light_range = 4
light_power = 10
alpha = 0
@@ -623,6 +639,7 @@
/obj/item/flashlight/eyelight
name = "eyelight"
desc = "This shouldn't exist outside of someone's head, how are you seeing this?"
+ light_system = MOVABLE_LIGHT
light_range = 15
light_power = 1
flags_1 = CONDUCT_1
diff --git a/code/game/objects/items/devices/forcefieldprojector.dm b/code/game/objects/items/devices/forcefieldprojector.dm
index 68a47eb19db09..7c6d8c1798069 100644
--- a/code/game/objects/items/devices/forcefieldprojector.dm
+++ b/code/game/objects/items/devices/forcefieldprojector.dm
@@ -87,7 +87,7 @@
mouse_opacity = MOUSE_OPACITY_OPAQUE
resistance_flags = INDESTRUCTIBLE
CanAtmosPass = ATMOS_PASS_DENSITY
- armor = list(MELEE = 0, BULLET = 25, LASER = 50, ENERGY = 50, BOMB = 25, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 25, LASER = 50, ENERGY = 50, BOMB = 25, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
var/obj/item/forcefield_projector/generator
/obj/structure/projected_forcefield/Initialize(mapload, obj/item/forcefield_projector/origin)
diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm
index dc48ec35dff31..e0a8ea48ed4f2 100644
--- a/code/game/objects/items/devices/laserpointer.dm
+++ b/code/game/objects/items/devices/laserpointer.dm
@@ -148,7 +148,7 @@
return
var/mob/living/carbon/human/H = M
if(iscatperson(H) && !H.is_blind()) //catpeople!
- if(user.mobility_flags & MOBILITY_STAND)
+ if(user.body_position == STANDING_UP)
H.setDir(get_dir(H,targloc)) // kitty always looks at the light
if(prob(effectchance))
H.visible_message("[H] makes a grab for the light! ","LIGHT! ")
@@ -161,9 +161,11 @@
else if(iscat(M)) //cats!
var/mob/living/simple_animal/pet/cat/C = M
if(prob(50))
+ if(C.resting)
+ C.set_resting(FALSE, instant = TRUE)
C.visible_message("[C] pounces on the light! ","LIGHT! ")
C.Move(targloc)
- C.set_resting(TRUE, FALSE)
+ C.Immobilize(1 SECONDS)
else
C.visible_message("[C] looks uninterested in your games. ","You spot [user] shining [src] at you. How insulting! ")
diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm
index 0d6fcfc51c18a..e448d54434215 100644
--- a/code/game/objects/items/devices/radio/intercom.dm
+++ b/code/game/objects/items/devices/radio/intercom.dm
@@ -14,8 +14,6 @@
/obj/item/radio/intercom/Initialize(mapload, ndir, building)
. = ..()
- if(building)
- setDir(ndir)
var/area/current_area = get_area(src)
if(!current_area)
return
@@ -159,12 +157,16 @@
desc = "A ready-to-go intercom. Just slap it on a wall and screw it in!"
icon_state = "intercom"
result_path = /obj/item/radio/intercom/unscrewed
- pixel_shift = 29
- inverse = TRUE
+ pixel_shift = 26
custom_materials = list(/datum/material/iron = 75, /datum/material/glass = 25)
+MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom, 26)
+
/obj/item/radio/intercom/chapel
name = "Confessional intercom"
anonymize = TRUE
frequency = 1481
broadcasting = TRUE
+
+//MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/prison, 26)
+MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/chapel, 26)
diff --git a/code/game/objects/items/devices/reverse_bear_trap.dm b/code/game/objects/items/devices/reverse_bear_trap.dm
index 296bc9981a0df..f1159d676953e 100644
--- a/code/game/objects/items/devices/reverse_bear_trap.dm
+++ b/code/game/objects/items/devices/reverse_bear_trap.dm
@@ -7,7 +7,6 @@
flags_1 = CONDUCT_1
resistance_flags = FIRE_PROOF | UNACIDABLE
w_class = WEIGHT_CLASS_NORMAL
- obj_integrity = 300
max_integrity = 300
item_state = "rack_parts"
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 39d8fcba33b86..0e106e49fec33 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -287,8 +287,6 @@ GENE SCANNER
healthy = FALSE
if(healthy)
message += "\tHealthy. "
- else
- message += "\tSubject does not have ears. "
var/obj/item/organ/eyes/eyes = C.getorganslot(ORGAN_SLOT_EYES)
message += "\t==EYE STATUS== "
if(istype(eyes))
@@ -310,9 +308,6 @@ GENE SCANNER
healthy = FALSE
if(healthy)
message += "\tHealthy. "
- else
- message += "\tSubject does not have eyes. "
-
// Body part damage report
if(iscarbon(M))
@@ -348,6 +343,7 @@ GENE SCANNER
var/minor_damage
var/major_damage
var/max_damage
+ var/list/missing_organ_list = list()
var/report_organs = FALSE
//Piece together the lists to be reported
@@ -377,7 +373,10 @@ GENE SCANNER
else
minor_damage = "\tMildly Damaged Organs: "
minor_damage += organ.name
-
+ for(var/obj/item/organ/each_organ as anything in H.dna.species.required_organs) //Start checking against the carbon mob, seeing if there is any organs missing.
+ if(isnull(H.getorgan(each_organ))) //Can we find the given organ in the mob?
+ missing_organ_list += initial(each_organ.name) //If not, add it to the list.
+ report_organs = TRUE
if(report_organs) //we either finish the list, or set it to be empty if no organs were reported in that category
if(!max_damage)
max_damage = "\tNon-Functional Organs: "
@@ -394,6 +393,8 @@ GENE SCANNER
message += minor_damage
message += major_damage
message += max_damage
+ if(length(missing_organ_list)) //If we have missing organs, display them in a fancy list.
+ message += "\tMissing Organs: [english_list(missing_organ_list)] "
//Genetic damage
if(advanced && H.has_dna())
message += "\tGenetic Stability: [H.dna.stability]%. "
@@ -456,8 +457,10 @@ GENE SCANNER
if(blood_id)
if(ishuman(C))
var/mob/living/carbon/human/H = C
- if(H.bleed_rate)
- message += "Subject is bleeding! "
+ if(H.is_bleeding())
+ message += "Subject is bleeding at a rate of [round(H.get_bleed_rate(), 0.1)]/s! "
+ else if (H.is_bandaged())
+ message += "Subject is bleeding (Bandaged)! "
var/blood_percent = round((C.blood_volume / BLOOD_VOLUME_NORMAL)*100)
var/blood_type = C.dna.blood_type
if(blood_id != /datum/reagent/blood)//special blood substance
@@ -466,12 +469,13 @@ GENE SCANNER
blood_type = R.name
else
blood_type = blood_id
+ var/blood_info = "[blood_type] (Compatible: [jointext(get_safe_blood(blood_type), ", ")])"
if(C.blood_volume <= BLOOD_VOLUME_SAFE && C.blood_volume > BLOOD_VOLUME_OKAY)
- message += "Blood level: LOW [blood_percent] %, [C.blood_volume] cl, type: [blood_type] "
+ message += "Blood level: LOW [blood_percent] %, [C.blood_volume] cl, type: [blood_info] "
else if(C.blood_volume <= BLOOD_VOLUME_OKAY)
- message += "Blood level: CRITICAL [blood_percent] % , [C.blood_volume] cl, type: [blood_type] "
+ message += "Blood level: CRITICAL [blood_percent] % , [C.blood_volume] cl, type: [blood_info] "
else
- message += "Blood level: [blood_percent] %, [C.blood_volume] cl, type: [blood_type] "
+ message += "Blood level: [blood_percent] %, [C.blood_volume] cl, type: [blood_info] "
var/list/cyberimp_detect = list()
for(var/obj/item/organ/cyberimp/CI in C.internal_organs)
diff --git a/code/game/objects/items/dualsaber.dm b/code/game/objects/items/dualsaber.dm
index 56f62fb6feb75..6b575424b02c8 100644
--- a/code/game/objects/items/dualsaber.dm
+++ b/code/game/objects/items/dualsaber.dm
@@ -26,7 +26,7 @@
block_sound = 'sound/weapons/egloves.ogg'
block_flags = BLOCKING_ACTIVE | BLOCKING_NASTY | BLOCKING_PROJECTILE
max_integrity = 200
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 70, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 70, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
light_system = MOVABLE_LIGHT
light_range = 6
@@ -71,6 +71,7 @@
to_chat(user, "You lack the grace to wield this! ")
return COMPONENT_TWOHANDED_BLOCK_WIELD
sharpness = IS_SHARP
+ bleed_force = BLEED_DEEP_WOUND
w_class = w_class_on
hitsound = 'sound/weapons/blade1.ogg'
START_PROCESSING(SSobj, src)
@@ -83,6 +84,7 @@
sharpness = initial(sharpness)
w_class = initial(w_class)
+ bleed_force = initial(bleed_force)
hitsound = "swing_hit"
STOP_PROCESSING(SSobj, src)
set_light_on(FALSE)
diff --git a/code/game/objects/items/fireaxe.dm b/code/game/objects/items/fireaxe.dm
index 2023b63f773f3..d5e4186e02a14 100644
--- a/code/game/objects/items/fireaxe.dm
+++ b/code/game/objects/items/fireaxe.dm
@@ -15,8 +15,9 @@
attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
max_integrity = 200
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 30, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
item_flags = ISWEAPON
var/icon_prefix = "fireaxe"
diff --git a/code/game/objects/items/food/meatdish.dm b/code/game/objects/items/food/meatdish.dm
index 88ed34df18b6b..23226ece4f125 100644
--- a/code/game/objects/items/food/meatdish.dm
+++ b/code/game/objects/items/food/meatdish.dm
@@ -317,7 +317,7 @@
food_reagents = list(/datum/reagent/consumable/nutriment/protein = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("meat" = 1)
foodtypes = MEAT | RAW
- eatverbs = list("bite","chew","nibble","deep throat","gobble","chomp")
+ eatverbs = list("bite","chew","nibble","gobble","chomp")
w_class = WEIGHT_CLASS_SMALL
/obj/item/food/raw_sausage/make_grillable()
diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm
index 521194548b7d3..f10620228adfb 100644
--- a/code/game/objects/items/handcuffs.dm
+++ b/code/game/objects/items/handcuffs.dm
@@ -6,19 +6,6 @@
user.visible_message("[user] is strangling [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide! ")
return OXYLOSS
-/obj/item/restraints/Destroy()
- if(iscarbon(loc))
- var/mob/living/carbon/M = loc
- if(M.handcuffed == src)
- M.set_handcuffed(null)
- M.update_handcuffed()
- if(M.buckled?.buckle_requires_restraints)
- M.buckled.unbuckle_mob(M)
- if(M.legcuffed == src)
- M.legcuffed = null
- M.update_inv_legcuffed()
- return ..()
-
//Handcuffs
/obj/item/restraints/handcuffs
@@ -39,7 +26,7 @@
throw_range = 5
custom_materials = list(/datum/material/iron=500)
breakouttime = 1 MINUTES
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0, BLEED = 0)
var/cuffsound = 'sound/weapons/handcuffs.ogg'
var/trashtype = null //for disposable cuffs
@@ -55,12 +42,12 @@
return
if(!C.handcuffed)
- if(C.get_num_arms(FALSE) >= 2 || C.get_arm_ignore())
+ if(C.canBeHandcuffed())
C.visible_message("[user] is trying to put [src.name] on [C]! ", \
"[user] is trying to put [src.name] on you! ")
playsound(loc, cuffsound, 30, 1, -2)
- if(do_after(user, 4 SECONDS, C) && (C.get_num_arms(FALSE) >= 2 || C.get_arm_ignore()))
+ if(do_after(user, 4 SECONDS, C) && C.canBeHandcuffed())
if(iscyborg(user))
apply_cuffs(C, user, TRUE)
else
@@ -272,9 +259,9 @@
var/def_zone = BODY_ZONE_CHEST
if(snap && iscarbon(L))
var/mob/living/carbon/C = L
- if(C.mobility_flags & MOBILITY_STAND)
+ if(C.body_position == STANDING_UP)
def_zone = pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
- if(!C.legcuffed && C.get_num_legs(FALSE) >= 2) //beartrap can't cuff your leg if there's already a beartrap or legcuffs, or you don't have two legs.
+ if(!C.legcuffed && C.num_legs >= 2) //beartrap can't cuff your leg if there's already a beartrap or legcuffs, or you don't have two legs.
C.legcuffed = src
forceMove(C)
C.update_equipment_speed_mods()
@@ -347,7 +334,7 @@
* * C - the carbon that we will try to ensnare
*/
/obj/item/restraints/legcuffs/bola/proc/ensnare(mob/living/carbon/C)
- if(!C.legcuffed && C.get_num_legs(FALSE) >= 2)
+ if(!C.legcuffed && C.num_legs >= 2)
visible_message("\The [src] ensnares [C]! ")
C.legcuffed = src
forceMove(C)
diff --git a/code/game/objects/items/his_grace.dm b/code/game/objects/items/his_grace.dm
index c47136f77d836..e4692b910edf5 100644
--- a/code/game/objects/items/his_grace.dm
+++ b/code/game/objects/items/his_grace.dm
@@ -72,7 +72,7 @@
else
. += "[src] is latched closed. "
-/obj/item/his_grace/relaymove(mob/living/user) //Allows changelings, etc. to climb out of Him after they revive, provided He isn't active
+/obj/item/his_grace/relaymove(mob/living/user, direction) //Allows changelings, etc. to climb out of Him after they revive, provided He isn't active
if(!awakened)
user.forceMove(get_turf(src))
user.visible_message("[user] scrambles out of [src]! ", "You climb out of [src]! ")
diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm
index 01b6d227c4b43..d3aab132c132a 100644
--- a/code/game/objects/items/holy_weapons.dm
+++ b/code/game/objects/items/holy_weapons.dm
@@ -329,6 +329,7 @@
block_level = 1
block_power = 30
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "tore", "ripped", "diced", "cut")
@@ -448,6 +449,7 @@
block_flags = BLOCKING_ACTIVE | BLOCKING_NASTY
slot_flags = ITEM_SLOT_BACK
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
attack_verb = list("chopped", "sliced", "cut", "reaped")
/obj/item/nullrod/scythe/Initialize(mapload)
@@ -488,7 +490,7 @@
hitsound = 'sound/weapons/rapierhit.ogg'
var/possessed = FALSE
-/obj/item/nullrod/scythe/talking/relaymove(mob/user)
+/obj/item/nullrod/scythe/talking/relaymove(mob/living/user, direction)
return //stops buckled message spam for the ghost.
/obj/item/nullrod/scythe/talking/attack_self(mob/living/user)
@@ -565,6 +567,7 @@
w_class = WEIGHT_CLASS_HUGE
item_flags = ABSTRACT | ISWEAPON
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
attack_verb = list("sawed", "tore", "cut", "chopped", "diced")
hitsound = 'sound/weapons/chainsawhit.ogg'
tool_behaviour = TOOL_SAW
@@ -589,6 +592,7 @@
worn_icon_state = "render"
hitsound = 'sound/items/bikehorn.ogg'
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "tore", "ripped", "diced", "cut")
/obj/item/nullrod/pride_hammer
@@ -639,6 +643,7 @@
throw_range = 7
throwforce = 30
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
attack_verb = list("enlightened", "redpilled")
/obj/item/nullrod/armblade
@@ -653,6 +658,7 @@
item_flags = ABSTRACT | ISWEAPON
w_class = WEIGHT_CLASS_HUGE
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
/obj/item/nullrod/armblade/Initialize(mapload)
. = ..()
@@ -712,6 +718,7 @@
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
w_class = WEIGHT_CLASS_HUGE
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
slot_flags = null
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "tore", "ripped", "diced", "cut")
@@ -745,6 +752,7 @@
attack_verb = list("poked", "impaled", "pierced", "jabbed")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
/obj/item/nullrod/egyptian
name = "egyptian staff"
@@ -785,6 +793,7 @@
slot_flags = ITEM_SLOT_BELT
armour_penetration = 10
sharpness = IS_SHARP_ACCURATE
+ bleed_force = BLEED_CUT
w_class = WEIGHT_CLASS_BULKY
attack_verb = list("stabbed", "poked", "slashed", "clocked")
hitsound = 'sound/weapons/bladeslice.ogg'
diff --git a/code/game/objects/items/hot_potato.dm b/code/game/objects/items/hot_potato.dm
index 9d05a23523b47..cb9ecb13a97d3 100644
--- a/code/game/objects/items/hot_potato.dm
+++ b/code/game/objects/items/hot_potato.dm
@@ -103,7 +103,7 @@
return FALSE
if(!victim.client)
to_chat(user, "[src] refuses to attach to a non-sapient creature! ")
- if(victim.stat != CONSCIOUS || !victim.get_num_legs())
+ if(victim.stat != CONSCIOUS || !victim.usable_legs)
to_chat(user, "[src] refuses to attach to someone incapable of using it! ")
user.temporarilyRemoveItemFromInventory(src, TRUE)
. = FALSE
diff --git a/code/game/objects/items/implants/implant_misc.dm b/code/game/objects/items/implants/implant_misc.dm
index 5f3c40b2a6f38..1cc169de68e8f 100644
--- a/code/game/objects/items/implants/implant_misc.dm
+++ b/code/game/objects/items/implants/implant_misc.dm
@@ -41,7 +41,6 @@
imp_in.SetImmobilized(0)
imp_in.adjustStaminaLoss(-200)
imp_in.set_resting(FALSE)
- imp_in.update_mobility()
imp_in.reagents.add_reagent(/datum/reagent/medicine/synaptizine, 10)
imp_in.reagents.add_reagent(/datum/reagent/medicine/omnizine, 10)
diff --git a/code/game/objects/items/implants/implantchair.dm b/code/game/objects/items/implants/implantchair.dm
index c8f4dc1e23c9f..d982a4eab9f28 100644
--- a/code/game/objects/items/implants/implantchair.dm
+++ b/code/game/objects/items/implants/implantchair.dm
@@ -134,7 +134,7 @@
"You successfully break out of [src]! ")
open_machine()
-/obj/machinery/implantchair/relaymove(mob/user)
+/obj/machinery/implantchair/relaymove(mob/living/user, direction)
if(message_cooldown <= world.time)
message_cooldown = world.time + 50
to_chat(user, "[src]'s door won't budge! ")
@@ -144,9 +144,10 @@
return
if(isliving(user))
var/mob/living/L = user
- if(!(L.mobility_flags & MOBILITY_STAND))
+ if(L.body_position == LYING_DOWN)
return
close_machine(target)
+
/obj/machinery/implantchair/close_machine(mob/living/user)
if((isnull(user) || istype(user)) && state_open)
diff --git a/code/game/objects/items/inducer.dm b/code/game/objects/items/inducer.dm
index c56fd8b8574e7..04ccf705ba49e 100644
--- a/code/game/objects/items/inducer.dm
+++ b/code/game/objects/items/inducer.dm
@@ -106,7 +106,10 @@
var/coefficient = 1
var/obj/item/organ/stomach/battery/battery
if(istype(A, /obj/item/gun/energy))
- to_chat(user,"Error unable to interface with device")
+ to_chat(user, "Error unable to interface with device. ")
+ return FALSE
+ if(istype(A, /obj/item/clothing/suit/space))
+ to_chat(user, "Error unable to interface with device. ")
return FALSE
if(istype(A, /obj))
O = A
diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm
index 55047742d7d46..04bcfbc2fee83 100644
--- a/code/game/objects/items/kitchen.dm
+++ b/code/game/objects/items/kitchen.dm
@@ -28,7 +28,7 @@
flags_1 = CONDUCT_1
attack_verb = list("attacked", "stabbed", "poked")
hitsound = 'sound/weapons/bladeslice.ogg'
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0, BLEED = 0)
var/datum/reagent/forkload //used to eat omelette
/obj/item/kitchen/fork/suicide_act(mob/living/carbon/user)
diff --git a/code/game/objects/items/knives.dm b/code/game/objects/items/knives.dm
index 7b67055fce7b9..c5ddeed82da17 100644
--- a/code/game/objects/items/knives.dm
+++ b/code/game/objects/items/knives.dm
@@ -19,6 +19,7 @@
attack_verb = list("slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts")
//attack_verb_simple = list("slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut")
sharpness = IS_SHARP_ACCURATE
+ bleed_force = BLEED_CUT
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50)
var/bayonet = FALSE //Can this be attached to a gun?
//wound_bonus = 5
@@ -156,7 +157,7 @@
throwforce = 12//fuck git
custom_materials = list()
attack_verb = list("shanked", "shivved")
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
// Shank - Makeshift weapon that can embed on throw
/obj/item/knife/shank
diff --git a/code/game/objects/items/manuals.dm b/code/game/objects/items/manuals.dm
index 5e22307559d44..db47e9aa38ca2 100644
--- a/code/game/objects/items/manuals.dm
+++ b/code/game/objects/items/manuals.dm
@@ -299,6 +299,53 @@
user.visible_message("[user] pretends to read \the [src] intently... then promptly dies of laughter! ")
return OXYLOSS
+/obj/item/book/manual/wiki/security_space_law/afterattack(atom/target, mob/living/user, proximity_flag, click_parameters)
+ . = ..()
+ if (target != user && isliving(target) && (user.mind.assigned_role == JOB_NAME_LAWYER || user.mind.assigned_role == JOB_NAME_HEADOFPERSONNEL))
+ INVOKE_ASYNC(src, PROC_REF(deconvert_target), user, target)
+
+/obj/item/book/manual/wiki/security_space_law/proc/deconvert_target(mob/living/user, mob/living/target)
+ if (user.do_afters)
+ return
+ for (var/i in 1 to 4)
+ if (user.do_afters)
+ return
+ if (!do_after(user, 2 SECONDS, target))
+ return
+ if (user.mind?.has_antag_datum(/datum/antagonist/rev))
+ switch (i)
+ if (1)
+ user.say("Number One: In 1945, corporations paid 50% of federal taxes; now they pay about 5%.", forced="space law")
+ if (2)
+ user.say("Number Two: In 1900, 90% of people were self employed; now it's about 2%... It's called consolidation; strengthen governments and corporations, weaken individuals. With taxes, this can be done imperceptibly over time.", forced="space law")
+ if (3)
+ user.say("Number Three: In the 2030s, there were strict regulations to prevent monopolies; now those regulations have been dismantled, allowing a few companies to control entire industries. This concentration of power stifles competition and innovation.")
+ if (4)
+ user.say("Number Four: In the past, media outlets were independent; now a handful of conglomerates control the majority of information. Control the narrative, control the minds of the masses.")
+ else
+ var/datum/crime/chosen = pick(subtypesof(/datum/crime) - /datum/crime/minor - /datum/crime/capital - /datum/crime/major - /datum/crime/misdemeanour)
+ user.say("[initial(chosen.tooltip)]", forced = "space law")
+ if (user.do_afters)
+ return
+ if (!do_after(user, 2 SECONDS, target))
+ return
+ if (user.mind?.has_antag_datum(/datum/antagonist/rev))
+ var/datum/antagonist/rev/rev = user.mind.has_antag_datum(/datum/antagonist/rev)
+ user.say("Isn't it obvious, Nanotrasen, the governments; everyone around us has been tricking us, playing us like we are pawns...", forced = "space law")
+ if (rev.add_revolutionary(target.mind, FALSE))
+ target.visible_message("[target] nods in approval, taking in the information! ", "That all makes perfect sense, the truth washes over you! ")
+ else
+ target.visible_message("[target] spits on the floor, disrespecting [user]'s authority! ", "You finish listening to [user]'s waffling. What a knobhead, you think to yourself... ")
+ else
+ user.say("These shall all be considered acts which are in violation of your contract of employment, and you are contractually obliged to not commit them.", forced = "space law")
+ if(target.mind?.has_antag_datum(/datum/antagonist/rev/head) || target.mind?.unconvertable)
+ target.visible_message("[target] spits on the floor, disrespecting [user]'s authority! ", "You finish listening to [user]'s waffling. What a knobhead, you think to yourself... ")
+ return
+ var/datum/antagonist/rev/rev = target.mind?.has_antag_datum(/datum/antagonist/rev)
+ if(rev)
+ rev.remove_revolutionary(FALSE, user)
+ target.visible_message("[target] nods in approval, taking in the information! ", "That all makes perfect sense, you feel a sense of pride to be working for Nanotrasen! ")
+
/obj/item/book/manual/wiki/infections
name = "Infections - Making your own pandemic!"
icon_state = "bookInfections"
@@ -348,13 +395,6 @@
title = "Research and Development 101"
page_link = "Guide_to_Research_and_Development"
-/obj/item/book/manual/wiki/experimentor
- name = "Mentoring your Experiments"
- icon_state = "rdbook"
- author = "Dr. H.P. Kritz"
- title = "Mentoring your Experiments"
- page_link = "Experimentor"
-
/obj/item/book/manual/wiki/medical_cloning
name = "Cloning techniques of the 26th century"
icon_state ="bookCloning"
@@ -424,7 +464,7 @@
if(prob(50))
step(W, pick(GLOB.alldirs))
ADD_TRAIT(H, TRAIT_DISFIGURED, TRAIT_GENERIC)
- H.bleed_rate = 5
+ H.add_bleeding(BLEED_CRITICAL)
H.gib_animation()
sleep(3)
H.adjustBruteLoss(1000) //to make the body super-bloody
diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm
index 5a3ab991f2a87..4dbf1a193df9b 100644
--- a/code/game/objects/items/melee/energy.dm
+++ b/code/game/objects/items/melee/energy.dm
@@ -3,7 +3,7 @@
hitsound_on = 'sound/weapons/blade1.ogg'
heat = 3500
max_integrity = 200
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 30, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
light_system = MOVABLE_LIGHT
light_range = 3
@@ -102,6 +102,7 @@
throw_speed = 3
throw_range = 5
sharpness = IS_SHARP
+ bleed_force_on = BLEED_DEEP_WOUND
embedding = list("embed_chance" = 200, "armour_block" = 60, "max_pain_mult" = 15)
armour_penetration = 35
block_level = 1
@@ -134,6 +135,7 @@
sword_color = null //stops icon from breaking when turned on.
w_class = WEIGHT_CLASS_NORMAL
sharpness = IS_SHARP
+ bleed_force_on = BLEED_DEEP_WOUND
light_color = "#40ceff"
tool_behaviour = TOOL_SAW
toolspeed = 0.7 //faster as a saw
@@ -164,6 +166,7 @@
hitcost = 75 //Costs more than a standard cyborg esword
w_class = WEIGHT_CLASS_NORMAL
sharpness = IS_SHARP
+ bleed_force_on = BLEED_DEEP_WOUND
light_color = "#40ceff"
tool_behaviour = TOOL_SAW
toolspeed = 0.7 //faster as a saw
@@ -261,6 +264,7 @@
w_class = WEIGHT_CLASS_BULKY//So you can't hide it in your pocket or some such.
var/datum/effect_system/spark_spread/spark_system
sharpness = IS_SHARP
+ bleed_force_on = BLEED_DEEP_WOUND
//Most of the other special functions are handled in their own files. aka special snowflake code so kewl
/obj/item/melee/transforming/energy/blade/Initialize(mapload)
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index e3b27ec60b476..b0e6ea72f9f53 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -45,6 +45,7 @@
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "tore", "ripped", "diced", "cut")
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
/obj/item/melee/synthetic_arm_blade/Initialize(mapload)
. = ..()
@@ -68,6 +69,7 @@
w_class = WEIGHT_CLASS_BULKY
armour_penetration = 75
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
attack_verb = list("slashed", "cut")
hitsound = 'sound/weapons/rapierhit.ogg'
custom_materials = list(/datum/material/iron = 1000)
@@ -352,9 +354,9 @@
cooldown = 0
stamina_damage = 30 // 4 hits to stamcrit < that was a lie
stun_animation = TRUE
- /// Per-mob sleep cooldowns.
+ /// Per-mob paralyze cooldowns.
/// [mob] = [world.time where the cooldown ends]
- var/static/list/sleep_cooldowns = list()
+ var/static/list/paralyze_cooldowns = list()
/// Per-mob trip cooldowns.
/// [mob] = [world.time where the cooldown ends]
var/static/list/trip_cooldowns = list()
@@ -416,19 +418,19 @@
else if(user.is_zone_selected(BODY_ZONE_HEAD) || user.is_zone_selected(BODY_ZONE_PRECISE_EYES) || user.is_zone_selected(BODY_ZONE_PRECISE_MOUTH))
target.apply_damage(stamina_damage*0.8, STAMINA, BODY_ZONE_HEAD, def_check) // 90 : 5 = 18 , 5 hits to KnockOut
- if(target.staminaloss > 89 && !target.has_status_effect(STATUS_EFFECT_SLEEPING) && (!sleep_cooldowns[target] || COOLDOWN_FINISHED(src, sleep_cooldowns[target])))
+ if(target.staminaloss > 89 && !target.has_status_effect(STATUS_EFFECT_PARALYZED) && (!paralyze_cooldowns[target] || COOLDOWN_FINISHED(src, paralyze_cooldowns[target])))
T.force_say(user)
- target.balloon_alert_to_viewers("Knock-Out!")
- if(!target.has_status_effect(STATUS_EFFECT_SLEEPING))
- target.Sleeping(80)
+ target.balloon_alert_to_viewers("Knock-Down!")
+ if(!target.has_status_effect(STATUS_EFFECT_PARALYZED))
+ target.Paralyze(80)
target.setStaminaLoss(0)
playsound(usr.loc, "sound/machines/bellsound.ogg", 15, 1)
- log_combat(user, target, "Knocked-Out", src)
+ log_combat(user, target, "Knocked-Down", src)
if(CHECK_BITFIELD(target.mobility_flags, MOBILITY_STAND)) //this is here so the "falls" message doesn't appear if the target is already on the floor
- target.visible_message("[T] [pick(list("falls unconscious.","falls limp like a bag of bricks.","falls to the ground, unresponsive.","lays down on the ground for a little nap.","got [T.p_their()] dome rung in."))] ")
+ target.visible_message("[T] [pick(list("falls limp like a bag of bricks.","falls to the ground, unresponsive.","lays down on the ground.","got [T.p_their()] dome rung in."))] ")
else
- target.visible_message("[T] [pick(list("falls unconscious.","falls into a deep sleep.","was sent to dreamland.","closes [T.p_their()] and prepares for a little nap."))] ")
- COOLDOWN_START(src, sleep_cooldowns[target], 16 SECONDS)
+ target.visible_message("[T] [pick(list("goes limp.","falls flat."))] ")
+ COOLDOWN_START(src, paralyze_cooldowns[target], 16 SECONDS)
else
log_combat(user, target, "stunned", src)
target.visible_message(desc["visiblestun"], desc["localstun"])
diff --git a/code/game/objects/items/melee/transforming.dm b/code/game/objects/items/melee/transforming.dm
index 8d0b3c587120e..be7012a8694ee 100644
--- a/code/game/objects/items/melee/transforming.dm
+++ b/code/game/objects/items/melee/transforming.dm
@@ -1,9 +1,11 @@
/obj/item/melee/transforming
sharpness = IS_SHARP
+ bleed_force = 0
var/active = FALSE
var/force_on = 30 //force when active
var/faction_bonus_force = 0 //Bonus force dealt against certain factions
var/throwforce_on = 20
+ var/bleed_force_on = BLEED_CUT
var/icon_state_on = "axe1"
var/hitsound_on = 'sound/weapons/blade1.ogg'
var/list/attack_verb_on = list("attacked", "slashed", "stabbed", "sliced", "tore", "ripped", "diced", "cut")
@@ -61,6 +63,7 @@
attack_verb = attack_verb_on
icon_state = icon_state_on
w_class = w_class_on
+ bleed_force = bleed_force_on
if(embedding)
updateEmbedding()
else
@@ -72,6 +75,7 @@
attack_verb = attack_verb_off
icon_state = initial(icon_state)
w_class = initial(w_class)
+ bleed_force = initial(bleed_force)
if(embedding)
disableEmbedding()
if(is_sharp())
diff --git a/code/game/objects/items/mjolnir.dm b/code/game/objects/items/mjolnir.dm
index 0d25fe18150e6..279edbcbe96b3 100644
--- a/code/game/objects/items/mjolnir.dm
+++ b/code/game/objects/items/mjolnir.dm
@@ -156,7 +156,7 @@
if (isobj(target))
var/obj/hit_structure = target
hit_structure.take_damage(120)
- if (hit_structure.obj_integrity > 0)
+ if (hit_structure.get_integrity() > 0)
qdel(src)
if (isliving(target))
var/mob/living/hit_mob = target
diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm
index 1156b9c8c5485..99035dc38fca4 100644
--- a/code/game/objects/items/mop.dm
+++ b/code/game/objects/items/mop.dm
@@ -124,4 +124,5 @@
throw_speed = 4
attack_verb = list("mopped", "stabbed", "shanked", "jousted")
sharpness = IS_SHARP
+ bleed_force = BLEED_SURFACE
embedding = list("armour_block" = 40)
diff --git a/code/game/objects/items/peppercloud.dm b/code/game/objects/items/peppercloud.dm
index 65d51f58ccae0..27c1ecf3bf5d1 100644
--- a/code/game/objects/items/peppercloud.dm
+++ b/code/game/objects/items/peppercloud.dm
@@ -102,4 +102,4 @@
playsound(src, 'sound/weapons/grenadelaunch.ogg', 70, FALSE, -2)
playsound(src, 'sound/effects/smoke.ogg', 50, TRUE, -2)
smoke.start()
- user.investigate_log("deployed a peppercloud at [COORD(center)].", INVESTIGATE_EXPERIMENTOR)
+ user.investigate_log("deployed a peppercloud at [COORD(center)].", INVESTIGATE_PEPPERSPRAY)
diff --git a/code/game/objects/items/pitchfork.dm b/code/game/objects/items/pitchfork.dm
index 41f97943791cb..4bf6ed8cda10e 100644
--- a/code/game/objects/items/pitchfork.dm
+++ b/code/game/objects/items/pitchfork.dm
@@ -13,8 +13,9 @@
attack_verb = list("attacked", "impaled", "pierced")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
max_integrity = 200
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 30, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
/obj/item/pitchfork/ComponentInitialize()
diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm
index efc174b85c5e2..60a67fdd8c713 100644
--- a/code/game/objects/items/plushes.dm
+++ b/code/game/objects/items/plushes.dm
@@ -371,14 +371,14 @@
desc = "An adorable stuffed toy that resembles a space carp."
icon_state = "carpplush"
attack_verb = list("bitten", "eaten", "fin slapped")
- squeak_override = list('sound/weapons/bite.ogg'=1)
+ squeak_override = list('sound/weapons/bite.ogg' = 1)
/obj/item/toy/plush/bubbleplush
name = "\improper Bubblegum plushie"
desc = "The friendly red demon that gives good miners gifts."
icon_state = "bubbleplush"
attack_verb = list("rent")
- squeak_override = list('sound/magic/demon_attack1.ogg'=1)
+ squeak_override = list('sound/magic/demon_attack1.ogg' = 1)
/obj/item/toy/plush/plushvar
name = "\improper Ratvar plushie"
@@ -554,8 +554,7 @@
attack_verb = list("blorbled", "slimed", "absorbed")
squeak_override = list('sound/effects/blobattack.ogg' = 1)
gender = FEMALE //given all the jokes and drawings, I'm not sure the xenobiologists would make a slimeboy
- squeak_override = list('sound/effects/blobattack.ogg' = 1)
-/// Most of the following is just stolen from the moth plush code for the slimes
+ /// Most of the following is just stolen from the moth plush code for the slimes
var/suicide_count = 0
/obj/item/toy/plush/slimeplushie/suicide_act(mob/living/user)
@@ -626,7 +625,7 @@
icon_state = "beeplush"
attack_verb = list("stung")
gender = FEMALE
- squeak_override = list('sound/voice/moth/scream_moth.ogg'=1)
+ squeak_override = list('sound/voice/moth/scream_moth.ogg' = 1)
/obj/item/toy/plush/rouny
name = "runner plushie"
@@ -640,7 +639,7 @@
desc = "An adorable mothperson plushie. It's a huggable bug!"
icon_state = "moffplush"
attack_verb = list("fluttered", "flapped")
- squeak_override = list('sound/voice/moth/scream_moth.ogg'=1)
+ squeak_override = list('sound/voice/moth/scream_moth.ogg' = 1)
///Used to track how many people killed themselves with item/toy/plush/moth
var/suicide_count = 0
@@ -791,25 +790,42 @@
name = "ghost plushie"
desc = "It reminds you of someone important, you just can't make out who."
icon_state = "crossedplush"
- squeak_override = list('sound/items/haunted/ghostitemattack.ogg'=1)
+ squeak_override = list('sound/items/haunted/ghostitemattack.ogg' = 1)
/obj/item/toy/plush/runtime
name = "Runtime plushie"
desc = "GPLUSH."
icon_state = "runtimeplush"
- squeak_override = list('sound/effects/meow1.ogg'=1)
+ squeak_override = list('sound/effects/meow1.ogg' = 1)
/obj/item/toy/plush/gondola
name = "gondola plushie"
desc = "The silent walker, in plush form."
icon_state = "gondolaplush"
- squeak_override = list('sound/misc/null.ogg'=1)
+ squeak_override = list('sound/misc/null.ogg' = 1)
/obj/item/toy/plush/flushed
name = "flushed plushie"
desc = "Hgrgrhrhg cute."
icon_state = "flushplush"
+/obj/item/toy/plush/shark
+ name = "shark plushie"
+ desc = "A big plushie depicting a rather cartoonish, yet cute shark. The tag calls it a 'søthai', noting that it was made by an obscure furniture manufacturer in Scandinavia."
+ lefthand_file = 'icons/mob/inhands/plushes_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/plushes_righthand.dmi'
+ icon_state = "cuteswedishsharkplush"
+ squeak_override = list('sound/weapons/bite.ogg' = 1)
+
+/obj/item/toy/plush/shark/equipped(mob/user, slot)
+ . = ..()
+ if(slot == ITEM_SLOT_HANDS)
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "big_plush", /datum/mood_event/bigplush, src)
+
+/obj/item/toy/plush/shark/dropped(mob/living/carbon/user)
+ ..()
+ SEND_SIGNAL(user, COMSIG_CLEAR_MOOD_EVENT, "big_plush")
+
/obj/item/toy/plush/flushed/rainbow
name = "rainbow flushed plushie"
desc = "Hgrgrhrhg cuter."
@@ -860,7 +876,8 @@
/obj/item/toy/plush/moth/royal,
/obj/item/toy/plush/moth/snow,
/obj/item/toy/plush/moth/whitefly,
- /obj/item/toy/plush/moth/witchwing
+ /obj/item/toy/plush/moth/witchwing,
+ /obj/item/toy/plush/shark,
)
/obj/item/choice_beacon/radial/plushie/generate_options(mob/living/M)
diff --git a/code/game/objects/items/pneumaticCannon.dm b/code/game/objects/items/pneumaticCannon.dm
index bf8a8eb6691ac..62301d1d3afc3 100644
--- a/code/game/objects/items/pneumaticCannon.dm
+++ b/code/game/objects/items/pneumaticCannon.dm
@@ -14,7 +14,7 @@
item_state = "bulldog"
lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 60, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 60, ACID = 50, STAMINA = 0, BLEED = 0)
var/maxWeightClass = 20 //The max weight of items that can fit into the cannon
var/loadedWeightClass = 0 //The weight of items currently in the cannon
var/obj/item/tank/internals/tank = null //The gas tank that is drawn from to fire things
diff --git a/code/game/objects/items/powerfist.dm b/code/game/objects/items/powerfist.dm
index 7d4ef3e5fd4b6..c730ba8171fdf 100644
--- a/code/game/objects/items/powerfist.dm
+++ b/code/game/objects/items/powerfist.dm
@@ -13,7 +13,7 @@
throw_range = 7
w_class = WEIGHT_CLASS_NORMAL
item_flags = ISWEAPON
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 40, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 40, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
var/click_delay = 1.5
var/fisto_setting = 1
diff --git a/code/game/objects/items/religion.dm b/code/game/objects/items/religion.dm
index 64fbbf3a7676f..1f30d22dd2618 100644
--- a/code/game/objects/items/religion.dm
+++ b/code/game/objects/items/religion.dm
@@ -246,47 +246,6 @@
desc = "It's a backpack with lots of extra room. A blue banner is attached, that can't be removed."
icon_state = "bannerpack-blue"
-//this is all part of one item set
-
-
-/obj/item/clothing/head/helmet/plate/crusader
- name = "Crusader's Hood"
- desc = "A brownish hood."
- icon = 'icons/obj/clothing/head/chaplain.dmi'
- worn_icon = 'icons/mob/clothing/head/chaplain.dmi'
- icon_state = "crusader"
- w_class = WEIGHT_CLASS_NORMAL
- flags_inv = HIDEHAIR|HIDEEARS|HIDEFACE
- armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 40, BOMB = 60, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 50)
-
-/obj/item/clothing/head/helmet/plate/crusader/blue
- icon_state = "crusader-blue"
- item_state = null
-
-/obj/item/clothing/head/helmet/plate/crusader/red
- icon_state = "crusader-red"
- item_state = null
-
-//Prophet helmet
-/obj/item/clothing/head/helmet/plate/crusader/prophet
- name = "Prophet's Hat"
- desc = "A religious-looking hat."
- icon_state = null
- worn_icon = 'icons/mob/large-worn-icons/64x64/head.dmi'
- item_state = null
- flags_1 = 0
- armor = list(MELEE = 60, BULLET = 60, LASER = 60, ENERGY = 50, BOMB = 70, BIO = 50, RAD = 50, FIRE = 60, ACID = 60, STAMINA = 60) //religion protects you from disease and radiation, honk.
- worn_x_dimension = 64
- worn_y_dimension = 64
-
-/obj/item/clothing/head/helmet/plate/crusader/prophet/red
- icon_state = "prophet-red"
- item_state = null
-
-/obj/item/clothing/head/helmet/plate/crusader/prophet/blue
- icon_state = "prophet-blue"
- item_state = null
-
//Structure conversion staff
/obj/item/godstaff
name = "godstaff"
@@ -338,7 +297,7 @@
desc = "Metal boots, they look heavy."
icon_state = "crusader"
w_class = WEIGHT_CLASS_NORMAL
- armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 40, BOMB = 60, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 30) //does this even do anything on boots?
+ armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 40, BOMB = 60, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 30, BLEED = 60) //does this even do anything on boots?
clothing_flags = NOSLIP
cold_protection = FEET
min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT
diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm
index 27498ecf81e19..5c0e7483a4dd1 100644
--- a/code/game/objects/items/robot/robot_items.dm
+++ b/code/game/objects/items/robot/robot_items.dm
@@ -76,7 +76,7 @@
user.do_attack_animation(M, ATTACK_EFFECT_BOOP)
playsound(loc, 'sound/weapons/tap.ogg', 50, 1, -1)
else if(ishuman(M))
- if(!(user.mobility_flags & MOBILITY_STAND))
+ if(user.body_position == LYING_DOWN)
user.visible_message("[user] shakes [M] trying to get [M.p_them()] up! ", \
"You shake [M] trying to get [M.p_them()] up! ")
else
@@ -91,7 +91,7 @@
if(1)
if(M.health >= 0)
if(ishuman(M))
- if(!(M.mobility_flags & MOBILITY_STAND))
+ if(M.body_position == LYING_DOWN)
user.visible_message("[user] shakes [M] trying to get [M.p_them()] up! ", \
"You shake [M] trying to get [M.p_them()] up! ")
else if(user.is_zone_selected(BODY_ZONE_HEAD, precise_only = TRUE))
@@ -114,7 +114,6 @@
M.electrocute_act(5, "[user]", flags = SHOCK_NOGLOVES)
user.visible_message("[user] electrocutes [M] with [user.p_their()] touch! ", \
"You electrocute [M] with your touch! ")
- M.update_mobility()
else
if(!iscyborg(M))
M.adjustFireLoss(10)
@@ -592,6 +591,7 @@
icon_state = "gumball"
ammo_type = /obj/item/food/gumball/cyborg
nodamage = TRUE
+ bleed_force = 0
/obj/projectile/bullet/reusable/gumball/handle_drop()
if(!dropped)
@@ -612,6 +612,7 @@
ammo_type = /obj/item/food/lollipop/cyborg
var/color2 = rgb(0, 0, 0)
nodamage = TRUE
+ bleed_force = 0
/obj/projectile/bullet/reusable/lollipop/Initialize(mapload)
. = ..()
diff --git a/code/game/objects/items/sharpener.dm b/code/game/objects/items/sharpener.dm
index daed28fd27ce5..d8df3e69ec8c4 100644
--- a/code/game/objects/items/sharpener.dm
+++ b/code/game/objects/items/sharpener.dm
@@ -40,6 +40,7 @@
user.visible_message("[user] sharpens [I] with [src]! ", "You sharpen [I], making it much more deadly than before. ")
playsound(src, 'sound/items/unsheath.ogg', 25, 1)
I.sharpness = IS_SHARP_ACCURATE
+ I.bleed_force *= 1.1
I.throwforce = clamp(I.throwforce + increment, 0, max)
I.name = "[prefix] [I.name]"
name = "worn out [name]"
diff --git a/code/game/objects/items/shrapnel.dm b/code/game/objects/items/shrapnel.dm
index 5ef59060bd9a1..103e8d676ea32 100644
--- a/code/game/objects/items/shrapnel.dm
+++ b/code/game/objects/items/shrapnel.dm
@@ -51,6 +51,7 @@
shrapnel_type = /obj/item/shrapnel
ricochet_incidence_leeway = 60
hit_stunned_targets = TRUE
+ bleed_force = BLEED_SURFACE
/obj/projectile/bullet/shrapnel/mega
name = "flying shrapnel hunk"
@@ -59,6 +60,7 @@
ricochets_max = 4
ricochet_chance = 90
ricochet_decay_chance = 0.9
+ bleed_force = BLEED_CUT
/obj/projectile/bullet/pellet/stingball
name = "stingball pellet"
diff --git a/code/game/objects/items/singularityhammer.dm b/code/game/objects/items/singularityhammer.dm
index e3a1f9f6a95cc..ad2ae95a1219a 100644
--- a/code/game/objects/items/singularityhammer.dm
+++ b/code/game/objects/items/singularityhammer.dm
@@ -14,7 +14,7 @@
throw_range = 1
w_class = WEIGHT_CLASS_HUGE
item_flags = ISWEAPON
- armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 0, BOMB = 50, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 0, BOMB = 50, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF | ACID_PROOF
force_string = "LORD SINGULOTH HIMSELF"
var/charged = 5
diff --git a/code/game/objects/items/spear.dm b/code/game/objects/items/spear.dm
index fbf1bb14eea94..fbf2f8b1ee2b5 100644
--- a/code/game/objects/items/spear.dm
+++ b/code/game/objects/items/spear.dm
@@ -18,8 +18,9 @@
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "poked", "jabbed", "torn", "gored")
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
max_integrity = 200
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0, BLEED = 0)
var/war_cry = "AAAAARGH!!!"
var/icon_prefix = "spearglass"
@@ -191,6 +192,7 @@
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "poked", "jabbed", "tore", "gored")
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
/obj/item/spear/bamboospear/ComponentInitialize()
. = ..()
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 08ad341ece0bd..91fd05087eeda 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -19,6 +19,8 @@
///What reagent does it apply?
var/list/reagent
///Is this for bruises?
+ var/heal_creatures = FALSE
+ ///Is this for bruises?
var/heal_brute = FALSE
///Is this for burns?
var/heal_burn = FALSE
@@ -56,7 +58,7 @@
if(critter.health == critter.maxHealth)
to_chat(user, "[M] is at full health. ")
return
- if(!heal_brute) //simplemobs can only take brute damage, and can only benefit from items intended to heal it
+ if(!heal_creatures) //simplemobs can only take brute damage, and can only benefit from items intended to heal it
to_chat(user, "[src] won't help [M] at all. ")
return
M.heal_bodypart_damage(REAGENT_AMOUNT_PER_ITEM)
@@ -72,15 +74,19 @@
return
if (!user.can_interact_with(M, TRUE))
to_chat(user, "You cannot reach [M]! ")
+ M.balloon_alert(user, "You cannot reach that.")
return
if (!user.can_interact_with(src, TRUE))
to_chat(user, "You cannot reach [src]! ")
+ M.balloon_alert(user, "You cannot reach that.")
return
if(M.stat == DEAD && !stop_bleeding)
to_chat(user, "\The [M] is dead, you cannot help [M.p_them()]! ")
+ M.balloon_alert(user, "[M] is dead.")
return
if(!iscarbon(M))
to_chat(user, "You don't know how to apply \the [src] to [M]! ")
+ M.balloon_alert(user, "You cannot use that.")
return
var/obj/item/bodypart/affecting
var/mob/living/carbon/C = M
@@ -91,29 +97,38 @@
if(!affecting) //Missing limb?
to_chat(user, "[C] doesn't have \a [parse_zone(zone_selected)]! ")
+ C.balloon_alert(user, "[C] has no [parse_zone(zone_selected)]!")
return
- if(ishuman(C)) //apparently only humans bleed? funky.
- var/mob/living/carbon/human/H = C
- if(stop_bleeding)
- if(!H.bleed_rate)
- to_chat(user, "[H] isn't bleeding! ")
- return
- if(H.bleedsuppress) //so you can't stack bleed suppression
- to_chat(user, "[H]'s bleeding is already bandaged! ")
- return
- H.suppress_bloodloss(stop_bleeding)
+ var/valid = FALSE
+ var/message = null
+
+ if(stop_bleeding)
+ if (C.is_bleeding())
+ valid = TRUE
+ else if (C.is_bandaged())
+ message = "[C]'s bleeding is already bandaged!"
+ else
+ message = "[C] isn't bleeding!"
if(!IS_ORGANIC_LIMB(affecting))
to_chat(user, "Medicine won't work on a robotic limb! ")
+ C.balloon_alert(user, "Cannot use on robotic limb!")
return
if(!(affecting.brute_dam || affecting.burn_dam))
- to_chat(user, "[M]'s [parse_zone(zone_selected)] isn't hurt! ")
- return
+ message = "[M]'s [parse_zone(zone_selected)] isn't hurt! "
+ else
+ valid = TRUE
if((affecting.brute_dam && !affecting.burn_dam && !heal_brute) || (affecting.burn_dam && !affecting.brute_dam && !heal_burn)) //suffer
- to_chat(user, "This type of medicine isn't appropriate for this type of wound. ")
+ message = "This type of medicine isn't appropriate for this type of wound."
+ else
+ valid = TRUE
+
+ if (!valid)
+ to_chat("[message] ")
+ C.balloon_alert(user, message)
return
if(C == user)
@@ -123,9 +138,19 @@
//After the do_mob to ensure metabolites have had time to process at least one tick.
if(reagent && (C.reagents.get_reagent_amount(/datum/reagent/metabolite/medicine/styptic_powder) || C.reagents.get_reagent_amount(/datum/reagent/metabolite/medicine/silver_sulfadiazine)))
to_chat(user, "That stuff really hurt! You'll need to wait for the pain to go away before you can apply [src] to your wounds again, maybe someone else can help put it on for you. ")
+ C.balloon_alert(user, "You fail to apply [src] to yourself!")
return
- user.visible_message("[user] applies [src] on [M]. ", "You apply [src] on [M]. ")
+ if(stop_bleeding)
+ C.suppress_bloodloss(stop_bleeding)
+ if (C.is_bleeding())
+ C.balloon_alert(user, "You reduce [M == user ? "your" : M.p_their()] bleeding to [C.get_bleed_rate_string()]")
+ else
+ C.balloon_alert(user, "You stop [M == user ? "your" : M.p_their()] bleeding!")
+ else
+ C.balloon_alert(user, "You apply [src] to [M == user ? "yourself" : M].")
+
+ user.visible_message("[user] applies [src] to [M]. ", "You apply [src] to [M]. ")
if(reagent)
reagents.reaction(M, PATCH, affecting = affecting)
M.reagents.add_reagent_list(reagent) //Stack size is reduced by one instead of actually removing reagents from the stack.
@@ -144,6 +169,7 @@
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
heal_brute = TRUE
+ heal_creatures = TRUE
reagent = list(/datum/reagent/medicine/styptic_powder = REAGENT_AMOUNT_PER_ITEM)
grind_results = list(/datum/reagent/medicine/styptic_powder = REAGENT_AMOUNT_PER_ITEM)
merge_type = /obj/item/stack/medical/bruise_pack
@@ -177,8 +203,8 @@
name = "medical gauze"
desc = "A roll of elastic cloth that is extremely effective at stopping bleeding, heals minor bruising."
icon_state = "gauze"
- stop_bleeding = 1800
- heal_brute = TRUE //Enables gauze to be used on simplemobs for healing
+ stop_bleeding = BLEED_CRITICAL
+ heal_creatures = TRUE //Enables gauze to be used on simplemobs for healing
max_amount = 12
merge_type = /obj/item/stack/medical/gauze
@@ -203,8 +229,8 @@
name = "improvised gauze"
singular_name = "improvised gauze"
desc = "A roll of cloth roughly cut from something that can stop bleeding, but does not heal wounds."
- stop_bleeding = 900
- heal_brute = 0
+ stop_bleeding = BLEED_SURFACE
+ heal_creatures = FALSE
merge_type = /obj/item/stack/medical/gauze/improvised
/obj/item/stack/medical/gauze/adv
diff --git a/code/game/objects/items/stacks/sheets/mineral/exotics.dm b/code/game/objects/items/stacks/sheets/mineral/exotics.dm
index 0453b51e9766d..f6b94c6cf2e42 100644
--- a/code/game/objects/items/stacks/sheets/mineral/exotics.dm
+++ b/code/game/objects/items/stacks/sheets/mineral/exotics.dm
@@ -49,7 +49,10 @@ Exotic mineral Sheets
item_state = "sheet-abductor"
singular_name = "alien alloy sheet"
sheettype = "abductor"
+ mats_per_unit = list(/datum/material/alloy/alien=MINERAL_MATERIAL_AMOUNT)
merge_type = /obj/item/stack/sheet/mineral/abductor
+ material_type = /datum/material/alloy/alien
+ walltype = /turf/closed/wall/mineral/abductor
/obj/item/stack/sheet/mineral/abductor/get_recipes()
return GLOB.abductor_recipes
diff --git a/code/game/objects/items/stacks/sheets/mineral/glass.dm b/code/game/objects/items/stacks/sheets/mineral/glass.dm
index 95015f024b374..3000342decf10 100644
--- a/code/game/objects/items/stacks/sheets/mineral/glass.dm
+++ b/code/game/objects/items/stacks/sheets/mineral/glass.dm
@@ -17,7 +17,7 @@
icon_state = "sheet-glass"
item_state = "sheet-glass"
mats_per_unit = list(/datum/material/glass=MINERAL_MATERIAL_AMOUNT)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 100, STAMINA = 0, BLEED = 0)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/glass
grind_results = list(/datum/reagent/silicon = 20)
@@ -70,7 +70,7 @@
icon_state = "sheet-rglass"
item_state = "sheet-rglass"
custom_materials = list(/datum/material/iron=MINERAL_MATERIAL_AMOUNT * 0.5, /datum/material/glass=MINERAL_MATERIAL_AMOUNT)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 70, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 70, ACID = 100, STAMINA = 0, BLEED = 0)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/rglass
grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/iron = 10)
@@ -113,8 +113,9 @@
singular_name = "plasma glass sheet"
icon_state = "sheet-pglass"
item_state = "sheet-pglass"
- mats_per_unit = list(/datum/material/plasma=MINERAL_MATERIAL_AMOUNT * 0.5, /datum/material/glass=MINERAL_MATERIAL_AMOUNT)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 75, ACID = 100, STAMINA = 0)
+ mats_per_unit = list(/datum/material/alloy/plasmaglass=MINERAL_MATERIAL_AMOUNT)
+ material_type = /datum/material/alloy/plasmaglass
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 75, ACID = 100, STAMINA = 0, BLEED = 0)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/plasmaglass
grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/toxin/plasma = 10)
@@ -150,8 +151,8 @@
singular_name = "reinforced plasma glass sheet"
icon_state = "sheet-prglass"
item_state = "sheet-prglass"
- mats_per_unit = list(/datum/material/plasma=MINERAL_MATERIAL_AMOUNT * 0.5, /datum/material/glass=MINERAL_MATERIAL_AMOUNT, /datum/material/iron = MINERAL_MATERIAL_AMOUNT * 0.5)
- armor = list(MELEE = 20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 100, STAMINA = 0)
+ mats_per_unit = list(/datum/material/alloy/plasmaglass=MINERAL_MATERIAL_AMOUNT, /datum/material/iron = MINERAL_MATERIAL_AMOUNT * 0.5)
+ armor = list(MELEE = 20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 100, STAMINA = 0, BLEED = 0)
resistance_flags = ACID_PROOF
material_flags = NONE
merge_type = /obj/item/stack/sheet/plasmarglass
@@ -170,8 +171,9 @@
singular_name = "titanium glass sheet"
icon_state = "sheet-titaniumglass"
item_state = "sheet-titaniumglass"
- mats_per_unit = list(/datum/material/titanium=MINERAL_MATERIAL_AMOUNT * 0.5, /datum/material/glass=MINERAL_MATERIAL_AMOUNT)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 100, STAMINA = 0)
+ mats_per_unit = list(/datum/material/alloy/titaniumglass=MINERAL_MATERIAL_AMOUNT)
+ material_type = /datum/material/alloy/titaniumglass
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 100, STAMINA = 0, BLEED = 0)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/titaniumglass
@@ -187,7 +189,7 @@
icon_state = "sheet-plastitaniumglass"
item_state = "sheet-plastitaniumglass"
mats_per_unit = list(/datum/material/titanium=MINERAL_MATERIAL_AMOUNT * 0.5, /datum/material/plasma=MINERAL_MATERIAL_AMOUNT * 0.5, /datum/material/glass=MINERAL_MATERIAL_AMOUNT)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 100, STAMINA = 0, BLEED = 0)
resistance_flags = ACID_PROOF
material_flags = NONE
merge_type = /obj/item/stack/sheet/plastitaniumglass
@@ -212,9 +214,10 @@
attack_verb = list("stabbed", "slashed", "sliced", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
resistance_flags = ACID_PROOF
- armor = list(MELEE = 100, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 100, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 100, STAMINA = 0, BLEED = 0)
max_integrity = 40
sharpness = IS_SHARP
+ bleed_force = BLEED_SURFACE
var/icon_prefix
embedding = list("embed_chance" = 65)
@@ -294,5 +297,5 @@
force = 6
throwforce = 11
icon_state = "plasmalarge"
- custom_materials = list(/datum/material/plasma=MINERAL_MATERIAL_AMOUNT * 0.5, /datum/material/glass=MINERAL_MATERIAL_AMOUNT)
+ custom_materials = list(/datum/material/alloy/plasmaglass=MINERAL_MATERIAL_AMOUNT)
icon_prefix = "plasma"
diff --git a/code/game/objects/items/stacks/sheets/mineral/materials.dm b/code/game/objects/items/stacks/sheets/mineral/materials.dm
index 256533a7ab67a..8ce8b3e34c4d8 100644
--- a/code/game/objects/items/stacks/sheets/mineral/materials.dm
+++ b/code/game/objects/items/stacks/sheets/mineral/materials.dm
@@ -198,7 +198,8 @@ Mineral Sheets
throw_speed = 1
throw_range = 3
sheettype = "plastitanium"
- mats_per_unit = list(/datum/material/titanium=MINERAL_MATERIAL_AMOUNT, /datum/material/plasma=MINERAL_MATERIAL_AMOUNT)
+ mats_per_unit = list(/datum/material/alloy/plastitanium=MINERAL_MATERIAL_AMOUNT)
+ material_type = /datum/material/alloy/plastitanium
point_value = 45
merge_type = /obj/item/stack/sheet/mineral/plastitanium
material_flags = NONE
diff --git a/code/game/objects/items/stacks/sheets/mineral/metals.dm b/code/game/objects/items/stacks/sheets/mineral/metals.dm
index fb274d1fd2473..cdcb2c53bd51d 100644
--- a/code/game/objects/items/stacks/sheets/mineral/metals.dm
+++ b/code/game/objects/items/stacks/sheets/mineral/metals.dm
@@ -56,10 +56,11 @@ Metals Sheets
desc = "This sheet is an alloy of iron and plasma."
icon_state = "sheet-plasteel"
item_state = "sheet-metal"
- mats_per_unit = list(/datum/material/iron=MINERAL_MATERIAL_AMOUNT, /datum/material/plasma=MINERAL_MATERIAL_AMOUNT)
+ mats_per_unit = list(/datum/material/alloy/plasteel=MINERAL_MATERIAL_AMOUNT)
+ material_type = /datum/material/alloy/plasteel
throwforce = 10
flags_1 = CONDUCT_1
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 80, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 80, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
merge_type = /obj/item/stack/sheet/plasteel
grind_results = list(/datum/reagent/iron = 20, /datum/reagent/toxin/plasma = 20)
diff --git a/code/game/objects/items/stacks/sheets/mineral/metals_recipes.dm b/code/game/objects/items/stacks/sheets/mineral/metals_recipes.dm
index 2be915d8e08b7..cbe052eba15c9 100644
--- a/code/game/objects/items/stacks/sheets/mineral/metals_recipes.dm
+++ b/code/game/objects/items/stacks/sheets/mineral/metals_recipes.dm
@@ -44,7 +44,15 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
)),
null, \
new/datum/stack_recipe("rack parts", /obj/item/rack_parts), \
- new/datum/stack_recipe("closet", /obj/structure/closet, 2, one_per_turf = TRUE, on_floor = TRUE, time = 2 SECONDS), \
+ new /datum/stack_recipe_list("closets", list( \
+ new/datum/stack_recipe("closet", /obj/structure/closet, 2, one_per_turf = TRUE, on_floor = TRUE, time = 1.5 SECONDS), \
+ new/datum/stack_recipe("emergency closet", /obj/structure/closet/emcloset/empty, 2, one_per_turf = TRUE, on_floor = TRUE, time = 1.5 SECONDS), \
+ new/datum/stack_recipe("fire closet", /obj/structure/closet/radiation/empty, 2, one_per_turf = TRUE, on_floor = TRUE, time = 1.5 SECONDS), \
+ new/datum/stack_recipe("radiation closet", /obj/structure/closet/firecloset/empty, 2, one_per_turf = TRUE, on_floor = TRUE, time = 1.5 SECONDS), \
+ new/datum/stack_recipe("tool closet", /obj/structure/closet/toolcloset/empty, 2, one_per_turf = TRUE, on_floor = TRUE, time = 1.5 SECONDS), \
+ new/datum/stack_recipe("wardrobe closet", /obj/structure/closet/wardrobe/empty, 2, one_per_turf = TRUE, on_floor = TRUE, time = 1.5 SECONDS), \
+ new/datum/stack_recipe("bomb closet", /obj/structure/closet/bombcloset/empty, 2, one_per_turf = TRUE, on_floor = TRUE, time = 1.5 SECONDS), \
+ )),
null, \
new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, one_per_turf = TRUE, on_floor = TRUE, time = 1.5 SECONDS), \
null, \
diff --git a/code/game/objects/items/stacks/sheets/organic/wood.dm b/code/game/objects/items/stacks/sheets/organic/wood.dm
index 4f214afd20bc5..9219242ab69fe 100644
--- a/code/game/objects/items/stacks/sheets/organic/wood.dm
+++ b/code/game/objects/items/stacks/sheets/organic/wood.dm
@@ -18,7 +18,7 @@ Woods Sheets
icon = 'icons/obj/stacks/organic.dmi'
mats_per_unit = list(/datum/material/wood=MINERAL_MATERIAL_AMOUNT)
sheettype = "wood"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 0, STAMINA = 0, BLEED = 0)
resistance_flags = FLAMMABLE
merge_type = /obj/item/stack/sheet/wood
material_type = /datum/material/wood
@@ -39,7 +39,7 @@ Woods Sheets
icon = 'icons/obj/stacks/organic.dmi'
force = 10
throwforce = 10
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 0, STAMINA = 0, BLEED = 0)
resistance_flags = FLAMMABLE
merge_type = /obj/item/stack/sheet/bamboo
grind_results = list("carbon" = 5)
diff --git a/code/game/objects/items/stacks/tiles/tile_iron.dm b/code/game/objects/items/stacks/tiles/tile_iron.dm
index f3cabe7210fe5..45a4781f85605 100644
--- a/code/game/objects/items/stacks/tiles/tile_iron.dm
+++ b/code/game/objects/items/stacks/tiles/tile_iron.dm
@@ -222,6 +222,13 @@
merge_type = /obj/item/stack/tile/iron/checker
tile_rotate_dirs = list(SOUTH, NORTH)
+/obj/item/stack/tile/iron/checker/other
+ name = "alternate checker tile"
+ singular_name = "alternate checker floor tile"
+ icon_state = "tile_checker"
+ turf_type = /turf/open/floor/iron/checker/other
+ merge_type = /obj/item/stack/tile/iron/checker/other
+
/obj/item/stack/tile/iron/dark/textured
name = "dark textured tile"
singular_name = "dark textured floor tile"
diff --git a/code/game/objects/items/stacks/tiles/tile_mineral.dm b/code/game/objects/items/stacks/tiles/tile_mineral.dm
index ffc84659536f6..d7976a575881c 100644
--- a/code/game/objects/items/stacks/tiles/tile_mineral.dm
+++ b/code/game/objects/items/stacks/tiles/tile_mineral.dm
@@ -109,6 +109,7 @@
icon_state = "tile_abductor"
item_state = "tile-abductor"
turf_type = /turf/open/floor/mineral/abductor
+ mats_per_unit = list(/datum/material/alloy/alien=MINERAL_MATERIAL_AMOUNT*0.25)
mineralType = "abductor"
merge_type = /obj/item/stack/tile/mineral/abductor
@@ -217,7 +218,7 @@
item_state = "tile-darkshuttle"
turf_type = /turf/open/floor/mineral/plastitanium
mineralType = "plastitanium"
- mats_per_unit = list(/datum/material/titanium=500, /datum/material/plasma=500)
+ mats_per_unit = list(/datum/material/alloy/plastitanium=MINERAL_MATERIAL_AMOUNT*0.50)
merge_type = /obj/item/stack/tile/mineral/plastitanium
tile_reskin_types = list(
/obj/item/stack/tile/mineral/plastitanium,
diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm
index add2689859b82..413f29af2861d 100644
--- a/code/game/objects/items/storage/backpack.dm
+++ b/code/game/objects/items/storage/backpack.dm
@@ -45,7 +45,7 @@
item_state = "holdingpack"
resistance_flags = FIRE_PROOF
item_flags = NO_MAT_REDEMPTION
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 60, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 60, ACID = 50, STAMINA = 0, BLEED = 0)
component_type = /datum/component/storage/concrete/bluespace/bag_of_holding
/obj/item/storage/backpack/holding/clown
@@ -81,7 +81,7 @@
worn_icon_state = "baguette"
resistance_flags = FIRE_PROOF
item_flags = NO_MAT_REDEMPTION
- armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
component_type = /datum/component/storage/concrete/bluespace/bag_of_holding
/obj/item/storage/backpack/hammerspace/ComponentInitialize()
diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm
index 61b7e6b08797e..4533039d5f8f1 100644
--- a/code/game/objects/items/storage/firstaid.dm
+++ b/code/game/objects/items/storage/firstaid.dm
@@ -22,7 +22,6 @@
throw_range = 7
w_class = WEIGHT_CLASS_LARGE
var/skin_type = MEDBOT_SKIN_DEFAULT
- var/empty = FALSE
/obj/item/storage/firstaid/regular
icon_state = "firstaid"
@@ -33,8 +32,6 @@
return BRUTELOSS
/obj/item/storage/firstaid/regular/PopulateContents()
- if(empty)
- return
var/static/items_inside = list(
/obj/item/stack/medical/gauze = 1,
/obj/item/stack/medical/bruise_pack = 2,
@@ -49,8 +46,6 @@
w_class = WEIGHT_CLASS_NORMAL //Intended to be used by ERTs or other uncommon roles
/obj/item/storage/firstaid/compact/PopulateContents()
- if(empty)
- return
var/static/items_inside = list(
/obj/item/stack/medical/gauze = 1,
/obj/item/stack/medical/bruise_pack = 2,
@@ -63,7 +58,7 @@
name = "doctor's bag"
icon_state = "firstaid-surgeryalt"
item_state = "firstaid-surgeryalt"
- worn_icon_state = "baguette"
+ worn_icon_state = "firstaid_surgeryalt"
desc = "A fancy high capacity aid kit for doctors, full of medical supplies and basic surgical equipment"
skin_type = null
w_class = WEIGHT_CLASS_BULKY
@@ -126,8 +121,6 @@
))
/obj/item/storage/firstaid/medical/PopulateContents()
- if(empty)
- return
var/static/items_inside = list(
/obj/item/stack/medical/gauze = 1,
/obj/item/stack/medical/bruise_pack = 2,
@@ -147,8 +140,6 @@
skin_type = null
/obj/item/storage/firstaid/ancient/PopulateContents()
- if(empty)
- return
var/static/items_inside = list(
/obj/item/stack/medical/gauze = 2,
/obj/item/stack/medical/bruise_pack = 3,
@@ -173,8 +164,6 @@
icon_state = pick("firstaid-burn","firstaid-burnalt")
/obj/item/storage/firstaid/fire/PopulateContents()
- if(empty)
- return
var/static/items_inside = list(
/obj/item/reagent_containers/pill/patch/silver_sulf = 4,
/obj/item/storage/pill_bottle/kelotane = 1,
@@ -222,8 +211,6 @@
return TOXLOSS
/obj/item/storage/firstaid/radbgone/PopulateContents()
- if(empty)
- return
var/static/items_inside = list(
/obj/item/reagent_containers/pill/antirad_plus = 2,
/obj/item/reagent_containers/pill/antirad = 2,
diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm
index a0690c4ecad7b..9812ad7f8933e 100644
--- a/code/game/objects/items/storage/secure.dm
+++ b/code/game/objects/items/storage/secure.dm
@@ -175,6 +175,8 @@
anchored = TRUE
density = FALSE
+MAPPING_DIRECTIONAL_HELPERS(/obj/item/storage/secure/safe, 32)
+
/obj/item/storage/secure/safe/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
@@ -214,6 +216,8 @@ It remains quite flush against the wall, and there only seems to be enough room
max_integrity = 300
color = "#ffdd33"
+MAPPING_DIRECTIONAL_HELPERS(/obj/item/storage/secure/safe/caps_spare, 32)
+
/obj/item/storage/secure/safe/caps_spare/Initialize(mapload)
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm
index 5c3ad5ce05660..1d9c101b8856f 100644
--- a/code/game/objects/items/storage/storage.dm
+++ b/code/game/objects/items/storage/storage.dm
@@ -4,13 +4,15 @@
w_class = WEIGHT_CLASS_NORMAL
var/rummage_if_nodrop = TRUE
var/component_type = /datum/component/storage/concrete
+ var/empty = FALSE
/obj/item/storage/get_dumping_location(obj/item/storage/source,mob/user)
return src
/obj/item/storage/Initialize(mapload)
. = ..()
- PopulateContents()
+ if(!empty)
+ PopulateContents()
/obj/item/storage/ComponentInitialize()
AddComponent(component_type)
diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm
index 578bf161ad573..feb0e77a45678 100644
--- a/code/game/objects/items/storage/uplink_kits.dm
+++ b/code/game/objects/items/storage/uplink_kits.dm
@@ -518,7 +518,7 @@
new /obj/item/book/granter/spell/mimery_guns(src)
/obj/item/storage/box/syndie_kit/centcom_costume/PopulateContents()
- new /obj/item/clothing/under/rank/centcom/officer(src)
+ new /obj/item/clothing/under/rank/centcom/official(src)
new /obj/item/clothing/shoes/sneakers/black(src)
new /obj/item/clothing/gloves/color/black(src)
new /obj/item/radio/headset/headset_cent/empty(src)
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index fa6fe4e7cdfe7..c9f8c581e1732 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -12,7 +12,7 @@
w_class = WEIGHT_CLASS_LARGE
item_flags = ISWEAPON
attack_verb = list("enforced the law upon")
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 0, BLEED = 0)
var/stunforce = 40
var/turned_on = FALSE
@@ -187,13 +187,14 @@
target.stuttering = 20
// Shoving
- var/shove_dir = get_dir(user.loc, target.loc)
- var/turf/target_shove_turf = get_step(target.loc, shove_dir)
- var/mob/living/carbon/human/target_collateral_human = locate(/mob/living/carbon) in target_shove_turf.contents
- if (target_collateral_human && target_shove_turf != get_turf(user))
- target.Knockdown(0.5 SECONDS)
- target_collateral_human.Knockdown(0.5 SECONDS)
- target.Move(target_shove_turf, shove_dir)
+ if(user.a_intent == INTENT_DISARM)
+ var/shove_dir = get_dir(user.loc, target.loc)
+ var/turf/target_shove_turf = get_step(target.loc, shove_dir)
+ var/mob/living/carbon/human/target_collateral_human = locate(/mob/living/carbon) in target_shove_turf.contents
+ if (target_collateral_human && target_shove_turf != get_turf(user))
+ target.Knockdown(0.5 SECONDS)
+ target_collateral_human.Knockdown(0.5 SECONDS)
+ target.Move(target_shove_turf, shove_dir)
target.do_stun_animation()
diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm
index b4413a5206869..6405e4b22a110 100644
--- a/code/game/objects/items/tanks/tanks.dm
+++ b/code/game/objects/items/tanks/tanks.dm
@@ -17,7 +17,7 @@
throw_range = 4
custom_materials = list(/datum/material/iron = 500)
actions_types = list(/datum/action/item_action/set_internals)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 80, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 80, ACID = 30, STAMINA = 0, BLEED = 0)
var/datum/gas_mixture/air_contents = null
var/distribute_pressure = ONE_ATMOSPHERE
var/integrity = 3
@@ -139,7 +139,7 @@
if(prob(50))
step(W, pick(GLOB.alldirs))
ADD_TRAIT(human_user, TRAIT_DISFIGURED, TRAIT_GENERIC)
- human_user.bleed_rate = 5
+ human_user.add_bleeding(BLEED_CRITICAL)
human_user.gib_animation()
sleep(3)
human_user.adjustBruteLoss(1000) //to make the body super-bloody
diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm
index a54c962fba487..7c7c944d047eb 100644
--- a/code/game/objects/items/tanks/watertank.dm
+++ b/code/game/objects/items/tanks/watertank.dm
@@ -12,7 +12,7 @@
slowdown = 1
actions_types = list(/datum/action/item_action/toggle_mister)
max_integrity = 200
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 30, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
var/obj/item/noz
diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm
index d62d696dd7bcb..ec9d47cfe22a4 100644
--- a/code/game/objects/items/teleportation.dm
+++ b/code/game/objects/items/teleportation.dm
@@ -110,7 +110,7 @@
throw_speed = 3
throw_range = 5
custom_materials = list(/datum/material/iron=10000)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/list/active_portal_pairs
var/max_portal_pairs = 3
@@ -387,7 +387,7 @@
/obj/item/teleporter/proc/telefrag(turf/fragging_location, mob/user)
for(var/mob/living/target in fragging_location)//Hit everything in the turf
// Skip any mobs that aren't standing, or aren't dense
- if (!(target.mobility_flags & MOBILITY_STAND) || !target.density || user == target)
+ if ((target.body_position == LYING_DOWN) || !target.density || user == target)
continue
// Run armour checks and apply damage
var/armor_block = target.run_armor_check(BODY_ZONE_CHEST, MELEE)
@@ -395,7 +395,7 @@
target.Paralyze(10 * (100 - armor_block) / 100)
target.Knockdown(40 * (100 - armor_block) / 100)
// Check if we successfully knocked them down
- if (!(target.mobility_flags & MOBILITY_STAND))
+ if (target.body_position == LYING_DOWN)
to_chat(target, "[user] teleports into you, knocking you to the floor with the bluespace wave! ")
else
to_chat(user, "[target] resists the force of your jaunt's wake, bringing you to stop! ")
diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm
index 63a6938164573..98e0ecc407fe4 100644
--- a/code/game/objects/items/tools/crowbar.dm
+++ b/code/game/objects/items/tools/crowbar.dm
@@ -16,7 +16,7 @@
attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked")
tool_behaviour = TOOL_CROWBAR
toolspeed = 1
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0, BLEED = 0)
drop_sound = 'sound/items/handling/crowbar_drop.ogg'
pickup_sound = 'sound/items/handling/crowbar_pickup.ogg'
diff --git a/code/game/objects/items/tools/powertools.dm b/code/game/objects/items/tools/powertools.dm
index 0b39452a64aae..935a5e82cc887 100644
--- a/code/game/objects/items/tools/powertools.dm
+++ b/code/game/objects/items/tools/powertools.dm
@@ -6,7 +6,7 @@
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
w_class = WEIGHT_CLASS_SMALL
custom_materials = list(/datum/material/iron=150,/datum/material/silver=50,/datum/material/titanium=25) //done for balance reasons, making them high value for research, but harder to get
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0, BLEED = 0)
flags_1 = CONDUCT_1
slot_flags = ITEM_SLOT_BELT
toolspeed = 0.7
diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm
index 98d2e689b0a74..3db95599ce19f 100644
--- a/code/game/objects/items/tools/screwdriver.dm
+++ b/code/game/objects/items/tools/screwdriver.dm
@@ -25,7 +25,7 @@
greyscale_config_inhand_left = /datum/greyscale_config/screwdriver_inhand_left
greyscale_config_inhand_right = /datum/greyscale_config/screwdriver_inhand_right
greyscale_config_belt = /datum/greyscale_config/screwdriver_belt
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0, BLEED = 0)
drop_sound = 'sound/items/handling/screwdriver_drop.ogg'
pickup_sound = 'sound/items/handling/screwdriver_pickup.ogg'
/// If the item should be assigned a random color
diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm
index 3e2df866fd0fd..5f78cff0474f6 100644
--- a/code/game/objects/items/tools/weldingtool.dm
+++ b/code/game/objects/items/tools/weldingtool.dm
@@ -26,7 +26,7 @@
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 30, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
custom_materials = list(/datum/material/iron=70, /datum/material/glass=30)
diff --git a/code/game/objects/items/tools/wirecutters.dm b/code/game/objects/items/tools/wirecutters.dm
index 0478da413700c..076d2ae251d9e 100644
--- a/code/game/objects/items/tools/wirecutters.dm
+++ b/code/game/objects/items/tools/wirecutters.dm
@@ -21,7 +21,7 @@
pickup_sound = 'sound/items/handling/wirecutter_pickup.ogg'
tool_behaviour = TOOL_WIRECUTTER
toolspeed = 1
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0, BLEED = 0)
var/random_color = TRUE
var/static/list/wirecutter_colors = list(
"blue" = "#1861d5",
diff --git a/code/game/objects/items/tools/wrench.dm b/code/game/objects/items/tools/wrench.dm
index 77c846b1fcb0c..2008a03831b1c 100644
--- a/code/game/objects/items/tools/wrench.dm
+++ b/code/game/objects/items/tools/wrench.dm
@@ -19,7 +19,7 @@
attack_verb = list("bashed", "battered", "bludgeoned", "whacked")
tool_behaviour = TOOL_WRENCH
toolspeed = 1
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30, STAMINA = 0, BLEED = 0)
/obj/item/wrench/suicide_act(mob/living/user)
user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide! ")
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index 82734d742cf5c..3639f4e3314ce 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -419,6 +419,11 @@
block_level = 0
item_flags = ISWEAPON
+/obj/item/dualsaber/toy/on_wield(obj/item/source, mob/living/carbon/user)
+ . = ..()
+ sharpness = IS_BLUNT
+ bleed_force = 0
+
/obj/item/dualsaber/toy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
return 0
@@ -447,6 +452,8 @@
hitsound = 'sound/weapons/bladeslice.ogg'
block_flags = BLOCKING_ACTIVE | BLOCKING_PROJECTILE //if it some how gets block level, katanas block projectiles for the meme
item_flags = ISWEAPON
+ sharpness = IS_SHARP
+ bleed_force = BLEED_SURFACE
/*
* Snap pops
@@ -1060,6 +1067,7 @@
card_throw_speed = 6
embedding = list("pain_mult" = 1, "embed_chance" = 80, "max_damage_mult" = 8, "fall_chance" = 0, "embed_chance_turf_mod" = 15, "armour_block" = 60) //less painful than throwing stars
card_sharpness = IS_SHARP
+ bleed_force = BLEED_SURFACE
card_throw_range = 7
card_attack_verb = list("attacked", "sliced", "diced", "slashed", "cut")
resistance_flags = NONE
diff --git a/code/game/objects/items/vending_items.dm b/code/game/objects/items/vending_items.dm
index 28e2eef2001fd..a740e0baad725 100644
--- a/code/game/objects/items/vending_items.dm
+++ b/code/game/objects/items/vending_items.dm
@@ -17,7 +17,7 @@
throw_speed = 1
throw_range = 7
w_class = WEIGHT_CLASS_BULKY
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 70, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 70, ACID = 30, STAMINA = 0, BLEED = 0)
// Built automatically from the corresponding vending machine.
// If null, considered to be full. Otherwise, is list(/typepath = amount).
diff --git a/code/game/objects/items/wall_mounted.dm b/code/game/objects/items/wall_mounted.dm
new file mode 100644
index 0000000000000..8b36921e0e949
--- /dev/null
+++ b/code/game/objects/items/wall_mounted.dm
@@ -0,0 +1,92 @@
+/obj/item/wallframe
+ icon = 'icons/obj/wallframe.dmi'
+ custom_materials = list(/datum/material/iron=MINERAL_MATERIAL_AMOUNT*2)
+ flags_1 = CONDUCT_1
+ item_state = "syringe_kit"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ w_class = WEIGHT_CLASS_SMALL
+ var/result_path
+ var/wall_external = FALSE // For frames that are external to the wall they are placed on, like light fixtures and cameras.
+ var/pixel_shift //The amount of pixels
+
+/obj/item/wallframe/proc/try_build(turf/on_wall, mob/user)
+ if(get_dist(on_wall,user)>1)
+ return
+ var/floor_to_wall = get_dir(user, on_wall)
+ if(!(floor_to_wall in GLOB.cardinals))
+ return
+ var/turf/T = get_turf(user)
+ var/area/A = get_area(T)
+ if(!isfloorturf(T))
+ to_chat(user, "You cannot place [src] on this spot! ")
+ return
+ if(A.always_unpowered)
+ to_chat(user, "You cannot place [src] in this area! ")
+ return
+ if(check_wall_item(T, floor_to_wall, wall_external))
+ to_chat(user, "There's already an item on this wall! ")
+ return
+
+ return TRUE
+
+/obj/item/wallframe/proc/attach(turf/on_wall, mob/user)
+ if(result_path)
+ playsound(src.loc, 'sound/machines/click.ogg', 75, TRUE)
+ user.visible_message("[user.name] attaches [src] to the wall.",
+ "You attach [src] to the wall. ",
+ "You hear clicking. ")
+ var/floor_to_wall = get_dir(user, on_wall)
+
+ var/obj/O = new result_path(get_turf(user), floor_to_wall, TRUE)
+ O.setDir(floor_to_wall)
+
+ if(pixel_shift)
+ switch(floor_to_wall)
+ if(NORTH)
+ O.pixel_y = pixel_shift
+ if(SOUTH)
+ O.pixel_y = -pixel_shift
+ if(EAST)
+ O.pixel_x = pixel_shift
+ if(WEST)
+ O.pixel_x = -pixel_shift
+ after_attach(O)
+
+ qdel(src)
+
+/obj/item/wallframe/proc/after_attach(var/obj/O)
+ transfer_fingerprints_to(O)
+
+/obj/item/wallframe/screwdriver_act(mob/living/user, obj/item/tool)
+ // For camera-building borgs
+ var/turf/T = get_step(get_turf(user), user.dir)
+ if(iswallturf(T))
+ T.attackby(src, user)
+ return TOOL_ACT_TOOLTYPE_SUCCESS
+
+/obj/item/wallframe/wrench_act(mob/living/user, obj/item/tool)
+ var/iron_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]/MINERAL_MATERIAL_AMOUNT) //Replace this shit later
+ var/glass_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)]/MINERAL_MATERIAL_AMOUNT) //Replace this shit later
+
+ if(!iron_amt && !glass_amt)
+ return FALSE
+ to_chat(user, "You dismantle [src]. ")
+ if(iron_amt)
+ new /obj/item/stack/sheet/iron(get_turf(src), iron_amt)
+ if(glass_amt)
+ new /obj/item/stack/sheet/glass(get_turf(src), glass_amt)
+ qdel(src)
+ return TOOL_ACT_TOOLTYPE_SUCCESS
+
+/obj/item/electronics
+ desc = "Looks like a circuit. Probably is."
+ icon = 'icons/obj/module.dmi'
+ icon_state = "door_electronics"
+ item_state = "electronic"
+ lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
+ flags_1 = CONDUCT_1
+ w_class = WEIGHT_CLASS_SMALL
+ custom_materials = list(/datum/material/iron=50, /datum/material/glass=50)
+ grind_results = list(/datum/reagent/iron = 10, /datum/reagent/silicon = 10)
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index 0fdc07a4bc782..195c3adacb1c4 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -12,7 +12,7 @@
throw_range = 7
attack_verb = list("banned")
max_integrity = 200
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 70, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 70, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
/obj/item/banhammer/suicide_act(mob/living/user)
@@ -82,8 +82,9 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
block_level = 1
block_flags = BLOCKING_ACTIVE | BLOCKING_NASTY
sharpness = IS_SHARP
+ bleed_force = BLEED_DEEP_WOUND
max_integrity = 200
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
/obj/item/claymore/Initialize(mapload)
@@ -121,7 +122,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
loc.layer = LARGE_MOB_LAYER //NO HIDING BEHIND PLANTS FOR YOU, DICKWEED (HA GET IT, BECAUSE WEEDS ARE PLANTS)
- H.bleedsuppress = TRUE //AND WE WON'T BLEED OUT LIKE COWARDS
+ H.cauterise_wounds(0.1)
else
if(!(flags_1 & ADMIN_SPAWNED_1))
qdel(src)
@@ -236,7 +237,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "tore", "ripped", "diced", "cut")
block_level = 0
block_power = 30
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0, BLEED = 0)
/obj/item/katana
name = "katana"
@@ -259,8 +260,9 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
block_upgrade_walk = 1
block_flags = BLOCKING_ACTIVE | BLOCKING_NASTY | BLOCKING_PROJECTILE
sharpness = IS_SHARP
+ bleed_force = BLEED_DEEP_WOUND
max_integrity = 200
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
/obj/item/katana/cursed
@@ -329,6 +331,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
item_flags = ISWEAPON
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
custom_materials = list(/datum/material/iron=500, /datum/material/glass=500)
resistance_flags = FIRE_PROOF
@@ -392,6 +395,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
attack_verb = list("slashed", "stabbed", "sliced", "tore", "ripped", "diced", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
else
force = initial(force)
w_class = WEIGHT_CLASS_SMALL
@@ -400,6 +404,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
attack_verb = list("stubbed", "poked")
hitsound = 'sound/weapons/genhit.ogg'
sharpness = IS_BLUNT
+ bleed_force = 0
/obj/item/switchblade/suicide_act(mob/living/user)
user.visible_message("[user] is slitting [user.p_their()] own throat with [src]! It looks like [user.p_theyre()] trying to commit suicide! ")
@@ -536,6 +541,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
throw_range = 0
throw_speed = 0
sharpness = IS_SHARP
+ bleed_force = BLEED_DEEP_WOUND
attack_verb = list("sawed", "tore", "cut", "chopped", "diced")
hitsound = 'sound/weapons/chainsawhit.ogg'
tool_behaviour = TOOL_SAW
@@ -980,6 +986,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
block_upgrade_walk = 1
block_flags = BLOCKING_ACTIVE | BLOCKING_NASTY
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
@@ -999,6 +1006,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
throwforce = 20
throw_speed = 4
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
attack_verb = list("cut", "sliced", "diced")
w_class = WEIGHT_CLASS_BULKY
item_flags = ISWEAPON
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index d459bcdda393b..0a4d9d7d8f926 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -14,9 +14,13 @@
damage_amount = run_obj_armor(damage_amount, damage_type, damage_flag, attack_dir, armour_penetration)
if(damage_amount < DAMAGE_PRECISION)
return
+ //Object is basssiiiiccaalllyyy guaranteed to take damage by this point, lets run our signal
+ if(SEND_SIGNAL(src, COMSIG_OBJ_TAKE_DAMAGE, damage_amount, damage_type, damage_flag, sound_effect, attack_dir, armour_penetration) & COMPONENT_NO_TAKE_DAMAGE)
+ return
. = damage_amount
- var/old_integ = obj_integrity
- obj_integrity = max(old_integ - damage_amount, 0)
+
+ update_integrity(obj_integrity - damage_amount)
+
//BREAKING FIRST
if(integrity_failure && obj_integrity <= integrity_failure * max_integrity)
obj_break(damage_flag)
@@ -25,6 +29,32 @@
if(obj_integrity <= 0)
obj_destruction(damage_flag)
+/// Proc for recovering obj_integrity. Returns the amount repaired by
+/obj/proc/repair_damage(amount)
+ if(amount <= 0) // We only recover here
+ return
+ var/new_integrity = min(max_integrity, obj_integrity + amount)
+ . = new_integrity - obj_integrity
+
+ update_integrity(new_integrity)
+
+ if(integrity_failure && obj_integrity > integrity_failure * max_integrity)
+ obj_fix()
+
+/// Handles the integrity of an object changing. This must be called instead of changing integrity directly.
+/obj/proc/update_integrity(new_value)
+ SHOULD_NOT_OVERRIDE(TRUE)
+ new_value = max(0, new_value)
+ if(obj_integrity == new_value)
+ return
+ obj_integrity = new_value
+ SEND_SIGNAL(src, COMSIG_OBJ_INTEGRITY_CHANGED)
+
+/// This mostly exists to keep obj_integrity private. Might be useful in the future.
+/obj/proc/get_integrity()
+ SHOULD_BE_PURE(TRUE)
+ return obj_integrity
+
//returns the damage value of the attack after processing the obj's various armor protections
/obj/proc/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir, armour_penetration = 0)
switch(damage_type)
@@ -254,9 +284,15 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
SEND_SIGNAL(src, COMSIG_OBJ_DECONSTRUCT, disassembled)
qdel(src)
-//what happens when the obj's health is below integrity_failure level.
+/// Called after the obj takes damage and integrity is below integrity_failure level
/obj/proc/obj_break(damage_flag)
- return
+ SHOULD_CALL_PARENT(TRUE)
+ SEND_SIGNAL(src, COMSIG_OBJ_BREAK)
+
+/// Called when integrity is repaired above the breaking point having been broken before
+/obj/proc/obj_fix()
+ SHOULD_CALL_PARENT(TRUE)
+ SEND_SIGNAL(src, COMSIG_OBJ_FIX)
//what happens when the obj's integrity reaches zero.
/obj/proc/obj_destruction(damage_flag)
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 0aad652574df6..b9dcdeb11204b 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -8,10 +8,12 @@
var/damtype = BRUTE
var/force = 0
+ /// How much bleeding damage do we cause, see __DEFINES/mobs.dm
+ var/bleed_force = 0
var/datum/armor/armor
/// The integrity the object starts at. Defaults to max_integrity.
- var/obj_integrity
+ VAR_PRIVATE/obj_integrity //defaults to max_integrity
/// The maximum integrity the object can have.
var/max_integrity = 500
/// The object will break once obj_integrity reaches this amount in take_damage(). 0 if we have no special broken behavior, otherwise is a percentage of at what point the obj breaks. 0.5 being 50%
@@ -70,8 +72,7 @@
armor = getArmor()
else if (!istype(armor, /datum/armor))
stack_trace("Invalid type [armor.type] found in .armor during /obj Initialize()")
- if(obj_integrity == null)
- obj_integrity = max_integrity
+ obj_integrity = max_integrity
. = ..() //Do this after, else mat datums is mad.
diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm
index 529696e591274..3f97e790cae44 100644
--- a/code/game/objects/structures.dm
+++ b/code/game/objects/structures.dm
@@ -11,7 +11,7 @@
/obj/structure/Initialize(mapload)
if (!armor)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0, BLEED = 0)
. = ..()
if(smoothing_flags & (SMOOTH_CORNERS|SMOOTH_BITMASK))
QUEUE_SMOOTH(src)
diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm
index 5b45e8b8ef67a..8517bb98133d6 100644
--- a/code/game/objects/structures/aliens.dm
+++ b/code/game/objects/structures/aliens.dm
@@ -332,6 +332,7 @@
break
/obj/structure/alien/egg/obj_break(damage_flag)
+ . = ..()
if(!(flags_1 & NODECONSTRUCT_1))
if(status != BURST)
Burst(kill=TRUE)
diff --git a/code/game/objects/structures/artstuff.dm b/code/game/objects/structures/artstuff.dm
index 026b9dc5561a1..87c427363bd59 100644
--- a/code/game/objects/structures/artstuff.dm
+++ b/code/game/objects/structures/artstuff.dm
@@ -242,7 +242,7 @@
flags_1 = NONE
icon_state = "frame-empty"
result_path = /obj/structure/sign/painting
- pixel_shift = -32
+ pixel_shift = 30
/obj/structure/sign/painting
name = "Painting"
diff --git a/code/game/objects/structures/barsigns.dm b/code/game/objects/structures/barsigns.dm
index 84842d31570c8..d47d71b3fa1d0 100644
--- a/code/game/objects/structures/barsigns.dm
+++ b/code/game/objects/structures/barsigns.dm
@@ -6,7 +6,7 @@
req_access = list(ACCESS_BAR)
max_integrity = 500
integrity_failure = 0.5
- armor = list(MELEE = 20, BULLET = 20, LASER = 20, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 20, BULLET = 20, LASER = 20, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0, BLEED = 0)
buildable_sign = 0
var/panel_open = FALSE
@@ -43,6 +43,7 @@
return set_sign(new_sign)
/obj/structure/sign/barsign/obj_break(damage_flag)
+ . = ..()
if(!broken && !(flags_1 & NODECONSTRUCT_1))
broken = TRUE
diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm
index 4c93ddb74d010..fd0877d97107d 100644
--- a/code/game/objects/structures/beds_chairs/chair.dm
+++ b/code/game/objects/structures/beds_chairs/chair.dm
@@ -387,6 +387,8 @@
buildstackamount = 1
item_chair = /obj/item/chair/stool
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool, 0)
+
/obj/structure/chair/stool/narsie_act()
return
@@ -410,6 +412,8 @@
icon_state = "bar"
item_chair = /obj/item/chair/stool/bar
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0)
+
/obj/structure/chair/stool/bamboo
name = "bamboo stool"
desc = "A makeshift bamboo stool with a rustic look."
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 55fb4fdb4881d..f6d0983296766 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -7,10 +7,9 @@
drag_slowdown = 1.5 // Same as a prone mob
max_integrity = 200
integrity_failure = 0.25
- armor = list(MELEE = 20, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 70, ACID = 60, STAMINA = 0)
+ armor = list(MELEE = 20, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 70, ACID = 60, STAMINA = 0, BLEED = 0)
blocks_emissive = EMISSIVE_BLOCK_GENERIC
pass_flags_self = LETPASSCLICKS | PASSSTRUCTURE
-
var/contents_initialised = FALSE
var/enable_door_overlay = TRUE
var/has_opened_overlay = TRUE
@@ -20,6 +19,7 @@
var/opened = FALSE
var/welded = FALSE
var/locked = FALSE
+ var/divable = TRUE //controls whether someone with skittish trait can enter the closet with CtrlShiftClick
var/large = TRUE
var/wall_mounted = 0 //never solid (You can always pass over it)
var/breakout_time = 1200
@@ -174,7 +174,7 @@
. += "Alt-click to [locked ? "unlock" : "lock"]. "
if(isliving(user))
var/mob/living/L = user
- if(HAS_TRAIT(L, TRAIT_SKITTISH))
+ if(divable && HAS_TRAIT(L, TRAIT_SKITTISH))
. += "Ctrl-Shift-click [src] to jump inside. "
/obj/structure/closet/CanAllowThrough(atom/movable/mover, border_dir)
@@ -315,6 +315,7 @@
qdel(src)
/obj/structure/closet/obj_break(damage_flag)
+ . = ..()
if(!broken && !(flags_1 & NODECONSTRUCT_1))
bust_open()
@@ -387,7 +388,7 @@
/obj/structure/closet/MouseDrop_T(atom/movable/O, mob/living/user)
if(!istype(O) || O.anchored || istype(O, /atom/movable/screen))
return
- if(!istype(user) || user.incapacitated() || !(user.mobility_flags & MOBILITY_STAND))
+ if(!istype(user) || user.incapacitated() || user.body_position == LYING_DOWN)
return
if(!Adjacent(user) || !user.Adjacent(O))
return
@@ -425,8 +426,8 @@
O.forceMove(T)
return TRUE
-/obj/structure/closet/relaymove(mob/user)
- if(user.stat || !isturf(loc) || !isliving(user))
+/obj/structure/closet/relaymove(mob/living/user, direction)
+ if(user.stat || !isturf(loc))
return
if(locked)
if(message_cooldown <= world.time)
@@ -439,12 +440,13 @@
. = ..()
if(.)
return
- if(!(user.mobility_flags & MOBILITY_STAND) && get_dist(src, user) > 0)
+ if(user.body_position == LYING_DOWN && get_dist(src, user) > 0)
return
if(!toggle(user))
togglelock(user)
+
/obj/structure/closet/attack_paw(mob/user)
return attack_hand(user)
@@ -524,7 +526,7 @@
togglelock(user)
/obj/structure/closet/CtrlShiftClick(mob/living/user)
- if(!HAS_TRAIT(user, TRAIT_SKITTISH))
+ if(!(divable && HAS_TRAIT(user, TRAIT_SKITTISH)))
return ..()
if(!user.canUseTopic(src, BE_CLOSE) || !isturf(user.loc))
return
diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm
index 41a835ef7681a..edb692aa3e896 100644
--- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm
+++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm
@@ -23,13 +23,14 @@
var/egged = 0
/obj/structure/closet/cardboard/relaymove(mob/living/user, direction)
- if(!istype(user) || opened || move_delay || user.incapacitated() || !isturf(loc) || !has_gravity(loc))
+ if(opened || move_delay || user.incapacitated() || !isturf(loc) || !has_gravity(loc))
return
move_delay = TRUE
- if(step(src, direction))
+ var/oldloc = loc
+ if(oldloc != loc)
addtimer(CALLBACK(src, PROC_REF(ResetMoveDelay)), CONFIG_GET(number/movedelay/walk_delay) * move_speed_multiplier)
else
- ResetMoveDelay()
+ move_delay = FALSE
/obj/structure/closet/cardboard/proc/ResetMoveDelay()
move_delay = FALSE
@@ -77,14 +78,3 @@
close_sound_volume = 50
material_drop = /obj/item/stack/sheet/plasteel
#undef SNAKE_SPAM_TICKS
-
-/obj/structure/closet/cardboard/relaymove(mob/living/user, direction)
- if(!istype(user) || opened || move_delay || user.incapacitated() || !isturf(loc) || !has_gravity(loc))
- return
- move_delay = TRUE
- var/oldloc = loc
- step(src, direction)
- if(oldloc != loc)
- addtimer(CALLBACK(src, PROC_REF(ResetMoveDelay)), CONFIG_GET(number/movedelay/walk_delay) * move_speed_multiplier)
- else
- move_delay = FALSE
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
index 1f5756a5449f9..c7e8806fa2614 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
@@ -110,6 +110,7 @@
new /obj/item/clothing/mask/gas(src)
new /obj/item/clothing/glasses/meson/engine(src)
new /obj/item/storage/box/emptysandbags(src)
+ new /obj/item/clothing/gloves/color/yellow(src)
/obj/structure/closet/secure_closet/atmospherics
name = "\proper atmospheric technician's locker"
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
index d9bec0c8ba199..8399b04611cf1 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
@@ -4,6 +4,14 @@
req_access = list(ACCESS_ALL_PERSONAL_LOCKERS)
var/registered_name = null
+/obj/structure/closet/secure_closet/personal/empty
+ desc = "It's a secure locker for personnel. The first card swiped gains control."
+ name = "personal closet"
+ req_access = list(ACCESS_ALL_PERSONAL_LOCKERS)
+
+/obj/structure/closet/secure_closet/personal/empty/PopulateContents()
+ return
+
/obj/structure/closet/secure_closet/personal/PopulateContents()
..()
if(prob(50))
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
index 93e5011c30fe5..f459dda04fb4a 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
@@ -4,7 +4,7 @@
locked = TRUE
icon_state = "secure"
max_integrity = 250
- armor = list(MELEE = 30, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 0)
+ armor = list(MELEE = 30, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 0, BLEED = 0)
secure = TRUE
/obj/structure/closet/secure_closet/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
diff --git a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
index 4af5206aba6e7..28be2cd91d92e 100644
--- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
@@ -17,6 +17,14 @@
desc = "It's a storage unit for emergency breath masks and O2 tanks."
icon_state = "emergency"
+/obj/structure/closet/emcloset/empty
+ name = "emergency closet"
+ desc = "It's a storage unit for emergency breath masks and O2 tanks."
+ icon_state = "emergency"
+
+/obj/structure/closet/emcloset/empty/PopulateContents()
+ return
+
/obj/structure/closet/emcloset/anchored
anchored = TRUE
@@ -66,6 +74,14 @@
desc = "It's a storage unit for fire-fighting supplies."
icon_state = "fire"
+/obj/structure/closet/firecloset/empty
+ name = "fire-safety closet"
+ desc = "It's a storage unit for fire-fighting supplies."
+ icon_state = "fire"
+
+/obj/structure/closet/firecloset/empty/PopulateContents()
+ return
+
/obj/structure/closet/firecloset/PopulateContents()
..()
@@ -92,6 +108,15 @@
icon_state = "eng"
icon_door = "eng_tool"
+/obj/structure/closet/toolcloset/empty
+ name = "tool closet"
+ desc = "It's a storage unit for tools."
+ icon_state = "eng"
+ icon_door = "eng_tool"
+
+/obj/structure/closet/toolcloset/empty/PopulateContents()
+ return
+
/obj/structure/closet/toolcloset/PopulateContents()
..()
if(prob(40))
@@ -135,6 +160,15 @@
icon_state = "eng"
icon_door = "eng_rad"
+/obj/structure/closet/radiation/empty
+ name = "radiation suit closet"
+ desc = "It's a storage unit for rad-protective suits."
+ icon_state = "eng"
+ icon_door = "eng_rad"
+
+/obj/structure/closet/radiation/empty/PopulateContents()
+ return
+
/obj/structure/closet/radiation/PopulateContents()
..()
new /obj/item/geiger_counter(src)
@@ -153,6 +187,14 @@
desc = "It's a storage unit for explosion-protective suits."
icon_state = "bomb"
+/obj/structure/closet/bombcloset/empty
+ name = "\improper EOD closet"
+ desc = "It's a storage unit for explosion-protective suits."
+ icon_state = "bomb"
+
+/obj/structure/closet/bombcloset/empty/PopulateContents()
+ return
+
/obj/structure/closet/bombcloset/PopulateContents()
..()
new /obj/item/clothing/suit/utility/bomb_suit(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
index f83db4c4aabd9..824c549fbe094 100644
--- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
+++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
@@ -3,6 +3,14 @@
desc = "It's a storage unit for standard-issue Nanotrasen attire."
icon_door = "blue"
+/obj/structure/closet/wardrobe/empty
+ name = "wardrobe"
+ desc = "It's a storage unit for standard-issue Nanotrasen attire."
+ icon_door = "blue"
+
+/obj/structure/closet/wardrobe/empty/PopulateContents()
+ return
+
/obj/structure/closet/wardrobe/PopulateContents()
..()
for(var/i in 1 to 3)
diff --git a/code/game/objects/structures/crates_lockers/crates/secure.dm b/code/game/objects/structures/crates_lockers/crates/secure.dm
index 0d173dcd57002..a3b28f10edaf0 100644
--- a/code/game/objects/structures/crates_lockers/crates/secure.dm
+++ b/code/game/objects/structures/crates_lockers/crates/secure.dm
@@ -5,7 +5,7 @@
secure = TRUE
locked = TRUE
max_integrity = 500
- armor = list(MELEE = 30, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 0)
+ armor = list(MELEE = 30, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 0, BLEED = 0)
var/tamperproof = 0
icon_door = "crate"
diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm
index 7c39e33e92dce..a2d071256fd45 100644
--- a/code/game/objects/structures/displaycase.dm
+++ b/code/game/objects/structures/displaycase.dm
@@ -6,7 +6,7 @@
density = TRUE
anchored = TRUE
resistance_flags = ACID_PROOF
- armor = list(MELEE = 30, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 70, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 30, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 70, ACID = 100, STAMINA = 0, BLEED = 0)
max_integrity = 200
integrity_failure = 0.25
var/obj/item/showpiece = null
@@ -100,6 +100,7 @@
qdel(src)
/obj/structure/displaycase/obj_break(damage_flag)
+ . = ..()
if(!broken && !(flags_1 & NODECONSTRUCT_1))
set_density(FALSE)
broken = TRUE
@@ -142,7 +143,7 @@
if(open) //You do not require access to close a case, only to open it.
to_chat(user, "You close [src]. ")
toggle_lock(user)
- else if(security_level_locked > GLOB.security_level || !allowed(user))
+ else if(security_level_locked > SSsecurity_level.get_current_level_as_number() || !allowed(user))
to_chat(user, "Access denied. ")
else
to_chat(user, "You open [src]. ")
diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm
index c8aa218581b37..ece0c709fbcad 100644
--- a/code/game/objects/structures/extinguisher.dm
+++ b/code/game/objects/structures/extinguisher.dm
@@ -11,6 +11,8 @@
var/obj/item/extinguisher/stored_extinguisher
var/opened = FALSE
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/extinguisher_cabinet, 29)
+
/obj/structure/extinguisher_cabinet/Initialize(mapload, ndir, building)
. = ..()
if(building)
@@ -134,6 +136,7 @@
icon_state = "extinguisher_empty"
/obj/structure/extinguisher_cabinet/obj_break(damage_flag)
+ . = ..()
if(!broken && !(flags_1 & NODECONSTRUCT_1))
broken = 1
opened = 1
@@ -159,4 +162,4 @@
desc = "Used for building wall-mounted extinguisher cabinets."
icon_state = "extinguisher"
result_path = /obj/structure/extinguisher_cabinet
- pixel_shift = -30
+ pixel_shift = 29
diff --git a/code/game/objects/structures/fireaxe.dm b/code/game/objects/structures/fireaxe.dm
index a70c4e34d14ba..b417c19d64091 100644
--- a/code/game/objects/structures/fireaxe.dm
+++ b/code/game/objects/structures/fireaxe.dm
@@ -5,7 +5,7 @@
icon_state = "fireaxe"
anchored = TRUE
density = FALSE
- armor = list(MELEE = 50, BULLET = 20, LASER = 0, ENERGY = 100, BOMB = 10, BIO = 100, RAD = 100, FIRE = 90, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 20, LASER = 0, ENERGY = 100, BOMB = 10, BIO = 100, RAD = 100, FIRE = 90, ACID = 50, STAMINA = 0, BLEED = 0)
max_integrity = 150
integrity_failure = 0.33
layer = ABOVE_WINDOW_LAYER
@@ -13,6 +13,8 @@
var/open = FALSE
var/obj/item/fireaxe/fireaxe
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/fireaxecabinet, 32)
+
/obj/structure/fireaxecabinet/Initialize(mapload)
. = ..()
fireaxe = new
@@ -84,10 +86,11 @@
update_appearance()
/obj/structure/fireaxecabinet/obj_break(damage_flag)
+ . = ..()
if(!broken && !(flags_1 & NODECONSTRUCT_1))
update_appearance()
broken = TRUE
- playsound(src, 'sound/effects/glassbr3.ogg', 100, 1)
+ playsound(src, 'sound/effects/glassbr3.ogg', 100, TRUE)
new /obj/item/shard(loc)
new /obj/item/shard(loc)
diff --git a/code/game/objects/structures/fluff.dm b/code/game/objects/structures/fluff.dm
index ffcdaaca5fc65..41a99e82c0cdb 100644
--- a/code/game/objects/structures/fluff.dm
+++ b/code/game/objects/structures/fluff.dm
@@ -185,3 +185,10 @@
/obj/structure/fluff/hedge/opaque //useful for mazes and such
opacity = TRUE
+
+/obj/structure/fluff/fans
+ icon = 'icons/obj/lavaland/survival_pod.dmi'
+ icon_state = "fan_tiny"
+ name = "environmental regulation system"
+ desc = "A vent nested into the wall, managing the airflow between the rooms"
+ anchored = TRUE
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index c0d495519e7f5..8d68cfdb57219 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -10,7 +10,7 @@
z_flags = Z_BLOCK_IN_DOWN | Z_BLOCK_IN_UP
pressure_resistance = 5*ONE_ATMOSPHERE
layer = BELOW_OBJ_LAYER
- armor = list(MELEE = 50, BULLET = 70, LASER = 70, ENERGY = 100, BOMB = 10, BIO = 100, RAD = 100, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 70, LASER = 70, ENERGY = 100, BOMB = 10, BIO = 100, RAD = 100, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
max_integrity = 50
integrity_failure = 0.4
var/rods_type = /obj/item/stack/rods
@@ -238,6 +238,7 @@
..()
/obj/structure/grille/obj_break()
+ . = ..()
if(!broken && !(flags_1 & NODECONSTRUCT_1))
new broken_type(src.loc)
var/drop_loc = drop_location()
@@ -296,13 +297,16 @@
/obj/structure/grille/broken // Pre-broken grilles for map placement
icon_state = "brokengrille"
density = FALSE
- obj_integrity = 20
broken = TRUE
rods_amount = 1
rods_broken = FALSE
grille_type = /obj/structure/grille
broken_type = null
+/obj/structure/grille/broken/Initialize(mapload)
+ . = ..()
+ take_damage(max_integrity * 0.6)
+
/obj/structure/grille/prison //grilles that trigger prison lockdown under some circumstances
name = "prison grille"
desc = "a set of rods under current used to protect the prison wing. An alarm will go off if they are breached."
diff --git a/code/game/objects/structures/gym/exercise_status.dm b/code/game/objects/structures/gym/exercise_status.dm
new file mode 100644
index 0000000000000..4f3bb5913fdf2
--- /dev/null
+++ b/code/game/objects/structures/gym/exercise_status.dm
@@ -0,0 +1,65 @@
+/// How much stun resistance you gain every time you exercise
+#define EXERCISE_INCREMENT 0.001
+/// The max amount that you can be improved by exercise
+#define EXERCISE_LIMIT 0.5
+/// How much exercise effect you lose every second.
+/// Each exercise will last 10 seconds.
+/// Maximum exercise lasts 1000 seconds, or about 16 minutes.
+#define EXERCISE_STEP 0.0005
+/// The minimum that exercise needs to change before we step (Rounded to percentages so 1%)
+#define EXERCISE_VISUAL_DELTA 0.005
+
+/datum/status_effect/exercised
+ id = "exericsed"
+ status_type = STATUS_EFFECT_MERGE
+ tick_interval = ((1 SECONDS) * EXERCISE_VISUAL_DELTA) / EXERCISE_STEP
+ alert_type = /atom/movable/screen/alert/status_effect/exercised
+ var/applied_amount = 0
+ var/exercise_amount = 0
+
+/datum/status_effect/exercised/on_creation(mob/living/new_owner, exercise_amount)
+ src.exercise_amount = exercise_amount * EXERCISE_INCREMENT
+ . = ..()
+ update_exercise()
+
+/datum/status_effect/exercised/merge(exercise_amount)
+ src.exercise_amount = min(src.exercise_amount + exercise_amount * EXERCISE_INCREMENT, EXERCISE_LIMIT)
+ update_exercise()
+
+/datum/status_effect/exercised/on_apply()
+ update_exercise()
+ return TRUE
+
+/datum/status_effect/exercised/on_remove()
+ if (ishuman(owner))
+ var/mob/living/carbon/human/human_owner = owner
+ human_owner.physiology.stun_add += applied_amount
+ applied_amount = 0
+
+/datum/status_effect/exercised/tick()
+ exercise_amount -= EXERCISE_VISUAL_DELTA
+ update_exercise()
+ return ..()
+
+/datum/status_effect/exercised/proc/update_exercise()
+ if (exercise_amount <= 0)
+ qdel(src)
+ return
+ if (ishuman(owner))
+ var/delta = exercise_amount - applied_amount
+ var/mob/living/carbon/human/human_owner = owner
+ human_owner.physiology.stun_add -= delta
+ applied_amount = exercise_amount
+ linked_alert?.maptext = MAPTEXT("[round(100 * exercise_amount / EXERCISE_LIMIT, 1)]%")
+ switch (exercise_amount)
+ if (0.3 to 0.5)
+ examine_text = "[owner.p_they(TRUE)] seem exceptionally strong! "
+ if (0.1 to 0.3)
+ examine_text = "[owner.p_they(TRUE)] seem very strong! "
+ else
+ examine_text = "[owner.p_they(TRUE)] seem strong! "
+
+/atom/movable/screen/alert/status_effect/exercised
+ name = "Exercised"
+ desc = "You have worked out recently, making you stronger and more resistant to being brought down by stunning weapons."
+ icon_state = "weights"
diff --git a/code/game/objects/structures/gym/punching_bag.dm b/code/game/objects/structures/gym/punching_bag.dm
index e5ec5dc64e805..49792013754e9 100644
--- a/code/game/objects/structures/gym/punching_bag.dm
+++ b/code/game/objects/structures/gym/punching_bag.dm
@@ -22,5 +22,5 @@
flick("[icon_state]-punch", src)
playsound(loc, pick(hit_sounds), 25, TRUE, -1)
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "exercise", /datum/mood_event/exercise)
- user.apply_status_effect(STATUS_EFFECT_EXERCISED)
+ user.apply_status_effect(STATUS_EFFECT_EXERCISED, 1)
diff --git a/code/game/objects/structures/gym/weight_machine.dm b/code/game/objects/structures/gym/weight_machine.dm
index 7d4aa22fbeb3e..b8e000a215779 100644
--- a/code/game/objects/structures/gym/weight_machine.dm
+++ b/code/game/objects/structures/gym/weight_machine.dm
@@ -76,7 +76,7 @@
if (user.client)
user.client.give_award(/datum/award/achievement/misc/weights, user)
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "exercise", /datum/mood_event/exercise)
- user.apply_status_effect(STATUS_EFFECT_EXERCISED)
+ user.apply_status_effect(STATUS_EFFECT_EXERCISED, 10)
end_workout()
/obj/structure/weightmachine/proc/end_workout()
diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm
index d5639986f9dd6..e4704b0e9e266 100644
--- a/code/game/objects/structures/holosign.dm
+++ b/code/game/objects/structures/holosign.dm
@@ -6,7 +6,7 @@
icon = 'icons/effects/effects.dmi'
anchored = TRUE
max_integrity = 1
- armor = list(MELEE = 0, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 0, BIO = 0, RAD = 0, FIRE = 20, ACID = 20, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 0, BIO = 0, RAD = 0, FIRE = 20, ACID = 20, STAMINA = 0, BLEED = 0)
layer = BELOW_OBJ_LAYER
var/obj/item/holosign_creator/projector
diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm
index 4f2ece534f413..8efc68e382e4f 100644
--- a/code/game/objects/structures/lattice.dm
+++ b/code/game/objects/structures/lattice.dm
@@ -9,7 +9,7 @@
canSmoothWith = list(SMOOTH_GROUP_OPEN_FLOOR, SMOOTH_GROUP_WALLS, SMOOTH_GROUP_WINDOW_FULLTILE, SMOOTH_GROUP_LATTICE)
density = FALSE
anchored = TRUE
- armor = list(MELEE = 50, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 50, STAMINA = 0, BLEED = 0)
max_integrity = 50
layer = LATTICE_LAYER //under pipes
plane = FLOOR_PLANE
diff --git a/code/game/objects/structures/manned_turret.dm b/code/game/objects/structures/manned_turret.dm
index a9ad8a66a82a1..d46b64636271b 100644
--- a/code/game/objects/structures/manned_turret.dm
+++ b/code/game/objects/structures/manned_turret.dm
@@ -9,7 +9,7 @@
anchored = FALSE
density = TRUE
max_integrity = 100
- buckle_lying = FALSE
+ buckle_lying = 0
layer = ABOVE_MOB_LAYER
move_resist = MOVE_FORCE_STRONG
var/view_range = 2.5
diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm
index 4f07ad17c9067..4a9790843926e 100644
--- a/code/game/objects/structures/mineral_doors.dm
+++ b/code/game/objects/structures/mineral_doors.dm
@@ -11,7 +11,7 @@
icon = 'icons/obj/doors/mineral_doors.dmi'
icon_state = "metal"
max_integrity = 200
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 10, BIO = 100, RAD = 100, FIRE = 50, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 10, BIO = 100, RAD = 100, FIRE = 50, ACID = 50, STAMINA = 0, BLEED = 0)
CanAtmosPass = ATMOS_PASS_DENSITY
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
rad_insulation = RAD_MEDIUM_INSULATION
diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm
index 02f2d717e58be..a154713a4ddf6 100644
--- a/code/game/objects/structures/mirror.dm
+++ b/code/game/objects/structures/mirror.dm
@@ -12,6 +12,8 @@
layer = ABOVE_WINDOW_LAYER
var/magical = FALSE
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror, 28)
+
/obj/structure/mirror/Initialize(mapload, dir, building)
. = ..()
if(icon_state == "mirror_broke" && !broken)
@@ -54,13 +56,15 @@
return ..()
/obj/structure/mirror/obj_break(damage_flag, mapload)
- if(!broken && !(flags_1 & NODECONSTRUCT_1))
- icon_state = "mirror_broke"
- if(!mapload)
- playsound(src, "shatter", 70, 1)
- if(desc == initial(desc))
- desc = "Oh no, seven years of bad luck!"
- broken = TRUE
+ . = ..()
+ if(broken || (flags_1 & NODECONSTRUCT_1))
+ return
+ icon_state = "mirror_broke"
+ if(!mapload)
+ playsound(src, "shatter", 70, 1)
+ if(desc == initial(desc))
+ desc = "Oh no, seven years of bad luck!"
+ broken = TRUE
/obj/structure/mirror/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm
index 6251008eaebda..f24d4caef73ad 100644
--- a/code/game/objects/structures/morgue.dm
+++ b/code/game/objects/structures/morgue.dm
@@ -48,7 +48,7 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an
/obj/structure/bodycontainer/update_icon()
return
-/obj/structure/bodycontainer/relaymove(mob/user)
+/obj/structure/bodycontainer/relaymove(mob/living/user, direction)
if(user.stat || !isturf(loc))
return
if(locked)
@@ -375,7 +375,7 @@ GLOBAL_LIST_EMPTY(crematoriums)
return
if(isliving(user))
var/mob/living/L = user
- if(!(L.mobility_flags & MOBILITY_STAND))
+ if(L.body_position == LYING_DOWN)
return
O.forceMove(src.loc)
if (user != O)
diff --git a/code/game/objects/structures/noticeboard.dm b/code/game/objects/structures/noticeboard.dm
index 3b3b2f65a15a0..36e0e98ae573c 100644
--- a/code/game/objects/structures/noticeboard.dm
+++ b/code/game/objects/structures/noticeboard.dm
@@ -15,6 +15,8 @@
// Current number of a pinned notices
var/notices = 0
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/noticeboard, 32)
+
/obj/structure/noticeboard/Initialize(mapload)
. = ..()
diff --git a/code/game/objects/structures/petrified_statue.dm b/code/game/objects/structures/petrified_statue.dm
index a5fb5cdbed9c1..eaf280d9b4940 100644
--- a/code/game/objects/structures/petrified_statue.dm
+++ b/code/game/objects/structures/petrified_statue.dm
@@ -19,6 +19,7 @@
L.visible_message("[L]'s skin rapidly turns to marble! ", "Your body freezes up! Can't... move... can't... think... ")
L.forceMove(src)
ADD_TRAIT(L, TRAIT_MUTE, STATUE_MUTE)
+ ADD_TRAIT(L, TRAIT_NO_BLOOD, STATUE_MUTE)
L.faction += "mimic" //Stops mimics from instaqdeling people in statues
L.status_flags |= GODMODE
obj_integrity = L.health + 100 //stoning damaged mobs will result in easier to shatter statues
@@ -60,6 +61,7 @@
petrified_mob.status_flags &= ~GODMODE
petrified_mob.forceMove(loc)
REMOVE_TRAIT(petrified_mob, TRAIT_MUTE, STATUE_MUTE)
+ REMOVE_TRAIT(petrified_mob, TRAIT_NO_BLOOD, STATUE_MUTE)
petrified_mob.take_overall_damage((petrified_mob.health - obj_integrity + 100)) //any new damage the statue incurred is transfered to the mob
petrified_mob.faction -= "mimic"
petrified_mob = null
@@ -81,7 +83,6 @@
return 0
var/obj/structure/statue/petrified/S = new(loc, src, statue_timer)
S.name = "statue of [name]"
- bleedsuppress = 1
S.copy_overlays(src)
var/newcolor = list(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
S.add_atom_colour(newcolor, FIXED_COLOUR_PRIORITY)
diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm
index a0973998601c8..dd48ca7d09a3c 100644
--- a/code/game/objects/structures/plasticflaps.dm
+++ b/code/game/objects/structures/plasticflaps.dm
@@ -3,7 +3,7 @@
desc = "Heavy duty, airtight, plastic flaps. Definitely can't get past those. No way."
icon = 'icons/obj/stationobjs.dmi'
icon_state = "plasticflaps"
- armor = list(MELEE = 100, BULLET = 80, LASER = 80, ENERGY = 100, BOMB = 50, BIO = 100, RAD = 100, FIRE = 50, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 100, BULLET = 80, LASER = 80, ENERGY = 100, BOMB = 50, BIO = 100, RAD = 100, FIRE = 50, ACID = 50, STAMINA = 0, BLEED = 0)
density = FALSE
anchored = TRUE
layer = BELOW_OBJ_LAYER
@@ -97,7 +97,7 @@
return TRUE
var/ventcrawler = HAS_TRAIT(living_mover, TRAIT_VENTCRAWLER_ALWAYS) || HAS_TRAIT(living_mover, TRAIT_VENTCRAWLER_NUDE)
- if((living_mover.mobility_flags & MOBILITY_STAND)&& !ventcrawler && living_mover.mob_size != MOB_SIZE_TINY) //If your not laying down, or a ventcrawler or a small creature, no pass.
+ if(living_mover.body_position == STANDING_UP && !ventcrawler && living_mover.mob_size != MOB_SIZE_TINY) //If your not laying down, or a ventcrawler or a small creature, no pass.
return FALSE
/obj/structure/plasticflaps/deconstruct(disassembled = TRUE)
diff --git a/code/game/objects/structures/signs/_signs.dm b/code/game/objects/structures/signs/_signs.dm
index 5c126938a2691..64077859247e6 100644
--- a/code/game/objects/structures/signs/_signs.dm
+++ b/code/game/objects/structures/signs/_signs.dm
@@ -5,7 +5,7 @@
density = FALSE
layer = SIGN_LAYER
max_integrity = 100
- armor = list(MELEE = 50, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0, BLEED = 0)
var/buildable_sign = 1 //unwrenchable and modifiable
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index f743b53c4764e..78b339cf690b8 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -50,7 +50,7 @@
if(!istype(H))
return
var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET))
- if(!HAS_TRAIT(H, TRAIT_ALWAYS_STUBS) && (H.shoes || feetCover || !(H.mobility_flags & MOBILITY_STAND) || HAS_TRAIT(H, TRAIT_PIERCEIMMUNE) || H.m_intent == MOVE_INTENT_WALK))
+ if(!HAS_TRAIT(H, TRAIT_ALWAYS_STUBS) && (H.shoes || feetCover || H.body_position == LYING_DOWN || HAS_TRAIT(H, TRAIT_PIERCEIMMUNE) || H.m_intent == MOVE_INTENT_WALK || H.dna?.species.bodytype & BODYTYPE_DIGITIGRADE))
return
if(HAS_TRAIT(H, TRAIT_ALWAYS_STUBS) || ((world.time >= last_bump + 100) && prob(5)))
to_chat(H, "You stub your toe on the [name]! ")
@@ -287,7 +287,7 @@
canSmoothWith = null
max_integrity = 70
resistance_flags = ACID_PROOF
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 100, STAMINA = 0, BLEED = 0)
var/list/debris = list()
/obj/structure/table/glass/Initialize(mapload)
@@ -476,7 +476,7 @@
buildstack = /obj/item/stack/sheet/plasteel
max_integrity = 200
integrity_failure = 0.25
- armor = list(MELEE = 10, BULLET = 30, LASER = 30, ENERGY = 100, BOMB = 20, BIO = 0, RAD = 0, FIRE = 80, ACID = 70, STAMINA = 0)
+ armor = list(MELEE = 10, BULLET = 30, LASER = 30, ENERGY = 100, BOMB = 20, BIO = 0, RAD = 0, FIRE = 80, ACID = 70, STAMINA = 0, BLEED = 0)
/obj/structure/table/reinforced/deconstruction_hints(mob/user)
if(deconstruction_ready)
@@ -561,7 +561,7 @@
smoothing_groups = null
canSmoothWith = null
can_buckle = 1
- buckle_lying = -1
+ buckle_lying = NO_BUCKLE_LYING
buckle_requires_restraints = 1
var/mob/living/carbon/human/patient = null
var/obj/machinery/computer/operating/computer = null
@@ -570,6 +570,18 @@
. = ..()
initial_link()
+/obj/structure/table/optable/ComponentInitialize()
+ . = ..()
+ var/static/list/loc_connections = list(
+ COMSIG_ATOM_ENTERED = PROC_REF(table_entered),
+ )
+ AddElement(/datum/element/connect_loc, loc_connections)
+
+/obj/structure/table/optable/Destroy()
+ . = ..()
+ if(computer?.table == src)
+ computer.table = null
+
/obj/structure/table/optable/examine(mob/user)
. = ..()
if(computer)
@@ -591,12 +603,6 @@
computer = found_computer
break
-
-/obj/structure/table/optable/Destroy()
- . = ..()
- if(computer?.table == src)
- computer.table = null
-
/obj/structure/table/optable/tablepush(mob/living/user, mob/living/pushed_mob)
pushed_mob.forceMove(loc)
if(!isanimal(pushed_mob) || iscat(pushed_mob))
@@ -604,20 +610,36 @@
visible_message("[user] has laid [pushed_mob] on [src]. ")
get_patient()
+/obj/structure/table/optable/proc/table_entered()
+ SIGNAL_HANDLER
+ get_patient()
+
/obj/structure/table/optable/proc/get_patient()
var/mob/living/carbon/M = locate(/mob/living/carbon) in loc
if(M)
- if(M.resting)
- set_patient(M)
+ set_patient(M)
else
set_patient(null)
/obj/structure/table/optable/proc/set_patient(new_patient)
if(patient)
UnregisterSignal(patient, COMSIG_PARENT_QDELETING)
+ UnregisterSignal(patient, COMSIG_LIVING_RESTING_UPDATED)
+ REMOVE_TRAIT(patient, TRAIT_NO_BLEEDING, TABLE_TRAIT)
patient = new_patient
if(patient)
RegisterSignal(patient, COMSIG_PARENT_QDELETING, PROC_REF(patient_deleted))
+ RegisterSignal(patient, COMSIG_LIVING_RESTING_UPDATED, PROC_REF(check_bleed_trait))
+ check_bleed_trait()
+
+/obj/structure/table/optable/proc/check_bleed_trait()
+ SIGNAL_HANDLER
+ if (!patient)
+ return
+ if (patient.resting)
+ ADD_TRAIT(patient, TRAIT_NO_BLEEDING, TABLE_TRAIT)
+ else
+ REMOVE_TRAIT(patient, TRAIT_NO_BLEEDING, TABLE_TRAIT)
/obj/structure/table/optable/proc/patient_deleted(datum/source)
SIGNAL_HANDLER
@@ -627,6 +649,8 @@
get_patient()
if(!patient)
return FALSE
+ if (!patient.resting)
+ return FALSE
if(ishuman(patient))
return TRUE
return FALSE
@@ -683,7 +707,7 @@
. = ..()
if(.)
return
- if(!(user.mobility_flags & MOBILITY_STAND) || user.get_num_legs() < 2)
+ if(user.body_position == LYING_DOWN || user.usable_legs < 2)
return
user.changeNext_move(CLICK_CD_MELEE)
user.do_attack_animation(src, ATTACK_EFFECT_KICK)
diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm
index 6f5d5463cfb82..35959589b5093 100644
--- a/code/game/objects/structures/target_stake.dm
+++ b/code/game/objects/structures/target_stake.dm
@@ -7,7 +7,7 @@
flags_1 = CONDUCT_1
can_buckle = TRUE
max_buckled_mobs = 1
- buckle_lying = FALSE
+ buckle_lying = 0
var/obj/item/target/pinned_target
/obj/structure/target_stake/Destroy()
diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
index ddcdb05e101a7..869b85ca5f0bc 100644
--- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
+++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
@@ -180,28 +180,32 @@
/obj/structure/transit_tube_pod/transfer_air_ratio(datum/gas_mixture/taker, ratio)
return air_contents.transfer_ratio_to(taker, ratio)
-/obj/structure/transit_tube_pod/relaymove(mob/mob, direction)
- if(istype(mob) && mob.client)
- if(!moving)
- for(var/obj/structure/transit_tube/station/station in loc)
- if(!station.pod_moving)
- if(direction == turn(station.boarding_dir,180))
- if(station.open_status == STATION_TUBE_OPEN)
- mob.forceMove(loc)
- update_icon()
- else
- station.open_animation()
-
- else if(direction in station.tube_dirs)
- setDir(direction)
- station.launch_pod()
- return
-
- for(var/obj/structure/transit_tube/TT in loc)
- if(dir in TT.tube_dirs)
- if(TT.has_exit(direction))
- setDir(direction)
- return
+
+/obj/structure/transit_tube_pod/relaymove(mob/living/user, direction)
+ if(!user.client || moving)
+ return
+
+ for(var/obj/structure/transit_tube/station/station in loc)
+ if(station.pod_moving)
+ return
+ if(direction == turn(station.boarding_dir,180))
+ if(station.open_status == STATION_TUBE_OPEN)
+ user.forceMove(loc)
+ update_icon()
+ else
+ station.open_animation()
+ else if(direction in station.tube_dirs)
+ setDir(direction)
+ station.launch_pod()
+ return
+
+ for(var/obj/structure/transit_tube/transit_tube in loc)
+ if(!(dir in transit_tube.tube_dirs))
+ continue
+ if(!transit_tube.has_exit(direction))
+ continue
+ setDir(direction)
+ return
/obj/structure/transit_tube_pod/return_temperature()
return air_contents.return_temperature()
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 31b25602d0288..f78f7986502a4 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -124,6 +124,8 @@
var/exposed = 0 // can you currently put an item inside
var/obj/item/hiddenitem = null // what's in the urinal
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/urinal, 32)
+
/obj/structure/urinal/Initialize(mapload)
. = ..()
hiddenitem = new /obj/item/food/urinalcake
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 61f81c584cc39..d4e0708538617 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -10,7 +10,7 @@
max_integrity = 50
can_be_unanchored = TRUE
resistance_flags = ACID_PROOF
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 100, STAMINA = 0, BLEED = 0)
CanAtmosPass = ATMOS_PASS_PROC
rad_insulation = RAD_VERY_LIGHT_INSULATION
rad_flags = RAD_PROTECT_CONTENTS
@@ -399,7 +399,7 @@
icon_state = "rwindow"
reinf = TRUE
heat_resistance = 1600
- armor = list(MELEE = 50, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 25, BIO = 100, RAD = 100, FIRE = 80, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 25, BIO = 100, RAD = 100, FIRE = 80, ACID = 100, STAMINA = 0, BLEED = 0)
max_integrity = 100
explosion_block = 1
glass_type = /obj/item/stack/sheet/rglass
@@ -424,7 +424,7 @@
icon_state = "plasmawindow"
reinf = FALSE
heat_resistance = 25000
- armor = list(MELEE = 75, BULLET = 5, LASER = 0, ENERGY = 0, BOMB = 45, BIO = 100, RAD = 100, FIRE = 99, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 75, BULLET = 5, LASER = 0, ENERGY = 0, BOMB = 45, BIO = 100, RAD = 100, FIRE = 99, ACID = 100, STAMINA = 0, BLEED = 0)
max_integrity = 300
glass_type = /obj/item/stack/sheet/plasmaglass
rad_insulation = RAD_NO_INSULATION
@@ -456,7 +456,7 @@
icon_state = "plasmarwindow"
reinf = TRUE
heat_resistance = 50000
- armor = list(MELEE = 85, BULLET = 20, LASER = 0, ENERGY = 0, BOMB = 60, BIO = 100, RAD = 100, FIRE = 99, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 85, BULLET = 20, LASER = 0, ENERGY = 0, BOMB = 60, BIO = 100, RAD = 100, FIRE = 99, ACID = 100, STAMINA = 0, BLEED = 0)
max_integrity = 500
explosion_block = 2
glass_type = /obj/item/stack/sheet/plasmarglass
@@ -487,7 +487,7 @@
icon_state = "duwindow"
reinf = TRUE
heat_resistance = 50000
- armor = list(MELEE = 45, BULLET = 20, LASER = 0, ENERGY = 0, BOMB = 60, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 45, BULLET = 20, LASER = 0, ENERGY = 0, BOMB = 60, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
max_integrity = 500
explosion_block = 2
glass_type = /obj/item/stack/sheet/mineral/uranium
@@ -619,7 +619,7 @@
flags_1 = PREVENT_CLICK_UNDER_1
reinf = TRUE
heat_resistance = 1600
- armor = list(MELEE = 50, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 100, RAD = 100, FIRE = 80, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 100, RAD = 100, FIRE = 80, ACID = 100, STAMINA = 0, BLEED = 0)
explosion_block = 3
glass_type = /obj/item/stack/sheet/titaniumglass
glass_amount = 2
@@ -649,7 +649,7 @@
flags_1 = PREVENT_CLICK_UNDER_1
reinf = TRUE
heat_resistance = 1600
- armor = list(MELEE = 50, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 100, RAD = 100, FIRE = 80, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 100, RAD = 100, FIRE = 80, ACID = 100, STAMINA = 0, BLEED = 0)
explosion_block = 3
glass_type = /obj/item/stack/sheet/plastitaniumglass
glass_amount = 2
@@ -676,7 +676,7 @@
decon_speed = 10
CanAtmosPass = ATMOS_PASS_YES
resistance_flags = FLAMMABLE
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
breaksound = 'sound/items/poster_ripped.ogg'
hitsound = 'sound/weapons/slashmiss.ogg'
var/static/mutable_appearance/torn = mutable_appearance('icons/obj/smooth_structures/windows/paperframes.dmi',icon_state = "torn", layer = ABOVE_OBJ_LAYER - 0.1)
diff --git a/code/game/shuttle_engines.dm b/code/game/shuttle_engines.dm
index 7fc2d2d0b5eba..3e75c43a45649 100644
--- a/code/game/shuttle_engines.dm
+++ b/code/game/shuttle_engines.dm
@@ -8,7 +8,7 @@
icon = 'icons/turf/shuttle.dmi'
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
max_integrity = 500
- armor = list(MELEE = 100, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 70, STAMINA = 0) //default + ignores melee
+ armor = list(MELEE = 100, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 70, STAMINA = 0, BLEED = 0) //default + ignores melee
/obj/structure/shuttle/engine
name = "engine"
diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm
index beaa41794ac26..77ae7704e3236 100644
--- a/code/game/turfs/change_turf.dm
+++ b/code/game/turfs/change_turf.dm
@@ -85,6 +85,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
var/old_lighting_corner_SW = lighting_corner_SW
var/old_lighting_corner_NW = lighting_corner_NW
var/old_directional_opacity = directional_opacity
+ var/old_dynamic_lumcount = dynamic_lumcount
var/old_opacity = opacity
// Z-Mimic: copy above
@@ -138,11 +139,15 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
lighting_corner_SW = old_lighting_corner_SW
lighting_corner_NW = old_lighting_corner_NW
+ dynamic_lumcount = old_dynamic_lumcount
+
if(SSlighting.initialized)
lighting_object = old_lighting_object
+
directional_opacity = old_directional_opacity
recalculate_directional_opacity()
+ //Bacon's Starlight lighting
if(fullbright_type != old_fullbright_type)
if (!fullbright_type)
lighting_build_overlay()
diff --git a/code/game/turfs/closed/wall/reinf_walls.dm b/code/game/turfs/closed/wall/reinf_walls.dm
index aab143bcf0564..6369006e63474 100644
--- a/code/game/turfs/closed/wall/reinf_walls.dm
+++ b/code/game/turfs/closed/wall/reinf_walls.dm
@@ -22,7 +22,7 @@
)
/turf/closed/wall/r_wall/get_armour_list()
- return list(MELEE = 30, BULLET = 30, LASER = 20, ENERGY = 20, BOMB = 10, BIO = 100, RAD = 100, FIRE = 80, ACID = 70, STAMINA = 0)
+ return list(MELEE = 30, BULLET = 30, LASER = 20, ENERGY = 20, BOMB = 10, BIO = 100, RAD = 100, FIRE = 80, ACID = 70, STAMINA = 0, BLEED = 0)
/turf/closed/wall/r_wall/deconstruction_hints(mob/user)
switch(d_state)
diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm
index b368aaf6fdfed..478e54c75e0c5 100644
--- a/code/game/turfs/open/_open.dm
+++ b/code/game/turfs/open/_open.dm
@@ -229,7 +229,7 @@
if(!(lube&GALOSHES_DONT_HELP)) //can't slip while buckled unless it's lube.
return 0
else
- if(!(lube & SLIP_WHEN_CRAWLING) && (!(slipper.mobility_flags & MOBILITY_STAND) || !(slipper.status_flags & CANKNOCKDOWN))) // can't slip unbuckled mob if they're lying or can't fall.
+ if(!(lube & SLIP_WHEN_CRAWLING) && slipper.body_position == LYING_DOWN || !(slipper.status_flags & CANKNOCKDOWN)) // can't slip unbuckled mob if they're lying or can't fall.
return 0
if(slipper.m_intent == MOVE_INTENT_WALK && (lube&NO_SLIP_WHEN_WALKING))
return 0
diff --git a/code/game/turfs/open/floor/iron_floor.dm b/code/game/turfs/open/floor/iron_floor.dm
index 65d439c896504..8d9c8173f6016 100644
--- a/code/game/turfs/open/floor/iron_floor.dm
+++ b/code/game/turfs/open/floor/iron_floor.dm
@@ -110,6 +110,11 @@
floor_tile = /obj/item/stack/tile/iron/dark_corner
/turf/open/floor/iron/checker
+ icon_state = "blackwhite"
+ base_icon_state = "blackwhite"
+ floor_tile = /obj/item/stack/tile/iron/checker
+
+/turf/open/floor/iron/checker/other
icon_state = "checker"
base_icon_state = "checker"
floor_tile = /obj/item/stack/tile/iron/checker
diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm
index 78965daaba484..edcc7d6ec0560 100644
--- a/code/game/turfs/open/lava.dm
+++ b/code/game/turfs/open/lava.dm
@@ -127,9 +127,7 @@
var/mob/living/L = thing
if(L.movement_type & FLYING)
continue //YOU'RE FLYING OVER IT
- var/buckle_check = L.buckling
- if(!buckle_check)
- buckle_check = L.buckled
+ var/buckle_check = L.buckled
if(isobj(buckle_check))
var/obj/O = buckle_check
if(O.resistance_flags & LAVA_PROOF)
diff --git a/code/modules/admin/admin_fax_panel.dm b/code/modules/admin/admin_fax_panel.dm
index a75f6de4003cb..911527a70a64e 100644
--- a/code/modules/admin/admin_fax_panel.dm
+++ b/code/modules/admin/admin_fax_panel.dm
@@ -124,7 +124,7 @@
break
fax_paper.name = "paper — [default_paper_name]"
- fax_paper.add_raw_text(params["rawText"])
+ fax_paper.add_raw_text(params["rawText"], advanced_html = TRUE)
if(stamp)
fax_paper.add_stamp(stamp_class, params["stampX"], params["stampY"], params["stampAngle"], stamp)
diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm
index 4fa19f0926171..fa3bc4b5b7290 100644
--- a/code/modules/admin/admin_investigate.dm
+++ b/code/modules/admin/admin_investigate.dm
@@ -23,7 +23,6 @@
INVESTIGATE_DEATHS,
INVESTIGATE_ENGINES,
INVESTIGATE_EXONET,
- INVESTIGATE_EXPERIMENTOR,
INVESTIGATE_GRAVITY,
INVESTIGATE_HALLUCINATIONS,
INVESTIGATE_ITEMS,
diff --git a/code/modules/admin/battle_royale.dm b/code/modules/admin/battle_royale.dm
index e74e41044e1be..8b3548d0a79f0 100644
--- a/code/modules/admin/battle_royale.dm
+++ b/code/modules/admin/battle_royale.dm
@@ -44,7 +44,7 @@ GLOBAL_LIST_INIT(battle_royale_basic_loot, list(
/obj/item/clothing/suit/armor/vest/russian_coat,
/obj/item/clothing/suit/armor/hos/trenchcoat,
/obj/item/clothing/mask/chameleon,
- /obj/item/clothing/head/hats/centhat,
+ /obj/item/clothing/head/hats/centcom_cap,
/obj/item/clothing/head/costume/crown,
/obj/item/clothing/head/hats/hos/syndicate,
/obj/item/clothing/head/helmet,
diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm
index 4e327ef6e3992..6244d23684627 100644
--- a/code/modules/admin/holder2.dm
+++ b/code/modules/admin/holder2.dm
@@ -91,6 +91,7 @@ GLOBAL_PROTECT(href_token)
deadmined = FALSE
if (GLOB.directory[target])
associate(GLOB.directory[target]) //find the client for a ckey if they are connected and associate them with us
+ load_mentors()
/datum/admins/proc/deactivate()
if(IsAdminAdvancedProcCall())
@@ -106,6 +107,7 @@ GLOBAL_PROTECT(href_token)
disassociate()
C.add_verb(/client/proc/readmin)
C.update_special_keybinds()
+ load_mentors()
/datum/admins/proc/associate(client/C)
if(IsAdminAdvancedProcCall())
@@ -114,23 +116,20 @@ GLOBAL_PROTECT(href_token)
log_admin("[key_name(usr)][msg]")
return
- if(!istype(C))
- return
- if(C.ckey != target)
- var/msg = " has attempted to associate with [target]'s admin datum"
- message_admins("[key_name_admin(C)][msg]")
- log_admin("[key_name(C)][msg]")
- return
- if (deadmined)
- activate()
- owner = C
- owner.holder = src
- owner.add_admin_verbs() //TODO <--- todo what? the proc clearly exists and works since its the backbone to our entire admin system
- owner.remove_verb(/client/proc/readmin)
- owner.update_special_keybinds()
- GLOB.admins |= C
- if(istype(owner.mentor_datum))
- owner.mentor_datum.activate()
+ if(istype(C))
+ if(C.ckey != target)
+ var/msg = " has attempted to associate with [target]'s admin datum"
+ message_admins("[key_name_admin(C)][msg]")
+ log_admin("[key_name(C)][msg]")
+ return
+ if (deadmined)
+ activate()
+ owner = C
+ owner.holder = src
+ owner.add_admin_verbs() //TODO <--- todo what? the proc clearly exists and works since its the backbone to our entire admin system
+ owner.remove_verb(/client/proc/readmin)
+ owner.update_special_keybinds()
+ GLOB.admins |= C
/datum/admins/proc/disassociate()
if(IsAdminAdvancedProcCall())
@@ -138,14 +137,11 @@ GLOBAL_PROTECT(href_token)
message_admins("[key_name_admin(usr)][msg]")
log_admin("[key_name(usr)][msg]")
return
- if(!owner)
- return
- GLOB.admins -= owner
- owner.remove_admin_verbs()
- if(istype(owner.mentor_datum))
- owner.mentor_datum.deactivate()
- owner.holder = null
- owner = null
+ if(owner)
+ GLOB.admins -= owner
+ owner.remove_admin_verbs()
+ owner.holder = null
+ owner = null
/datum/admins/proc/check_for_rights(rights_required)
if(rights_required && !(rights_required & rank.rights))
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 811f786e4d797..6b792cbc60bac 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -840,13 +840,16 @@ Traitors and the like can also be revived with the previous role mostly intact.
if(!check_rights(R_ADMIN))
return
- var/level = input("Select security level to change to","Set Security Level") as null|anything in list("green","blue","red","delta")
- if(level)
- set_security_level(level)
+ var/level = tgui_input_list(usr, "Select Security Level:", "Set Security Level", SSsecurity_level.available_levels)
- log_admin("[key_name(usr)] changed the security level to [level]")
- message_admins("[key_name_admin(usr)] changed the security level to [level]")
- SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Security Level [capitalize(level)]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+ if(!level)
+ return
+
+ SSsecurity_level.set_level(level)
+
+ log_admin("[key_name(usr)] changed the security level to [level]")
+ message_admins("[key_name_admin(usr)] changed the security level to [level]")
+ SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Security Level [capitalize(level)]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/toggle_nuke(obj/machinery/nuclearbomb/N in GLOB.nuke_list)
set name = "Toggle Nuke"
diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
index ef500c0332626..22d7187f89a31 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
@@ -13,7 +13,7 @@
icon_state = "vest_stealth"
item_state = "armor"
blood_overlay_type = "armor"
- armor = list(MELEE = 15, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 15, BIO = 15, RAD = 15, FIRE = 70, ACID = 70, STAMINA = 30)
+ armor = list(MELEE = 15, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 15, BIO = 15, RAD = 15, FIRE = 70, ACID = 70, STAMINA = 30, BLEED = 40)
actions_types = list(/datum/action/item_action/hands_free/activate)
allowed = list(
/obj/item/abductor,
@@ -28,8 +28,8 @@
/// Cooldown in seconds
var/combat_cooldown = 20
var/datum/icon_snapshot/disguise
- var/stealth_armor = list(MELEE = 15, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 15, BIO = 15, RAD = 15, FIRE = 70, ACID = 70, STAMINA = 30)
- var/combat_armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 50, RAD = 50, FIRE = 90, ACID = 90, STAMINA = 60)
+ var/stealth_armor = list(MELEE = 15, BULLET = 15, LASER = 15, ENERGY = 15, BOMB = 15, BIO = 15, RAD = 15, FIRE = 70, ACID = 70, STAMINA = 30, BLEED = 40)
+ var/combat_armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 50, RAD = 50, FIRE = 90, ACID = 90, STAMINA = 60, BLEED = 80)
/obj/item/clothing/suit/armor/abductor/vest/Initialize(mapload)
. = ..()
@@ -553,11 +553,11 @@ Congratulations! You are now trained for invasive xenobiology research!"}
return
var/mob/living/carbon/C = L
if(!C.handcuffed)
- if(C.get_num_arms(FALSE) >= 2 || C.get_arm_ignore())
+ if(C.canBeHandcuffed())
playsound(src, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2)
C.visible_message("[user] begins restraining [C] with [src]! ", \
"[user] begins shaping an energy field around your hands! ")
- if(do_after(user, 3 SECONDS, C) && (C.get_num_arms(FALSE) >= 2 || C.get_arm_ignore()))
+ if(do_after(user, 3 SECONDS, C) && C.canBeHandcuffed())
if(!C.handcuffed)
C.set_handcuffed(new /obj/item/restraints/handcuffs/energy/used(C))
C.update_handcuffed()
@@ -876,5 +876,5 @@ Congratulations! You are now trained for invasive xenobiology research!"}
icon_state = "abductor-suit"
item_state = "bl_suit"
worn_icon = 'icons/mob/clothing/under/syndicate.dmi'
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
can_adjust = FALSE
diff --git a/code/modules/antagonists/abductor/machinery/experiment.dm b/code/modules/antagonists/abductor/machinery/experiment.dm
index 42ca6bea048be..403a1e55bce35 100644
--- a/code/modules/antagonists/abductor/machinery/experiment.dm
+++ b/code/modules/antagonists/abductor/machinery/experiment.dm
@@ -16,8 +16,7 @@
var/breakout_time = 450
/obj/machinery/abductor/experiment/MouseDrop_T(mob/target, mob/user)
- var/mob/living/L = user
- if(user.stat || (isliving(user) && (!(L.mobility_flags & MOBILITY_STAND) || !(L.mobility_flags & MOBILITY_UI))) || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target))
+ if(user.stat != CONSCIOUS || HAS_TRAIT(user, TRAIT_UI_BLOCKED) || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target))
return
if(isabductor(target))
return
@@ -177,6 +176,7 @@
/obj/machinery/abductor/experiment/proc/send_back(mob/living/carbon/human/H)
H.Sleeping(160)
H.uncuff()
+ H.cauterise_wounds()
if(console && console.pad && console.pad.teleport_target)
do_teleport(H, console.pad.teleport_target, channel = TELEPORT_CHANNEL_BLINK, no_effects = TRUE, teleport_mode = TELEPORT_MODE_ABDUCTORS)
return
diff --git a/code/modules/antagonists/blob/blobstrains/_blobstrain.dm b/code/modules/antagonists/blob/blobstrains/_blobstrain.dm
index 34b82011cd1e7..ca64a3aeb3822 100644
--- a/code/modules/antagonists/blob/blobstrains/_blobstrain.dm
+++ b/code/modules/antagonists/blob/blobstrains/_blobstrain.dm
@@ -52,7 +52,7 @@ GLOBAL_LIST_INIT(valid_blobstrains, subtypesof(/datum/blobstrain) - list(/datum/
if(resource_delay <= world.time)
resource_delay = world.time + 10 // 1 second
overmind.add_points(point_rate)
- overmind.blob_core.obj_integrity = min(overmind.blob_core.max_integrity, overmind.blob_core.obj_integrity+core_regen)
+ overmind.blob_core.repair_damage(core_regen)
/datum/blobstrain/proc/attack_living(var/mob/living/L) // When the blob attacks people
send_message(L)
diff --git a/code/modules/antagonists/blob/blobstrains/energized_jelly.dm b/code/modules/antagonists/blob/blobstrains/energized_jelly.dm
index dc4033f2f2284..9d95096285b9a 100644
--- a/code/modules/antagonists/blob/blobstrains/energized_jelly.dm
+++ b/code/modules/antagonists/blob/blobstrains/energized_jelly.dm
@@ -10,7 +10,7 @@
reagent = /datum/reagent/blob/energized_jelly
/datum/blobstrain/reagent/energized_jelly/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
- if((damage_flag == MELEE || damage_flag == BULLET || damage_flag == LASER) && B.obj_integrity - damage <= 0 && prob(10))
+ if((damage_flag == MELEE || damage_flag == BULLET || damage_flag == LASER) && B.get_integrity() - damage <= 0 && prob(10))
do_sparks(rand(2, 4), FALSE, B)
return ..()
diff --git a/code/modules/antagonists/blob/blobstrains/reactive_spines.dm b/code/modules/antagonists/blob/blobstrains/reactive_spines.dm
index fed527ad1f0e6..4b562ea6b902c 100644
--- a/code/modules/antagonists/blob/blobstrains/reactive_spines.dm
+++ b/code/modules/antagonists/blob/blobstrains/reactive_spines.dm
@@ -12,7 +12,7 @@
reagent = /datum/reagent/blob/reactive_spines
/datum/blobstrain/reagent/reactive_spines/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
- if(damage && damage_type == BRUTE && B.obj_integrity - damage > 0) //is there any damage, is it brute, and will we be alive
+ if(damage && damage_type == BRUTE && B.get_integrity() - damage > 0) //is there any damage, is it brute, and will we be alive
if(damage_flag == MELEE)
B.visible_message("The blob retaliates, lashing out! ")
for(var/atom/A as() in range(1, B))
diff --git a/code/modules/antagonists/blob/blobstrains/replicating_foam.dm b/code/modules/antagonists/blob/blobstrains/replicating_foam.dm
index c9cdba3224f84..58c5cf96346a2 100644
--- a/code/modules/antagonists/blob/blobstrains/replicating_foam.dm
+++ b/code/modules/antagonists/blob/blobstrains/replicating_foam.dm
@@ -13,10 +13,10 @@
/datum/blobstrain/reagent/replicating_foam/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
if(damage_type == BRUTE)
damage = damage * 2
- else if(damage_type == BURN && damage > 0 && B.obj_integrity - damage > 0 && prob(60))
+ else if(damage_type == BURN && damage > 0 && B.get_integrity() - damage > 0 && prob(60))
var/obj/structure/blob/newB = B.expand(null, null, 0)
if(newB)
- newB.obj_integrity = B.obj_integrity - damage
+ newB.update_integrity(B.get_integrity() - damage)
newB.update_icon()
return ..()
diff --git a/code/modules/antagonists/blob/blobstrains/shifting_fragments.dm b/code/modules/antagonists/blob/blobstrains/shifting_fragments.dm
index c36e27c79a282..9ba70ffbc69ee 100644
--- a/code/modules/antagonists/blob/blobstrains/shifting_fragments.dm
+++ b/code/modules/antagonists/blob/blobstrains/shifting_fragments.dm
@@ -15,7 +15,7 @@
B.forceMove(T)
/datum/blobstrain/reagent/shifting_fragments/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
- if((damage_flag == MELEE || damage_flag == BULLET || damage_flag == LASER) && damage > 0 && B.obj_integrity - damage > 0 && prob(60-damage))
+ if((damage_flag == MELEE || damage_flag == BULLET || damage_flag == LASER) && damage > 0 && B.get_integrity() - damage > 0 && prob(60-damage))
var/list/blobstopick = list()
for(var/obj/structure/blob/OB in orange(1, B))
if((istype(OB, /obj/structure/blob/normal) || (istype(OB, /obj/structure/blob/shield) && prob(25))) && OB.overmind && OB.overmind.blobstrain.type == B.overmind.blobstrain.type)
diff --git a/code/modules/antagonists/blob/blobstrains/zombifying_pods.dm b/code/modules/antagonists/blob/blobstrains/zombifying_pods.dm
index 66625f40fbdaf..06e97d89a66c0 100644
--- a/code/modules/antagonists/blob/blobstrains/zombifying_pods.dm
+++ b/code/modules/antagonists/blob/blobstrains/zombifying_pods.dm
@@ -12,7 +12,7 @@
reagent = /datum/reagent/blob/zombifying_pods
/datum/blobstrain/reagent/zombifying_pods/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
- if((damage_flag == MELEE || damage_flag == BULLET || damage_flag == LASER) && damage <= 20 && B.obj_integrity - damage <= 0 && prob(30)) //if the cause isn't fire or a bomb, the damage is less than 21, we're going to die from that damage, 20% chance of a shitty spore.
+ if((damage_flag == MELEE || damage_flag == BULLET || damage_flag == LASER) && damage <= 20 && B.get_integrity() - damage <= 0 && prob(30)) //if the cause isn't fire or a bomb, the damage is less than 21, we're going to die from that damage, 20% chance of a shitty spore.
B.visible_message("A spore floats free of the blob! ")
var/mob/living/simple_animal/hostile/blob/blobspore/weak/BS = new/mob/living/simple_animal/hostile/blob/blobspore/weak(B.loc)
BS.overmind = B.overmind
diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm
index fb2e7fba7d486..d5215bf517976 100644
--- a/code/modules/antagonists/blob/overmind.dm
+++ b/code/modules/antagonists/blob/overmind.dm
@@ -115,7 +115,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
else if(!victory_in_progress && (blobs_legit.len >= blobwincount))
victory_in_progress = TRUE
priority_announce("Biohazard has reached critical mass. Station loss is imminent.", "Biohazard Alert", SSstation.announcer.get_rand_alert_sound())
- set_security_level("delta")
+ SSsecurity_level.set_level(SEC_LEVEL_DELTA)
max_blob_points = INFINITY
blob_points = INFINITY
addtimer(CALLBACK(src, PROC_REF(victory)), 450)
@@ -197,7 +197,9 @@ GLOBAL_LIST_EMPTY(blob_nodes)
return ..()
/mob/camera/blob/Login()
- ..()
+ . = ..()
+ if(!. || !client)
+ return FALSE
to_chat(src, "You are the overmind! ")
blob_help()
update_health_hud()
@@ -211,10 +213,11 @@ GLOBAL_LIST_EMPTY(blob_nodes)
/mob/camera/blob/update_health_hud()
if(blob_core)
- hud_used.healths.maptext = MAPTEXT("[round(blob_core.obj_integrity)]
")
+ var/current_health = round((blob_core.get_integrity() / blob_core.max_integrity) * 100)
+ hud_used.healths.maptext = MAPTEXT("[current_health]
")
for(var/mob/living/simple_animal/hostile/blob/blobbernaut/B in blob_mobs)
if(B.hud_used?.blobpwrdisplay)
- B.hud_used.blobpwrdisplay.maptext = MAPTEXT("[round(blob_core.obj_integrity)]
")
+ B.hud_used.blobpwrdisplay.maptext = MAPTEXT("[current_health]
")
/mob/camera/blob/proc/add_points(points)
blob_points = clamp(blob_points + points, 0, max_blob_points)
@@ -264,7 +267,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
/mob/camera/blob/get_stat_tab_status()
var/list/tab_data = ..()
if(blob_core)
- tab_data["Core Health"] = GENERATE_STAT_TEXT("[blob_core.obj_integrity]")
+ tab_data["Core Health"] = GENERATE_STAT_TEXT("[blob_core.get_integrity()]")
tab_data["Power Stored"] = GENERATE_STAT_TEXT("[blob_points]/[max_blob_points]")
tab_data["Blobs to Win"] = GENERATE_STAT_TEXT("[blobs_legit.len]/[blobwincount]")
if(free_strain_rerolls)
diff --git a/code/modules/antagonists/blob/powers.dm b/code/modules/antagonists/blob/powers.dm
index e7964f479467a..4cff5d61a3f47 100644
--- a/code/modules/antagonists/blob/powers.dm
+++ b/code/modules/antagonists/blob/powers.dm
@@ -128,7 +128,7 @@
if(S)
if(!can_buy(BLOB_REFLECTOR_COST))
return
- if(S.obj_integrity < S.max_integrity * 0.5)
+ if(S.get_integrity() < S.max_integrity * 0.5)
add_points(BLOB_REFLECTOR_COST)
to_chat(src, "This shield blob is too damaged to be modified properly! ")
return
@@ -167,7 +167,7 @@
if(B.naut) //if it already made a blobbernaut, it can't do it again
to_chat(src, "This factory blob is already sustaining a blobbernaut. ")
return
- if(B.obj_integrity < B.max_integrity * 0.5)
+ if(B.get_integrity() < B.max_integrity * 0.5)
to_chat(src, "This factory blob is too damaged to sustain a blobbernaut. ")
return
if(!can_buy(40))
@@ -177,8 +177,7 @@
to_chat(src, "You attempt to produce a blobbernaut. ")
var/list/mob/dead/observer/candidates = poll_ghost_candidates("Do you want to play as a [blobstrain.name] blobbernaut?", ROLE_BLOB, /datum/role_preference/midround_ghost/blob, 7.5 SECONDS, ignore_category = POLL_IGNORE_BLOB_HELPER) //players must answer rapidly
if(LAZYLEN(candidates)) //if we got at least one candidate, they're a blobbernaut now.
- B.max_integrity = initial(B.max_integrity) * 0.25 //factories that produced a blobbernaut have much lower health
- B.obj_integrity = min(B.obj_integrity, B.max_integrity)
+ B.modify_max_integrity(initial(B.max_integrity) * 0.25) //factories that produced a blobbernaut have much lower health
B.update_icon()
B.visible_message("The blobbernaut [pick("rips", "tears", "shreds")] its way out of the factory blob! ")
playsound(B.loc, 'sound/effects/splat.ogg', 50, 1)
diff --git a/code/modules/antagonists/blob/structures/_blob.dm b/code/modules/antagonists/blob/structures/_blob.dm
index 3c84ee7235c92..e7870b87acfaf 100644
--- a/code/modules/antagonists/blob/structures/_blob.dm
+++ b/code/modules/antagonists/blob/structures/_blob.dm
@@ -12,7 +12,7 @@
CanAtmosPass = ATMOS_PASS_PROC
var/point_return = 0 //How many points the blob gets back when it removes a blob of that type. If less than 0, blob cannot be removed.
max_integrity = 30
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 70, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 70, STAMINA = 0, BLEED = 0)
var/health_regen = 2 //how much health this blob regens when pulsed
var/pulse_timestamp = 0 //we got pulsed when?
var/heal_timestamp = 0 //we got healed when?
@@ -332,11 +332,14 @@
name = "normal blob"
icon_state = "blob"
light_range = 0
- obj_integrity = 21 //doesn't start at full health
max_integrity = 25
health_regen = 1
brute_resist = 0.25
+/obj/structure/blob/normal/Initialize(mapload)
+ . = ..()
+ update_integrity(21) //doesn't start at full health
+
/obj/structure/blob/normal/scannerreport()
if(obj_integrity <= 15)
return "Currently weak to brute damage."
diff --git a/code/modules/antagonists/blob/structures/core.dm b/code/modules/antagonists/blob/structures/core.dm
index a586d5d877d0d..1840b272ed2c7 100644
--- a/code/modules/antagonists/blob/structures/core.dm
+++ b/code/modules/antagonists/blob/structures/core.dm
@@ -4,7 +4,7 @@
icon_state = "blank_blob"
desc = "A huge, pulsating yellow mass."
max_integrity = 400
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 75, ACID = 90, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 75, ACID = 90, STAMINA = 0, BLEED = 0)
explosion_block = 6
point_return = -1
health_regen = 0 //we regen in Life() instead of when pulsed
diff --git a/code/modules/antagonists/blob/structures/node.dm b/code/modules/antagonists/blob/structures/node.dm
index dae14efb9ba47..7657d896696e4 100644
--- a/code/modules/antagonists/blob/structures/node.dm
+++ b/code/modules/antagonists/blob/structures/node.dm
@@ -4,7 +4,7 @@
icon_state = "blank_blob"
desc = "A large, pulsating yellow mass."
max_integrity = 200
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 65, ACID = 90, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 65, ACID = 90, STAMINA = 0, BLEED = 0)
health_regen = 3
point_return = 25
resistance_flags = LAVA_PROOF
diff --git a/code/modules/antagonists/blob/structures/shield.dm b/code/modules/antagonists/blob/structures/shield.dm
index 1d809d4fe104c..f39f8613c25e7 100644
--- a/code/modules/antagonists/blob/structures/shield.dm
+++ b/code/modules/antagonists/blob/structures/shield.dm
@@ -9,7 +9,7 @@
explosion_block = 3
point_return = 4
atmosblock = TRUE
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 90, ACID = 90, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 90, ACID = 90, STAMINA = 0, BLEED = 0)
/obj/structure/blob/shield/scannerreport()
if(atmosblock)
diff --git a/code/modules/antagonists/changeling/powers/adrenaline.dm b/code/modules/antagonists/changeling/powers/adrenaline.dm
index 05f2b8016d034..5dea5ea3a8c3d 100644
--- a/code/modules/antagonists/changeling/powers/adrenaline.dm
+++ b/code/modules/antagonists/changeling/powers/adrenaline.dm
@@ -11,7 +11,7 @@
//Recover from stuns.
/datum/action/changeling/adrenaline/sting_action(mob/living/user)
..()
- to_chat(user, "Energy rushes through us.[(!(user.mobility_flags & MOBILITY_STAND)) ? " We arise." : ""] ")
+ to_chat(user, "Energy rushes through us.[(user.body_position == LYING_DOWN) ? " We arise." : ""] ")
user.SetSleeping(0)
user.SetUnconscious(0)
user.SetStun(0)
diff --git a/code/modules/antagonists/changeling/powers/fakedeath.dm b/code/modules/antagonists/changeling/powers/fakedeath.dm
index 13a40871292d9..1d068e1352658 100644
--- a/code/modules/antagonists/changeling/powers/fakedeath.dm
+++ b/code/modules/antagonists/changeling/powers/fakedeath.dm
@@ -24,7 +24,6 @@
else
to_chat(user, "We begin our stasis, preparing energy to arise once more. ")
user.fakedeath("changeling") //play dead
- user.update_mobility()
addtimer(CALLBACK(src, PROC_REF(ready_to_regenerate), user.mind), LING_FAKEDEATH_TIME, TIMER_UNIQUE)
return TRUE
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index bb06f2f7fd0a5..c940b068ef220 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -160,6 +160,7 @@
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "tore", "ripped", "diced", "cut")
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
var/can_drop = FALSE
var/fake = FALSE
@@ -401,9 +402,12 @@
item_flags = DROPDEL
clothing_flags = STOPSPRESSUREDAMAGE | HEADINTERNALS //Not THICKMATERIAL because it's organic tissue, so if somebody tries to inject something into it, it still ends up in your blood. (also balance but muh fluff)
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/oxygen)
- armor = list(MELEE = 35, BULLET = 25, LASER = 25, ENERGY = 30, BOMB = 30, BIO = 20, RAD = 20, FIRE = 90, ACID = 90, STAMINA = 10)//Bit less armoured than the Syndicate space suit
+ armor = list(MELEE = 35, BULLET = 25, LASER = 25, ENERGY = 30, BOMB = 30, BIO = 20, RAD = 20, FIRE = 90, ACID = 90, STAMINA = 10, BLEED = 80)//Bit less armoured than the Syndicate space suit
slowdown = 0.2
var/datum/reagent/salbutamol = /datum/reagent/medicine/salbutamol
+ actions_types = list()
+ cell = null
+ show_hud = FALSE
/obj/item/clothing/suit/space/changeling/Initialize(mapload)
. = ..()
@@ -412,10 +416,15 @@
loc.visible_message("[loc.name]\'s flesh rapidly inflates, forming a bloated mass around [loc.p_their()] body! ", "We inflate our flesh, creating a spaceproof suit! ", "You hear organic matter ripping and tearing! ")
START_PROCESSING(SSobj, src)
+// seal the cell door
+/obj/item/clothing/suit/space/changeling/toggle_spacesuit_cell(mob/user)
+ return
+
/obj/item/clothing/suit/space/changeling/process(delta_time)
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
H.reagents.add_reagent(salbutamol, initial(salbutamol.metabolization_rate) * (delta_time / SSMOBS_DT))
+ H.adjust_bodytemperature(temperature_setting - H.bodytemperature) // force changelings to normal temp step mode played badly
/obj/item/clothing/head/helmet/space/changeling
name = "flesh mass"
@@ -426,7 +435,7 @@
desc = "A covering of armored pressure and temperature-resistant organic tissue with a glass-like chitin front."
item_flags = DROPDEL
clothing_flags = STOPSPRESSUREDAMAGE
- armor = list(MELEE = 35, BULLET = 25, LASER = 25, ENERGY = 30, BOMB = 30, BIO = 20, RAD = 20, FIRE = 90, ACID = 90, STAMINA = 10)
+ armor = list(MELEE = 35, BULLET = 25, LASER = 25, ENERGY = 30, BOMB = 30, BIO = 20, RAD = 20, FIRE = 90, ACID = 90, STAMINA = 10, BLEED = 80)
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
/obj/item/clothing/head/helmet/space/changeling/Initialize(mapload)
@@ -459,7 +468,7 @@
item_state = null
item_flags = DROPDEL
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
- armor = list(MELEE = 40, BULLET = 40, LASER = 50, ENERGY = 50, BOMB = 25, BIO = 0, RAD = 0, FIRE = 25, ACID = 25, STAMINA = 30)
+ armor = list(MELEE = 40, BULLET = 40, LASER = 50, ENERGY = 50, BOMB = 25, BIO = 0, RAD = 0, FIRE = 25, ACID = 25, STAMINA = 30, BLEED = 90)
flags_inv = HIDEJUMPSUIT
cold_protection = 0
heat_protection = 0
@@ -478,7 +487,7 @@
icon_state = "lingarmorhelmet"
item_state = null
item_flags = DROPDEL
- armor = list(MELEE = 40, BULLET = 40, LASER = 50, ENERGY = 50, BOMB = 25, BIO = 0, RAD = 0, FIRE = 25, ACID = 25, STAMINA = 30)
+ armor = list(MELEE = 40, BULLET = 40, LASER = 50, ENERGY = 50, BOMB = 25, BIO = 0, RAD = 0, FIRE = 25, ACID = 25, STAMINA = 30, BLEED = 90)
flags_inv = HIDEEARS|HIDEHAIR|HIDEEYES|HIDEFACIALHAIR|HIDEFACE|HIDESNOUT
/obj/item/clothing/head/helmet/changeling/Initialize(mapload)
diff --git a/code/modules/antagonists/changeling/powers/regenerate.dm b/code/modules/antagonists/changeling/powers/regenerate.dm
index 1690ff483552e..2ab0b25a04306 100644
--- a/code/modules/antagonists/changeling/powers/regenerate.dm
+++ b/code/modules/antagonists/changeling/powers/regenerate.dm
@@ -73,7 +73,6 @@
"Our [BP] forms into a horrifying snake and heads towards our attackers! ")
BP.dismember()
BP.Destroy()
- C.update_mobility()
//Deploy limbsnake
var/mob/living/snek = new /mob/living/simple_animal/hostile/poison/limbsnake(get_turf(user))
//assign faction
diff --git a/code/modules/antagonists/clock_cult/clockwork_massive.dm b/code/modules/antagonists/clock_cult/clockwork_massive.dm
index 46c74b77669fa..aa19c1480fbce 100644
--- a/code/modules/antagonists/clock_cult/clockwork_massive.dm
+++ b/code/modules/antagonists/clock_cult/clockwork_massive.dm
@@ -88,7 +88,7 @@ GLOBAL_LIST_INIT(clockwork_portals, list())
for(var/obj/effect/portal/wormhole/clockcult/CC in GLOB.all_wormholes)
qdel(CC)
SSshuttle.clearHostileEnvironment(src)
- set_security_level(SEC_LEVEL_RED)
+ SSsecurity_level.set_level(SEC_LEVEL_RED)
addtimer(CALLBACK(src, PROC_REF(clockies_win)), 300)
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/clockies_win()
@@ -134,7 +134,7 @@ GLOBAL_LIST_INIT(clockwork_portals, list())
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/announce_gateway()
set_dynamic_high_impact_event("clockwork ark has opened")
activated = TRUE
- set_security_level(SEC_LEVEL_DELTA)
+ SSsecurity_level.set_level(SEC_LEVEL_DELTA)
mass_recall(TRUE)
var/grace_time = GLOB.narsie_breaching ? 0 : 1800
addtimer(CALLBACK(src, PROC_REF(begin_assault)), grace_time)
diff --git a/code/modules/antagonists/clock_cult/clockwork_turfs.dm b/code/modules/antagonists/clock_cult/clockwork_turfs.dm
index 5c84fd4915323..329b56ba411c8 100644
--- a/code/modules/antagonists/clock_cult/clockwork_turfs.dm
+++ b/code/modules/antagonists/clock_cult/clockwork_turfs.dm
@@ -500,7 +500,6 @@
/obj/structure/grille/ratvar/broken
icon_state = "brokenratvargrille"
density = FALSE
- obj_integrity = 20
broken = TRUE
rods_type = /obj/item/stack/sheet/brass
rods_amount = 1
@@ -508,6 +507,10 @@
grille_type = /obj/structure/grille/ratvar
broken_type = null
+/obj/structure/grille/ratvar/broken/Initialize(mapload)
+ . = ..()
+ take_damage(max_integrity * 0.6)
+
//=================================================
//Ratvar Window: A transparent window
//=================================================
@@ -519,7 +522,7 @@
icon_state = "clockwork_window_single"
resistance_flags = FIRE_PROOF | ACID_PROOF
max_integrity = 80
- armor = list(MELEE = 40, BULLET = -20, LASER = 0, ENERGY = 0, BOMB = 25, BIO = 100, RAD = 100, FIRE = 80, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 40, BULLET = -20, LASER = 0, ENERGY = 0, BOMB = 25, BIO = 100, RAD = 100, FIRE = 80, ACID = 100, STAMINA = 0, BLEED = 0)
explosion_block = 2 //fancy AND hard to destroy. the most useful combination.
decon_speed = 40
glass_type = /obj/item/stack/sheet/brass
diff --git a/code/modules/antagonists/clock_cult/helpers/clockcult_ending.dm b/code/modules/antagonists/clock_cult/helpers/clockcult_ending.dm
index de51ca0ba2f06..6085f97b93802 100644
--- a/code/modules/antagonists/clock_cult/helpers/clockcult_ending.dm
+++ b/code/modules/antagonists/clock_cult/helpers/clockcult_ending.dm
@@ -1,7 +1,7 @@
/proc/trigger_clockcult_victory(hostile)
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(clockcult_gg)), 700)
sleep(50)
- set_security_level("delta")
+ SSsecurity_level.set_level(SEC_LEVEL_DELTA)
priority_announce("Huge gravitational-energy spike detected emminating from a neutron star near your sector. Event has been determined to be survivable by 0% of life. ESTIMATED TIME UNTIL ENERGY PULSE REACHES [GLOB.station_name]: 56 SECONDS. Godspeed crew, glory to Nanotrasen. -Admiral Telvig.", "Central Command Anomolous Materials Division", 'sound/misc/bloblarm.ogg')
for(var/client/C in GLOB.clients)
SEND_SOUND(C, sound('sound/misc/airraid.ogg', 1))
diff --git a/code/modules/antagonists/clock_cult/items/brass_clothing.dm b/code/modules/antagonists/clock_cult/items/brass_clothing.dm
index 7da92890c6589..28ef84e13a5ca 100644
--- a/code/modules/antagonists/clock_cult/items/brass_clothing.dm
+++ b/code/modules/antagonists/clock_cult/items/brass_clothing.dm
@@ -5,7 +5,7 @@
icon_state = "clockwork_cuirass"
worn_icon = 'icons/mob/clothing/suits/armor.dmi'
worn_icon_state = "clockwork_cuirass"
- armor = list(MELEE = 50, BULLET = 60, LASER = 30, ENERGY = 80, BOMB = 80, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 60)
+ armor = list(MELEE = 50, BULLET = 60, LASER = 30, ENERGY = 80, BOMB = 80, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 60, BLEED = 60)
slowdown = 0.6
resistance_flags = FIRE_PROOF | ACID_PROOF
w_class = WEIGHT_CLASS_BULKY
@@ -39,14 +39,14 @@
worn_icon_state = "clockwork_cuirass_speed"
slowdown = -0.3
resistance_flags = FIRE_PROOF | ACID_PROOF
- armor = list(MELEE = 40, BULLET = 40, LASER = 10, ENERGY = -20, BOMB = 60, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 30)
+ armor = list(MELEE = 40, BULLET = 40, LASER = 10, ENERGY = -20, BOMB = 60, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 30, BLEED = 40)
/obj/item/clothing/suit/clockwork/cloak
name = "shrouding cloak"
desc = "A faltering cloak that bends light around it, distorting the user's appearance, making it hard to see them with the naked eye. However, it provides very little protection."
icon_state = "clockwork_cloak"
worn_icon_state = "clockwork_cloak"
- armor = list(MELEE = 10, BULLET = 60, LASER = 40, ENERGY = 20, BOMB = 40, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 20)
+ armor = list(MELEE = 10, BULLET = 60, LASER = 40, ENERGY = 20, BOMB = 40, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 20, BLEED = 20)
slowdown = 0.4
resistance_flags = FIRE_PROOF | ACID_PROOF
var/shroud_active = FALSE
@@ -143,7 +143,7 @@
desc = "A strong, brass helmet worn by the soldiers of the Ratvarian armies. Includes an integrated light-dimmer for flash protection, as well as occult-grade muffling for factory based environments."
icon = 'icons/obj/clothing/clockwork_garb.dmi'
icon_state = "clockwork_helmet"
- armor = list(MELEE = 50, BULLET = 60, LASER = 30, ENERGY = 80, BOMB = 80, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 60)
+ armor = list(MELEE = 50, BULLET = 60, LASER = 30, ENERGY = 80, BOMB = 80, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 60, BLEED = 60)
resistance_flags = FIRE_PROOF | ACID_PROOF
w_class = WEIGHT_CLASS_BULKY
flash_protect = 1
@@ -168,4 +168,4 @@
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
resistance_flags = NONE
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 50, STAMINA = 0, BLEED = 0, BLEED = 20)
diff --git a/code/modules/antagonists/clock_cult/items/clockwork_weapon.dm b/code/modules/antagonists/clock_cult/items/clockwork_weapon.dm
index 0e145c143a17f..85d88b5dc51ca 100644
--- a/code/modules/antagonists/clock_cult/items/clockwork_weapon.dm
+++ b/code/modules/antagonists/clock_cult/items/clockwork_weapon.dm
@@ -19,6 +19,7 @@
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "poked", "jabbed", "torn", "gored")
sharpness = IS_SHARP_ACCURATE
+ bleed_force = BLEED_CUT
max_integrity = 200
var/clockwork_hint = ""
var/obj/effect/proc_holder/spell/targeted/summon_spear/SS
diff --git a/code/modules/antagonists/clock_cult/items/replica_fabricator.dm b/code/modules/antagonists/clock_cult/items/replica_fabricator.dm
index 3ede705c2568a..069bbeb1f9b1b 100644
--- a/code/modules/antagonists/clock_cult/items/replica_fabricator.dm
+++ b/code/modules/antagonists/clock_cult/items/replica_fabricator.dm
@@ -44,12 +44,12 @@
if(GLOB.clockcult_power < 200)
to_chat(user, "You need [200 - GLOB.clockcult_power]W more to repair the [C]... ")
return
- if(C.max_integrity == C.obj_integrity)
+ if(C.max_integrity == C.get_integrity())
to_chat(user, "\The [C] is already repaired! ")
return
to_chat(user, "You begin repairing [C]... ")
if(do_after(user, 60, target=target))
- if(C.max_integrity == C.obj_integrity)
+ if(C.max_integrity == C.get_integrity())
to_chat(user, "\The [C] is already repaired! ")
return
if(GLOB.clockcult_power < 200)
@@ -57,7 +57,7 @@
return
GLOB.clockcult_power -= 200
to_chat(user, "You repair some of the damage on \the [C]. ")
- C.obj_integrity = clamp(C.obj_integrity + 15, 0, C.max_integrity)
+ C.repair_damage(clamp(C.get_integrity() + 15, 0, C.max_integrity))
else
to_chat(user, "You fail to repair the damage of \the [C]... ")
diff --git a/code/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm b/code/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm
index 2e7bfb21164af..a3078affd54aa 100644
--- a/code/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm
+++ b/code/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm
@@ -49,6 +49,8 @@ GLOBAL_LIST_EMPTY(clockwork_marauders)
/mob/living/simple_animal/hostile/clockwork_marauder/Login()
. = ..()
+ if(!. || !client)
+ return FALSE
add_servant_of_ratvar(src)
to_chat(src, "You can block up to 4 attacks with your shield, however it requires a welder to be repaired. ")
diff --git a/code/modules/antagonists/clock_cult/mobs/eminence.dm b/code/modules/antagonists/clock_cult/mobs/eminence.dm
index 06056a2d9e95f..a197b70acae51 100644
--- a/code/modules/antagonists/clock_cult/mobs/eminence.dm
+++ b/code/modules/antagonists/clock_cult/mobs/eminence.dm
@@ -101,6 +101,8 @@
/mob/living/simple_animal/eminence/Login()
. = ..()
+ if(!. || !client)
+ return FALSE
var/datum/antagonist/servant_of_ratvar/S = add_servant_of_ratvar(src, silent=TRUE)
S.prefix = CLOCKCULT_PREFIX_EMINENCE
to_chat(src, "You are the Eminence! ")
diff --git a/code/modules/antagonists/clock_cult/scriptures/abstraction_crystal.dm b/code/modules/antagonists/clock_cult/scriptures/abstraction_crystal.dm
index 3ca85d0b900ad..8df79d2861c15 100644
--- a/code/modules/antagonists/clock_cult/scriptures/abstraction_crystal.dm
+++ b/code/modules/antagonists/clock_cult/scriptures/abstraction_crystal.dm
@@ -61,7 +61,7 @@ GLOBAL_LIST_INIT(abstraction_crystals, list())
. = ..()
ADD_TRAIT(src, TRAIT_IGNOREDAMAGESLOWDOWN, ABSTRACTION_HOLOGRAM_TRAIT)
ADD_TRAIT(src, TRAIT_NODISMEMBER, ABSTRACTION_HOLOGRAM_TRAIT)
- dna.species.species_traits |= NOBLOOD
+ ADD_TRAIT(src, TRAIT_NO_BLOOD, ABSTRACTION_HOLOGRAM_TRAIT)
/mob/living/carbon/human/abstraction_hologram/death(gibbed)
//Put the person back in their body
@@ -85,7 +85,7 @@ GLOBAL_LIST_INIT(abstraction_crystals, list())
var/health_lost = last_check_health - health
if(health_lost > 0)
damage_crystal(health_lost)
- var/required_health = (linked_crystal.obj_integrity / linked_crystal.max_integrity) * maxHealth
+ var/required_health = (linked_crystal.get_integrity() / linked_crystal.max_integrity) * maxHealth
var/health_delta_needed = max(health - required_health, 0)
adjustCloneLoss(health_delta_needed) //Adjust clone loss so that our health = crystals health
last_check_health = health
diff --git a/code/modules/antagonists/clock_cult/scriptures/interdiction_lens.dm b/code/modules/antagonists/clock_cult/scriptures/interdiction_lens.dm
index 89bec9d8fad8c..39b5e43984879 100644
--- a/code/modules/antagonists/clock_cult/scriptures/interdiction_lens.dm
+++ b/code/modules/antagonists/clock_cult/scriptures/interdiction_lens.dm
@@ -20,7 +20,6 @@
anchored = TRUE
break_message = "The interdiction lens breaks into multiple fragments, which gently float to the ground. "
max_integrity = 150
- obj_integrity = 150
minimum_power = 5
var/enabled = FALSE //Misnomer - Whether we want to be enabled or not, processing would be if we are enabled
var/processing = FALSE
diff --git a/code/modules/antagonists/clock_cult/scriptures/kindle.dm b/code/modules/antagonists/clock_cult/scriptures/kindle.dm
index 31fc93a3febe0..ae944eba40d30 100644
--- a/code/modules/antagonists/clock_cult/scriptures/kindle.dm
+++ b/code/modules/antagonists/clock_cult/scriptures/kindle.dm
@@ -27,7 +27,7 @@
//Anti magic abilities
var/anti_magic_source = M.anti_magic_check(holy = TRUE)
if(anti_magic_source)
- M.mob_light(_color = LIGHT_COLOR_HOLY_MAGIC, _range = 2, _duration = 100)
+ M.mob_light(color = LIGHT_COLOR_HOLY_MAGIC, range = 2, duration = 100)
var/mutable_appearance/forbearance = mutable_appearance('icons/effects/genetics.dmi', "servitude", CALCULATE_MOB_OVERLAY_LAYER(MUTATIONS_LAYER))
M.add_overlay(forbearance)
addtimer(CALLBACK(M, TYPE_PROC_REF(/atom, cut_overlay), forbearance), 100)
@@ -37,7 +37,7 @@
return TRUE
//Blood Cultist Effect
if(iscultist(M))
- M.mob_light(_color = LIGHT_COLOR_BLOOD_MAGIC, _range = 2, _duration = 300)
+ M.mob_light(color = LIGHT_COLOR_BLOOD_MAGIC, range = 2, duration = 300)
M.stuttering += 15
M.Jitter(15)
var/mob_color = M.color
@@ -48,7 +48,7 @@
playsound(invoker, 'sound/magic/mm_hit.ogg', 50, TRUE)
return TRUE
//Successful Invokation
- invoker.mob_light(_color = LIGHT_COLOR_CLOCKWORK, _range = 2, _duration = 10)
+ invoker.mob_light(color = LIGHT_COLOR_CLOCKWORK, range = 2, duration = 10)
if(!is_reebe(invoker.z))
if(!HAS_TRAIT(M, TRAIT_MINDSHIELD))
M.Paralyze(150)
diff --git a/code/modules/antagonists/clock_cult/scriptures/ocular_warden.dm b/code/modules/antagonists/clock_cult/scriptures/ocular_warden.dm
index 9494d3a34d3a9..9197614fe896b 100644
--- a/code/modules/antagonists/clock_cult/scriptures/ocular_warden.dm
+++ b/code/modules/antagonists/clock_cult/scriptures/ocular_warden.dm
@@ -32,7 +32,7 @@
break_message = "A black ooze leaks from the ocular warden as it slowly sinks to the ground. "
icon_state = "ocular_warden"
max_integrity = 60
- armor = list(MELEE = -80, BULLET = -50, LASER = 40, ENERGY = 40, BOMB = 20, BIO = 0, RAD = 0, STAMINA = 0)
+ armor = list(MELEE = -80, BULLET = -50, LASER = 40, ENERGY = 40, BOMB = 20, BIO = 0, RAD = 0, STAMINA = 0, BLEED = 0)
var/cooldown
/obj/structure/destructible/clockwork/ocular_warden/process(delta_time)
diff --git a/code/modules/antagonists/clock_cult/scriptures/prosperity_prism.dm b/code/modules/antagonists/clock_cult/scriptures/prosperity_prism.dm
index 3a954e39edd8d..7eb2b5e49d47b 100644
--- a/code/modules/antagonists/clock_cult/scriptures/prosperity_prism.dm
+++ b/code/modules/antagonists/clock_cult/scriptures/prosperity_prism.dm
@@ -22,7 +22,6 @@
anchored = TRUE
break_message = "The prism falls apart, toxic liquid leaking out into the air. "
max_integrity = 150
- obj_integrity = 150
minimum_power = 4
var/powered = FALSE
var/toggled_on = TRUE
diff --git a/code/modules/antagonists/clock_cult/traps/receivers/skewer.dm b/code/modules/antagonists/clock_cult/traps/receivers/skewer.dm
index 377d63f93a9c5..d951eb4e22e5f 100644
--- a/code/modules/antagonists/clock_cult/traps/receivers/skewer.dm
+++ b/code/modules/antagonists/clock_cult/traps/receivers/skewer.dm
@@ -12,7 +12,6 @@
unwrench_path = /obj/item/clockwork/trap_placer/skewer
buckle_lying = FALSE
max_integrity = 40
- obj_integrity = 40
var/cooldown = 0
var/extended = FALSE
var/mutable_appearance/stab_overlay
@@ -37,8 +36,9 @@
M.apply_damage(5, BRUTE, BODY_ZONE_CHEST)
if(ishuman(M))
var/mob/living/carbon/human/H = M
- if(!H.bleed_rate)
- H.bleed(30)
+ var/armour_block = H.run_armor_check(BODY_ZONE_CHEST, BLEED)
+ var/hit_amount = (100 - armour_block) / 100
+ H.add_bleeding(BLEED_CRITICAL * hit_amount)
if(target_stabbed)
if(!stab_overlay)
stab_overlay = mutable_appearance('icons/obj/clockwork_objects.dmi', "brass_skewer_pokeybit", layer=ABOVE_MOB_LAYER)
diff --git a/code/modules/antagonists/clock_cult/traps/senders/delay.dm b/code/modules/antagonists/clock_cult/traps/senders/delay.dm
index 58597b4927f31..2ae5b7dd28b5f 100644
--- a/code/modules/antagonists/clock_cult/traps/senders/delay.dm
+++ b/code/modules/antagonists/clock_cult/traps/senders/delay.dm
@@ -11,7 +11,6 @@
component_datum = /datum/component/clockwork_trap/delay
unwrench_path = /obj/item/wallframe/clocktrap/delay
max_integrity = 15
- obj_integrity = 15
/datum/component/clockwork_trap/delay
takes_input = TRUE
diff --git a/code/modules/antagonists/clock_cult/traps/senders/lever.dm b/code/modules/antagonists/clock_cult/traps/senders/lever.dm
index c5bc5f074dfd3..b2fb0c7989b7f 100644
--- a/code/modules/antagonists/clock_cult/traps/senders/lever.dm
+++ b/code/modules/antagonists/clock_cult/traps/senders/lever.dm
@@ -11,7 +11,6 @@
unwrench_path = /obj/item/wallframe/clocktrap/lever
component_datum = /datum/component/clockwork_trap/lever
max_integrity = 75
- obj_integrity = 75
/datum/component/clockwork_trap/lever
sends_input = TRUE
diff --git a/code/modules/antagonists/clock_cult/traps/senders/pressure_sensor.dm b/code/modules/antagonists/clock_cult/traps/senders/pressure_sensor.dm
index 8673d10476393..159afb8ace32e 100644
--- a/code/modules/antagonists/clock_cult/traps/senders/pressure_sensor.dm
+++ b/code/modules/antagonists/clock_cult/traps/senders/pressure_sensor.dm
@@ -13,7 +13,6 @@
alpha = 60
layer = PRESSURE_PLATE_LAYER
max_integrity = 5
- obj_integrity = 5
/datum/component/clockwork_trap/pressure_sensor
sends_input = TRUE
diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index c28d4f4d26fae..42da7a651f33e 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -356,6 +356,7 @@
var/uses = 1
var/health_cost = 0 //The amount of health taken from the user when invoking the spell
var/datum/action/innate/cult/blood_spell/source
+
/obj/item/melee/blood_magic/Initialize(mapload, var/spell)
. = ..()
if(!istype(spell, /datum/action/innate/cult/blood_spell))
@@ -422,13 +423,12 @@
if(iscultist(user))
user.visible_message("[user] floods [L]'s mind with an eldritch energy! ", \
"You attempt to stun [L] with the spell! ")
-
- user.mob_light(_range = 3, _color = LIGHT_COLOR_BLOOD_MAGIC, _duration = 0.2 SECONDS)
+ user.mob_light(range = 3, color = LIGHT_COLOR_BLOOD_MAGIC, duration = 0.2 SECONDS)
var/anti_magic_source = L.anti_magic_check(holy = TRUE)
if(anti_magic_source)
- L.mob_light(_range = 2, _color = LIGHT_COLOR_HOLY_MAGIC, _duration = 10 SECONDS)
+ L.mob_light(range = 2, color = LIGHT_COLOR_HOLY_MAGIC, duration = 10 SECONDS)
var/mutable_appearance/forbearance = mutable_appearance('icons/effects/genetics.dmi', "servitude", CALCULATE_MOB_OVERLAY_LAYER(MUTATIONS_LAYER))
L.add_overlay(forbearance)
addtimer(CALLBACK(L, TYPE_PROC_REF(/atom, cut_overlay), forbearance), 100)
@@ -511,7 +511,7 @@
/obj/item/melee/blood_magic/shackles/afterattack(atom/target, mob/living/carbon/user, proximity)
if(iscultist(user) && iscarbon(target) && proximity)
var/mob/living/carbon/C = target
- if(C.get_num_arms(FALSE) >= 2 || C.get_arm_ignore())
+ if(C.canBeHandcuffed())
CuffAttack(C, user)
else
user.visible_message("This victim doesn't have enough arms to complete the restraint! ")
@@ -690,7 +690,7 @@
if(proximity)
if(ishuman(target))
var/mob/living/carbon/human/H = target
- if(NOBLOOD in H.dna.species.species_traits)
+ if((NOBLOOD in H.dna.species.species_traits) || HAS_TRAIT(H, TRAIT_NO_BLOOD))
to_chat(user,"Blood rites do not work on species with no blood! ")
return
if(iscultist(H))
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index 800a3a2d1a02b..b4e2230551530 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -48,6 +48,7 @@ Striking a noncultist, however, will tear their flesh."}
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
flags_1 = CONDUCT_1
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
w_class = WEIGHT_CLASS_BULKY
block_level = 1
block_upgrade_walk = 1
@@ -138,7 +139,7 @@ Striking a noncultist, however, will tear their flesh."}
desc = "A torn, dust-caked hood. Strange letters line the inside."
flags_inv = HIDEFACE|HIDEHAIR|HIDEEARS
flags_cover = HEADCOVERSEYES
- armor = list(MELEE = 30, BULLET = 30, LASER = 20, ENERGY = 20, BOMB = 25, BIO = 10, RAD = 0, FIRE = 10, ACID = 10, STAMINA = 40)
+ armor = list(MELEE = 30, BULLET = 30, LASER = 20, ENERGY = 20, BOMB = 25, BIO = 10, RAD = 0, FIRE = 10, ACID = 10, STAMINA = 40, BLEED = 20)
cold_protection = HEAD
min_cold_protection_temperature = HELMET_MIN_TEMP_PROTECT
heat_protection = HEAD
@@ -153,7 +154,7 @@ Striking a noncultist, however, will tear their flesh."}
item_state = "cultrobes"
body_parts_covered = CHEST|GROIN|LEGS|ARMS
allowed = list(/obj/item/tome, /obj/item/melee/cultblade)
- armor = list(MELEE = 30, BULLET = 30, LASER = 20, ENERGY = 20, BOMB = 25, BIO = 10, RAD = 0, FIRE = 10, ACID = 10, STAMINA = 40)
+ armor = list(MELEE = 30, BULLET = 30, LASER = 20, ENERGY = 20, BOMB = 25, BIO = 10, RAD = 0, FIRE = 10, ACID = 10, STAMINA = 40, BLEED = 20)
flags_inv = HIDEJUMPSUIT
cold_protection = CHEST|GROIN|LEGS|ARMS
min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT
@@ -187,7 +188,7 @@ Striking a noncultist, however, will tear their flesh."}
item_state = null
desc = "A helm worn by the followers of Nar'Sie."
flags_inv = HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDEEARS|HIDEEYES|HIDESNOUT
- armor = list(MELEE = 50, BULLET = 30, LASER = 50, ENERGY = 20, BOMB = 25, BIO = 10, RAD = 0, FIRE = 10, ACID = 10, STAMINA = 50)
+ armor = list(MELEE = 50, BULLET = 30, LASER = 50, ENERGY = 20, BOMB = 25, BIO = 10, RAD = 0, FIRE = 10, ACID = 10, STAMINA = 50, BLEED = 50)
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
/obj/item/clothing/suit/magusred
@@ -199,7 +200,7 @@ Striking a noncultist, however, will tear their flesh."}
item_state = null
body_parts_covered = CHEST|GROIN|LEGS|ARMS
allowed = list(/obj/item/tome, /obj/item/melee/cultblade)
- armor = list(MELEE = 50, BULLET = 30, LASER = 50, ENERGY = 20, BOMB = 25, BIO = 10, RAD = 0, FIRE = 10, ACID = 10, STAMINA = 50)
+ armor = list(MELEE = 50, BULLET = 30, LASER = 50, ENERGY = 20, BOMB = 25, BIO = 10, RAD = 0, FIRE = 10, ACID = 10, STAMINA = 50, BLEED = 20)
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
/obj/item/sharpener/cult
@@ -220,7 +221,7 @@ Striking a noncultist, however, will tear their flesh."}
icon_state = "cult_armor"
item_state = null
w_class = WEIGHT_CLASS_BULKY
- armor = list(MELEE = 40, BULLET = 30, LASER = 40, ENERGY = 30, BOMB = 50, BIO = 30, RAD = 30, FIRE = 50, ACID = 60, STAMINA = 40)
+ armor = list(MELEE = 40, BULLET = 30, LASER = 40, ENERGY = 30, BOMB = 50, BIO = 30, RAD = 30, FIRE = 50, ACID = 60, STAMINA = 40, BLEED = 20)
hoodtype = /obj/item/clothing/head/hooded/cult_hoodie
/// if anyone can equip this. used by the prefs menu
var/allow_any = FALSE
@@ -228,10 +229,8 @@ Striking a noncultist, however, will tear their flesh."}
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/anyone
allow_any = TRUE
-/obj/item/clothing/suit/hooded/cultrobes/cult_shield/Initialize()
- . = ..()
- // note that these charges don't regenerate
- AddComponent(/datum/component/shielded, recharge_start_delay = 0, shield_icon_file = 'icons/effects/cult_effects.dmi', shield_icon = "shield-cult", run_hit_callback = CALLBACK(src, PROC_REF(shield_damaged)))
+/obj/item/clothing/suit/hooded/cultrobes/cult_shield/setup_shielding()
+ AddComponent(/datum/component/shielded, recharge_start_delay = 0 SECONDS, shield_icon_file = 'icons/effects/cult_effects.dmi', shield_icon = "shield-cult", run_hit_callback = CALLBACK(src, PROC_REF(shield_damaged)))
/// A proc for callback when the shield breaks, since cult robes are stupid and have different effects
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/proc/shield_damaged(mob/living/wearer, attack_text, new_current_charges)
@@ -244,7 +243,7 @@ Striking a noncultist, however, will tear their flesh."}
name = "empowered cultist helmet"
desc = "Empowered helmet which creates a powerful shield around the user."
icon_state = "cult_hoodalt"
- armor = list(MELEE = 40, BULLET = 30, LASER = 40, ENERGY = 30, BOMB = 50, BIO = 30, RAD = 30, FIRE = 50, ACID = 60, STAMINA = 40)
+ armor = list(MELEE = 40, BULLET = 30, LASER = 40, ENERGY = 30, BOMB = 50, BIO = 30, RAD = 30, FIRE = 50, ACID = 60, STAMINA = 40, BLEED = 20)
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/equipped(mob/living/user, slot)
..()
@@ -259,14 +258,14 @@ Striking a noncultist, however, will tear their flesh."}
name = "flagellant's robes"
desc = "Blood-soaked robes infused with dark magic; allows the user to move at inhuman speeds, but at the cost of reduced protection."
allowed = list(/obj/item/tome, /obj/item/melee/cultblade)
- armor = list(MELEE = 10, BULLET = 20, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 40)
+ armor = list(MELEE = 10, BULLET = 20, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 40, BLEED = 20)
slowdown = -0.4
hoodtype = /obj/item/clothing/head/hooded/cult_hoodie/berserkerhood
/obj/item/clothing/head/hooded/cult_hoodie/berserkerhood
name = "flagellant's hood"
desc = "Blood-soaked hood infused with dark magic."
- armor = list(MELEE = 10, BULLET = 20, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 40)
+ armor = list(MELEE = 10, BULLET = 20, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 40, BLEED = 20)
/obj/item/clothing/suit/hooded/cultrobes/berserker/equipped(mob/living/user, slot)
..()
@@ -325,7 +324,7 @@ Striking a noncultist, however, will tear their flesh."}
if(SSshuttle.emergency.mode == SHUTTLE_CALL)
var/cursetime = 1800
var/timer = SSshuttle.emergency.timeLeft(1) + cursetime
- var/security_num = seclevel2num(get_security_level())
+ var/security_num = SSsecurity_level.get_current_level_as_number()
var/set_coefficient = 1
switch(security_num)
if(SEC_LEVEL_GREEN)
@@ -479,6 +478,7 @@ Striking a noncultist, however, will tear their flesh."}
block_upgrade_walk = 1
attack_verb = list("attacked", "impaled", "stabbed", "tore", "gored")
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
hitsound = 'sound/weapons/bladeslice.ogg'
var/datum/action/innate/cult/spear/spear_act
diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm
index e2e4d257e83ea..33a8af9597a99 100644
--- a/code/modules/antagonists/cult/cult_structures.dm
+++ b/code/modules/antagonists/cult/cult_structures.dm
@@ -188,11 +188,13 @@
continue
new /obj/effect/temp_visual/heal(get_turf(src), "#960000")
if(ishuman(L))
+ var/mob/living/carbon/C = L
L.adjustBruteLoss(-5*delta_time, 0)
L.adjustFireLoss(-5*delta_time, 0)
L.updatehealth()
if(L.blood_volume < BLOOD_VOLUME_NORMAL)
- L.blood_volume += 1.0
+ L.blood_volume += 20
+ C.cauterise_wounds(1.4)
else if(isshade(L) || isconstruct(L))
var/mob/living/simple_animal/M = L
M.adjustHealth(-15*delta_time)
diff --git a/code/modules/antagonists/cult/narsie.dm b/code/modules/antagonists/cult/narsie.dm
index 3fd0470a5fd2d..73a3102022e85 100644
--- a/code/modules/antagonists/cult/narsie.dm
+++ b/code/modules/antagonists/cult/narsie.dm
@@ -206,7 +206,7 @@
sleep(500)
priority_announce("Simulations on acausal dimensional event complete. Deploying solution package now. Deployment ETA: ONE MINUTE. ", "Central Command Higher Dimensional Affairs", SSstation.announcer.get_rand_alert_sound())
sleep(50)
- set_security_level("delta")
+ SSsecurity_level.set_level(SEC_LEVEL_DELTA)
SSshuttle.registerHostileEnvironment(src)
sleep(600)
if(resolved == FALSE)
diff --git a/code/modules/antagonists/devil/true_devil/_true_devil.dm b/code/modules/antagonists/devil/true_devil/_true_devil.dm
index a89fb0c4f4a41..a149f946b06e8 100644
--- a/code/modules/antagonists/devil/true_devil/_true_devil.dm
+++ b/code/modules/antagonists/devil/true_devil/_true_devil.dm
@@ -18,8 +18,14 @@
spacewalk = TRUE
mob_size = MOB_SIZE_LARGE
held_items = list(null, null)
- bodyparts = list(/obj/item/bodypart/chest/devil, /obj/item/bodypart/head/devil, /obj/item/bodypart/l_arm/devil,
- /obj/item/bodypart/r_arm/devil, /obj/item/bodypart/r_leg/devil, /obj/item/bodypart/l_leg/devil)
+ bodyparts = list(
+ /obj/item/bodypart/chest/devil,
+ /obj/item/bodypart/head/devil,
+ /obj/item/bodypart/l_arm/devil,
+ /obj/item/bodypart/r_arm/devil,
+ /obj/item/bodypart/r_leg/devil,
+ /obj/item/bodypart/l_leg/devil
+ )
hud_type = /datum/hud/devil
var/ascended = FALSE
var/mob/living/oldform
@@ -53,7 +59,9 @@
real_name = name
/mob/living/carbon/true_devil/Login()
- ..()
+ . = ..()
+ if(!. || !client)
+ return FALSE
var/datum/antagonist/devil/devilinfo = mind.has_antag_datum(/datum/antagonist/devil)
devilinfo.greet()
mind.announce_objectives()
@@ -173,7 +181,7 @@
log_combat(M, src, "attacked", M)
updatehealth()
if ("disarm")
- if (!(mobility_flags & MOBILITY_STAND) && !ascended) //No stealing the arch devil's pitchfork.
+ if (body_position == LYING_DOWN && !ascended) //No stealing the arch devil's pitchfork.
if (prob(5))
Unconscious(40)
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
diff --git a/code/modules/antagonists/heretic/items/heretic_armor.dm b/code/modules/antagonists/heretic/items/heretic_armor.dm
index 717e474a3e934..35815ff66ae45 100644
--- a/code/modules/antagonists/heretic/items/heretic_armor.dm
+++ b/code/modules/antagonists/heretic/items/heretic_armor.dm
@@ -31,7 +31,7 @@
allowed = list(/obj/item/melee/sickly_blade)
hoodtype = /obj/item/clothing/head/hooded/cult_hoodie/eldritch
// Slightly better than normal cult robes
- armor = list(MELEE = 50, BULLET = 50, LASER = 50,ENERGY = 50, BOMB = 35, BIO = 20, RAD = 20, FIRE = 20, ACID = 20, STAMINA = 50)
+ armor = list(MELEE = 50, BULLET = 50, LASER = 50,ENERGY = 50, BOMB = 35, BIO = 20, RAD = 20, FIRE = 20, ACID = 20, STAMINA = 50, BLEED = 40)
/obj/item/clothing/suit/hooded/cultrobes/eldritch/examine(mob/user)
. = ..()
@@ -51,7 +51,7 @@
flags_cover = NONE
desc = "Black like tar and doesn't reflect any light. Runic symbols line the outside, with each flash you lose comprehension of what you are seeing."
item_flags = EXAMINE_SKIP
- armor = list(MELEE = 30, BULLET = 30, LASER = 30,ENERGY = 30, BOMB = 15, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 30)
+ armor = list(MELEE = 30, BULLET = 30, LASER = 30,ENERGY = 30, BOMB = 15, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 30, BLEED = 40)
/obj/item/clothing/head/hooded/cult_hoodie/void/Initialize(mapload)
. = ..()
@@ -66,7 +66,7 @@
hoodtype = /obj/item/clothing/head/hooded/cult_hoodie/void
flags_inv = NONE
// slightly worse than normal cult robes
- armor = list(MELEE = 30, BULLET = 30, LASER = 30,ENERGY = 30, BOMB = 15, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 30)
+ armor = list(MELEE = 30, BULLET = 30, LASER = 30,ENERGY = 30, BOMB = 15, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 30, BLEED = 40)
body_parts_covered = CHEST|GROIN|ARMS
pocket_storage_component_path = /datum/component/storage/concrete/pockets/void_cloak
qdel_hood = TRUE
diff --git a/code/modules/antagonists/heretic/items/heretic_blades.dm b/code/modules/antagonists/heretic/items/heretic_blades.dm
index 660da9582d9b3..0c908df48b41b 100644
--- a/code/modules/antagonists/heretic/items/heretic_blades.dm
+++ b/code/modules/antagonists/heretic/items/heretic_blades.dm
@@ -10,6 +10,7 @@
inhand_y_dimension = 64
flags_1 = CONDUCT_1
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
w_class = WEIGHT_CLASS_LARGE
force = 24
throwforce = 10
diff --git a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm
index e9f0fd6eb0255..32c5ebb716b1a 100644
--- a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm
@@ -306,7 +306,7 @@
return
var/mob/living/carbon/human/human_target = target
- human_target.bleed_rate += 5
+ human_target.add_bleeding(BLEED_DEEP_WOUND)
/datum/heretic_knowledge/summon/stalker
name = "Lonely Ritual"
diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm
index 025238b8cdf2f..b1defc3b27bc6 100644
--- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm
+++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm
@@ -32,7 +32,7 @@
/datum/status_effect/unholy_determination/tick()
// The amount we heal of each damage type per tick. If we're missing legs we heal better because we can't dodge.
- var/healing_amount = 1 + (2 - owner.get_num_legs())
+ var/healing_amount = 1 + (2 - owner.usable_legs)
// In softcrit you're, strong enough to stay up.
if(owner.health <= owner.crit_threshold && owner.health >= HEALTH_THRESHOLD_FULLCRIT)
diff --git a/code/modules/antagonists/heretic/knowledge/side_ash_flesh.dm b/code/modules/antagonists/heretic/knowledge/side_ash_flesh.dm
index 7715f45988a4f..b8cc3ee7df2f8 100644
--- a/code/modules/antagonists/heretic/knowledge/side_ash_flesh.dm
+++ b/code/modules/antagonists/heretic/knowledge/side_ash_flesh.dm
@@ -38,22 +38,25 @@
route = HERETIC_PATH_SIDE
/datum/heretic_knowledge/curse/paralysis/curse(mob/living/carbon/human/chosen_mob)
- if(chosen_mob.get_num_legs() <= 0) // What're you gonna do, curse someone who already can't walk?
+ if(chosen_mob.usable_legs <= 0) // What're you gonna do, curse someone who already can't walk?
to_chat(chosen_mob, "You feel a slight pain for a moment, but it passes shortly. Odd. ")
else
- to_chat(chosen_mob, "You suddenly lose feeling in your leg[chosen_mob.get_num_legs() == 1 ? "":"s"]! ")
+ to_chat(chosen_mob, "You suddenly lose feeling in your leg[chosen_mob.usable_legs == 1 ? "":"s"]! ")
ADD_TRAIT(chosen_mob, TRAIT_PARALYSIS_L_LEG, type)
ADD_TRAIT(chosen_mob, TRAIT_PARALYSIS_R_LEG, type)
/datum/heretic_knowledge/curse/paralysis/uncurse(mob/living/carbon/human/chosen_mob)
+ if(QDELETED(chosen_mob))
+ return
+
REMOVE_TRAIT(chosen_mob, TRAIT_PARALYSIS_L_LEG, type)
REMOVE_TRAIT(chosen_mob, TRAIT_PARALYSIS_R_LEG, type)
- if(chosen_mob.get_num_legs() <= 0) // What're you gonna do, curse someone who already can't walk?
+ if(chosen_mob.usable_legs <= 0) // What're you gonna do, curse someone who already can't walk?
to_chat(chosen_mob, "The slight pain returns, but disperses shortly. ")
else
- to_chat(chosen_mob, "You regain feeling in your leg[chosen_mob.get_num_legs() == 1 ? "":"s"]! ")
+ to_chat(chosen_mob, "You regain feeling in your leg[chosen_mob.usable_legs == 1 ? "":"s"]! ")
/datum/heretic_knowledge/summon/ashy
name = "Ashen Ritual"
diff --git a/code/modules/antagonists/heretic/magic/blood_cleave.dm b/code/modules/antagonists/heretic/magic/blood_cleave.dm
index 5d2550fe21f9f..c9597c5841c05 100644
--- a/code/modules/antagonists/heretic/magic/blood_cleave.dm
+++ b/code/modules/antagonists/heretic/magic/blood_cleave.dm
@@ -41,7 +41,7 @@
"Your veins burst from within and unholy flame erupts from your blood! "
)
- victim.bleed_rate += 5
+ victim.add_bleeding(BLEED_DEEP_WOUND)
victim.adjustFireLoss(20)
new /obj/effect/temp_visual/cleave(victim.drop_location())
diff --git a/code/modules/antagonists/heretic/structures/carving_knife.dm b/code/modules/antagonists/heretic/structures/carving_knife.dm
index e22f2d34eee68..070b1370df972 100644
--- a/code/modules/antagonists/heretic/structures/carving_knife.dm
+++ b/code/modules/antagonists/heretic/structures/carving_knife.dm
@@ -7,6 +7,7 @@
icon_state = "rune_carver"
flags_1 = CONDUCT_1
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
w_class = WEIGHT_CLASS_SMALL
force = 10
throwforce = 20
diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
index 9f79aaf5d78c7..1da124706b09f 100644
--- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
+++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
@@ -46,7 +46,7 @@
STOP_PROCESSING(SSobj, core)
update_icon()
AddElement(/datum/element/point_of_interest)
- previous_level = get_security_level()
+ previous_level = SSsecurity_level.get_current_level_as_text()
/obj/machinery/nuclearbomb/Destroy()
safety = FALSE
@@ -427,7 +427,7 @@
safety = !safety
if(safety)
if(timing)
- set_security_level(previous_level)
+ SSsecurity_level.set_level(previous_level)
stop_soundtrack_music(stop_playing = TRUE)
for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
S.switch_mode_to(initial(S.mode))
@@ -443,12 +443,12 @@
return
timing = !timing
if(timing)
- previous_level = get_security_level()
+ previous_level = SSsecurity_level.get_current_level_as_number()
detonation_timer = world.time + (timer_set * 10)
for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
S.switch_mode_to(TRACK_INFILTRATOR)
countdown.start()
- set_security_level(SEC_LEVEL_DELTA)
+ SSsecurity_level.set_level(SEC_LEVEL_DELTA)
if (proper_bomb) // Why does this exist
set_dynamic_high_impact_event("nuclear bomb has been armed")
@@ -456,7 +456,7 @@
else
detonation_timer = null
- set_security_level(previous_level)
+ SSsecurity_level.set_level(previous_level)
stop_soundtrack_music(stop_playing = TRUE)
for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
@@ -585,7 +585,7 @@
detonation_timer = null
exploding = FALSE
exploded = TRUE
- set_security_level(previous_level)
+ SSsecurity_level.set_level(previous_level)
for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
S.switch_mode_to(initial(S.mode))
S.alert = FALSE
@@ -654,7 +654,7 @@ This is here to make the tiles around the station mininuke change when it's arme
icon_state = "nucleardisk"
persistence_replacement = /obj/item/disk/nuclear/fake
max_integrity = 250
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/fake = FALSE
var/turf/lastlocation
diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm
index ec1ab12c6282b..696d00bbe2ee1 100644
--- a/code/modules/antagonists/revenant/revenant.dm
+++ b/code/modules/antagonists/revenant/revenant.dm
@@ -115,7 +115,9 @@
name = built_name
/mob/living/simple_animal/revenant/Login()
- ..()
+ . = ..()
+ if(!. || !client)
+ return FALSE
to_chat(src, "You are a revenant. ")
to_chat(src, "Your formerly mundane spirit has been infused with alien energies and empowered into a revenant. ")
to_chat(src, "You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds. ")
diff --git a/code/modules/antagonists/revenant/revenant_blight.dm b/code/modules/antagonists/revenant/revenant_blight.dm
index 5ac98e68db402..fd4c1bd5423f5 100644
--- a/code/modules/antagonists/revenant/revenant_blight.dm
+++ b/code/modules/antagonists/revenant/revenant_blight.dm
@@ -29,7 +29,7 @@
/datum/disease/revblight/stage_act()
..()
affected_mob.adjustStaminaLoss(1) //Provides gradual exhaustion, but mostly to prevent regeneration and set an upper limit on disease duration to about five minutes
- if(!(affected_mob.mobility_flags & MOBILITY_STAND))
+ if(affected_mob.body_position == LYING_DOWN)
if(HAS_TRAIT_FROM(affected_mob, TRAIT_INCAPACITATED, STAMINA) && !finalstage)
stage = 5
if(!startresting || restingat != get_turf(affected_mob))
diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm
index c3171ed781a2e..0bc77d033a1d8 100644
--- a/code/modules/antagonists/revolution/revolution.dm
+++ b/code/modules/antagonists/revolution/revolution.dm
@@ -12,9 +12,6 @@
var/hud_type = "rev"
var/datum/team/revolution/rev_team
- /// What message should the player receive when they are being demoted, and the revolution has won?
- var/victory_message = "The revolution has overpowered the command staff! Viva la revolution! Execute any head of staff and security should you find them alive."
-
/datum/antagonist/rev/can_be_owned(datum/mind/new_owner)
. = ..()
if(.)
@@ -49,10 +46,10 @@
. = ..()
/datum/antagonist/rev/greet()
- to_chat(owner, "You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution! ")
+ to_chat(owner, "You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Establish a new command structure for the station that will bring fairness to all. ")
owner.announce_objectives()
owner.current.client?.tgui_panel?.give_antagonist_popup("Revolution",
- "Eliminate the heads of staff. Viva la revolution!")
+ "Establish a new command structure to live a better life. Viva la revolution!")
/datum/antagonist/rev/create_team(datum/team/revolution/new_team)
if(!new_team)
@@ -212,38 +209,19 @@
new_rev.silent = FALSE
to_chat(old_owner, "Revolution has been disappointed of your leader traits! You are a regular revolutionary now! ")
-/// Checks if the revolution succeeded, and lets them know.
-/datum/antagonist/rev/proc/announce_victorious()
- . = rev_team.check_rev_victory()
-
- if (!.)
- return
-
- to_chat(owner, "[victory_message] ")
-
/datum/antagonist/rev/farewell()
- if (announce_victorious())
- return
-
if(ishuman(owner.current))
- owner.current.visible_message("[owner.current] looks like [owner.current.p_theyve()] just remembered [owner.current.p_their()] real allegiance! ", null, null, null, owner.current)
to_chat(owner, "You are no longer a brainwashed revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you... ")
else if(issilicon(owner.current))
- owner.current.visible_message("The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it. ", null, null, null, owner.current)
to_chat(owner, "The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you. ")
/datum/antagonist/rev/head/farewell()
- if (announce_victorious())
- return
-
if((ishuman(owner.current)))
if(owner.current.stat != DEAD)
- owner.current.visible_message("[owner.current] looks like [owner.current.p_theyve()] just remembered [owner.current.p_their()] real allegiance! ", null, null, null, owner.current)
to_chat(owner, "You have given up your cause of overthrowing the command staff. You are no longer a Head Revolutionary. ")
else
to_chat(owner, "The sweet release of death. You are no longer a Head Revolutionary. ")
else if(issilicon(owner.current))
- owner.current.visible_message("The frame beeps contentedly, suppressing the disloyal personality traits from the MMI before initalizing it. ", null, null, null, owner.current)
to_chat(owner, "The frame's firmware detects and suppresses your unwanted personality traits! You feel more content with the leadership around these parts. ")
//blunt trauma deconversions call this through species.dm spec_attacked_by()
@@ -287,22 +265,6 @@
S.Insert(H, special = FALSE, drop_if_replaced = FALSE)
to_chat(H, "Your eyes have been implanted with a cybernetic security HUD which will help you keep track of who is mindshield-implanted, and therefore unable to be recruited.")
-/// "Enemy of the Revolutionary", given to heads and security when the revolution wins
-/datum/antagonist/revolution_enemy
- name = "Enemy of the Revolution"
- show_in_antagpanel = FALSE
- banning_key = UNBANNABLE_ANTAGONIST
-
-/datum/antagonist/revolution_enemy/on_gain()
- owner.special_role = "revolution enemy"
-
- var/datum/objective/survive/survive = new /datum/objective/survive
- survive.owner = owner
- survive.explanation_text = "The station has been overrun by revolutionaries, stay alive until the end."
- objectives += survive
-
- return ..()
-
/datum/team/revolution
name = "Revolution"
var/max_headrevs = 3
@@ -310,15 +272,8 @@
var/list/ex_revs = list()
/datum/team/revolution/proc/update_objectives(initial = FALSE)
- var/untracked_heads = SSjob.get_all_heads()
- for(var/datum/objective/mutiny/O in objectives)
- untracked_heads -= O.target
- for(var/datum/mind/M in untracked_heads)
- var/datum/objective/mutiny/new_target = new()
- new_target.team = src
- new_target.set_target(M)
- new_target.update_explanation_text()
- objectives += new_target
+ if (!objectives)
+ objectives += new /datum/objective/revolution()
for(var/datum/mind/M in members)
var/datum/antagonist/rev/R = M.has_antag_datum(/datum/antagonist/rev)
R.objectives |= objectives
@@ -359,15 +314,13 @@
addtimer(CALLBACK(src,PROC_REF(update_heads)),HEAD_UPDATE_PERIOD,TIMER_UNIQUE)
-/datum/team/revolution/proc/save_members()
- ex_headrevs = get_antag_minds(/datum/antagonist/rev/head, TRUE)
- ex_revs = get_antag_minds(/datum/antagonist/rev, TRUE)
-
/// Checks if revs have won
/datum/team/revolution/proc/check_rev_victory()
- for(var/datum/objective/mutiny/objective in objectives)
- if(!(objective.check_completion()))
- return FALSE
+ for(var/datum/mind/staff_mind in SSjob.get_all_heads())
+ var/turf/location = get_turf(staff_mind.current)
+ if(!considered_afk(staff_mind) && considered_alive(staff_mind) && is_station_level(location.z))
+ if(ishuman(staff_mind.current))
+ return FALSE
return TRUE
/// Checks if heads have won
@@ -384,69 +337,9 @@
/// If revs_win_injection_amount is passed, then that amount of threat will be added if the revs win.
/datum/team/revolution/proc/process_victory(revs_win_injection_amount)
if (check_rev_victory())
- . = REVOLUTION_VICTORY
+ return REVOLUTION_VICTORY
else if (check_heads_victory())
- . = STATION_VICTORY
- else
- return
-
- SSshuttle.clearHostileEnvironment(src)
- save_members()
-
- // Remove everyone as a revolutionary
- for (var/_rev_mind in members)
- var/datum/mind/rev_mind = _rev_mind
- if (rev_mind.has_antag_datum(/datum/antagonist/rev))
- var/datum/antagonist/rev/rev_antag = rev_mind.has_antag_datum(/datum/antagonist/rev)
- rev_antag.remove_revolutionary(FALSE, . == STATION_VICTORY ? DECONVERTER_STATION_WIN : DECONVERTER_REVS_WIN)
- LAZYADD(rev_mind.special_statuses, "Former [(rev_mind in ex_headrevs) ? "head revolutionary" : "revolutionary"] ")
-
- if (. == STATION_VICTORY)
- // If the revolution was quelled, make rev heads unable to be revived through pods
- for (var/_rev_head_mind in ex_revs)
- var/datum/mind/rev_head_mind = _rev_head_mind
- var/mob/living/carbon/rev_head_body = rev_head_mind.current
- if(istype(rev_head_body) && rev_head_body.stat == DEAD)
- rev_head_body.makeUncloneable()
-
- priority_announce("It appears the mutiny has been quelled. Please return yourself and your incapacitated colleagues to work. \
- We have remotely blacklisted the head revolutionaries in your medical records to prevent accidental revival.", null, SSstation.announcer.get_rand_report_sound(), null, "Central Command Loyalty Monitoring Division")
- else
- for (var/_player in GLOB.player_list)
- var/mob/player = _player
- var/datum/mind/mind = player.mind
-
- if (isnull(mind))
- continue
-
- if (!(mind.assigned_role in GLOB.command_positions + GLOB.security_positions))
- continue
-
- var/mob/living/carbon/target_body = mind.current
-
- mind.add_antag_datum(/datum/antagonist/revolution_enemy)
-
- if (!istype(target_body))
- continue
-
- if (target_body.stat == DEAD)
- target_body.makeUncloneable()
- else
- mind.announce_objectives()
-
- for (var/job_name in GLOB.command_positions + GLOB.security_positions)
- var/datum/job/job = SSjob.GetJob(job_name)
- job.allow_bureaucratic_error = FALSE
- job.total_positions = 0
-
- if (revs_win_injection_amount)
- var/datum/game_mode/dynamic/dynamic = SSticker.mode
- dynamic.unfavorable_situation()
-
- priority_announce("A recent assessment of your station has marked your station as a severe risk area for high ranking Nanotrasen officials. \
- For the safety of our staff, we have blacklisted your station for new employment of security and command. \
- [pick(world.file2list("strings/anti_union_propaganda.txt"))]", null, SSstation.announcer.get_rand_report_sound(), null, "Central Command Loyalty Monitoring Division")
- addtimer(CALLBACK(SSshuttle.emergency, TYPE_PROC_REF(/obj/docking_port/mobile/emergency, request), null, 1), 50)
+ return STATION_VICTORY
/// Mutates the ticker to report that the revs have won
/datum/team/revolution/proc/round_result(finished)
@@ -456,6 +349,9 @@
else if (finished == STATION_VICTORY)
SSticker.mode_result = "loss - rev heads killed"
SSticker.news_report = REVS_LOSE
+ else
+ SSticker.mode_result = "minor win - station forced to be abandoned"
+ SSticker.news_report = STATION_EVACUATED
/datum/team/revolution/roundend_report()
if(!members.len && !ex_headrevs.len)
@@ -552,5 +448,12 @@
/datum/team/revolution/is_gamemode_hero()
return SSticker.mode.name == "revolution"
+/datum/objective/revolution
+ name = "revolution"
+ explanation_text = "Establish a new chain of command by throwing out the old heads of staff and promoting new ones."
+
+/datum/objective/revolution/get_completion_message()
+ return "[explanation_text]"
+
#undef DECONVERTER_STATION_WIN
#undef DECONVERTER_REVS_WIN
diff --git a/code/modules/antagonists/role_preference/role_antagonists.dm b/code/modules/antagonists/role_preference/role_antagonists.dm
index d5a24a49f900f..07f1b18a58bc0 100644
--- a/code/modules/antagonists/role_preference/role_antagonists.dm
+++ b/code/modules/antagonists/role_preference/role_antagonists.dm
@@ -368,7 +368,7 @@
/datum/outfit/nuclear_operative
name = "Nuclear Operative (Preview only)"
- suit = /obj/item/clothing/suit/space/hardsuit/syndi
+ suit = /obj/item/clothing/suit/space/hardsuit/syndipreview
head = /obj/item/clothing/head/helmet/space/hardsuit/syndi
/datum/role_preference/antagonist/wizard
diff --git a/code/modules/antagonists/role_preference/role_midrounds.dm b/code/modules/antagonists/role_preference/role_midrounds.dm
index cf7f35082f362..806ba77182bd0 100644
--- a/code/modules/antagonists/role_preference/role_midrounds.dm
+++ b/code/modules/antagonists/role_preference/role_midrounds.dm
@@ -127,7 +127,7 @@
/datum/outfit/pirate_space_preview
name = "Space Pirate (Preview only)"
uniform = /obj/item/clothing/under/costume/pirate
- suit = /obj/item/clothing/suit/space/pirate
+ suit = /obj/item/clothing/suit/costume/pirate
head = /obj/item/clothing/head/helmet/space/pirate/bandana
glasses = /obj/item/clothing/glasses/eyepatch
diff --git a/code/modules/antagonists/space_dragon/carp_rift.dm b/code/modules/antagonists/space_dragon/carp_rift.dm
index 2b661ae86a07a..c16d71bd6d90f 100644
--- a/code/modules/antagonists/space_dragon/carp_rift.dm
+++ b/code/modules/antagonists/space_dragon/carp_rift.dm
@@ -60,7 +60,7 @@
/obj/structure/carp_rift
name = "carp rift"
desc = "A rift akin to the ones space carp use to travel long distances."
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
max_integrity = 300
icon = 'icons/obj/carp_rift.dmi'
icon_state = "carp_rift_carpspawn"
diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm
index 748478204e4bb..cbb89d8abde64 100644
--- a/code/modules/antagonists/swarmer/swarmer.dm
+++ b/code/modules/antagonists/swarmer/swarmer.dm
@@ -195,9 +195,9 @@
return 0
/obj/item/IntegrateAmount() //returns the amount of resources gained when eating this item
- if(custom_materials)
- if(custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)] || custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)])
- return 1
+ var/list/mats = get_material_composition(ALL) // Ensures that items made from plasteel, and plas/titanium/plastitaniumglass get integrated correctly.
+ if(length(mats) && (mats[SSmaterials.GetMaterialRef(/datum/material/iron)] || mats[SSmaterials.GetMaterialRef(/datum/material/glass)]))
+ return 1
return ..()
/obj/item/gun/swarmer_act()//Stops you from eating the entire armory
diff --git a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm
index 3332b7e412fc1..c9a15ce60686e 100644
--- a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm
+++ b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm
@@ -326,7 +326,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
if(!owner || QDELETED(owner))
return
priority_announce("Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.", "Anomaly Alert", ANNOUNCER_AIMALF)
- set_security_level("delta")
+ SSsecurity_level.set_level(SEC_LEVEL_DELTA)
owner.log_message("activated malf module [name]", LOG_GAME)
var/obj/machinery/doomsday_device/DOOM = new(owner_AI)
owner_AI.nuking = TRUE
@@ -424,7 +424,6 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/datum/AI_Module/large/upgrade_turrets/upgrade(mob/living/silicon/ai/AI)
for(var/obj/machinery/porta_turret/ai/turret in GLOB.machines)
turret.max_integrity = 200
- turret.obj_integrity = 200
turret.emp_proofing = TRUE
turret.AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES | EMP_PROTECT_CONTENTS)
turret.stun_projectile = /obj/projectile/beam/disabler/pass_glass //// AI defenses are often built with glass, so this is big.
diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm
index 494bcf7d613dc..b90cc238e660f 100644
--- a/code/modules/antagonists/wizard/equipment/artefact.dm
+++ b/code/modules/antagonists/wizard/equipment/artefact.dm
@@ -462,7 +462,6 @@
user.invisibility = initial(user.invisibility)
user.status_flags &= ~GODMODE
REMOVE_TRAIT(user, TRAIT_IMMOBILIZED, WARPWHISTLE_TRAIT)
- user.update_mobility()
/obj/item/warpwhistle/attack_self(mob/living/carbon/user)
if(!istype(user) || on_cooldown)
diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm
index fd338255106c6..411269dfffb60 100644
--- a/code/modules/antagonists/wizard/equipment/soulstone.dm
+++ b/code/modules/antagonists/wizard/equipment/soulstone.dm
@@ -72,7 +72,8 @@
if(istype(S))
// Things that *really should always* happen to the shade when it comes out should go here.
S.status_flags &= ~GODMODE
- S.mobility_flags = MOBILITY_FLAGS_DEFAULT
+ REMOVE_TRAIT(S, TRAIT_IMMOBILIZED, SOULSTONE_TRAIT)
+ REMOVE_TRAIT(S, TRAIT_HANDS_BLOCKED, SOULSTONE_TRAIT)
S.cancel_camera()
if(theme == THEME_HOLY)
S.icon_state = "shade_angelic"
@@ -346,7 +347,8 @@
T.dust_animation()
var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade(src)
S.status_flags |= GODMODE //So they won't die inside the stone somehow
- S.mobility_flags = NONE //Can't move out of the soul stone
+ ADD_TRAIT(S, TRAIT_IMMOBILIZED, SOULSTONE_TRAIT)
+ ADD_TRAIT(S, TRAIT_HANDS_BLOCKED, SOULSTONE_TRAIT)
S.name = "Shade of [T.real_name]"
S.real_name = "Shade of [T.real_name]"
S.key = shade_controller.key
diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm
index 804c52dda0ec4..33004949966fd 100644
--- a/code/modules/assembly/flash.dm
+++ b/code/modules/assembly/flash.dm
@@ -255,7 +255,7 @@
to_chat(M, "You are blinded by [src]! ")
//Will be 0 if the user has no stmaina loss, will be 1 if they are in stamcrit
var/flash_proportion = CLAMP01(M.getStaminaLoss() / (M.maxHealth - M.crit_threshold))
- if (!(M.mobility_flags & MOBILITY_STAND))
+ if (M.body_position == LYING_DOWN)
flash_proportion = 1
if(flash_proportion > 0.4)
M.Paralyze(70 * flash_proportion)
diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm
index 4471fbe27ba25..ceb6c37234717 100644
--- a/code/modules/assembly/signaler.dm
+++ b/code/modules/assembly/signaler.dm
@@ -252,6 +252,12 @@
icon_state = "hallucination_core"
anomaly_type = /obj/effect/anomaly/hallucination
+/obj/item/assembly/signaler/anomaly/blood
+ name = "\improper blood anomaly core"
+ desc = "The neutralized core of a blood anomaly. You feel your blood running through your veins when you are around it. It'd probably be valuable for research."
+ icon_state = "hallucination_core"
+ anomaly_type = /obj/effect/anomaly/blood
+
/obj/item/assembly/signaler/anomaly/attack_self()
return
diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm
index 476f6a1fb717e..a3158f5a33ae6 100644
--- a/code/modules/atmospherics/environmental/LINDA_fire.dm
+++ b/code/modules/atmospherics/environmental/LINDA_fire.dm
@@ -234,9 +234,4 @@
/obj/effect/hotspot/singularity_pull()
return
-/obj/effect/dummy/lighting_obj/moblight/fire
- name = "fire"
- light_color = LIGHT_COLOR_FIRE
- light_range = LIGHT_RANGE_FIRE
-
#undef INSUFFICIENT
diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm
index c72272eea7584..f02f560c3ab11 100644
--- a/code/modules/atmospherics/machinery/airalarm.dm
+++ b/code/modules/atmospherics/machinery/airalarm.dm
@@ -44,6 +44,7 @@
icon = 'icons/obj/monitors.dmi'
icon_state = "alarm_bitem"
result_path = /obj/machinery/airalarm
+ pixel_shift = 24
#define AALARM_MODE_SCRUBBING 1
#define AALARM_MODE_VENTING 2 //makes draught
@@ -61,7 +62,7 @@
name = "air alarm"
desc = "A machine that monitors atmosphere levels and alerts if the area is dangerous."
icon = 'icons/obj/monitors.dmi'
- icon_state = "alarm0"
+ icon_state = "alarmp"
use_power = IDLE_POWER_USE
idle_power_usage = 4
active_power_usage = 8
@@ -69,7 +70,7 @@
req_access = list(ACCESS_ATMOSPHERICS)
max_integrity = 250
integrity_failure = 0.33
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 90, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 90, ACID = 30, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
clicksound = 'sound/machines/terminal_select.ogg'
layer = ABOVE_WINDOW_LAYER
@@ -170,21 +171,7 @@
/obj/machinery/airalarm/away //general away mission access
req_access = list(ACCESS_AWAY_GENERAL)
-/obj/machinery/airalarm/directional/north //Pixel offsets get overwritten on New()
- dir = SOUTH
- pixel_y = 24
-
-/obj/machinery/airalarm/directional/south
- dir = NORTH
- pixel_y = -24
-
-/obj/machinery/airalarm/directional/east
- dir = WEST
- pixel_x = 24
-
-/obj/machinery/airalarm/directional/west
- dir = EAST
- pixel_x = -24
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/airalarm, 24)
//all air alarms in area are connected via magic
/area
@@ -202,8 +189,6 @@
if(nbuild)
buildstage = 0
panel_open = TRUE
- pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
- pixel_y = (dir & 3)? (dir == 1 ? -24 : 24) : 0
if(name == initial(name))
name = "[get_area_name(src)] Air Alarm"
@@ -619,7 +604,26 @@
"set_internal_pressure" = 0
), signal_source)
-/obj/machinery/airalarm/update_icon()
+/obj/machinery/airalarm/update_appearance(updates)
+ . = ..()
+
+ if(panel_open || (machine_stat & (NOPOWER|BROKEN)) || shorted)
+ set_light(0)
+ return
+
+ var/area/our_area = get_area(src)
+ var/color
+ switch(max(danger_level, !!our_area.active_alarms[ALARM_ATMOS]))
+ if(0)
+ color = "#03A728" // green
+ if(1)
+ color = "#EC8B2F" // yellow
+ if(2)
+ color = "#DA0205" // red
+
+ set_light(1.4, 1, color)
+
+/obj/machinery/airalarm/update_icon_state()
if(panel_open)
switch(buildstage)
if(2)
@@ -628,20 +632,29 @@
icon_state = "alarm_b2"
if(0)
icon_state = "alarm_b1"
- return
+ return ..()
+
+ icon_state = "alarmp"
+ return ..()
+
+/obj/machinery/airalarm/update_overlays()
+ . = ..()
if((machine_stat & (NOPOWER|BROKEN)) || shorted)
- icon_state = "alarmp"
return
var/area/our_area = get_area(src)
+ var/state
switch(max(danger_level, !!our_area.active_alarms[ALARM_ATMOS]))
if(0)
- icon_state = "alarm0"
+ state = "alarm0"
if(1)
- icon_state = "alarm2" //yes, alarm2 is yellow alarm
+ state = "alarm2" //yes, alarm2 is yellow alarm
if(2)
- icon_state = "alarm1"
+ state = "alarm1"
+
+ . += mutable_appearance(icon, state)
+ . += emissive_appearance(icon, state, alpha = src.alpha)
/obj/machinery/airalarm/process()
if((machine_stat & (NOPOWER|BROKEN)) || shorted)
@@ -852,7 +865,7 @@
new /obj/item/stack/sheet/iron(loc, 2)
var/obj/item/I = new /obj/item/electronics/airalarm(loc)
if(!disassembled)
- I.obj_integrity = I.max_integrity * 0.5
+ I.take_damage(I.max_integrity * 0.5, sound_effect=FALSE)
new /obj/item/stack/cable_coil(loc, 3)
qdel(src)
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index f91b1b04431a8..6ca21c506f8a7 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -57,7 +57,7 @@
normalize_cardinal_directions()
nodes = new(device_type)
if (!armor)
- armor = list(MELEE = 25, BULLET = 10, LASER = 10, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 100, ACID = 70, STAMINA = 0)
+ armor = list(MELEE = 25, BULLET = 10, LASER = 10, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 100, ACID = 70, STAMINA = 0, BLEED = 0)
..()
if(process)
SSair.start_processing_machine(src)
@@ -249,7 +249,7 @@
var/obj/item/pipe/stored = new construction_type(loc, null, dir, src)
stored.setPipingLayer(piping_layer)
if(!disassembled)
- stored.obj_integrity = stored.max_integrity * 0.5
+ stored.take_damage(stored.max_integrity * 0.5, sound_effect=FALSE)
transfer_fingerprints_to(stored)
. = stored
..()
@@ -312,7 +312,7 @@
if(pipenetdiff.len)
user.update_pipe_vision(target_move)
user.forceMove(target_move)
- user.client.eye = target_move //Byond only updates the eye every tick, This smooths out the movement
+ user.client.set_eye(target_move) //Byond only updates the eye every tick, This smooths out the movement
if(world.time - user.last_played_vent > VENT_SOUND_DELAY)
user.last_played_vent = world.time
playsound(src, 'sound/machines/ventcrawl.ogg', 50, 1, -3)
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
index 5c20e4d4fe45a..3ef275765c9ce 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
@@ -8,7 +8,7 @@
icon_state = "pod-off"
density = TRUE
max_integrity = 350
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 30, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 30, ACID = 30, STAMINA = 0, BLEED = 0)
layer = ABOVE_WINDOW_LAYER
state_open = FALSE
circuit = /obj/item/circuitboard/machine/cryo_tube
@@ -261,7 +261,7 @@
update_parents()
-/obj/machinery/atmospherics/components/unary/cryo_cell/relaymove(mob/user)
+/obj/machinery/atmospherics/components/unary/cryo_cell/relaymove(mob/living/user, direction)
if(message_cooldown <= world.time)
message_cooldown = world.time + 50
to_chat(user, "[src]'s door won't budge! ")
@@ -271,9 +271,6 @@
on = FALSE
for(var/mob/M in contents) //only drop mobs
M.forceMove(get_turf(src))
- if(isliving(M))
- var/mob/living/L = M
- L.update_mobility()
set_occupant(null)
flick("pod-open-anim", src)
..()
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
index 41e2ce70afe5e..e7e7c4650972b 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
@@ -7,7 +7,7 @@
density = TRUE
max_integrity = 300
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 80, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 80, ACID = 30, STAMINA = 0, BLEED = 0)
layer = OBJ_LAYER
circuit = /obj/item/circuitboard/machine/thermomachine
diff --git a/code/modules/atmospherics/machinery/other/meter.dm b/code/modules/atmospherics/machinery/other/meter.dm
index 9781ad4a96a64..24d3e44239728 100644
--- a/code/modules/atmospherics/machinery/other/meter.dm
+++ b/code/modules/atmospherics/machinery/other/meter.dm
@@ -9,7 +9,7 @@
idle_power_usage = 2
active_power_usage = 4
max_integrity = 150
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 40, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 40, ACID = 0, STAMINA = 0, BLEED = 0)
var/frequency = 0
var/atom/target
var/target_layer = PIPING_LAYER_DEFAULT
diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm
index c03e608a92018..b0070488a00af 100644
--- a/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm
+++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm
@@ -2,7 +2,7 @@
var/minimum_temperature_difference = 1
var/thermal_conductivity = WINDOW_HEAT_TRANSFER_COEFFICIENT
color = "#404040"
- buckle_lying = -1
+ buckle_lying = NO_BUCKLE_LYING
var/icon_temperature = T20C //stop small changes in temperature causing icon refresh
resistance_flags = LAVA_PROOF | FIRE_PROOF
hide = TRUE
diff --git a/code/modules/atmospherics/machinery/pipes/layermanifold.dm b/code/modules/atmospherics/machinery/pipes/layermanifold.dm
index d01b60d5b508a..d0473acdaab3d 100644
--- a/code/modules/atmospherics/machinery/pipes/layermanifold.dm
+++ b/code/modules/atmospherics/machinery/pipes/layermanifold.dm
@@ -129,16 +129,15 @@
back_nodes[i] = null
update_appearance()
-/obj/machinery/atmospherics/pipe/layer_manifold/relaymove(mob/living/user, dir)
- if(initialize_directions & dir)
+/obj/machinery/atmospherics/pipe/layer_manifold/relaymove(mob/living/user, direction)
+ if(initialize_directions & direction)
return ..()
- if((NORTH|EAST) & dir)
+ if((NORTH|EAST) & direction)
user.ventcrawl_layer = clamp(user.ventcrawl_layer + 1, PIPING_LAYER_MIN, PIPING_LAYER_MAX)
- if((SOUTH|WEST) & dir)
+ if((SOUTH|WEST) & direction)
user.ventcrawl_layer = clamp(user.ventcrawl_layer - 1, PIPING_LAYER_MIN, PIPING_LAYER_MAX)
to_chat(user, "You align yourself with the [user.ventcrawl_layer]\th output.")
/obj/machinery/atmospherics/pipe/layer_manifold/visible
hide = FALSE
layer = GAS_PIPE_VISIBLE_LAYER
- hide = FALSE
diff --git a/code/modules/atmospherics/machinery/pipes/mapping.dm b/code/modules/atmospherics/machinery/pipes/mapping.dm
index cafb0053ce1b3..1be896d3882c6 100644
--- a/code/modules/atmospherics/machinery/pipes/mapping.dm
+++ b/code/modules/atmospherics/machinery/pipes/mapping.dm
@@ -18,6 +18,14 @@
piping_layer = 4; \
icon_state = Iconbase + "-4"; \
} \
+ ##Fulltype/visible/layer1 { \
+ piping_layer = 1; \
+ icon_state = Iconbase + "-1"; \
+ } \
+ ##Fulltype/visible/layer5 { \
+ piping_layer = 5; \
+ icon_state = Iconbase + "-5"; \
+ } \
##Fulltype/hidden { \
hide = TRUE; \
} \
@@ -28,6 +36,14 @@
##Fulltype/hidden/layer4 { \
piping_layer = 4; \
icon_state = Iconbase + "-4"; \
+ } \
+ ##Fulltype/hidden/layer1 { \
+ piping_layer = 1; \
+ icon_state = Iconbase + "-1"; \
+ } \
+ ##Fulltype/hidden/layer5 { \
+ piping_layer = 5; \
+ icon_state = Iconbase + "-5"; \
}
#define HELPER_PARTIAL_NAMED(Fulltype, Type, Iconbase, Color, Name) \
@@ -39,12 +55,14 @@
#define HELPER(Type, Color) \
HELPER_PARTIAL(/obj/machinery/atmospherics/pipe/simple/##Type, #Type, "pipe11", Color) \
HELPER_PARTIAL(/obj/machinery/atmospherics/pipe/manifold/##Type, #Type, "manifold", Color) \
- HELPER_PARTIAL(/obj/machinery/atmospherics/pipe/manifold4w/##Type, #Type, "manifold4w", Color)
+ HELPER_PARTIAL(/obj/machinery/atmospherics/pipe/manifold4w/##Type, #Type, "manifold4w", Color) \
+ HELPER_PARTIAL(/obj/effect/mapping_helpers/simple_pipes/##Type, #Type, "pipe", Color)
#define HELPER_NAMED(Type, Name, Color) \
HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/pipe/simple/##Type, #Type, "pipe11", Color, Name) \
HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/pipe/manifold/##Type, #Type, "manifold", Color, Name) \
- HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/pipe/manifold4w/##Type, #Type, "manifold4w", Color, Name)
+ HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/pipe/manifold4w/##Type, #Type, "manifold4w", Color, Name) \
+ HELPER_PARTIAL_NAMED(/obj/effect/mapping_helpers/simple_pipes/##Type, #Type, "pipe", Color, Name)
HELPER(general, null)
HELPER(yellow, rgb(255, 198, 0))
diff --git a/code/modules/atmospherics/machinery/pipes/pipes.dm b/code/modules/atmospherics/machinery/pipes/pipes.dm
index 4ace48b93e9cf..1258f5504392b 100644
--- a/code/modules/atmospherics/machinery/pipes/pipes.dm
+++ b/code/modules/atmospherics/machinery/pipes/pipes.dm
@@ -10,13 +10,13 @@
//Buckling
can_buckle = 1
buckle_requires_restraints = 1
- buckle_lying = -1
+ buckle_lying = NO_BUCKLE_LYING
FASTDMM_PROP(\
set_instance_vars(\
icon_state = INSTANCE_VAR_DEFAULT\
- ),\
- )
+ ),\
+ )
/obj/machinery/atmospherics/pipe/New()
add_atom_colour(pipe_color, FIXED_COLOUR_PRIORITY)
diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm
index 463ef5df40d75..d828301a6a128 100644
--- a/code/modules/atmospherics/machinery/portable/canister.dm
+++ b/code/modules/atmospherics/machinery/portable/canister.dm
@@ -9,7 +9,7 @@
greyscale_colors = "#ffff00#000000"
density = TRUE
volume = 1000
- armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 10, BIO = 100, RAD = 100, FIRE = 80, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 10, BIO = 100, RAD = 100, FIRE = 80, ACID = 50, STAMINA = 0, BLEED = 0)
max_integrity = 250
integrity_failure = 0.4
pressure_resistance = 7 * ONE_ATMOSPHERE
diff --git a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
index 0e9d101d8b382..36f8f066a4066 100644
--- a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
+++ b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
@@ -3,7 +3,7 @@
icon = 'icons/obj/atmos.dmi'
use_power = NO_POWER_USE
max_integrity = 250
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 60, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 60, ACID = 30, STAMINA = 0, BLEED = 0)
anchored = FALSE
interacts_with_air = TRUE
diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm
index 19bd2559278a8..556863d9f45a8 100644
--- a/code/modules/awaymissions/capture_the_flag.dm
+++ b/code/modules/awaymissions/capture_the_flag.dm
@@ -424,7 +424,7 @@
continue
if(isstructure(atm))
var/obj/structure/S = atm
- S.obj_integrity = S.max_integrity
+ S.repair_damage(S.max_integrity - S.get_integrity())
else if(!is_type_in_typecache(atm, ctf_object_typecache))
qdel(atm)
@@ -568,7 +568,7 @@
name = "CTF"
ears = /obj/item/radio/headset
uniform = /obj/item/clothing/under/syndicate
- suit = /obj/item/clothing/suit/space/hardsuit/shielded/ctf
+ suit = /obj/item/clothing/suit/armor/vest/ctf
toggle_helmet = FALSE // see the whites of their eyes
shoes = /obj/item/clothing/shoes/combat
gloves = /obj/item/clothing/gloves/combat
@@ -601,7 +601,7 @@
shoes = /obj/item/clothing/shoes/jackboots/fast
/datum/outfit/ctf/red
- suit = /obj/item/clothing/suit/space/hardsuit/shielded/ctf/red
+ suit = /obj/item/clothing/suit/armor/vest/ctf/red
r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/red
l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/red
r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/red
@@ -611,7 +611,7 @@
shoes = /obj/item/clothing/shoes/jackboots/fast
/datum/outfit/ctf/blue
- suit = /obj/item/clothing/suit/space/hardsuit/shielded/ctf/blue
+ suit = /obj/item/clothing/suit/armor/vest/ctf/blue
r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/blue
l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/blue
r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/blue
diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm
index c332b6e0d1ce2..307a09807e2dc 100644
--- a/code/modules/awaymissions/corpse.dm
+++ b/code/modules/awaymissions/corpse.dm
@@ -472,7 +472,7 @@
/datum/outfit/nanotrasenbridgeofficercorpse
name = "Bridge Officer Corpse"
ears = /obj/item/radio/headset/heads/head_of_personnel
- uniform = /obj/item/clothing/under/rank/centcom/officer
+ uniform = /obj/item/clothing/under/rank/centcom/official
suit = /obj/item/clothing/suit/armor/bulletproof
shoes = /obj/item/clothing/shoes/sneakers/black
glasses = /obj/item/clothing/glasses/sunglasses/advanced
diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm
index df8eade196a78..0ff32fdc3e236 100644
--- a/code/modules/awaymissions/mission_code/snowdin.dm
+++ b/code/modules/awaymissions/mission_code/snowdin.dm
@@ -187,9 +187,7 @@
if("snow" in L.weather_immunities)
continue
- var/buckle_check = L.buckling
- if(!buckle_check)
- buckle_check = L.buckled
+ var/buckle_check = L.buckled
if(isobj(buckle_check))
var/obj/O = buckle_check
if(O.resistance_flags & FREEZE_PROOF)
@@ -545,7 +543,7 @@
/obj/item/clothing/under/syndicate/coldres
name = "insulated tactical turtleneck"
desc = "A nondescript and slightly suspicious-looking turtleneck with digital camouflage cargo pants. The interior has been padded with special insulation for both warmth and protection."
- armor = list(MELEE = 20, BULLET = 10, LASER = 0, ENERGY = 5, BOMB = 0, BIO = 0, RAD = 0, FIRE = 25, ACID = 25, STAMINA = 30)
+ armor = list(MELEE = 20, BULLET = 10, LASER = 0, ENERGY = 5, BOMB = 0, BIO = 0, RAD = 0, FIRE = 25, ACID = 25, STAMINA = 30, BLEED = 10)
cold_protection = CHEST|GROIN|ARMS|LEGS
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
diff --git a/code/modules/cargo/bounties/assistant.dm b/code/modules/cargo/bounties/assistant.dm
index 233967008dd89..9605ac55ce2a1 100644
--- a/code/modules/cargo/bounties/assistant.dm
+++ b/code/modules/cargo/bounties/assistant.dm
@@ -1,9 +1,3 @@
-/datum/bounty/item/assistant/strange_object
- name = "Strange Object"
- description = "Nanotrasen has taken an interest in strange objects. Find one in maint, and ship it off to CentCom right away."
- reward = 1200
- wanted_types = list(/obj/item/relic)
-
/datum/bounty/item/assistant/scooter
name = "Scooter"
description = "Nanotrasen has determined walking to be wasteful. Ship a scooter to CentCom to speed operations up."
diff --git a/code/modules/cargo/supplypod.dm b/code/modules/cargo/supplypod.dm
index afed380c46ad8..6f7043fd0ac3b 100644
--- a/code/modules/cargo/supplypod.dm
+++ b/code/modules/cargo/supplypod.dm
@@ -11,7 +11,8 @@
allow_dense = TRUE
delivery_icon = null
can_weld_shut = FALSE
- armor = list(MELEE = 30, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 100, BIO = 0, RAD = 0, FIRE = 100, ACID = 80, STAMINA = 0)
+ divable = FALSE
+ armor = list(MELEE = 30, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 100, BIO = 0, RAD = 0, FIRE = 100, ACID = 80, STAMINA = 0, BLEED = 0)
anchored = TRUE //So it cant slide around after landing
anchorable = FALSE
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index d0543a335f72e..6dc7cb14216b5 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -8,6 +8,9 @@
//ADMIN THINGS//
////////////////
+ /// If this client has been fully initialized or not
+ var/fully_created = FALSE
+
/// The admin state of the client. If this is null, the client is not an admin.
var/datum/admins/holder = null
var/datum/click_intercept = null // Needs to implement InterceptClickOn(user,params,atom) proc
@@ -106,7 +109,7 @@
var/next_keysend_trip_reset = 0
var/keysend_tripped = FALSE
- var/datum/viewData/view_size
+ var/datum/view_data/view_size
// List of all asset filenames sent to this client by the asset cache, along with their assoicated md5s
var/list/sent_assets = list()
@@ -127,3 +130,6 @@
/// Whether or not this client has standard hotkeys enabled
var/hotkeys = TRUE
+
+ /// client/eye is immediately changed, and it makes a lot of errors to track eye change
+ var/datum/weakref/eye_weakref
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index be4056cfa17e3..0972273f30368 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -493,6 +493,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
//Load the TGUI stat in case of TGUI subsystem not ready (startup)
mob.UpdateMobStat(TRUE)
+ fully_created = TRUE
/client/proc/time_to_redirect()
var/redirect_address = CONFIG_GET(string/redirect_address)
@@ -581,6 +582,9 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
send2tgs("Server", "[cheesy_message] (No admins online)")
+ if(isatom(eye)) // admeme vv failproof. eye must be atom
+ var/atom/eye_thing = eye
+ LAZYREMOVE(eye_thing.eye_users, src)
GLOB.requests.client_logout(src)
GLOB.directory -= ckey
GLOB.clients -= src
@@ -966,6 +970,24 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
..()
+/// Sets client eye to 1st param.
+/// * WARN: Do not change old_eye. Check client/var/eye_weakref
+/client/proc/set_eye(atom/new_eye, atom/old_eye = src.eye)
+ if(new_eye == old_eye)
+ return
+
+ if(isatom(old_eye)) // admeme vv failproof. /datum can't be their eyes
+ LAZYREMOVE(old_eye.eye_users, src)
+
+ eye = new_eye
+ eye_weakref = WEAKREF(eye)
+
+ if(isatom(new_eye))
+ LAZYADD(new_eye.eye_users, src)
+
+ // SEND_SIGNAL(src, COMSIG_CLIENT_SET_EYE, old_eye, new_eye) // use this when you want a thing from TG
+
+
/client/proc/add_verbs_from_config()
if (interviewee)
return
@@ -1045,8 +1067,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if (isliving(mob))
var/mob/living/M = mob
M.update_damage_hud()
- if (prefs?.read_player_preference(/datum/preference/toggle/auto_fit_viewport))
- addtimer(CALLBACK(src,.verb/fit_viewport,10)) //Delayed to avoid wingets from Login calls.
+ attempt_auto_fit_viewport()
/client/proc/generate_clickcatcher()
if(!void)
diff --git a/code/modules/client/preferences/preference_entry.dm b/code/modules/client/preferences/preference_entry.dm
index fa90c93cc7702..93afba9fe2672 100644
--- a/code/modules/client/preferences/preference_entry.dm
+++ b/code/modules/client/preferences/preference_entry.dm
@@ -201,6 +201,8 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key())
// things running pre-assets-initialization.
if (!isnull(Master.current_initializing_subsystem))
extra_info = "Info was attempted to be retrieved while [Master.current_initializing_subsystem] was initializing."
+ else if (!MC_RUNNING())
+ extra_info = "Info was attempted to be retrieved before the MC started, but not while it was actively initializing a subsystem"
CRASH("Preference type `[preference_typepath]` is invalid! [extra_info]")
return get_preference_holder(preference_entry).read_preference(src, preference_entry)
diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm
index 3c5274ac23ab7..d77cd48baa712 100644
--- a/code/modules/client/verbs/ooc.dm
+++ b/code/modules/client/verbs/ooc.dm
@@ -249,9 +249,31 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
// Calculate desired pixel width using window size and aspect ratio
var/sizes = params2list(winget(src, "mainwindow.split;mapwindow", "size"))
- var/map_size = splittext(sizes["mapwindow.size"], "x")
- var/height = text2num(map_size[2])
- var/desired_width = round(height * aspect_ratio)
+
+ // Client closed the window? Some other error? This is unexpected behaviour, let's
+ // CRASH with some info.
+ if(!sizes["mapwindow.size"])
+ CRASH("sizes does not contain mapwindow.size key. This means a winget failed to return what we wanted. --- sizes var: [sizes] --- sizes length: [length(sizes)]")
+
+ var/list/map_size = splittext(sizes["mapwindow.size"], "x")
+
+ // Gets the type of zoom we're currently using from our view datum
+ // If it's 0 we do our pixel calculations based off the size of the mapwindow
+ // If it's not, we already know how big we want our window to be, since zoom is the exact pixel ratio of the map
+ var/zoom_value = src.view_size?.zoom || 0
+
+ var/desired_width = 0
+ if(zoom_value)
+ desired_width = round(view_size[1] * zoom_value * world.icon_size)
+ else
+
+ // Looks like we expect mapwindow.size to be "ixj" where i and j are numbers.
+ // If we don't get our expected 2 outputs, let's give some useful error info.
+ if(length(map_size) != 2)
+ CRASH("map_size of incorrect length --- map_size var: [map_size] --- map_size length: [length(map_size)]")
+ var/height = text2num(map_size[2])
+ desired_width = round(height * aspect_ratio)
+
if (text2num(map_size[1]) == desired_width)
// Nothing to do
return
@@ -284,6 +306,15 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
pct += delta
winset(src, "mainwindow.split", "splitter=[pct]")
+/// Attempt to automatically fit the viewport, assuming the user wants it
+/client/proc/attempt_auto_fit_viewport()
+ if (!prefs.read_preference(/datum/preference/toggle/auto_fit_viewport))
+ return
+ if(fully_created)
+ INVOKE_ASYNC(src, VERB_REF(fit_viewport))
+ else //Delayed to avoid wingets from Login calls.
+ addtimer(CALLBACK(src, VERB_REF(fit_viewport), 1 SECONDS))
+
/client/verb/view_runtimes_minimal()
set name = "View Minimal Runtimes"
set category = "OOC"
diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm
index fa1e9ccd02f85..90bec770bbb80 100644
--- a/code/modules/clothing/chameleon.dm
+++ b/code/modules/clothing/chameleon.dm
@@ -356,7 +356,7 @@
random_sensor = FALSE
resistance_flags = NONE
can_adjust = FALSE
- armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10, BLEED = 10)
var/datum/action/item_action/chameleon/change/chameleon_action
@@ -433,7 +433,7 @@
item_state = "armor"
blood_overlay_type = "armor"
resistance_flags = NONE
- armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10, BLEED = 10)
var/datum/action/item_action/chameleon/change/chameleon_action
@@ -477,7 +477,7 @@
icon_state = "meson"
item_state = "meson"
resistance_flags = NONE
- armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10, BLEED = 10)
var/datum/action/item_action/chameleon/change/chameleon_action
@@ -530,7 +530,7 @@
worn_icon_state = "ygloves"
resistance_flags = NONE
- armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10, BLEED = 10)
var/datum/action/item_action/chameleon/change/chameleon_action
@@ -581,7 +581,7 @@
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
- armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10, BLEED = 10)
/obj/item/clothing/head/chameleon
name = "grey cap"
@@ -591,7 +591,7 @@
clothing_flags = SNUG_FIT
icon_state = "greysoft"
resistance_flags = NONE
- armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10, BLEED = 10)
var/datum/action/item_action/chameleon/change/chameleon_action
@@ -655,7 +655,7 @@
// The camohat, I mean, holographic hat projection, is part of the
// drone itself.
clothing_flags = SNUG_FIT
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
// which means it offers no protection, it's just air and light
/obj/item/clothing/head/chameleon/drone/Initialize(mapload)
@@ -709,7 +709,7 @@
icon_state = "gas_alt"
item_state = "gas_alt"
resistance_flags = NONE
- armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10, BLEED = 10)
clothing_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEFACIALHAIR|HIDESNOUT
gas_transfer_coefficient = 0.01
@@ -778,7 +778,7 @@
/obj/item/clothing/mask/chameleon/drone
//Same as the drone chameleon hat, undroppable and no protection
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0, BLEED = 10)
// Can drones use the voice changer part? Let's not find out.
voice_change = FALSE
@@ -803,7 +803,7 @@
desc = "A pair of black shoes."
permeability_coefficient = 0.05
resistance_flags = NONE
- armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10, BLEED = 10)
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
var/datum/action/item_action/chameleon/change/chameleon_action
@@ -1043,7 +1043,7 @@
desc = "A neosilk clip-on tie."
icon_state = "blacktie"
resistance_flags = NONE
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0, BLEED = 0)
/obj/item/clothing/neck/chameleon
var/datum/action/item_action/chameleon/change/chameleon_action
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 47a218632d5c8..9b3cce7e14807 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -218,7 +218,7 @@
compare_to = thing
break
var/list/readout = list("PROTECTION CLASSES ")
- if(armor.bio || armor.bomb || armor.bullet || armor.energy || armor.laser || armor.magic || armor.melee || armor.rad || armor.stamina)
+ if(armor.bio || armor.bomb || armor.bullet || armor.energy || armor.laser || armor.magic || armor.melee || armor.rad || armor.stamina || armor.bleed)
readout += "ARMOR (I-X) "
if(armor.bio || compare_to?.armor?.bio)
readout += " TOXIN [armor_to_protection_class(armor.bio, compare_to?.armor?.bio)]"
@@ -238,6 +238,8 @@
readout += " RADIATION [armor_to_protection_class(armor.rad, compare_to?.armor?.rad)]"
if(armor.stamina || compare_to?.armor?.stamina)
readout += " STAMINA [armor_to_protection_class(armor.stamina, compare_to?.armor?.stamina)]"
+ if(armor.bleed || compare_to?.armor?.bleed)
+ readout += " BLEEDING [armor_to_protection_class(armor.bleed, compare_to?.armor?.bleed)]"
if(armor.fire || armor.acid)
readout += "DURABILITY (I-X) "
if(armor.fire || compare_to?.armor?.fire)
@@ -275,6 +277,7 @@
. = "[.] "
/obj/item/clothing/obj_break(damage_flag)
+ . = ..()
if(!damaged_clothes)
update_clothes_damaged_state(TRUE)
if(ismob(loc)) //It's not important enough to warrant a message if nobody's wearing it
diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm
index 3deaa56984fc7..2b2d663dc7bcb 100644
--- a/code/modules/clothing/glasses/_glasses.dm
+++ b/code/modules/clothing/glasses/_glasses.dm
@@ -123,6 +123,7 @@
attack_verb = list("sliced")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ bleed_force = BLEED_SURFACE
/obj/item/clothing/glasses/meson/prescription
name = "prescription meson scanner"
@@ -142,7 +143,7 @@
actions_types = list(/datum/action/item_action/toggle_research_scanner)
glass_colour_type = /datum/client_colour/glass_colour/purple
resistance_flags = ACID_PROOF
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 100, STAMINA = 0, BLEED = 0)
/obj/item/clothing/glasses/science/item_action_slot_check(slot)
if(slot == ITEM_SLOT_EYES)
@@ -154,7 +155,7 @@
icon_state = "prescscihud"
emissive_state = "prehud_emissive"
resistance_flags = NONE
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 20, ACID = 40, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 20, ACID = 40, STAMINA = 0, BLEED = 0)
vision_correction = 1
/obj/item/clothing/glasses/science/sciencesun
@@ -223,6 +224,7 @@
attack_verb = list("sliced")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ bleed_force = BLEED_SURFACE
glass_colour_type = /datum/client_colour/glass_colour/lightgreen
/obj/item/clothing/glasses/regular
@@ -306,6 +308,7 @@
attack_verb = list("sliced")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ bleed_force = BLEED_SURFACE
/obj/item/clothing/glasses/sunglasses/advanced/garb/supergarb
name = "black giga gar glasses"
@@ -326,6 +329,7 @@
attack_verb = list("sliced")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ bleed_force = BLEED_SURFACE
glass_colour_type = /datum/client_colour/glass_colour/orange
/obj/item/clothing/glasses/sunglasses/advanced/gar/supergar
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index fc8fde641339d..7750907ad3cdb 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -292,6 +292,7 @@
attack_verb = list("sliced")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ bleed_force = BLEED_SURFACE
/obj/item/clothing/glasses/hud/security/sunglasses/gars/supergars
name = "giga HUD gar glasses"
diff --git a/code/modules/clothing/gloves/color.dm b/code/modules/clothing/gloves/color.dm
index 7043a304d7cfd..7b6e4a9108017 100644
--- a/code/modules/clothing/gloves/color.dm
+++ b/code/modules/clothing/gloves/color.dm
@@ -178,7 +178,7 @@
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
strip_delay = 60
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 70, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 70, ACID = 50, STAMINA = 0, BLEED = 0)
/obj/item/clothing/gloves/color/latex
name = "latex gloves"
diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm
index acd01cd5bb2fe..e993df33d96ca 100644
--- a/code/modules/clothing/gloves/miscellaneous.dm
+++ b/code/modules/clothing/gloves/miscellaneous.dm
@@ -25,7 +25,7 @@
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
resistance_flags = NONE
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 70, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 70, ACID = 30, STAMINA = 0, BLEED = 0)
/obj/item/clothing/gloves/combat
name = "combat gloves"
@@ -41,7 +41,7 @@
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
resistance_flags = NONE
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 50, STAMINA = 20)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 50, STAMINA = 20, BLEED = 10)
/obj/item/clothing/gloves/bracer
name = "bone bracers"
@@ -57,7 +57,7 @@
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
resistance_flags = NONE
- armor = list(MELEE = 15, BULLET = 35, LASER = 35, ENERGY = 20, BOMB = 35, BIO = 35, RAD = 35, FIRE = 0, ACID = 0, STAMINA = 20)
+ armor = list(MELEE = 15, BULLET = 35, LASER = 35, ENERGY = 20, BOMB = 35, BIO = 35, RAD = 35, FIRE = 0, ACID = 0, STAMINA = 20, BLEED = 20)
/obj/item/clothing/gloves/rapid
name = "Gloves of the North Star"
diff --git a/code/modules/clothing/head/beanie.dm b/code/modules/clothing/head/beanie.dm
index 3317d4f3a1fba..5e2360d757310 100644
--- a/code/modules/clothing/head/beanie.dm
+++ b/code/modules/clothing/head/beanie.dm
@@ -89,7 +89,7 @@
name = "durathread beanie"
desc = "A beanie made from durathread, its resilient fibres provide some protection to the wearer."
icon_state = "beaniedurathread"
- armor = list(MELEE = 15, BULLET = 25, LASER = 15, ENERGY = 5, BOMB = 10, BIO = 0, RAD = 0, FIRE = 30, ACID = 5, STAMINA = 20)
+ armor = list(MELEE = 15, BULLET = 25, LASER = 15, ENERGY = 5, BOMB = 10, BIO = 0, RAD = 0, FIRE = 30, ACID = 5, STAMINA = 20, BLEED = 40)
/obj/item/clothing/head/beanie/waldo
name = "red striped bobble hat"
diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm
index aac6425962fac..53a77aaffcd89 100644
--- a/code/modules/clothing/head/hardhat.dm
+++ b/code/modules/clothing/head/hardhat.dm
@@ -7,13 +7,13 @@
desc = "A piece of headgear used in dangerous working conditions to protect the head. Comes with a built-in flashlight."
icon_state = "hardhat0_yellow"
item_state = null
- armor = list(MELEE = 15, BULLET = 5, LASER = 20, ENERGY = 10, BOMB = 20, BIO = 10, RAD = 20, FIRE = 100, ACID = 50, STAMINA = 20)
+ armor = list(MELEE = 15, BULLET = 5, LASER = 20, ENERGY = 10, BOMB = 20, BIO = 10, RAD = 20, FIRE = 100, ACID = 50, STAMINA = 20, BLEED = 60)
flags_inv = NONE
actions_types = list(/datum/action/item_action/toggle_helmet_light)
resistance_flags = FIRE_PROOF
clothing_flags = SNUG_FIT
- light_system = MOVABLE_LIGHT
+ light_system = MOVABLE_LIGHT_DIRECTIONAL
light_range = 4
light_power = 0.8
light_on = FALSE
diff --git a/code/modules/clothing/head/hat.dm b/code/modules/clothing/head/hat.dm
index 365031204086b..0444630fb8dd7 100644
--- a/code/modules/clothing/head/hat.dm
+++ b/code/modules/clothing/head/hat.dm
@@ -12,6 +12,15 @@
strip_delay = 80
clothing_flags = SNUG_FIT // prevents bypassing the strip delay
+/obj/item/clothing/head/hats/centcom_cap
+ name = "\improper CentCom commander cap"
+ icon_state = "centcom_cap"
+ desc = "Worn by the finest of CentCom commanders. Inside the lining of the cap, lies two faint initials."
+ item_state = "that"
+ flags_inv = 0
+ armor = list(MELEE = 30, BULLET = 15, LASER = 30, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30)
+ strip_delay = (8 SECONDS)
+
/obj/item/clothing/head/costume/canada
name = "striped red tophat"
desc = "It smells like fresh donut holes. / Il sent comme des trous de beignets frais. "
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index 549653969a5f6..9f53df84a6946 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -5,7 +5,7 @@
worn_icon = 'icons/mob/clothing/head/helmet.dmi'
icon_state = "helmet"
item_state = "helmet"
- armor = list(MELEE = 35, BULLET = 30, LASER = 30, ENERGY = 40, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 35, BULLET = 30, LASER = 30, ENERGY = 40, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30, BLEED = 50)
flags_inv = HIDEEARS
cold_protection = HEAD
heat_protection = HEAD
@@ -57,7 +57,7 @@
desc = "A bulletproof combat helmet that excels in protecting the wearer against traditional projectile weaponry and explosives to a minor extent."
icon_state = "helmetalt"
item_state = "helmetalt"
- armor = list(MELEE = 15, BULLET = 60, LASER = 10, ENERGY = 15, BOMB = 40, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 15, BULLET = 60, LASER = 10, ENERGY = 15, BOMB = 40, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30, BLEED = 50)
/obj/item/clothing/head/helmet/alt/Initialize(mapload)
. = ..()
@@ -116,7 +116,7 @@
item_state = "helmet"
toggle_message = "You pull the visor down on"
alt_toggle_message = "You push the visor up on"
- armor = list(MELEE = 50, BULLET = 10, LASER = 10, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 50)
+ armor = list(MELEE = 50, BULLET = 10, LASER = 10, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 50, BLEED = 70)
flags_inv = HIDEEARS|HIDEFACE|HIDESNOUT
strip_delay = 80
actions_types = list(/datum/action/item_action/toggle)
@@ -149,7 +149,7 @@
/obj/item/clothing/head/helmet/toggleable/justice/Initialize(mapload)
. = ..()
- weewooloop = new(list(src), FALSE, FALSE)
+ weewooloop = new(src, FALSE, FALSE)
/obj/item/clothing/head/helmet/toggleable/justice/Destroy()
QDEL_NULL(weewooloop)
@@ -172,7 +172,7 @@
desc = "An extremely robust, space-worthy helmet in a nefarious red and black stripe pattern."
icon_state = "swatsyndie"
item_state = "swatsyndie"
- armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 40, BOMB = 50, BIO = 90, RAD = 20, FIRE = 50, ACID = 50, STAMINA = 50)
+ armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 40, BOMB = 50, BIO = 90, RAD = 20, FIRE = 50, ACID = 50, STAMINA = 50, BLEED = 70)
cold_protection = HEAD
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
heat_protection = HEAD
@@ -198,7 +198,7 @@
flags_inv = HIDEEARS|HIDEHAIR
icon_state = "thunderdome"
item_state = "thunderdome"
- armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 50, BOMB = 100, BIO = 100, RAD = 100, FIRE = 90, ACID = 90, STAMINA = 0)
+ armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 50, BOMB = 100, BIO = 100, RAD = 100, FIRE = 90, ACID = 90, STAMINA = 0, BLEED = 0)
cold_protection = HEAD
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
heat_protection = HEAD
@@ -208,14 +208,14 @@
/obj/item/clothing/head/helmet/thunderdome/holosuit
cold_protection = null
heat_protection = null
- armor = list(MELEE = 10, BULLET = 10, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 10, BULLET = 10, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
/obj/item/clothing/head/helmet/roman
name = "\improper Roman helmet"
desc = "An ancient helmet made of bronze and leather."
flags_inv = HIDEEARS|HIDEHAIR
flags_cover = HEADCOVERSEYES
- armor = list(MELEE = 25, BULLET = 0, LASER = 25, ENERGY = 30, BOMB = 10, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 40)
+ armor = list(MELEE = 25, BULLET = 0, LASER = 25, ENERGY = 30, BOMB = 10, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 40, BLEED = 50)
resistance_flags = FIRE_PROOF
icon_state = "roman"
item_state = "roman"
@@ -223,7 +223,7 @@
/obj/item/clothing/head/helmet/roman/fake
desc = "An ancient helmet made of plastic and leather."
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0, BLEED = 10)
/obj/item/clothing/head/helmet/roman/legionnaire
name = "\improper Roman legionnaire helmet"
@@ -233,7 +233,7 @@
/obj/item/clothing/head/helmet/roman/legionnaire/fake
desc = "An ancient helmet made of plastic and leather. Has a red crest on top of it."
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0, BLEED = 10)
/obj/item/clothing/head/helmet/gladiator
name = "gladiator helmet"
@@ -249,7 +249,7 @@
icon_state = "redtaghelm"
flags_cover = HEADCOVERSEYES
item_state = "redtaghelm"
- armor = list(MELEE = 15, BULLET = 10, LASER = 20, ENERGY = 30, BOMB = 20, BIO = 0, RAD = 0, FIRE = 0, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 15, BULLET = 10, LASER = 20, ENERGY = 30, BOMB = 20, BIO = 0, RAD = 0, FIRE = 0, ACID = 50, STAMINA = 10, BLEED = 10)
/obj/item/clothing/head/helmet/bluetaghelm
name = "blue laser tag helmet"
@@ -257,14 +257,14 @@
icon_state = "bluetaghelm"
flags_cover = HEADCOVERSEYES
item_state = "bluetaghelm"
- armor = list(MELEE = 15, BULLET = 10, LASER = 20, ENERGY = 30, BOMB = 20, BIO = 0, RAD = 0, FIRE = 0, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 15, BULLET = 10, LASER = 20, ENERGY = 30, BOMB = 20, BIO = 0, RAD = 0, FIRE = 0, ACID = 50, STAMINA = 10, BLEED = 10)
/obj/item/clothing/head/helmet/knight
name = "medieval helmet"
desc = "A classic metal helmet."
icon_state = "knight_green"
item_state = "knight_green"
- armor = list(MELEE = 50, BULLET = 10, LASER = 10, ENERGY = 10, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 50)
+ armor = list(MELEE = 50, BULLET = 10, LASER = 10, ENERGY = 10, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 50, BLEED = 10)
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
strip_delay = 80
@@ -287,7 +287,7 @@
desc = "An intimidating tribal helmet, it doesn't look very comfortable."
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDESNOUT
flags_cover = HEADCOVERSEYES
- armor = list(MELEE = 35, BULLET = 25, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 20)
+ armor = list(MELEE = 35, BULLET = 25, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 20, BLEED = 40)
icon_state = "skull"
item_state = "skull"
strip_delay = 100
@@ -298,7 +298,7 @@
icon_state = "durathread"
item_state = "durathread"
resistance_flags = FLAMMABLE
- armor = list(MELEE = 20, BULLET = 40, LASER = 30, ENERGY = 5, BOMB = 15, BIO = 0, RAD = 0, FIRE = 40, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 20, BULLET = 40, LASER = 30, ENERGY = 5, BOMB = 15, BIO = 0, RAD = 0, FIRE = 40, ACID = 50, STAMINA = 30, BLEED = 60)
strip_delay = 60
/obj/item/clothing/head/helmet/rus_helmet
@@ -306,7 +306,7 @@
desc = "It can hold a bottle of vodka."
icon_state = "rus_helmet"
item_state = "rus_helmet"
- armor = list(MELEE = 25, BULLET = 30, LASER = 0, ENERGY = 15, BOMB = 10, BIO = 0, RAD = 20, FIRE = 20, ACID = 50, STAMINA = 20)
+ armor = list(MELEE = 25, BULLET = 30, LASER = 0, ENERGY = 15, BOMB = 10, BIO = 0, RAD = 20, FIRE = 20, ACID = 50, STAMINA = 20, BLEED = 15)
pocket_storage_component_path = /datum/component/storage/concrete/pockets/helmet
/obj/item/clothing/head/helmet/rus_ushanka
@@ -316,8 +316,8 @@
item_state = "rus_ushanka"
body_parts_covered = HEAD
cold_protection = HEAD
- min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
- armor = list(MELEE = 25, BULLET = 20, LASER = 20, ENERGY = 10, BOMB = 20, BIO = 50, RAD = 20, FIRE = -10, ACID = 50, STAMINA = 20)
+ min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
+ armor = list(MELEE = 25, BULLET = 20, LASER = 20, ENERGY = 10, BOMB = 20, BIO = 50, RAD = 20, FIRE = -10, ACID = 50, STAMINA = 20, BLEED = 15)
/obj/item/clothing/head/helmet/outlaw
name = "outlaw's hat"
@@ -328,4 +328,4 @@
item_state = "cowboy"
worn_icon_state = "cowboy_outlaw"
body_parts_covered = HEAD
- armor = list(MELEE = 25, BULLET = 25, LASER = 20, ENERGY = 10, BOMB = 30, BIO = 30, RAD = 20, FIRE = 0, ACID = 40, STAMINA = 25)
+ armor = list(MELEE = 25, BULLET = 25, LASER = 20, ENERGY = 10, BOMB = 30, BIO = 30, RAD = 20, FIRE = 0, ACID = 40, STAMINA = 25, BLEED = 15)
diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm
index 8522ecdd3a61a..debc8f0c7bc1d 100644
--- a/code/modules/clothing/head/jobs.dm
+++ b/code/modules/clothing/head/jobs.dm
@@ -32,7 +32,7 @@
icon_state = "captain"
item_state = "that"
flags_inv = 0
- armor = list(MELEE = 25, BULLET = 15, LASER = 25, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 25, BULLET = 15, LASER = 25, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30, BLEED = 30)
strip_delay = 60
dog_fashion = /datum/dog_fashion/head/captain
dying_key = DYE_REGISTRY_CAP
@@ -50,7 +50,7 @@
name = "head of personnel's cap"
icon_state = "hopcap"
desc = "The symbol of true bureaucratic micromanagement."
- armor = list(MELEE = 25, BULLET = 15, LASER = 25, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 25, BULLET = 15, LASER = 25, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30, BLEED = 15)
dog_fashion = /datum/dog_fashion/head/hop
dying_key = DYE_REGISTRY_CAP
@@ -74,7 +74,7 @@
/obj/item/clothing/head/fedora/det_hat
name = "detective's fedora"
desc = "There's only one man who can sniff out the dirty stench of crime, and he's likely wearing this hat."
- armor = list(MELEE = 25, BULLET = 5, LASER = 25, ENERGY = 30, BOMB = 0, BIO = 0, RAD = 0, FIRE = 30, ACID = 50, STAMINA = 25)
+ armor = list(MELEE = 25, BULLET = 5, LASER = 25, ENERGY = 30, BOMB = 0, BIO = 0, RAD = 0, FIRE = 30, ACID = 50, STAMINA = 25, BLEED = 20)
icon_state = "detective"
item_state = "det_hat"
var/candy_cooldown = 0
@@ -171,7 +171,7 @@
name = "durathread beret"
desc = "A beret made from durathread, its resilient fibres provide some protection to the wearer."
icon_state = "beretdurathread"
- armor = list(MELEE = 15, BULLET = 25, LASER = 15, ENERGY = 20, BOMB = 10, BIO = 0, RAD = 0, FIRE = 30, ACID = 5, STAMINA = 20)
+ armor = list(MELEE = 15, BULLET = 25, LASER = 15, ENERGY = 20, BOMB = 10, BIO = 0, RAD = 0, FIRE = 30, ACID = 5, STAMINA = 20, BLEED = 45)
//Security
@@ -179,7 +179,7 @@
name = "head of security cap"
desc = "The robust standard-issue cap of the Head of Security. For showing the officers who's in charge."
icon_state = "hoscap"
- armor = list(MELEE = 40, BULLET = 30, LASER = 25, ENERGY = 30, BOMB = 25, BIO = 10, RAD = 0, FIRE = 50, ACID = 60, STAMINA = 30)
+ armor = list(MELEE = 40, BULLET = 30, LASER = 25, ENERGY = 30, BOMB = 25, BIO = 10, RAD = 0, FIRE = 50, ACID = 60, STAMINA = 30, BLEED = 30)
strip_delay = 80
dynamic_hair_suffix = ""
dying_key = DYE_REGISTRY_CAP
@@ -205,7 +205,7 @@
name = "warden's police hat"
desc = "It's a special armored hat issued to the Warden of a security force. Protects the head from impacts."
icon_state = "policehelm"
- armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 30, ACID = 60, STAMINA = 30)
+ armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 30, ACID = 60, STAMINA = 30, BLEED = 25)
strip_delay = 60
dog_fashion = /datum/dog_fashion/head/warden
@@ -282,14 +282,14 @@
name = "corporate warden beret"
desc = "A special black beret with the Warden's insignia in the middle. This one is commonly worn by wardens of the corporation."
icon_state = "beret_corporate_warden"
- armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 30, ACID = 60, STAMINA = 30)
+ armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 30, ACID = 60, STAMINA = 30, BLEED = 25)
strip_delay = 60
/obj/item/clothing/head/beret/sec
name = "security beret"
desc = "A robust beret with the security insignia emblazoned on it. Uses reinforced fabric to offer sufficient protection."
icon_state = "beret_badge"
- armor = list(MELEE = 35, BULLET = 30, LASER = 30, ENERGY = 40, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 35, BULLET = 30, LASER = 30, ENERGY = 40, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30, BLEED = 25)
strip_delay = 60
dog_fashion = null
@@ -297,14 +297,14 @@
name = "corporate security beret"
desc = "A special black beret for the mundane life of a corporate security officer."
icon_state = "beret_corporate_officer"
- armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 20, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 20, ACID = 50, STAMINA = 30, BLEED = 25)
strip_delay = 60
/obj/item/clothing/head/beret/spacepol
name = "spacepol officer beret"
desc = "A special black beret for the mundane life of a SpacePol officer."
icon_state = "beret_corporate_officer"
- armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 20, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 20, ACID = 50, STAMINA = 30, BLEED = 25)
strip_delay = 60
/obj/item/clothing/head/beret/sec/navyhos
@@ -316,7 +316,7 @@
name = "warden's beret"
desc = "A special beret with the Warden's insignia emblazoned on it. For wardens with class."
icon_state = "wardenberet"
- armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 30, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 30, ACID = 50, STAMINA = 30, BLEED = 25)
strip_delay = 60
/obj/item/clothing/head/beret/sec/navyofficer
@@ -333,35 +333,35 @@
name = "engineering beret"
desc = "A beret with the engineering insignia emblazoned on it. For engineers that are more inclined towards style than safety."
icon_state = "beret_engineering"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 10, FIRE = 10, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 10, FIRE = 10, ACID = 0, STAMINA = 0, BLEED = 0)
strip_delay = 60
/obj/item/clothing/head/beret/atmos
name = "atmospherics beret"
desc = "A beret for those who have shown immaculate proficienty in piping. Or plumbing."
icon_state = "beret_atmospherics"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 10, FIRE = 10, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 10, FIRE = 10, ACID = 0, STAMINA = 0, BLEED = 0)
strip_delay = 60
/obj/item/clothing/head/beret/ce
name = "chief engineer beret"
desc = "A white beret with the engineering insignia emblazoned on it. Its owner knows what they're doing. Probably."
icon_state = "beret_ce"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 20, FIRE = 30, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 20, FIRE = 30, ACID = 0, STAMINA = 0, BLEED = 0)
strip_delay = 60
/obj/item/clothing/head/beret/sci
name = "science beret"
desc = "A purple beret with the science insignia emblazoned on it. It has that authentic burning plasma smell."
icon_state = "beret_sci"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 5, BIO = 5, RAD = 0, FIRE = 5, ACID = 10, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 5, BIO = 5, RAD = 0, FIRE = 5, ACID = 10, STAMINA = 0, BLEED = 0)
strip_delay = 60
/obj/item/clothing/head/beret/supply
name = "supply beret"
desc = "A brown beret with the supply insignia emblazoned on it. You can't help but wonder how much it'd sell for."
icon_state = "beret_supply"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 10, FIRE = 10, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 10, FIRE = 10, ACID = 0, STAMINA = 0, BLEED = 0)
strip_delay = 60
//Medical
@@ -369,14 +369,14 @@
name = "medical beret"
desc = "A white beret with a blue cross finely threaded into it. It has that sterile smell about it."
icon_state = "beret_med"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 20, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 20, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
strip_delay = 60
/obj/item/clothing/head/beret/cmo
name = "chief medical officer beret"
desc = "A baby blue beret with the insignia of Medistan. It smells very sterile."
icon_state = "beret_cmo"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 30, RAD = 10, FIRE = 0, ACID = 20, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 30, RAD = 10, FIRE = 0, ACID = 20, STAMINA = 0, BLEED = 0)
strip_delay = 60
//CentCom
@@ -384,21 +384,21 @@
name = "central command captain beret"
desc = "A pure white beret with a Captain insignia of Central Command."
icon_state = "beret_centcom_captain"
- armor = list(melee = 80, bullet = 80, laser = 80, energy = 80, bomb = 80, bio = 80, rad = 80, fire = 80, acid = 80, stamina = 80)
+ armor = list(melee = 80, bullet = 80, laser = 80, energy = 80, bomb = 80, bio = 80, rad = 80, fire = 80, acid = 80, stamina = 80, BLEED = 80)
strip_delay = 120
/obj/item/clothing/head/beret/ccofficer
name = "central command officer beret"
desc = "A black Central Command Officer beret with matching insignia."
icon_state = "beret_centcom_officer"
- armor = list(melee = 80, bullet = 80, laser = 80, energy = 80, bomb = 80, bio = 80, rad = 80, fire = 80, acid = 80, stamina = 80)
+ armor = list(melee = 80, bullet = 80, laser = 80, energy = 80, bomb = 80, bio = 80, rad = 80, fire = 80, acid = 80, stamina = 80, BLEED = 80)
strip_delay = 120
/obj/item/clothing/head/beret/ccofficernavy
name = "central command naval officer beret"
desc = "A Navy beret commonly worn by Central Command Naval Officers."
icon_state = "beret_centcom_officer_navy"
- armor = list(melee = 80, bullet = 80, laser = 80, energy = 80, bomb = 80, bio = 80, rad = 80, fire = 80, acid = 80, stamina = 80)
+ armor = list(melee = 80, bullet = 80, laser = 80, energy = 80, bomb = 80, bio = 80, rad = 80, fire = 80, acid = 80, stamina = 80, BLEED = 80)
strip_delay = 120
//For blueshields, but those aren't in so I renamed them to centcom guards
@@ -406,30 +406,40 @@
name = "officer beret"
desc = "A black CentCom guard's beret."
icon_state = "beret_centcom_officer"
- armor = list(melee = 40, bullet = 20, laser = 10, energy = 10, bomb = 10, bio = 5, rad = 5, fire = 5, acid = 30, stamina = 30)
+ armor = list(melee = 40, bullet = 20, laser = 10, energy = 10, bomb = 10, bio = 5, rad = 5, fire = 5, acid = 30, stamina = 30, BLEED = 20)
strip_delay = 60
/obj/item/clothing/head/beret/ccguardnavy
name = "navy officer beret"
desc = "A navy CentCom guard's beret."
icon_state = "beret_centcom_officer_navy"
- armor = list(melee = 40, bullet = 20, laser = 10, energy = 10, bomb = 10, bio = 5, rad = 5, fire = 5, acid = 30, stamina = 30)
+ armor = list(melee = 40, bullet = 20, laser = 10, energy = 10, bomb = 10, bio = 5, rad = 5, fire = 5, acid = 30, stamina = 30, BLEED = 20)
strip_delay = 60
/obj/item/clothing/head/beret/sergeant
name = "spacepol sergeant beret"
desc = "A navy SpacePol sergeant's beret."
icon_state = "beret_centcom_officer_navy"
- armor = list(melee = 40, bullet = 20, laser = 10, energy = 10, bomb = 10, bio = 5, rad = 5, fire = 5, acid = 30, stamina = 30)
+ armor = list(melee = 40, bullet = 20, laser = 10, energy = 10, bomb = 10, bio = 5, rad = 5, fire = 5, acid = 30, stamina = 30, BLEED = 20)
strip_delay = 60
/obj/item/clothing/head/beret/captain
name = "captain beret"
desc = "A lovely blue Captain beret with a gold and white insignia."
icon_state = "beret_captain"
- armor = list(melee = 50, bullet = 30, laser = 20, energy = 30, bomb = 15, bio = 10, rad = 10, fire = 10, acid = 60, stamina = 40)
+ armor = list(melee = 50, bullet = 30, laser = 20, energy = 30, bomb = 15, bio = 10, rad = 10, fire = 10, acid = 60, stamina = 40, BLEED = 20)
strip_delay = 90
+
+//CentCom
+/obj/item/clothing/head/beret/centcom_formal
+ name = "\improper CentCom Formal Beret"
+ desc = "Sometimes, a compromise between fashion and defense needs to be made. Thanks to Nanotrasen's most recent nano-fabric durability enhancements, this time, it's not the case."
+ icon_state = "beret_badge"
+ greyscale_colors = "#46b946#f2c42e"
+ armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 50, BOMB = 100, BIO = 100, FIRE = 100, ACID = 90)
+ strip_delay = 10 SECONDS
+
#undef DRILL_DEFAULT
#undef DRILL_SHOUTING
#undef DRILL_YELLING
diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm
index 626be7660e166..ffeb296e16c42 100644
--- a/code/modules/clothing/head/soft_caps.dm
+++ b/code/modules/clothing/head/soft_caps.dm
@@ -100,7 +100,7 @@
desc = "It's a robust baseball hat in tasteful red colour."
icon_state = "secsoft"
soft_color = "sec"
- armor = list(MELEE = 30, BULLET = 25, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 20, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 30, BULLET = 25, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 20, ACID = 50, STAMINA = 30, BLEED = 10)
strip_delay = 60
/obj/item/clothing/head/soft/sec/brig_physician
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index d57c3f6f02af6..0b11d95207a2c 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -11,6 +11,14 @@
flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH
resistance_flags = NONE
+/obj/item/clothing/mask/gas/atmos/centcom
+ name = "\improper CentCom gas mask"
+ desc = "Oooh, gold and green. Fancy! This should help as you sit in your office."
+ icon = 'icons/obj/clothing/masks.dmi'
+ icon_state = "gas_centcom"
+ item_state = "gas_centcom"
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+
// **** Welding gas mask ****
/obj/item/clothing/mask/gas/welding
@@ -20,7 +28,7 @@
custom_materials = list(/datum/material/iron=4000, /datum/material/glass=2000)
flash_protect = 2
tint = 2
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 55, STAMINA = 15)
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 55, STAMINA = 15, BLEED = 5)
actions_types = list(/datum/action/item_action/toggle)
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDESNOUT
flags_cover = MASKCOVERSEYES
@@ -45,7 +53,7 @@
desc = "A modernised version of the classic design, this mask will not only filter out toxins but it can also be connected to an air supply."
icon_state = "plaguedoctor"
item_state = "gas_mask"
- armor = list(MELEE = 0, BULLET = 0, LASER = 2, ENERGY = 2, BOMB = 0, BIO = 75, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 2, ENERGY = 2, BOMB = 0, BIO = 75, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
/obj/item/clothing/mask/gas/syndicate
name = "syndicate mask"
diff --git a/code/modules/clothing/masks/hailer.dm b/code/modules/clothing/masks/hailer.dm
index e57031859a5ec..7dd01b5036195 100644
--- a/code/modules/clothing/masks/hailer.dm
+++ b/code/modules/clothing/masks/hailer.dm
@@ -33,7 +33,7 @@
aggressiveness = 3
flags_inv = HIDEFACIALHAIR | HIDEFACE | HIDEEYES | HIDEEARS | HIDEHAIR | HIDESNOUT
visor_flags_inv = 0
- armor = list(MELEE = 10, BULLET = 5, LASER = 5, ENERGY = 5, BOMB = 0, BIO = 50, RAD = 0, FIRE = 20, ACID = 40, STAMINA = 30)
+ armor = list(MELEE = 10, BULLET = 5, LASER = 5, ENERGY = 5, BOMB = 0, BIO = 50, RAD = 0, FIRE = 20, ACID = 40, STAMINA = 30, BLEED = 30)
/obj/item/clothing/mask/gas/sechailer/swat/spacepol
name = "spacepol mask"
diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm
index 820e797ab04ad..36de595d0c701 100644
--- a/code/modules/clothing/masks/miscellaneous.dm
+++ b/code/modules/clothing/masks/miscellaneous.dm
@@ -28,7 +28,7 @@
visor_flags_cover = MASKCOVERSMOUTH
gas_transfer_coefficient = 0.9
permeability_coefficient = 0.01
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 25, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 25, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
actions_types = list(/datum/action/item_action/adjust)
/obj/item/clothing/mask/surgical/attack_self(mob/user)
diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm
index 1fdf76ea2f5be..bcf67ded1cdc1 100644
--- a/code/modules/clothing/outfits/ert.dm
+++ b/code/modules/clothing/outfits/ert.dm
@@ -1,7 +1,7 @@
/datum/outfit/ert
name = "ERT Common"
- uniform = /obj/item/clothing/under/rank/centcom/officer
+ uniform = /obj/item/clothing/under/rank/centcom/official
mask = /obj/item/clothing/mask/gas/sechailer
shoes = /obj/item/clothing/shoes/combat/swat
gloves = /obj/item/clothing/gloves/combat
@@ -165,7 +165,8 @@
/datum/outfit/centcom_official
name = JOB_CENTCOM_OFFICIAL
- uniform = /obj/item/clothing/under/rank/centcom/officer
+ uniform = /obj/item/clothing/under/rank/centcom/official
+ suit = /obj/item/clothing/suit/hooded/wintercoat/centcom
shoes = /obj/item/clothing/shoes/sneakers/black
gloves = /obj/item/clothing/gloves/color/black
ears = /obj/item/radio/headset/headset_cent
@@ -371,6 +372,7 @@
/datum/outfit/centcom_intern/leader
name = "CentCom Head Intern"
belt = /obj/item/melee/baton/loaded
+ uniform = /obj/item/clothing/under/rank/centcom/officer_skirt
suit = /obj/item/clothing/suit/armor/vest
suit_store = /obj/item/gun/ballistic/rifle/boltaction
l_hand = /obj/item/megaphone
diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm
index d4e7ca70c98fa..4c3778b87311f 100644
--- a/code/modules/clothing/outfits/standard.dm
+++ b/code/modules/clothing/outfits/standard.dm
@@ -19,6 +19,7 @@
/obj/item/debug/human_spawner=1,\
/obj/item/debug/omnitool=1,\
/obj/item/xenoartifact_labeler/debug=1,\
+ /obj/item/map_template_diver=1,\
/obj/item/debug/orb_of_power=1
)
@@ -237,13 +238,13 @@
name = JOB_CENTCOM_COMMANDER
uniform = /obj/item/clothing/under/rank/centcom/commander
- suit = /obj/item/clothing/suit/armor/bulletproof
+ suit = /obj/item/clothing/suit/armor/centcom_formal
shoes = /obj/item/clothing/shoes/combat/swat
gloves = /obj/item/clothing/gloves/combat
ears = /obj/item/radio/headset/headset_cent/commander
glasses = /obj/item/clothing/glasses/eyepatch
mask = /obj/item/clothing/mask/cigarette/cigar/cohiba
- head = /obj/item/clothing/head/hats/centhat
+ head = /obj/item/clothing/head/hats/centcom_cap
belt = /obj/item/gun/ballistic/revolver/mateba
r_pocket = /obj/item/lighter
l_pocket = /obj/item/ammo_box/a357
@@ -282,7 +283,7 @@
glasses = /obj/item/clothing/glasses/thermal/eyepatch
ears = /obj/item/radio/headset/headset_cent/commander
mask = /obj/item/clothing/mask/cigarette/cigar/havana
- head = /obj/item/clothing/head/helmet/space/beret
+ head = /obj/item/clothing/head/hats/centhat
belt = /obj/item/gun/energy/pulse/pistol/m1911
r_pocket = /obj/item/lighter
back = /obj/item/storage/backpack/satchel/leather
diff --git a/code/modules/clothing/shoes/bananashoes.dm b/code/modules/clothing/shoes/bananashoes.dm
index 1ae58dd045454..c3984da7b676f 100644
--- a/code/modules/clothing/shoes/bananashoes.dm
+++ b/code/modules/clothing/shoes/bananashoes.dm
@@ -10,7 +10,7 @@
/obj/item/clothing/shoes/clown_shoes/banana_shoes/Initialize(mapload)
. = ..()
- AddComponent(/datum/component/material_container, list(/datum/material/bananium), 200000, TRUE, /obj/item/stack)
+ AddComponent(/datum/component/material_container, list(/datum/material/bananium), 200000, MATCONTAINER_EXAMINE|MATCONTAINER_ANY_INTENT|MATCONTAINER_SILENT, /obj/item/stack)
AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg'=1), 75, falloff_exponent = 20)
RegisterSignal(src, COMSIG_SHOES_STEP_ACTION, PROC_REF(on_step))
if(always_noslip)
diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm
index f8866bb182728..6e3a364ab8ff3 100644
--- a/code/modules/clothing/shoes/magboots.dm
+++ b/code/modules/clothing/shoes/magboots.dm
@@ -65,7 +65,7 @@
icon_state = "advmag0"
magboot_state = "advmag"
slowdown_active = SHOES_SLOWDOWN
- armor = list(MELEE = 40, BULLET = 30, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 30, RAD = 30, FIRE = 90, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 40, BULLET = 30, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 30, RAD = 30, FIRE = 90, ACID = 50, STAMINA = 30, BLEED = 40)
clothing_flags = NOSLIP
/obj/item/clothing/shoes/magboots/commando/attack_self(mob/user) //Code for the passive no-slip of the commando magboots to always apply, kind of a shit code solution though.
@@ -90,7 +90,7 @@
return
var/turf/T = user.loc
for (var/mob/living/A in T)
- if (A != user && !(A.mobility_flags & MOBILITY_STAND))
+ if (A != user && A.body_position == LYING_DOWN)
A.adjustBruteLoss(rand(10,13))
to_chat(A,"[user]'s magboots press down on you, crushing you! ")
INVOKE_ASYNC(A, TYPE_PROC_REF(/mob, emote), "scream")
diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm
index 68eb7b389753b..5264e741c872e 100644
--- a/code/modules/clothing/shoes/miscellaneous.dm
+++ b/code/modules/clothing/shoes/miscellaneous.dm
@@ -6,7 +6,7 @@
item_state = "jackboots"
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
- armor = list(MELEE = 25, BULLET = 25, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 10, RAD = 0, FIRE = 70, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 25, BULLET = 25, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 10, RAD = 0, FIRE = 70, ACID = 50, STAMINA = 30, BLEED = 20)
strip_delay = 40
resistance_flags = NONE
permeability_coefficient = 0.05 //Thick soles, and covers the ankle
@@ -17,7 +17,7 @@
desc = "High speed, no drag combat boots."
permeability_coefficient = 0.01
clothing_flags = NOSLIP
- armor = list(MELEE = 40, BULLET = 30, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 30, RAD = 30, FIRE = 90, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 40, BULLET = 30, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 30, RAD = 30, FIRE = 90, ACID = 50, STAMINA = 30, BLEED = 20)
/obj/item/clothing/shoes/sandal
desc = "A pair of rather plain wooden sandals."
@@ -44,7 +44,7 @@
strip_delay = 30
equip_delay_other = 50
resistance_flags = NONE
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 40, ACID = 75, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 40, ACID = 75, STAMINA = 0, BLEED = 0)
can_be_bloody = FALSE
custom_price = 100
diff --git a/code/modules/clothing/spacesuits/_spacesuits.dm b/code/modules/clothing/spacesuits/_spacesuits.dm
index 890e117ce4d66..f753d1e455d3e 100644
--- a/code/modules/clothing/spacesuits/_spacesuits.dm
+++ b/code/modules/clothing/spacesuits/_spacesuits.dm
@@ -1,5 +1,7 @@
-//Note: Everything in modules/clothing/spacesuits should have the entire suit grouped together.
-// Meaning the the suit is defined directly after the corrisponding helmet. Just like below!
+#define THERMAL_REGULATOR_COST 18 // the cost per tick for the thermal regulator
+
+//Note: Everything in modules/clothing/spacesuits should have the entire suit grouped together.
+// Meaning the the suit is defined directly after the corrisponding helmet. Just like below!
/obj/item/clothing/head/helmet/space
name = "space helmet"
icon = 'icons/obj/clothing/head/spacehelm.dmi'
@@ -9,7 +11,7 @@
desc = "A special helmet with solar UV shielding to protect your eyes from harmful rays."
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SNUG_FIT | HEADINTERNALS
permeability_coefficient = 0.01
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 50, FIRE = 80, ACID = 70, STAMINA = 10)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 50, FIRE = 80, ACID = 70, STAMINA = 10, BLEED = 50)
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
dynamic_hair_suffix = ""
dynamic_fhair_suffix = ""
@@ -38,12 +40,224 @@
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
allowed = list(/obj/item/flashlight, /obj/item/tank/internals)
slowdown = 1
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 50, FIRE = 80, ACID = 70, STAMINA = 10)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 50, FIRE = 80, ACID = 70, STAMINA = 10, BLEED = 50)
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
cold_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS
- min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
+ min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT_OFF
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT
strip_delay = 80
equip_delay_other = 80
resistance_flags = NONE
+ actions_types = list(/datum/action/item_action/toggle_spacesuit)
+ var/temperature_setting = BODYTEMP_NORMAL /// The default temperature setting
+ var/obj/item/stock_parts/cell/cell = /obj/item/stock_parts/cell/high /// If this is a path, this gets created as an object in Initialize.
+ var/cell_cover_open = FALSE /// Status of the cell cover on the suit
+ var/thermal_on = FALSE /// Status of the thermal regulator
+ var/show_hud = TRUE /// If this is FALSE the battery status UI will be disabled. This is used for suits that don't use batteries like the changeling's flesh suit mutation.
+
+/obj/item/clothing/suit/space/Initialize(mapload)
+ . = ..()
+ if(ispath(cell))
+ cell = new cell(src)
+
+/// Start Processing on the space suit when it is worn to heat the wearer
+/obj/item/clothing/suit/space/equipped(mob/user, slot)
+ . = ..()
+ if(slot == ITEM_SLOT_OCLOTHING) // Check that the slot is valid
+ START_PROCESSING(SSobj, src)
+ update_hud_icon(user) // update the hud
+
+// On removal stop processing, save battery
+/obj/item/clothing/suit/space/dropped(mob/user)
+ . = ..()
+ STOP_PROCESSING(SSobj, src)
+ var/mob/living/carbon/human/human = user
+ if(istype(human))
+ human.update_spacesuit_hud_icon("0")
+
+// Space Suit temperature regulation and power usage
+/obj/item/clothing/suit/space/process()
+ var/mob/living/carbon/human/user = src.loc
+ if(!user || !ishuman(user) || !(user.wear_suit == src))
+ return
+
+ // Do nothing if thermal regulators are off
+ if(!thermal_on)
+ return
+
+ // If we got here, thermal regulators are on. If there's no cell, turn them
+ // off
+ if(!cell)
+ toggle_spacesuit()
+ update_hud_icon(user)
+ return
+
+ // cell.use will return FALSE if charge is lower than THERMAL_REGULATOR_COST
+ if(!cell.use(THERMAL_REGULATOR_COST))
+ toggle_spacesuit()
+ update_hud_icon(user)
+ to_chat(user, "The thermal regulator cuts off as [cell] runs out of charge. ")
+ return
+
+ // If we got here, it means thermals are on, the cell is in and the cell has
+ // just had enough charge subtracted from it to power the thermal regulator
+ user.adjust_bodytemperature(get_temp_change_amount((temperature_setting - user.bodytemperature), 0.16))
+ update_hud_icon(user)
+
+// Clean up the cell on destroy
+/obj/item/clothing/suit/space/Destroy()
+ if(cell)
+ QDEL_NULL(cell)
+ var/mob/living/carbon/human/human = src.loc
+ if(istype(human))
+ human.update_spacesuit_hud_icon("0")
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+// Clean up the cell on destroy
+/obj/item/clothing/suit/space/handle_atom_del(atom/A)
+ if(A == cell)
+ cell = null
+ thermal_on = FALSE
+ return ..()
+
+// support for items that interact with the cell
+/obj/item/clothing/suit/space/get_cell()
+ return cell
+
+// Show the status of the suit and the cell
+/obj/item/clothing/suit/space/examine(mob/user)
+ . = ..()
+ if(in_range(src, user) || isobserver(user))
+ . += "The thermal regulator is [thermal_on ? "on" : "off"] and the temperature is set to \
+ [round(temperature_setting-T0C,0.1)] °C ([round(temperature_setting*1.8-459.67,0.1)] °F)"
+ . += "The power meter shows [cell ? "[round(cell.percent(), 0.1)]%" : "!invalid!"] charge remaining."
+ if(cell_cover_open)
+ . += "The cell cover is open exposing the cell and setting knobs."
+ if(!cell)
+ . += "The slot for a cell is empty."
+ else
+ . += "\The [cell] is firmly in place."
+
+// object handling for accessing features of the suit
+/obj/item/clothing/suit/space/attackby(obj/item/I, mob/user, params)
+ if(I.tool_behaviour == TOOL_CROWBAR)
+ toggle_spacesuit_cell(user)
+ return
+ else if(cell_cover_open && I.tool_behaviour == TOOL_SCREWDRIVER)
+ var/range_low = 20 // Default min temp c
+ var/range_high = 45 // default max temp c
+ if(obj_flags & EMAGGED)
+ range_low = -20 // emagged min temp c
+ range_high = 120 // emagged max temp c
+
+ var/deg_c = input(user, "What temperature would you like to set the thermal regulator to? \
+ ([range_low]-[range_high] degrees celcius)") as null|num
+ if(deg_c && deg_c >= range_low && deg_c <= range_high)
+ temperature_setting = round(T0C + deg_c, 0.1)
+ to_chat(user, "You see the readout change to [deg_c] c. ")
+ return
+ else if(cell_cover_open && istype(I, /obj/item/stock_parts/cell))
+ if(cell)
+ to_chat(user, "[src] already has a cell installed. ")
+ return
+ if(user.transferItemToLoc(I, src))
+ cell = I
+ to_chat(user, "You successfully install \the [cell] into [src]. ")
+ return
+ return ..()
+
+/// Open the cell cover when ALT+Click on the suit
+/obj/item/clothing/suit/space/AltClick(mob/living/user)
+ if(!user || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return ..()
+ toggle_spacesuit_cell(user)
+
+/// Remove the cell whent he cover is open on CTRL+Click
+/obj/item/clothing/suit/space/CtrlClick(mob/living/user)
+ if(user && user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ if(cell_cover_open && cell)
+ remove_cell(user)
+ return
+ return ..()
+
+// Remove the cell when using the suit on its self
+/obj/item/clothing/suit/space/attack_self(mob/user)
+ remove_cell(user)
+
+/// Remove the cell from the suit if the cell cover is open
+/obj/item/clothing/suit/space/proc/remove_cell(mob/user)
+ if(cell_cover_open && cell)
+ user.visible_message("[user] removes \the [cell] from [src]! ", \
+ "You remove [cell]. ")
+ cell.add_fingerprint(user)
+ user.put_in_hands(cell)
+ cell = null
+
+/// Toggle the space suit's cell cover
+/obj/item/clothing/suit/space/proc/toggle_spacesuit_cell(mob/user)
+ cell_cover_open = !cell_cover_open
+ to_chat(user, "You [cell_cover_open ? "open" : "close"] the cell cover on \the [src]. ")
+
+/// Toggle the space suit's thermal regulator status
+/obj/item/clothing/suit/space/proc/toggle_spacesuit()
+ // If we're turning thermal protection on, check for valid cell and for enough
+ // charge that cell. If it's too low, we shouldn't bother with setting the
+ // thermal protection value and should just return out early.
+ var/mob/living/carbon/human/user = src.loc
+ if(!thermal_on && !(cell && cell.charge >= THERMAL_REGULATOR_COST))
+ to_chat(user, "The thermal regulator on \the [src] has no charge. ")
+ return
+
+ thermal_on = !thermal_on
+ min_cold_protection_temperature = thermal_on ? SPACE_SUIT_MIN_TEMP_PROTECT : SPACE_SUIT_MIN_TEMP_PROTECT_OFF
+ if(user)
+ to_chat(user, "You turn [thermal_on ? "on" : "off"] \the [src]'s thermal regulator. ")
+ SEND_SIGNAL(src, COMSIG_SUIT_SPACE_TOGGLE)
+
+// let emags override the temperature settings
+/obj/item/clothing/suit/space/on_emag(mob/user)
+ ..()
+ user.visible_message("You emag [src], overwriting thermal regulator restrictions. ")
+ log_game("[key_name(user)] emagged [src] at [AREACOORD(src)], overwriting thermal regulator restrictions.")
+ playsound(src, "sparks", 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
+
+// update the HUD icon
+/obj/item/clothing/suit/space/proc/update_hud_icon(mob/user)
+ var/mob/living/carbon/human/human = user
+
+ if(!show_hud)
+ return
+
+ if(!cell)
+ human.update_spacesuit_hud_icon("missing")
+ return
+
+ var/cell_percent = cell.percent()
+
+ // Check if there's enough charge to trigger a thermal regulator tick and
+ // if there is, whethere the cell's capacity indicates high, medium or low
+ // charge based on it.
+ if(cell.charge >= THERMAL_REGULATOR_COST)
+ if(cell_percent > 60)
+ human.update_spacesuit_hud_icon("high")
+ return
+ if(cell_percent > 20)
+ human.update_spacesuit_hud_icon("mid")
+ return
+ human.update_spacesuit_hud_icon("low")
+ return
+
+ human.update_spacesuit_hud_icon("empty")
+ return
+
+// zap the cell if we get hit with an emp
+/obj/item/clothing/suit/space/emp_act(severity)
+ . = ..()
+ if(. & EMP_PROTECT_CONTENTS)
+ return
+ if(cell)
+ cell.emp_act(severity)
+
+#undef THERMAL_REGULATOR_COST
diff --git a/code/modules/clothing/spacesuits/chronosuit.dm b/code/modules/clothing/spacesuits/chronosuit.dm
index 1d2a6df1be4db..a9dbc7b1f9c47 100644
--- a/code/modules/clothing/spacesuits/chronosuit.dm
+++ b/code/modules/clothing/spacesuits/chronosuit.dm
@@ -4,7 +4,7 @@
icon_state = "chronohelmet"
item_state = "chronohelmet"
slowdown = 1
- armor = list(MELEE = 60, BULLET = 60, LASER = 60, ENERGY = 60, BOMB = 30, BIO = 90, RAD = 90, FIRE = 100, ACID = 100, STAMINA = 70)
+ armor = list(MELEE = 60, BULLET = 60, LASER = 60, ENERGY = 60, BOMB = 30, BIO = 90, RAD = 90, FIRE = 100, ACID = 100, STAMINA = 70, BLEED = 80)
resistance_flags = FIRE_PROOF | ACID_PROOF
var/obj/item/clothing/suit/space/chronos/suit
@@ -23,8 +23,8 @@
desc = "An advanced spacesuit equipped with time-bluespace teleportation and anti-compression technology."
icon_state = "chronosuit"
item_state = "chronosuit"
- actions_types = list(/datum/action/item_action/toggle)
- armor = list(MELEE = 60, BULLET = 60, LASER = 60, ENERGY = 60, BOMB = 30, BIO = 90, RAD = 90, FIRE = 100, ACID = 1000, STAMINA = 70)
+ actions_types = list(/datum/action/item_action/toggle_spacesuit, /datum/action/item_action/toggle)
+ armor = list(MELEE = 60, BULLET = 60, LASER = 60, ENERGY = 60, BOMB = 30, BIO = 90, RAD = 90, FIRE = 100, ACID = 1000, STAMINA = 70, BLEED = 80)
resistance_flags = FIRE_PROOF | ACID_PROOF
var/list/chronosafe_items = list(/obj/item/chrono_eraser, /obj/item/gun/energy/chrono_gun)
var/obj/item/clothing/head/helmet/space/chronos/helmet
@@ -166,6 +166,7 @@
finish_chronowalk(user, to_turf)
/obj/item/clothing/suit/space/chronos/process()
+ . = ..()
if(activated)
var/mob/living/carbon/human/user = src.loc
if(user && ishuman(user) && (user.wear_suit == src))
@@ -178,8 +179,6 @@
camera.remove_target_ui()
else
new_camera(user)
- else
- STOP_PROCESSING(SSobj, src)
/obj/item/clothing/suit/space/chronos/proc/activate()
if(!activating && !activated && !teleporting)
@@ -199,7 +198,6 @@
to_chat(user, "\[ ok \] Starting ui display driver")
to_chat(user, "\[ ok \] Initializing chronowalk4-view")
new_camera(user)
- START_PROCESSING(SSobj, src)
activated = 1
else
to_chat(user, "\[ fail \] Mounting /dev/helm")
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index 100f5a28e4450..448e6be1c812e 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -1,4 +1,7 @@
- //Baseline hardsuits
+/// How much damage you take from an emp when wearing a hardsuit
+#define HARDSUIT_EMP_BURN 2 // a very orange number
+
+//Baseline hardsuits
/obj/item/clothing/head/helmet/space/hardsuit
name = "hardsuit helmet"
desc = "A special helmet designed for work in a hazardous, low-pressure environment. Has radiation shielding."
@@ -7,8 +10,8 @@
icon_state = "hardsuit0-engineering"
item_state = "eng_helm"
max_integrity = 300
- armor = list(MELEE = 10, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 75, FIRE = 50, ACID = 75, STAMINA = 20)
- light_system = MOVABLE_LIGHT
+ armor = list(MELEE = 10, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 75, FIRE = 50, ACID = 75, STAMINA = 20, BLEED = 70)
+ light_system = MOVABLE_LIGHT_DIRECTIONAL
light_range = 4
light_power = 1
light_on = FALSE
@@ -133,11 +136,14 @@
icon_state = "hardsuit-engineering"
item_state = "eng_hardsuit"
max_integrity = 300
- armor = list(MELEE = 10, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 75, FIRE = 50, ACID = 75, STAMINA = 20)
+ armor = list(MELEE = 10, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 75, FIRE = 50, ACID = 75, STAMINA = 20, BLEED = 70)
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/t_scanner, /obj/item/construction/rcd, /obj/item/pipe_dispenser)
siemens_coefficient = 0
var/obj/item/clothing/head/helmet/space/hardsuit/helmet
- actions_types = list(/datum/action/item_action/toggle_helmet)
+ actions_types = list(
+ /datum/action/item_action/toggle_spacesuit,
+ /datum/action/item_action/toggle_helmet
+ )
var/helmettype = /obj/item/clothing/head/helmet/space/hardsuit
var/obj/item/tank/jetpack/suit/jetpack = null
pocket_storage_component_path = null
@@ -154,6 +160,11 @@
user.changeNext_move(CLICK_CD_MELEE)
..()
+/obj/item/clothing/suit/space/hardsuit/examine(mob/user)
+ . = ..()
+ if(!helmet && helmettype)
+ . += " The helmet on [src] seems to be malfunctioning. It's light bulb needs to be replaced. "
+
/obj/item/clothing/suit/space/hardsuit/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/tank/jetpack/suit))
if(jetpack)
@@ -167,7 +178,7 @@
jetpack = I
to_chat(user, "You successfully install the jetpack into [src]. ")
return
- else if(I.tool_behaviour == TOOL_SCREWDRIVER)
+ else if(!cell_cover_open && I.tool_behaviour == TOOL_SCREWDRIVER)
if(!jetpack)
to_chat(user, "[src] has no jetpack installed. ")
return
@@ -180,6 +191,22 @@
jetpack = null
to_chat(user, "You successfully remove the jetpack from [src]. ")
return
+ else if(istype(I, /obj/item/light) && helmettype)
+ if(src == user.get_item_by_slot(ITEM_SLOT_OCLOTHING))
+ to_chat(user, "You cannot replace the bulb in the helmet of [src] while wearing it. ")
+ return
+ if(helmet)
+ to_chat(user, "The helmet of [src] does not require a new bulb. ")
+ return
+ var/obj/item/light/L = I
+ if(L.status)
+ to_chat(user, "This bulb is too damaged to use as a replacement! ")
+ return
+ if(do_after(user, 5 SECONDS, 1, src))
+ qdel(I)
+ helmet = new helmettype(src)
+ to_chat(user, "You have successfully repaired [src]'s helmet. ")
+ new /obj/item/light/bulb/broken(drop_location())
return ..()
@@ -236,13 +263,25 @@
if(slot == ITEM_SLOT_OCLOTHING) //we only give the mob the ability to toggle the helmet if he's wearing the hardsuit.
return 1
+/// Burn the person inside the hard suit just a little, the suit got really hot for a moment
+/obj/item/clothing/suit/space/emp_act(severity)
+ . = ..()
+ var/mob/living/carbon/human/user = src.loc
+ if(istype(user))
+ user.apply_damage(HARDSUIT_EMP_BURN, BURN)
+ to_chat(user, "You feel \the [src] heat up from the EMP burning you slightly. ")
+
+ // Chance to scream
+ if (user.stat < UNCONSCIOUS && prob(10))
+ user.emote("scream")
+
//Engineering
/obj/item/clothing/head/helmet/space/hardsuit/engine
name = "engineering hardsuit helmet"
desc = "A special helmet designed for work in a hazardous, low-pressure environment. Has radiation shielding."
icon_state = "hardsuit0-engineering"
item_state = "eng_helm"
- armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 12, BOMB = 10, BIO = 100, RAD = 75, FIRE = 100, ACID = 75, STAMINA = 20)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 12, BOMB = 10, BIO = 100, RAD = 75, FIRE = 100, ACID = 75, STAMINA = 20, BLEED = 70)
hardsuit_type = "engineering"
resistance_flags = FIRE_PROOF
@@ -251,7 +290,7 @@
desc = "A special suit that protects against hazardous, low pressure environments. Has radiation shielding."
icon_state = "hardsuit-engineering"
item_state = "eng_hardsuit"
- armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 75, FIRE = 100, ACID = 75, STAMINA = 20)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 75, FIRE = 100, ACID = 75, STAMINA = 20, BLEED = 70)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/engine
resistance_flags = FIRE_PROOF
@@ -262,7 +301,7 @@
icon_state = "hardsuit0-atmospherics"
item_state = "atmo_helm"
hardsuit_type = "atmospherics"
- armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 25, FIRE = 100, ACID = 75, STAMINA = 20)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 25, FIRE = 100, ACID = 75, STAMINA = 20, BLEED = 70)
heat_protection = HEAD //Uncomment to enable firesuit protection
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
@@ -271,7 +310,7 @@
desc = "A special suit that protects against hazardous, low pressure environments. Has thermal shielding."
icon_state = "hardsuit-atmospherics"
item_state = "atmo_hardsuit"
- armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 25, FIRE = 100, ACID = 75, STAMINA = 20)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 25, FIRE = 100, ACID = 75, STAMINA = 20, BLEED = 70)
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS //Uncomment to enable firesuit protection
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/engine/atmos
@@ -284,7 +323,7 @@
icon_state = "hardsuit0-white"
item_state = "ce_helm"
hardsuit_type = "white"
- armor = list(MELEE = 40, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 90, STAMINA = 30)
+ armor = list(MELEE = 40, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 90, STAMINA = 30, BLEED = 70)
heat_protection = HEAD
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
@@ -293,11 +332,12 @@
name = "advanced hardsuit"
desc = "An advanced suit that protects against hazardous, low pressure environments. Shines with a high polish."
item_state = "ce_hardsuit"
- armor = list(MELEE = 40, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 90, STAMINA = 30)
+ armor = list(MELEE = 40, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 90, STAMINA = 30, BLEED = 70)
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/engine/elite
jetpack = /obj/item/tank/jetpack/suit
+ cell = /obj/item/stock_parts/cell/super
//Mining hardsuit
/obj/item/clothing/head/helmet/space/hardsuit/mining
@@ -309,7 +349,7 @@
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF
heat_protection = HEAD
- armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 50, BIO = 100, RAD = 50, FIRE = 50, ACID = 75, STAMINA = 40)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 50, BIO = 100, RAD = 50, FIRE = 50, ACID = 75, STAMINA = 40, BLEED = 70)
light_range = 7
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator)
high_pressure_multiplier = 0.6
@@ -326,7 +366,7 @@
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF
supports_variations = DIGITIGRADE_VARIATION
- armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 50, BIO = 100, RAD = 50, FIRE = 50, ACID = 75, STAMINA = 40)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 50, BIO = 100, RAD = 50, FIRE = 50, ACID = 75, STAMINA = 40, BLEED = 70)
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/storage/bag/ore, /obj/item/pickaxe)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/mining
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
@@ -344,7 +384,7 @@
item_state = "death_commando_mask"
hardsuit_type = "exploration"
heat_protection = HEAD
- armor = list(MELEE = 35, BULLET = 15, LASER = 20, ENERGY = 10, BOMB = 50, BIO = 100, RAD = 50, FIRE = 50, ACID = 75, STAMINA = 20)
+ armor = list(MELEE = 35, BULLET = 15, LASER = 20, ENERGY = 10, BOMB = 50, BIO = 100, RAD = 50, FIRE = 50, ACID = 75, STAMINA = 20, BLEED = 70)
light_range = 6
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator)
actions_types = list(
@@ -369,24 +409,20 @@
desc = "An advanced space-proof hardsuit designed to protect against off-station threats. Despite looking remarkably similar to the mining hardsuit \
Nanotrasen officials note that it is unique in every way and the design has not been copied in any way."
item_state = "exploration_hardsuit"
- armor = list(MELEE = 35, BULLET = 15, LASER = 20, ENERGY = 10, BOMB = 50, BIO = 100, RAD = 50, FIRE = 50, ACID = 75, STAMINA = 20)
+ armor = list(MELEE = 35, BULLET = 15, LASER = 20, ENERGY = 10, BOMB = 50, BIO = 100, RAD = 50, FIRE = 50, ACID = 75, STAMINA = 20, BLEED = 70)
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/storage/bag/ore, /obj/item/pickaxe)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/exploration
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
- actions_types = list(
- /datum/action/item_action/toggle_helmet
- )
-
- //Cybersun Hardsuit
- //A kind of side-grade to the explorer suit, sacrificing burn protection for brute. If you can kill the guy inside it, anyways.
+//Cybersun Hardsuit
+//A kind of side-grade to the explorer suit, sacrificing burn protection for brute. If you can kill the guy inside it, anyways.
/obj/item/clothing/head/helmet/space/hardsuit/cybersun
name = "Cybersun hardsuit helmet"
desc = "A bulbous red helmet designed for scavenging in hazardous, low pressure environments. Has dual floodlights, and a 360 Degree view."
icon_state = "hardsuit0-cybersun"
item_state = "death_commando_mask"
hardsuit_type = "cybersun"
- armor = list(MELEE = 30, BULLET = 35, LASER = 15, ENERGY = 15, BOMB = 60, BIO = 100, RAD = 55, FIRE = 30, ACID = 60, STAMINA = 15)
+ armor = list(MELEE = 30, BULLET = 35, LASER = 15, ENERGY = 15, BOMB = 60, BIO = 100, RAD = 55, FIRE = 30, ACID = 60, STAMINA = 15, BLEED = 70)
strip_delay = 600
/obj/item/clothing/suit/space/hardsuit/cybersun
@@ -395,7 +431,7 @@
desc = "A bulky, protective suit designed to protect against the perils facing Cybersun Employed Engineers, Researchers, and more as they head from the safety of \
more stable employment to the dangers of Nanotrasen Controlled Deep Space. Designed to get the job done despite on-site hazards in derelicts, laser armor was \
sacrificed in favor of more effective blunt armor plates and radiation shielding."
- armor = list(MELEE = 30, BULLET = 35, LASER = 15, ENERGY = 15, BOMB = 60, BIO = 100, RAD = 55, FIRE = 30, ACID = 60, STAMINA = 15)
+ armor = list(MELEE = 30, BULLET = 35, LASER = 15, ENERGY = 15, BOMB = 60, BIO = 100, RAD = 55, FIRE = 30, ACID = 60, STAMINA = 15, BLEED = 70)
hardsuit_type = "cybersun"
item_state = "death_commando_mask"
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/cybersun
@@ -409,11 +445,13 @@
icon_state = "hardsuit1-syndi"
item_state = "syndie_helm"
hardsuit_type = "syndi"
- armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 55, BOMB = 35, BIO = 100, RAD = 50, FIRE = 50, ACID = 90, STAMINA = 60)
+ armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 55, BOMB = 35, BIO = 100, RAD = 50, FIRE = 50, ACID = 90, STAMINA = 60, BLEED = 70)
on = TRUE
var/obj/item/clothing/suit/space/hardsuit/syndi/linkedsuit = null
- actions_types = list(/datum/action/item_action/toggle_helmet_mode,\
- /datum/action/item_action/toggle_beacon_hud)
+ actions_types = list(
+ /datum/action/item_action/toggle_helmet_mode,
+ /datum/action/item_action/toggle_beacon_hud
+ )
visor_flags_inv = HIDEMASK|HIDEEYES|HIDEFACE|HIDEFACIALHAIR|HIDEEARS|HIDESNOUT
visor_flags = STOPSPRESSUREDAMAGE | HEADINTERNALS
@@ -498,13 +536,15 @@
hardsuit_type = "syndi"
w_class = WEIGHT_CLASS_NORMAL
supports_variations = DIGITIGRADE_VARIATION
- armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 55, BOMB = 35, BIO = 100, RAD = 50, FIRE = 50, ACID = 90, STAMINA = 60)
+ armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 55, BOMB = 35, BIO = 100, RAD = 50, FIRE = 50, ACID = 90, STAMINA = 60, BLEED = 70)
allowed = list(/obj/item/gun, /obj/item/ammo_box,/obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/transforming/energy/sword/saber, /obj/item/restraints/handcuffs, /obj/item/tank/internals)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/syndi
jetpack = /obj/item/tank/jetpack/suit
+ cell = /obj/item/stock_parts/cell/hyper
item_flags = ILLEGAL //Syndicate only and difficult to obtain outside of uplink anyway. Nukie hardsuits on the ship are illegal.
slowdown = 0.5
actions_types = list(
+ /datum/action/item_action/toggle_spacesuit,
/datum/action/item_action/toggle_helmet,
/datum/action/item_action/toggle_beacon,
/datum/action/item_action/toggle_beacon_frequency
@@ -555,6 +595,15 @@
H.update_inv_wear_suit()
H.update_inv_w_uniform()
+//Stupid snowflake type so we dont freak out the spritesheets. Its not actually used ingame
+/obj/item/clothing/suit/space/hardsuit/syndipreview
+ name = "blood-red hardsuit"
+ icon_state = "hardsuit1-syndi"
+ item_state = "syndie_hardsuit"
+ hardsuit_type = "syndi"
+ cell = null
+ show_hud = FALSE
+
//Elite Syndie suit
/obj/item/clothing/head/helmet/space/hardsuit/syndi/elite
name = "elite syndicate hardsuit helmet"
@@ -562,7 +611,7 @@
alt_desc = "An elite version of the syndicate helmet, with improved armour and fireproofing. It is in combat mode. Property of Gorlex Marauders."
icon_state = "hardsuit0-syndielite"
hardsuit_type = "syndielite"
- armor = list(MELEE = 60, BULLET = 60, LASER = 50, ENERGY = 80, BOMB = 55, BIO = 100, RAD = 70, FIRE = 100, ACID = 100, STAMINA = 80)
+ armor = list(MELEE = 60, BULLET = 60, LASER = 50, ENERGY = 80, BOMB = 55, BIO = 100, RAD = 70, FIRE = 100, ACID = 100, STAMINA = 80, BLEED = 70)
heat_protection = HEAD
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF
@@ -574,10 +623,11 @@
icon_state = "hardsuit0-syndielite"
hardsuit_type = "syndielite"
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/syndi/elite
- armor = list(MELEE = 60, BULLET = 60, LASER = 50, ENERGY = 80, BOMB = 55, BIO = 100, RAD = 70, FIRE = 100, ACID = 100, STAMINA = 80)
+ armor = list(MELEE = 60, BULLET = 60, LASER = 50, ENERGY = 80, BOMB = 55, BIO = 100, RAD = 70, FIRE = 100, ACID = 100, STAMINA = 80, BLEED = 70)
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF
+ cell = /obj/item/stock_parts/cell/bluespace
//The Owl Hardsuit
/obj/item/clothing/head/helmet/space/hardsuit/syndi/owl
@@ -609,7 +659,7 @@
item_state = "wiz_helm"
hardsuit_type = "wiz"
resistance_flags = FIRE_PROOF | ACID_PROOF //No longer shall our kind be foiled by lone chemists with spray bottles!
- armor = list(MELEE = 40, BULLET = 40, LASER = 40, ENERGY = 50, BOMB = 35, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 70)
+ armor = list(MELEE = 40, BULLET = 40, LASER = 40, ENERGY = 50, BOMB = 35, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 70, BLEED = 70)
heat_protection = HEAD //Uncomment to enable firesuit protection
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
@@ -620,11 +670,12 @@
item_state = "wiz_hardsuit"
w_class = WEIGHT_CLASS_NORMAL
resistance_flags = FIRE_PROOF | ACID_PROOF
- armor = list(MELEE = 40, BULLET = 40, LASER = 40, ENERGY = 50, BOMB = 35, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 70)
+ armor = list(MELEE = 40, BULLET = 40, LASER = 40, ENERGY = 50, BOMB = 35, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 70, BLEED = 70)
allowed = list(/obj/item/teleportation_scroll, /obj/item/tank/internals)
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS //Uncomment to enable firesuit protection
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/wizard
+ cell = /obj/item/stock_parts/cell/hyper
jetpack = /obj/item/tank/jetpack/suit
slowdown = 0.3
@@ -642,7 +693,7 @@
item_state = "medical_helm"
hardsuit_type = "medical"
flash_protect = 0
- armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 60, FIRE = 60, ACID = 75, STAMINA = 20)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 60, FIRE = 60, ACID = 75, STAMINA = 20, BLEED = 70)
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SNUG_FIT | SCAN_REAGENTS | HEADINTERNALS
/obj/item/clothing/suit/space/hardsuit/medical
@@ -652,7 +703,7 @@
item_state = "medical_hardsuit"
supports_variations = DIGITIGRADE_VARIATION
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/storage/firstaid, /obj/item/healthanalyzer, /obj/item/stack/medical)
- armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 60, FIRE = 60, ACID = 75, STAMINA = 20)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 10, BIO = 100, RAD = 60, FIRE = 60, ACID = 75, STAMINA = 20, BLEED = 70)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/medical
slowdown = 0.5
@@ -673,10 +724,13 @@
hardsuit_type = "rd"
resistance_flags = ACID_PROOF | FIRE_PROOF
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
- armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 100, BIO = 100, RAD = 60, FIRE = 60, ACID = 80, STAMINA = 30)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 100, BIO = 100, RAD = 60, FIRE = 60, ACID = 80, STAMINA = 30, BLEED = 70)
var/obj/machinery/doppler_array/integrated/bomb_radar
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SNUG_FIT | SCAN_REAGENTS | HEADINTERNALS
- actions_types = list(/datum/action/item_action/toggle_helmet_light, /datum/action/item_action/toggle_research_scanner)
+ actions_types = list(
+ /datum/action/item_action/toggle_helmet_light,
+ /datum/action/item_action/toggle_research_scanner
+ )
/obj/item/clothing/head/helmet/space/hardsuit/rd/Initialize(mapload)
. = ..()
@@ -704,8 +758,9 @@
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT //Same as an emergency firesuit. Not ideal for extended exposure.
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/gun/energy/wormhole_projector,
/obj/item/hand_tele, /obj/item/aicard)
- armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 100, BIO = 100, RAD = 60, FIRE = 60, ACID = 80, STAMINA = 30)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 15, BOMB = 100, BIO = 100, RAD = 60, FIRE = 60, ACID = 80, STAMINA = 30, BLEED = 70)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/rd
+ cell = /obj/item/stock_parts/cell/super
/obj/item/clothing/suit/space/hardsuit/research_director/ComponentInitialize()
. = ..()
@@ -718,7 +773,7 @@
icon_state = "hardsuit0-sec"
item_state = "sec_helm"
hardsuit_type = "sec"
- armor = list(MELEE = 35, BULLET = 35, LASER = 30, ENERGY = 50, BOMB = 40, BIO = 100, RAD = 50, FIRE = 75, ACID = 75, STAMINA = 50)
+ armor = list(MELEE = 35, BULLET = 35, LASER = 30, ENERGY = 50, BOMB = 40, BIO = 100, RAD = 50, FIRE = 75, ACID = 75, STAMINA = 50, BLEED = 70)
/obj/item/clothing/suit/space/hardsuit/security
@@ -727,7 +782,7 @@
desc = "A bulky, armored suit designed to protect security personnel in low pressure environments."
item_state = "sec_hardsuit"
supports_variations = DIGITIGRADE_VARIATION
- armor = list(MELEE = 35, BULLET = 35, LASER = 30, ENERGY = 50, BOMB = 40, BIO = 100, RAD = 50, FIRE = 75, ACID = 75, STAMINA = 50)
+ armor = list(MELEE = 35, BULLET = 35, LASER = 30, ENERGY = 50, BOMB = 40, BIO = 100, RAD = 50, FIRE = 75, ACID = 75, STAMINA = 50, BLEED = 70)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/security
/obj/item/clothing/suit/space/hardsuit/security/Initialize(mapload)
@@ -740,7 +795,7 @@
desc = "A bulky, armored helmet designed to protect security personnel in low pressure environments. This one has markings for the head of security."
icon_state = "hardsuit0-hos"
hardsuit_type = "hos"
- armor = list(MELEE = 35, BULLET = 35, LASER = 30, ENERGY = 50, BOMB = 40, BIO = 100, RAD = 50, FIRE = 75, ACID = 75, STAMINA = 50)
+ armor = list(MELEE = 35, BULLET = 35, LASER = 30, ENERGY = 50, BOMB = 40, BIO = 100, RAD = 50, FIRE = 75, ACID = 75, STAMINA = 50, BLEED = 70)
/obj/item/clothing/suit/space/hardsuit/security/head_of_security
@@ -748,9 +803,10 @@
name = "head of security's hardsuit"
supports_variations = DIGITIGRADE_VARIATION
desc = "A bulky, armored suit designed to protect security personnel in low pressure environments. This one has markings for the head of security."
- armor = list(MELEE = 35, BULLET = 35, LASER = 30, ENERGY = 50, BOMB = 40, BIO = 100, RAD = 50, FIRE = 75, ACID = 75, STAMINA = 50)
+ armor = list(MELEE = 35, BULLET = 35, LASER = 30, ENERGY = 50, BOMB = 40, BIO = 100, RAD = 50, FIRE = 75, ACID = 75, STAMINA = 50, BLEED = 70)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/security/hos
jetpack = /obj/item/tank/jetpack/suit
+ cell = /obj/item/stock_parts/cell/super
//SWAT MKII
/obj/item/clothing/head/helmet/space/hardsuit/swat
@@ -758,26 +814,27 @@
icon_state = "swat2helm"
item_state = "swat2helm"
desc = "A tactical SWAT helmet MK.II."
- armor = list(MELEE = 40, BULLET = 50, LASER = 50, ENERGY = 60, BOMB = 50, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 60)
+ armor = list(MELEE = 40, BULLET = 50, LASER = 50, ENERGY = 60, BOMB = 50, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 60, BLEED = 70)
resistance_flags = FIRE_PROOF | ACID_PROOF
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT
heat_protection = HEAD
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
actions_types = list()
-/obj/item/clothing/head/helmet/space/hardsuit/swat/attack_self()
+/obj/item/clothing/head/helmet/space/hardsuit/swat/attack_self() //What the fuck
/obj/item/clothing/suit/space/hardsuit/swat
name = "\improper MK.II SWAT Suit"
desc = "A MK.II SWAT suit with streamlined joints and armor made out of superior materials, insulated against intense heat. The most advanced tactical armor available."
icon_state = "swat2"
item_state = "swat2"
- armor = list(MELEE = 40, BULLET = 50, LASER = 50, ENERGY = 60, BOMB = 50, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 60)
+ armor = list(MELEE = 40, BULLET = 50, LASER = 50, ENERGY = 60, BOMB = 50, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 60, BLEED = 70)
resistance_flags = FIRE_PROOF | ACID_PROOF
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT //this needed to be added a long fucking time ago
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/swat
+// SWAT and Captain get EMP Protection
/obj/item/clothing/suit/space/hardsuit/swat/Initialize(mapload)
. = ..()
allowed = GLOB.security_hardsuit_allowed
@@ -795,6 +852,7 @@
icon_state = "caparmor"
item_state = "capspacesuit"
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/swat/captain
+ cell = /obj/item/stock_parts/cell/super
//Clown
/obj/item/clothing/head/helmet/space/hardsuit/clown
@@ -802,7 +860,7 @@
desc = "A special helmet designed for work in a hazardous, low-humor environment. Has radiation shielding."
icon_state = "hardsuit0-clown"
item_state = "hardsuit0-clown"
- armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, RAD = 75, FIRE = 60, ACID = 30, STAMINA = 20)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, RAD = 75, FIRE = 60, ACID = 30, STAMINA = 20, BLEED = 70)
hardsuit_type = "clown"
/obj/item/clothing/suit/space/hardsuit/clown
@@ -810,7 +868,7 @@
desc = "A special suit that protects against hazardous, low humor environments. Has radiation shielding. Only a true clown can wear it."
icon_state = "hardsuit-clown"
item_state = "clown_hardsuit"
- armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, RAD = 75, FIRE = 60, ACID = 30, STAMINA = 20)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, RAD = 75, FIRE = 60, ACID = 30, STAMINA = 20, BLEED = 70)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/clown
/obj/item/clothing/suit/space/hardsuit/clown/mob_can_equip(mob/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
@@ -828,7 +886,7 @@
desc = "Early prototype RIG hardsuit helmet, designed to quickly shift over a user's head. Design constraints of the helmet mean it has no inbuilt cameras, thus it restricts the users visability."
icon_state = "hardsuit0-ancient"
item_state = "anc_helm"
- armor = list(MELEE = 30, BULLET = 5, LASER = 5, ENERGY = 10, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 75, STAMINA = 30)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 5, ENERGY = 10, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 75, STAMINA = 30, BLEED = 70)
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/gun/energy/plasmacutter, /obj/item/gun/energy/plasmacutter/adv, /obj/item/gun/energy/laser/retro, /obj/item/gun/energy/laser/retro/old, /obj/item/gun/energy/e_gun/old)
hardsuit_type = "ancient"
resistance_flags = FIRE_PROOF
@@ -838,7 +896,7 @@
desc = "Prototype powered RIG hardsuit. Provides excellent protection from the elements of space while being comfortable to move around in, thanks to the powered locomotives. Remains very bulky however."
icon_state = "hardsuit-ancient"
item_state = "anc_hardsuit"
- armor = list(MELEE = 30, BULLET = 5, LASER = 5, ENERGY = 10, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 75, STAMINA = 30)
+ armor = list(MELEE = 30, BULLET = 5, LASER = 5, ENERGY = 10, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 75, STAMINA = 30, BLEED = 70)
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/storage/bag/ore, /obj/item/pickaxe, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/gun/energy/laser/retro, /obj/item/gun/energy/laser/retro/old, /obj/item/gun/energy/e_gun/old)
slowdown = 3
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ancient
@@ -854,83 +912,83 @@
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/security/hos
allowed = null
supports_variations = DIGITIGRADE_VARIATION
- armor = list(MELEE = 30, BULLET = 15, LASER = 30, ENERGY = 40, BOMB = 10, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 60)
+ armor = list(MELEE = 30, BULLET = 15, LASER = 30, ENERGY = 40, BOMB = 10, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 60, BLEED = 70)
resistance_flags = FIRE_PROOF | ACID_PROOF
- /// How many charges total the shielding has
- var/max_charges = 3
- /// How long after we've been shot before we can start recharging.
- var/recharge_delay = 20 SECONDS
- /// How quickly the shield recharges each charge once it starts charging
- var/recharge_rate = 1 SECONDS
- /// The icon for the shield
- var/shield_icon = "shield-old"
-
-/obj/item/clothing/suit/space/hardsuit/shielded/Initialize(mapload)
- . = ..()
- if(!allowed)
- allowed = GLOB.advanced_hardsuit_allowed
-/obj/item/clothing/suit/space/hardsuit/shielded/ComponentInitialize()
- . = ..()
- AddComponent(/datum/component/shielded, max_charges = max_charges, recharge_start_delay = recharge_delay, charge_increment_delay = recharge_rate, shield_icon = shield_icon)
+/obj/item/clothing/suit/space/hardsuit/shielded/setup_shielding()
+ AddComponent(/datum/component/shielded, max_charges = 3, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, shield_icon = "shield-old")
/obj/item/clothing/head/helmet/space/hardsuit/shielded
resistance_flags = FIRE_PROOF | ACID_PROOF
///////////////Capture the Flag////////////////////
-/obj/item/clothing/suit/space/hardsuit/shielded/ctf
- name = "white shielded hardsuit"
- desc = "Standard issue hardsuit for playing capture the flag."
- icon_state = "ert_medical"
- item_state = "ert_medical"
- hardsuit_type = "ert_medical"
+// SHIELDED VEST
+
+/obj/item/clothing/suit/armor/vest/ctf
+ name = "white shielded vest"
+ desc = "Standard issue vest for playing capture the flag."
+ icon = 'icons/mob/clothing/suits/ctf.dmi'
+ worn_icon = 'icons/mob/clothing/suits/ctf.dmi'
+ icon_state = "standard"
// Adding TRAIT_NODROP is done when the CTF spawner equips people
- helmettype = /obj/item/clothing/head/helmet/space/hardsuit/shielded/ctf
- armor = list(MELEE = 0, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 50, BIO = 100, RAD = 100, FIRE = 95, ACID = 95, STAMINA = 0)
- slowdown = 0
- max_charges = 5
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0) // CTF gear gives no protection outside of the shield
+ allowed = null
+ greyscale_config = /datum/greyscale_config/ctf_standard
+ greyscale_config_worn = /datum/greyscale_config/ctf_standard_worn
+ greyscale_colors = "#ffffff"
-/obj/item/clothing/suit/space/hardsuit/shielded/ctf/red
- name = "red shielded hardsuit"
- icon_state = "ert_security"
- item_state = "ert_security"
- hardsuit_type = "ert_security"
- helmettype = /obj/item/clothing/head/helmet/space/hardsuit/shielded/ctf/red
- shield_icon = "shield-red"
-
-/obj/item/clothing/suit/space/hardsuit/shielded/ctf/blue
- name = "blue shielded hardsuit"
- desc = "Standard issue hardsuit for playing capture the flag."
- icon_state = "ert_command"
- item_state = "ert_command"
- helmettype = /obj/item/clothing/head/helmet/space/hardsuit/shielded/ctf/blue
+ ///Icon state to be fed into the shielded component
+ var/team_shield_icon = "shield-old"
+/obj/item/clothing/suit/armor/vest/ctf/setup_shielding()
+ AddComponent(/datum/component/shielded, max_charges = 150, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 30, lose_multiple_charges = TRUE, shield_icon = team_shield_icon)
+// LIGHT SHIELDED VEST
-/obj/item/clothing/head/helmet/space/hardsuit/shielded/ctf
- name = "shielded hardsuit helmet"
- desc = "Standard issue hardsuit helmet for playing capture the flag."
- icon_state = "hardsuit0-ert_medical"
- item_state = "hardsuit0-ert_medical"
- hardsuit_type = "ert_medical"
- armor = list(MELEE = 0, BULLET = 30, LASER = 30, ENERGY = 40, BOMB = 50, BIO = 100, RAD = 100, FIRE = 95, ACID = 95, STAMINA = 0)
+/obj/item/clothing/suit/armor/vest/ctf/light
+ name = "light white shielded vest"
+ desc = "Lightweight vest for playing capture the flag."
+ icon_state = "light"
+ greyscale_config = /datum/greyscale_config/ctf_light
+ greyscale_config_worn = /datum/greyscale_config/ctf_light_worn
+ slowdown = -0.25
+/obj/item/clothing/suit/armor/vest/ctf/light/setup_shielding()
+ AddComponent(/datum/component/shielded, max_charges = 30, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 30, lose_multiple_charges = TRUE, shield_icon = team_shield_icon)
-/obj/item/clothing/head/helmet/space/hardsuit/shielded/ctf/red
- icon_state = "hardsuit0-ert_security"
- item_state = "hardsuit0-ert_security"
- hardsuit_type = "ert_security"
+// RED TEAM SUITS
-/obj/item/clothing/head/helmet/space/hardsuit/shielded/ctf/blue
- name = "shielded hardsuit helmet"
- desc = "Standard issue hardsuit helmet for playing capture the flag."
- icon_state = "hardsuit0-ert_commander"
- item_state = "hardsuit0-ert_commander"
- hardsuit_type = "ert_commander"
+// Regular
+/obj/item/clothing/suit/armor/vest/ctf/red
+ name = "red shielded vest"
+ item_state = "ert_security"
+ team_shield_icon = "shield-red"
+ greyscale_colors = COLOR_VIVID_RED
+// Light
+/obj/item/clothing/suit/armor/vest/ctf/light/red
+ name = "light red shielded vest"
+ item_state = "ert_security"
+ team_shield_icon = "shield-red"
+ greyscale_colors = COLOR_VIVID_RED
+// BLUE TEAM SUITS
+
+// Regular
+/obj/item/clothing/suit/armor/vest/ctf/blue
+ name = "blue shielded vest"
+ item_state = "ert_command"
+ team_shield_icon = "shield-old"
+ greyscale_colors = COLOR_DARK_CYAN
+
+// Light
+/obj/item/clothing/suit/armor/vest/ctf/light/blue
+ name = "light blue shielded vest"
+ item_state = "ert_command"
+ team_shield_icon = "shield-old"
+ greyscale_colors = COLOR_DARK_CYAN
//////Syndicate Version
@@ -941,18 +999,21 @@
icon_state = "hardsuit1-syndi"
item_state = "syndie_hardsuit"
hardsuit_type = "syndi"
- armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 40, BOMB = 35, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 60)
+ armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 40, BOMB = 35, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 60, BLEED = 70)
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/transforming/energy/sword/saber, /obj/item/restraints/handcuffs, /obj/item/tank/internals)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/shielded/syndi
slowdown = 0
- shield_icon = "shield-red"
actions_types = list(
+ /datum/action/item_action/toggle_spacesuit,
/datum/action/item_action/toggle_helmet,
/datum/action/item_action/toggle_beacon,
/datum/action/item_action/toggle_beacon_frequency
)
jetpack = /obj/item/tank/jetpack/suit
+/obj/item/clothing/suit/space/hardsuit/shielded/syndi/setup_shielding()
+ AddComponent(/datum/component/shielded, max_charges = 3, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, shield_icon = "shield-red")
+
/obj/item/clothing/suit/space/hardsuit/shielded/syndi/ComponentInitialize()
. = ..()
AddComponent(/datum/component/anti_artifact, INFINITY, FALSE, 100)
@@ -974,9 +1035,11 @@
icon_state = "hardsuit1-syndi"
item_state = "syndie_helm"
hardsuit_type = "syndi"
- armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 40, BOMB = 35, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 60)
- actions_types = list(/datum/action/item_action/toggle_helmet_light,\
- /datum/action/item_action/toggle_beacon_hud)
+ armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 40, BOMB = 35, BIO = 100, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 60, BLEED = 70)
+ actions_types = list(
+ /datum/action/item_action/toggle_helmet_light,
+ /datum/action/item_action/toggle_beacon_hud
+ )
/obj/item/clothing/head/helmet/space/hardsuit/shielded/syndi/Initialize(mapload)
. = ..()
@@ -1002,22 +1065,23 @@
icon_state = "deathsquad"
item_state = "swat_suit"
hardsuit_type = "syndi"
- max_charges = 4
- recharge_delay = 1.5 SECONDS
- armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY =60, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100)
+ armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY =60, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100, BLEED = 100)
strip_delay = 130
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
jetpack = /obj/item/tank/jetpack/suit
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/shielded/swat
dog_fashion = /datum/dog_fashion/back/deathsquad
+/obj/item/clothing/suit/space/hardsuit/shielded/swat/setup_shielding()
+ AddComponent(/datum/component/shielded, max_charges = 4, recharge_start_delay = 1.5 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, shield_icon = "shield-old")
+
/obj/item/clothing/head/helmet/space/hardsuit/shielded/swat
name = "death commando helmet"
desc = "A tactical helmet with built in energy shielding."
icon_state = "deathsquad"
item_state = "deathsquad"
hardsuit_type = "syndi"
- armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 60, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100)
+ armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 60, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100, BLEED = 100)
strip_delay = 130
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
actions_types = list()
@@ -1044,21 +1108,24 @@
desc = "A somehow spaceworthy set of armor with outstanding protection against almost everything. Comes in an oddly nostalgic green. "
icon_state = "doomguy"
item_state = "doomguy"
- max_charges = 1
- recharge_delay = 100
- armor = list(MELEE = 135, BULLET = 135, LASER = 135, ENERGY = 135, BOMB = 135, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100)
+ armor = list(MELEE = 135, BULLET = 135, LASER = 135, ENERGY = 135, BOMB = 135, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100, BLEED = 100)
strip_delay = 130
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF | LAVA_PROOF
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/shielded/doomguy
dog_fashion = /datum/dog_fashion/back/deathsquad
+/obj/item/clothing/suit/space/hardsuit/shielded/doomguy/setup_shielding()
+ AddComponent(/datum/component/shielded, max_charges = 1, recharge_start_delay = 1 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, shield_icon = "shield-old")
+
/obj/item/clothing/head/helmet/space/hardsuit/shielded/doomguy
name = "juggernaut helmet"
desc = "A dusty old helmet, somehow capable of resisting the strongest of blows."
icon_state = "doomguy"
item_state = "doomguy"
- armor = list(MELEE = 135, BULLET = 135, LASER = 135, ENERGY = 135, BOMB = 135, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100)
+ armor = list(MELEE = 135, BULLET = 135, LASER = 135, ENERGY = 135, BOMB = 135, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100, BLEED = 100)
strip_delay = 130
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
actions_types = list()
+
+#undef HARDSUIT_EMP_BURN
diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm
index 36bed1c8ae5d9..af61ae8dab4be 100644
--- a/code/modules/clothing/spacesuits/miscellaneous.dm
+++ b/code/modules/clothing/spacesuits/miscellaneous.dm
@@ -22,7 +22,7 @@ Contains:
desc = "An advanced tactical space helmet."
icon_state = "deathsquad"
item_state = "deathsquad"
- armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 50, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100)
+ armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 50, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100, BLEED = 100)
strip_delay = 130
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF
@@ -37,41 +37,45 @@ Contains:
icon_state = "deathsquad"
item_state = "swat_suit"
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/knife/combat)
- armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 50, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100)
+ armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 50, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100, BLEED = 100)
strip_delay = 130
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/deathsquad
dog_fashion = /datum/dog_fashion/back/deathsquad
+ cell = /obj/item/stock_parts/cell/bluespace
move_sound = list('sound/effects/suitstep1.ogg', 'sound/effects/suitstep2.ogg')
/obj/item/clothing/head/helmet/space/beret
- name = "officer's beret"
+ name = "CentCom officer's beret"
desc = "An armored beret commonly used by special operations officers. Uses advanced force field technology to protect the head from space."
icon = 'icons/obj/clothing/head/beret.dmi'
worn_icon = 'icons/mob/clothing/head/beret.dmi'
- icon_state = "dsberet"
+ icon_state = "beret_badge"
+ greyscale_colors = "#397F3F#FFCE5B"
dynamic_hair_suffix = "+generic"
dynamic_fhair_suffix = "+generic"
flags_inv = 0
- armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 50, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100)
+ armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 50, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100, BLEED = 100)
strip_delay = 130
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF
/obj/item/clothing/suit/space/officer
- name = "officer's coat"
+ name = "CentCom officer's coat"
desc = "An armored, space-proof coat used in special operations."
- icon_state = "specops"
+ icon = 'icons/obj/clothing/suits/armor.dmi'
+ worn_icon = 'icons/mob/clothing/suits/jacket.dmi'
+ icon_state = "centcom_coat"
icon = 'icons/obj/clothing/suits/jacket.dmi'
worn_icon = 'icons/mob/clothing/suits/jacket.dmi'
- item_state = "specops"
+ item_state = "centcom"
blood_overlay_type = "coat"
slowdown = 0
flags_inv = 0
w_class = WEIGHT_CLASS_NORMAL
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals)
- armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 50, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100)
+ armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 50, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100, BLEED = 100)
strip_delay = 130
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF
@@ -112,7 +116,7 @@ Contains:
worn_icon = 'icons/mob/clothing/head/costume.dmi'
icon_state = "pirate"
item_state = "pirate"
- armor = list(MELEE = 30, BULLET = 50, LASER = 30, ENERGY = 15, BOMB = 30, BIO = 30, RAD = 30, FIRE = 60, ACID = 75, STAMINA = 20)
+ armor = list(MELEE = 30, BULLET = 50, LASER = 30, ENERGY = 15, BOMB = 30, BIO = 30, RAD = 30, FIRE = 60, ACID = 75, STAMINA = 20, BLEED = 20)
flags_inv = HIDEHAIR
strip_delay = 40
equip_delay_other = 20
@@ -131,10 +135,9 @@ Contains:
icon_state = "pirate"
item_state = "pirate"
w_class = WEIGHT_CLASS_NORMAL
- flags_inv = 0
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/melee/transforming/energy/sword/pirate, /obj/item/clothing/glasses/eyepatch, /obj/item/reagent_containers/food/drinks/bottle/rum)
slowdown = 0
- armor = list(MELEE = 30, BULLET = 50, LASER = 30, ENERGY = 15, BOMB = 30, BIO = 30, RAD = 30, FIRE = 60, ACID = 75, STAMINA = 20)
+ armor = list(MELEE = 30, BULLET = 50, LASER = 30, ENERGY = 15, BOMB = 30, BIO = 30, RAD = 30, FIRE = 60, ACID = 75, STAMINA = 20, BLEED = 20)
strip_delay = 40
equip_delay_other = 20
@@ -144,7 +147,7 @@ Contains:
desc = "The integrated helmet of an ERT hardsuit, this one has blue highlights."
icon_state = "hardsuit0-ert_commander"
item_state = "hardsuit0-ert_commander"
- armor = list(MELEE = 65, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 100, RAD = 100, FIRE = 80, ACID = 80, STAMINA = 70)
+ armor = list(MELEE = 65, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 100, RAD = 100, FIRE = 80, ACID = 80, STAMINA = 70, BLEED = 70)
strip_delay = 130
light_range = 7
resistance_flags = FIRE_PROOF
@@ -182,7 +185,7 @@ Contains:
item_state = "ert_command"
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals)
- armor = list(MELEE = 65, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 100, RAD = 100, FIRE = 80, ACID = 80, STAMINA = 70)
+ armor = list(MELEE = 65, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 100, RAD = 100, FIRE = 80, ACID = 80, STAMINA = 70, BLEED = 70)
slowdown = 0
strip_delay = 130
resistance_flags = FIRE_PROOF
@@ -194,6 +197,11 @@ Contains:
/datum/action/item_action/toggle_beacon_frequency
)
+// ERT suit's gets EMP Protection
+/obj/item/clothing/suit/space/hardsuit/ert/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/empprotection, EMP_PROTECT_CONTENTS)
+
/obj/item/clothing/suit/space/hardsuit/ert/ui_action_click(mob/user, datum/actiontype)
switch(actiontype.type)
if(/datum/action/item_action/toggle_helmet)
@@ -276,7 +284,7 @@ Contains:
icon_state = "space"
item_state = "eva_suit"
desc = "A lightweight space suit with the basic ability to protect the wearer from the vacuum of space during emergencies."
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 20, FIRE = 50, ACID = 65, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 20, FIRE = 50, ACID = 65, STAMINA = 0, BLEED = 0, BLEED = 30)
/obj/item/clothing/head/helmet/space/eva
name = "EVA helmet"
@@ -284,7 +292,7 @@ Contains:
item_state = "eva_helmet"
desc = "A lightweight space helmet with the basic ability to protect the wearer from the vacuum of space during emergencies."
flash_protect = 0
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 20, FIRE = 50, ACID = 65, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 20, FIRE = 50, ACID = 65, STAMINA = 0, BLEED = 0, BLEED = 30)
/obj/item/clothing/head/helmet/space/freedom
name = "eagle helmet"
@@ -293,7 +301,7 @@ Contains:
worn_icon = 'icons/mob/clothing/head/costume.dmi'
icon_state = "griffinhat"
item_state = null
- armor = list(MELEE = 20, BULLET = 40, LASER = 30, ENERGY = 25, BOMB = 100, BIO = 100, RAD = 100, FIRE = 80, ACID = 80, STAMINA = 10)
+ armor = list(MELEE = 20, BULLET = 40, LASER = 30, ENERGY = 25, BOMB = 100, BIO = 100, RAD = 100, FIRE = 80, ACID = 80, STAMINA = 10, BLEED = 30)
strip_delay = 130
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = ACID_PROOF | FIRE_PROOF
@@ -304,7 +312,7 @@ Contains:
icon_state = "freedom"
item_state = "freedom"
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals)
- armor = list(MELEE = 20, BULLET = 40, LASER = 30, ENERGY = 25, BOMB = 100, BIO = 100, RAD = 100, FIRE = 80, ACID = 80, STAMINA = 10)
+ armor = list(MELEE = 20, BULLET = 40, LASER = 30, ENERGY = 25, BOMB = 100, BIO = 100, RAD = 100, FIRE = 80, ACID = 80, STAMINA = 10, BLEED = 30)
strip_delay = 130
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = ACID_PROOF | FIRE_PROOF
@@ -385,7 +393,7 @@ Contains:
desc = "A bulky, air-tight helmet meant to protect the user during emergency situations. It doesn't look very durable."
icon_state = "syndicate-helm-orange"
item_state = "syndicate-helm-orange"
- armor = list(MELEE = 5, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 10, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 5, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 10, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 5)
strip_delay = 65
flash_protect = 0
@@ -396,7 +404,7 @@ Contains:
icon_state = "syndicate-orange"
item_state = "syndicate-orange"
slowdown = 2
- armor = list(MELEE = 5, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 10, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 5, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 10, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 5)
strip_delay = 65
w_class = WEIGHT_CLASS_NORMAL
@@ -416,9 +424,10 @@ Contains:
icon_state = "hunter"
item_state = "swat_suit"
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/knife/combat)
- armor = list(melee = 60, bullet = 40, laser = 40, energy = 50, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100, stamina = 70)
+ armor = list(melee = 60, bullet = 40, laser = 40, energy = 50, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100, stamina = 70, BLEED = 70)
strip_delay = 130
resistance_flags = FIRE_PROOF | ACID_PROOF
+ cell = /obj/item/stock_parts/cell/hyper
/obj/item/clothing/head/helmet/space/hardsuit/skinsuit
name = "skinsuit helmet"
@@ -429,7 +438,7 @@ Contains:
max_integrity = 200
desc = "An airtight helmet meant to protect the wearer during emergency situations."
permeability_coefficient = 0.01
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 20, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 20, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10)
min_cold_protection_temperature = EMERGENCY_HELM_MIN_TEMP_PROTECT
heat_protection = NONE
flash_protect = 0
@@ -458,7 +467,7 @@ Contains:
species_restricted = null
gas_transfer_coefficient = 0.5
permeability_coefficient = 0.5
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10)
allowed = list(/obj/item/flashlight, /obj/item/tank/internals)
min_cold_protection_temperature = EMERGENCY_SUIT_MIN_TEMP_PROTECT
heat_protection = NONE
@@ -474,4 +483,4 @@ Contains:
icon_state = "hunter"
item_state = "hunter"
resistance_flags = FIRE_PROOF | ACID_PROOF
- armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 20)
+ armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 20, BLEED = 40)
diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm
index f48881e11cde0..a5b0dd6acb854 100644
--- a/code/modules/clothing/spacesuits/plasmamen.dm
+++ b/code/modules/clothing/spacesuits/plasmamen.dm
@@ -5,7 +5,7 @@
name = "EVA plasma envirosuit"
desc = "A special plasma containment suit designed to be space-worthy, as well as worn over other clothing. Like its smaller counterpart, it can automatically extinguish the wearer in a crisis, and holds twice as many charges."
allowed = list(/obj/item/gun, /obj/item/ammo_casing, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/transforming/energy/sword, /obj/item/restraints/handcuffs, /obj/item/tank)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 100, ACID = 75, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 100, ACID = 75, STAMINA = 0, BLEED = 10)
resistance_flags = FIRE_PROOF
icon_state = "plasmaman_suit"
item_state = "plasmaman_suit"
@@ -51,9 +51,9 @@
strip_delay = 80
flash_protect = 2
tint = 2
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 100, ACID = 75, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 100, ACID = 75, STAMINA = 0, BLEED = 10)
resistance_flags = FIRE_PROOF
- light_system = MOVABLE_LIGHT
+ light_system = MOVABLE_LIGHT_DIRECTIONAL
light_range = 4
light_on = FALSE
var/helmet_on = FALSE
@@ -244,7 +244,7 @@
name = "security envirosuit helmet"
desc = "A plasmaman containment helmet designed for security officers, protecting them from burning alive, along-side other undesirables."
greyscale_colors = "#9F2A2E#2D2D2D#7D282D"
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 100, ACID = 75, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 100, ACID = 75, STAMINA = 10, BLEED = 10)
/obj/item/clothing/head/helmet/space/plasmaman/security/warden
name = "warden's envirosuit helmet"
@@ -295,7 +295,7 @@
name = "engineering envirosuit helmet"
desc = "A space-worthy helmet specially designed for engineer plasmamen, the usual purple stripes being replaced by engineering's orange."
greyscale_colors = "#F0DE00#D75600#F0DE00"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 10, FIRE = 100, ACID = 75, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 10, FIRE = 100, ACID = 75, STAMINA = 0, BLEED = 10)
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
/obj/item/clothing/head/helmet/space/plasmaman/engineering/atmospherics
@@ -461,7 +461,7 @@
name = "security Mk.II envirosuit helmet"
desc = "A stylish new iteration upon the original plasmaman containment helmet design for security officers, retaining all the old protections for a new era of fragile law enforcement."
greyscale_colors = "#9F2A2E#2D2D2D"
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 100, ACID = 75, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 100, ACID = 75, STAMINA = 10, BLEED = 10)
/obj/item/clothing/head/helmet/space/plasmaman/mark2/security/warden
name = "warden's Mk.II envirosuit helmet"
@@ -512,7 +512,7 @@
name = "engineering Mk.II envirosuit helmet"
desc = "A new iteration upon the classic space-worthy design, painted in classic engineering pigments."
greyscale_colors = "#E8D700#D75600"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 10, FIRE = 100, ACID = 75, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 10, FIRE = 100, ACID = 75, STAMINA = 0, BLEED = 10)
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
/obj/item/clothing/head/helmet/space/plasmaman/mark2/engineering/atmospherics
@@ -713,7 +713,7 @@
name = "engineering protective envirosuit helmet"
desc = "A safer looking re-imagining of the classic space-worthy design, painted in classic engineering pigments."
greyscale_colors = "#E8D700#D75600"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 10, FIRE = 100, ACID = 75, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 10, FIRE = 100, ACID = 75, STAMINA = 0, BLEED = 10)
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
/obj/item/clothing/head/helmet/space/plasmaman/protective/engineering/atmospherics
diff --git a/code/modules/clothing/spacesuits/syndi.dm b/code/modules/clothing/spacesuits/syndi.dm
index 38f43419aaa22..8d6552506a5ca 100644
--- a/code/modules/clothing/spacesuits/syndi.dm
+++ b/code/modules/clothing/spacesuits/syndi.dm
@@ -4,7 +4,7 @@
icon_state = "syndicate"
item_state = "syndicate"
desc = "Has a tag on it: Totally not property of an enemy corporation, honest!"
- armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 40, BOMB = 30, BIO = 30, RAD = 30, FIRE = 80, ACID = 85, STAMINA = 50)
+ armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 40, BOMB = 30, BIO = 30, RAD = 30, FIRE = 80, ACID = 85, STAMINA = 50, BLEED = 40)
/obj/item/clothing/suit/space/syndicate
name = "red space suit"
@@ -13,8 +13,8 @@
desc = "Has a tag on it: Totally not property of an enemy corporation, honest!"
w_class = WEIGHT_CLASS_NORMAL
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/transforming/energy/sword/saber, /obj/item/restraints/handcuffs, /obj/item/tank/internals)
- armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 40, BOMB = 30, BIO = 30, RAD = 30, FIRE = 80, ACID = 85, STAMINA = 50)
-
+ armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 40, BOMB = 30, BIO = 30, RAD = 30, FIRE = 80, ACID = 85, STAMINA = 50, BLEED = 40)
+ cell = /obj/item/stock_parts/cell/hyper
//Green syndicate space suit
/obj/item/clothing/head/helmet/space/syndicate/green
diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm
index c5e44eed3df98..3ddbb1945e747 100644
--- a/code/modules/clothing/suits/_suits.dm
+++ b/code/modules/clothing/suits/_suits.dm
@@ -10,7 +10,7 @@
/obj/item/tank/internals/emergency_oxygen,
/obj/item/tank/internals/plasmaman
)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 5)
slot_flags = ITEM_SLOT_OCLOTHING
var/blood_overlay_type = "suit"
var/move_sound = null
@@ -18,6 +18,9 @@
var/mob/listeningTo
pocket_storage_component_path = /datum/component/storage/concrete/pockets/exo
+/obj/item/clothing/suit/Initialize(mapload)
+ . = ..()
+ setup_shielding()
/obj/item/clothing/suit/worn_overlays(mutable_appearance/standing, isinhands = FALSE, icon_file, item_layer, atom/origin)
. = list()
@@ -81,4 +84,13 @@
listeningTo = null
. = ..()
+/**
+ * Wrapper proc to apply shielding through AddComponent().
+ * Called in /obj/item/clothing/Initialize().
+ * Override with an AddComponent(/datum/component/shielded, args) call containing the desired shield statistics.
+ * See /datum/component/shielded documentation for a description of the arguments
+ **/
+/obj/item/clothing/suit/proc/setup_shielding()
+ return
+
#undef FOOTSTEP_COOLDOWN
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index b8794bcd84bd7..c4738d10b14c4 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -11,7 +11,7 @@
equip_delay_other = 40
max_integrity = 250
resistance_flags = NONE
- armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 40, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 40, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30, BLEED = 50)
clothing_flags = THICKMATERIAL
slowdown = 0.08
@@ -42,10 +42,12 @@
/obj/item/clothing/suit/armor/vest/blueshirt
name = "large armor vest"
- desc = "A large, yet comfortable piece of armor, protecting you from some threats. Type H-L"
+ desc = "A type H-L armored vest which provides greater protection than its I-A counterpart, at the cost of being bulkier."
icon_state = "blueshift"
item_state = null
custom_premium_price = 600
+ armor = list(MELEE = 40, BULLET = 40, LASER = 40, ENERGY = 45, BOMB = 30, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 40)
+ slowdown = 0.14
/obj/item/clothing/suit/armor/vest/corporate
name = "corporate Jacket"
@@ -53,7 +55,8 @@
icon_state = "secjacket"
item_state = "secjacket"
body_parts_covered = CHEST|ARMS
- armor = list(MELEE = 25, BULLET = 25, LASER = 25, ENERGY = 35, BOMB = 20, BIO = 0, RAD = 0, FIRE = 45, ACID = 45, STAMINA = 30)
+ armor = list(MELEE = 25, BULLET = 25, LASER = 25, ENERGY = 35, BOMB = 20, BIO = 0, RAD = 0, FIRE = 45, ACID = 45, STAMINA = 30, BLEED = 20)
+ slowdown = 0.02
/obj/item/clothing/suit/armor/hos
name = "armored greatcoat"
@@ -61,7 +64,7 @@
icon_state = "hos"
item_state = "greatcoat"
body_parts_covered = CHEST|GROIN|ARMS|LEGS
- armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 40, BOMB = 25, BIO = 0, RAD = 0, FIRE = 70, ACID = 90, STAMINA = 40)
+ armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 40, BOMB = 25, BIO = 0, RAD = 0, FIRE = 70, ACID = 90, STAMINA = 40, BLEED = 40)
cold_protection = CHEST|GROIN|LEGS|ARMS
heat_protection = CHEST|GROIN|LEGS|ARMS
strip_delay = 80
@@ -112,7 +115,7 @@
icon_state = "capcarapace"
item_state = "armor"
body_parts_covered = CHEST|GROIN
- armor = list(MELEE = 50, BULLET = 40, LASER = 50, ENERGY = 60, BOMB = 25, BIO = 0, RAD = 0, FIRE = 100, ACID = 90, STAMINA = 40)
+ armor = list(MELEE = 50, BULLET = 40, LASER = 50, ENERGY = 60, BOMB = 25, BIO = 0, RAD = 0, FIRE = 100, ACID = 90, STAMINA = 40, BLEED = 60)
dog_fashion = null
resistance_flags = FIRE_PROOF
@@ -134,7 +137,7 @@
icon_state = "capjacket"
item_state = null
body_parts_covered = CHEST|ARMS
- armor = list(MELEE = 40, BULLET = 30, LASER = 40, ENERGY = 50, BOMB = 55, BIO = 0, RAD = 0, FIRE = 90, ACID = 80, STAMINA = 40)
+ armor = list(MELEE = 40, BULLET = 30, LASER = 40, ENERGY = 50, BOMB = 55, BIO = 0, RAD = 0, FIRE = 90, ACID = 80, STAMINA = 40, BLEED = 30)
/obj/item/clothing/suit/armor/riot
name = "riot suit"
@@ -144,7 +147,7 @@
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
- armor = list(MELEE = 50, BULLET = 10, LASER = 10, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 50)
+ armor = list(MELEE = 50, BULLET = 10, LASER = 10, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 50, BLEED = 70)
blocks_shove_knockdown = TRUE
strip_delay = 80
equip_delay_other = 60
@@ -157,7 +160,7 @@
icon_state = "bonearmor"
item_state = "bonearmor"
blood_overlay_type = "armor"
- armor = list(MELEE = 35, BULLET = 25, LASER = 25, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 20)
+ armor = list(MELEE = 35, BULLET = 25, LASER = 25, ENERGY = 30, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 20, BLEED = 50)
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS
slowdown = 0.1
@@ -167,7 +170,7 @@
icon_state = "bulletproof"
item_state = "armor"
blood_overlay_type = "armor"
- armor = list(MELEE = 15, BULLET = 60, LASER = 10, ENERGY = 10, BOMB = 40, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 40)
+ armor = list(MELEE = 15, BULLET = 60, LASER = 10, ENERGY = 10, BOMB = 40, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 40, BLEED = 60)
strip_delay = 70
equip_delay_other = 50
@@ -177,7 +180,7 @@
icon_state = "armor_reflec"
item_state = "armor_reflec"
blood_overlay_type = "armor"
- armor = list(MELEE = 10, BULLET = 10, LASER = 60, ENERGY = 80, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 40)
+ armor = list(MELEE = 10, BULLET = 10, LASER = 60, ENERGY = 80, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 40, BLEED = 10)
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/hit_reflect_chance = 40
@@ -199,23 +202,6 @@
allowed = GLOB.detective_vest_allowed
//All of the armor below is mostly unused
-
-/obj/item/clothing/suit/armor/centcom
- name = "\improper CentCom armor"
- desc = "A suit that protects against some damage."
- icon_state = "centcom"
- item_state = "centcom"
- w_class = WEIGHT_CLASS_BULKY
- body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
- allowed = list(/obj/item/gun/energy, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
- flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
- cold_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS
- min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
- heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
- max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT
- armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 60, BOMB = 100, BIO = 100, RAD = 100, FIRE = 90, ACID = 90, STAMINA = 70)
- slowdown = 0.1
-
/obj/item/clothing/suit/armor/heavy
name = "heavy armor"
desc = "A heavily armored suit that protects against moderate damage."
@@ -226,7 +212,7 @@
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
slowdown = 3
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
- armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 60, BOMB = 100, BIO = 100, RAD = 100, FIRE = 90, ACID = 90, STAMINA = 60)
+ armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 60, BOMB = 100, BIO = 100, RAD = 100, FIRE = 90, ACID = 90, STAMINA = 60, BLEED = 70)
move_sound = list('sound/effects/suitstep1.ogg', 'sound/effects/suitstep2.ogg')
slowdown = 0.3
@@ -235,7 +221,7 @@
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
- armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 60, BOMB = 100, BIO = 100, RAD = 100, FIRE = 90, ACID = 90, STAMINA = 0)
+ armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 60, BOMB = 100, BIO = 100, RAD = 100, FIRE = 90, ACID = 90, STAMINA = 0, BLEED = 0)
move_sound = list('sound/effects/suitstep1.ogg', 'sound/effects/suitstep2.ogg')
/obj/item/clothing/suit/armor/tdome/red
@@ -252,7 +238,7 @@
/obj/item/clothing/suit/armor/tdome/holosuit
name = "thunderdome suit"
- armor = list(MELEE = 10, BULLET = 10, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 10, BULLET = 10, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
cold_protection = null
heat_protection = null
@@ -295,14 +281,14 @@
equip_delay_other = 40
max_integrity = 200
resistance_flags = FLAMMABLE
- armor = list(MELEE = 20, BULLET = 40, LASER = 30, ENERGY = 40, BOMB = 15, BIO = 0, RAD = 0, FIRE = 40, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 20, BULLET = 40, LASER = 30, ENERGY = 40, BOMB = 15, BIO = 0, RAD = 0, FIRE = 40, ACID = 50, STAMINA = 30, BLEED = 60)
/obj/item/clothing/suit/armor/vest/russian
name = "russian vest"
desc = "A bulletproof vest with forest camo. Good thing there's plenty of forests to hide in around here, right?"
icon_state = "rus_armor"
item_state = "rus_armor"
- armor = list(MELEE = 25, BULLET = 30, LASER = 0, ENERGY = 15, BOMB = 10, BIO = 0, RAD = 20, FIRE = 20, ACID = 50, STAMINA = 25)
+ armor = list(MELEE = 25, BULLET = 30, LASER = 0, ENERGY = 15, BOMB = 10, BIO = 0, RAD = 20, FIRE = 20, ACID = 50, STAMINA = 25, BLEED = 20)
slowdown = 0.05
/obj/item/clothing/suit/armor/vest/russian_coat
@@ -313,4 +299,17 @@
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
- armor = list(MELEE = 25, BULLET = 20, LASER = 20, ENERGY = 30, BOMB = 20, BIO = 50, RAD = 20, FIRE = -10, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 25, BULLET = 20, LASER = 20, ENERGY = 30, BOMB = 20, BIO = 50, RAD = 20, FIRE = -10, ACID = 50, STAMINA = 30, BLEED = 20)
+
+/obj/item/clothing/suit/armor/centcom_formal
+ name = "\improper CentCom formal coat"
+ desc = "A stylish coat given to CentCom Commanders. Perfect for sending ERTs to suicide missions with style!"
+ icon_state = "centcom_formal"
+ item_state = "centcom"
+ body_parts_covered = CHEST|GROIN|ARMS
+ armor = list(MELEE = 35, BULLET = 40, LASER = 40, ENERGY = 50, BOMB = 35, BIO = 10, RAD = 10, FIRE = 10, ACID = 60, STAMINA = 40, BLEED = 20)
+
+/obj/item/clothing/suit/armor/centcom_formal/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/toggle_icon)
+ allowed = GLOB.security_wintercoat_allowed
diff --git a/code/modules/clothing/suits/bio.dm b/code/modules/clothing/suits/bio.dm
index 3dde7ff43b8dc..3c54e15f9bdeb 100644
--- a/code/modules/clothing/suits/bio.dm
+++ b/code/modules/clothing/suits/bio.dm
@@ -8,7 +8,7 @@
item_state = "bio_hood"
permeability_coefficient = 0.01
clothing_flags = THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | SNUG_FIT
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 80, FIRE = 30, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 80, FIRE = 30, ACID = 100, STAMINA = 0, BLEED = 5)
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEHAIR|HIDEFACIALHAIR|HIDEFACE|HIDESNOUT
resistance_flags = ACID_PROOF
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
@@ -27,7 +27,7 @@
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
slowdown = 1
allowed = list(/obj/item/tank/internals, /obj/item/pen, /obj/item/flashlight/pen, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 80, FIRE = 30, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 80, FIRE = 30, ACID = 100, STAMINA = 0, BLEED = 5)
flags_inv = HIDEGLOVES|HIDEJUMPSUIT
strip_delay = 70
equip_delay_other = 70
@@ -53,11 +53,11 @@
//Security biosuit, grey with red stripe across the chest
/obj/item/clothing/head/bio_hood/security
- armor = list(MELEE = 25, BULLET = 15, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 100, RAD = 80, FIRE = 30, ACID = 100, STAMINA = 20)
+ armor = list(MELEE = 25, BULLET = 15, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 100, RAD = 80, FIRE = 30, ACID = 100, STAMINA = 20, BLEED = 10)
icon_state = "bio_security"
/obj/item/clothing/suit/bio_suit/security
- armor = list(MELEE = 25, BULLET = 15, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 100, RAD = 80, FIRE = 30, ACID = 100, STAMINA = 20)
+ armor = list(MELEE = 25, BULLET = 15, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 100, RAD = 80, FIRE = 30, ACID = 100, STAMINA = 20, BLEED = 10)
icon_state = "bio_security"
diff --git a/code/modules/clothing/suits/chaplainsuits.dm b/code/modules/clothing/suits/chaplainsuits.dm
index de791187c41ac..5ba05f80d4d4f 100644
--- a/code/modules/clothing/suits/chaplainsuits.dm
+++ b/code/modules/clothing/suits/chaplainsuits.dm
@@ -130,6 +130,44 @@
slowdown = 0
move_sound = null
+/obj/item/clothing/head/helmet/plate/crusader
+ name = "Crusader's Hood"
+ desc = "A brownish hood."
+ icon = 'icons/obj/clothing/head/chaplain.dmi'
+ worn_icon = 'icons/mob/clothing/head/chaplain.dmi'
+ icon_state = "crusader"
+ w_class = WEIGHT_CLASS_NORMAL
+ flags_inv = HIDEHAIR|HIDEEARS|HIDEFACE
+ armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 40, BOMB = 60, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 50, BLEED = 60)
+
+/obj/item/clothing/head/helmet/plate/crusader/blue
+ icon_state = "crusader-blue"
+ item_state = null
+
+/obj/item/clothing/head/helmet/plate/crusader/red
+ icon_state = "crusader-red"
+ item_state = null
+
+//Prophet helmet
+/obj/item/clothing/head/helmet/plate/crusader/prophet
+ name = "Prophet's Hat"
+ desc = "A religious-looking hat."
+ icon_state = null
+ worn_icon = 'icons/mob/large-worn-icons/64x64/head.dmi'
+ item_state = null
+ flags_1 = 0
+ armor = list(MELEE = 60, BULLET = 60, LASER = 60, ENERGY = 50, BOMB = 70, BIO = 50, RAD = 50, FIRE = 60, ACID = 60, STAMINA = 60, BLEED = 60) //religion protects you from disease and radiation, honk.
+ worn_x_dimension = 64
+ worn_y_dimension = 64
+
+/obj/item/clothing/head/helmet/plate/crusader/prophet/red
+ icon_state = "prophet-red"
+ item_state = null
+
+/obj/item/clothing/head/helmet/plate/crusader/prophet/blue
+ icon_state = "prophet-blue"
+ item_state = null
+
/obj/item/clothing/head/helmet/chaplain/cage
name = "cage"
desc = "A cage that restrains the will of the self, allowing one to see the profane world for what it is."
diff --git a/code/modules/clothing/suits/cloaks.dm b/code/modules/clothing/suits/cloaks.dm
index 4d17d97204bbe..2e2214d96b77f 100644
--- a/code/modules/clothing/suits/cloaks.dm
+++ b/code/modules/clothing/suits/cloaks.dm
@@ -63,7 +63,7 @@
icon_state = "goliath_cloak"
desc = "A staunch, practical cape made out of numerous monster materials, it is coveted amongst exiles & hermits."
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/pickaxe, /obj/item/spear, /obj/item/spear/bonespear, /obj/item/organ/regenerative_core/legion, /obj/item/knife/combat/bone, /obj/item/knife/combat/survival)
- armor = list(MELEE = 50, BULLET = 10, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 30) //a fair alternative to bone armor, requiring alternative materials and gaining a suit slot
+ armor = list(MELEE = 50, BULLET = 10, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 30, BLEED = 20) //a fair alternative to bone armor, requiring alternative materials and gaining a suit slot
hoodtype = /obj/item/clothing/head/hooded/cloakhood/goliath
body_parts_covered = CHEST|GROIN|ARMS
resistance_flags = FIRE_PROOF
@@ -72,7 +72,7 @@
name = "goliath cloak hood"
icon_state = "golhood"
desc = "A protective & concealing hood."
- armor = list(MELEE = 50, BULLET = 10, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 30)
+ armor = list(MELEE = 50, BULLET = 10, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 30, BLEED = 30)
flags_inv = HIDEEARS|HIDEEYES|HIDEHAIR|HIDEFACIALHAIR
transparent_protection = HIDEMASK
resistance_flags = FIRE_PROOF
@@ -82,7 +82,7 @@
icon_state = "dragon"
desc = "A suit of armour fashioned from the remains of an ash drake."
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe, /obj/item/spear)
- armor = list(MELEE = 70, BULLET = 30, LASER = 50, ENERGY = 40, BOMB = 70, BIO = 60, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 30)
+ armor = list(MELEE = 70, BULLET = 30, LASER = 50, ENERGY = 40, BOMB = 70, BIO = 60, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 30, BLEED = 50)
hoodtype = /obj/item/clothing/head/hooded/cloakhood/drake
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
@@ -95,7 +95,7 @@
name = "drake helm"
icon_state = "dragon"
desc = "The skull of a dragon."
- armor = list(MELEE = 70, BULLET = 30, LASER = 50, ENERGY = 40, BOMB = 70, BIO = 60, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 30)
+ armor = list(MELEE = 70, BULLET = 30, LASER = 50, ENERGY = 40, BOMB = 70, BIO = 60, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 30, BLEED = 50)
heat_protection = HEAD
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF
@@ -105,7 +105,7 @@
name = "Heavy bone armor"
icon_state = "hbonearmor"
desc = "A tribal armor plate, crafted from animal bone. A heavier variation of standard bone armor."
- armor = list(MELEE = 40, BULLET = 25, LASER = 30, ENERGY = 30, BOMB = 30, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 20)
+ armor = list(MELEE = 40, BULLET = 25, LASER = 30, ENERGY = 30, BOMB = 30, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 20, BLEED = 70)
hoodtype = /obj/item/clothing/head/hooded/cloakhood/bone
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS
@@ -117,7 +117,7 @@
name = "bone helmet"
icon_state = "hskull"
desc = "An intimidating tribal helmet, it doesn't look very comfortable."
- armor = list(MELEE = 35, BULLET = 25, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 20)
+ armor = list(MELEE = 35, BULLET = 25, LASER = 25, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 20, BLEED = 50)
heat_protection = HEAD
max_heat_protection_temperature = HELMET_MAX_TEMP_PROTECT
resistance_flags = NONE
diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm
index 1c20f88f186f2..26a9f314d52eb 100644
--- a/code/modules/clothing/suits/jobs.dm
+++ b/code/modules/clothing/suits/jobs.dm
@@ -75,7 +75,7 @@
item_state = "det_suit"
blood_overlay_type = "coat"
body_parts_covered = CHEST|GROIN|ARMS
- armor = list(MELEE = 25, BULLET = 10, LASER = 25, ENERGY = 10, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 45, STAMINA = 40)
+ armor = list(MELEE = 25, BULLET = 10, LASER = 25, ENERGY = 10, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 45, STAMINA = 40, BLEED = 30)
cold_protection = CHEST|GROIN|ARMS
heat_protection = CHEST|GROIN|ARMS
supports_variations = DIGITIGRADE_VARIATION_NO_NEW_ICON
@@ -106,7 +106,7 @@
icon_state = "brig_phys_vest"
item_state = "sec_helm"//looks kinda similar, I guess
allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/storage/firstaid, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/police/telescopic, /obj/item/soap, /obj/item/sensor_device, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30)
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 30, BLEED = 20)
//Engineering
/obj/item/clothing/suit/hazardvest
@@ -228,7 +228,7 @@
/obj/item/tank/internals,
/obj/item/melee/curator_whip
)
- armor = list(MELEE = 25, BULLET = 10, LASER = 25, ENERGY = 10, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 45, STAMINA = 30)
+ armor = list(MELEE = 25, BULLET = 10, LASER = 25, ENERGY = 10, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 45, STAMINA = 30, BLEED = 10)
cold_protection = CHEST|ARMS
heat_protection = CHEST|ARMS
diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm
index d33ab50e1a761..38daa6ea23bad 100644
--- a/code/modules/clothing/suits/labcoat.dm
+++ b/code/modules/clothing/suits/labcoat.dm
@@ -28,7 +28,7 @@
/obj/item/tank/internals/emergency_oxygen,
/obj/item/tank/internals/plasmaman
)
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 50, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 50, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 0, BLEED = 5)
species_exception = list(/datum/species/golem)
/obj/item/clothing/suit/toggle/labcoat/cmo
@@ -47,7 +47,7 @@
name = "security medic's labcoat"
icon_state = "labcoat_sec"
item_state = "labcoat_sec"
- armor = list(melee = 10, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 10, rad = 0, fire = 50, acid = 50, stamina = 30)
+ armor = list(melee = 10, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 10, rad = 0, fire = 50, acid = 50, stamina = 30, BLEED = 10)
/obj/item/clothing/suit/toggle/labcoat/mad
name = "\proper The Mad's labcoat"
diff --git a/code/modules/clothing/suits/reactive_armour.dm b/code/modules/clothing/suits/reactive_armour.dm
index e3c17fb717cd5..bfacbf6ee3390 100644
--- a/code/modules/clothing/suits/reactive_armour.dm
+++ b/code/modules/clothing/suits/reactive_armour.dm
@@ -12,7 +12,8 @@
/obj/effect/anomaly/bioscrambler = /obj/item/clothing/suit/armor/reactive/bioscrambling,
/obj/effect/anomaly/flux = /obj/item/clothing/suit/armor/reactive/tesla,
/obj/effect/anomaly/grav = /obj/item/clothing/suit/armor/reactive/repulse,
- /obj/effect/anomaly/hallucination = /obj/item/clothing/suit/armor/reactive/hallucinating
+ /obj/effect/anomaly/hallucination = /obj/item/clothing/suit/armor/reactive/hallucinating,
+ /obj/effect/anomaly/blood = /obj/item/clothing/suit/armor/reactive/bleed
)
if(istype(weapon, /obj/item/assembly/signaler/anomaly))
@@ -32,7 +33,7 @@
icon_state = "reactiveoff"
item_state = "reactiveoff"
blood_overlay_type = "armor"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 10)
actions_types = list(/datum/action/item_action/toggle)
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
hit_reaction_chance = 50
@@ -390,3 +391,32 @@
owner.visible_message("[src] blocks [attack_text], but pulls a massive charge of biohazard material into [owner] from the surrounding environment! ")
bioscrambler_pulse(owner, range, TRUE, TRUE)
return TRUE
+
+//Bleeding
+
+/obj/item/clothing/suit/armor/reactive/bleed
+ name = "reactive bleed armor"
+ desc = "An experimental suit of armor with sensitive detectors hooked up to a biohazard release valve. It has some kind of blood boiling anomaly inside."
+ cooldown_message = "Your blood runs cold... "
+ emp_message = "Oh fuck... "
+ ///Range of the effect.
+ var/range = 4
+
+/obj/item/clothing/suit/armor/reactive/bleed/cooldown_activation(mob/living/carbon/human/owner)
+ var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread
+ sparks.set_up(1, 1, src)
+ sparks.start()
+ return ..()
+
+/obj/item/clothing/suit/armor/reactive/bleed/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ owner.visible_message("[src] blocks [attack_text], the blood anomaly from within releasing a massive cloud of razors! ")
+ owner.AddComponent(/datum/component/pellet_cloud, projectile_type=/obj/projectile/bullet/shrapnel/bleed, magnitude=3)
+ playsound(src, 'sound/weapons/shrapnel.ogg', 70, TRUE)
+ return TRUE
+
+/obj/item/clothing/suit/armor/reactive/bleed/emp_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ owner.visible_message("[src] blocks [attack_text], but pulls a massive charge of biohazard material into [owner] from the surrounding environment! ")
+ owner.AddComponent(/datum/component/pellet_cloud, projectile_type=/obj/projectile/bullet/shrapnel/bleed, magnitude=5)
+ owner.add_bleeding(BLEED_CRITICAL)
+ playsound(src, 'sound/weapons/shrapnel.ogg', 70, TRUE)
+ return TRUE
diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm
index 62c1aae304ab3..1acedc879ad5a 100644
--- a/code/modules/clothing/suits/toggles.dm
+++ b/code/modules/clothing/suits/toggles.dm
@@ -41,7 +41,7 @@
/obj/item/clothing/suit/hooded/proc/RemoveHood()
src.icon_state = "[initial(icon_state)]"
hood_up = FALSE
-
+
if(hood)
if(ishuman(hood.loc))
var/mob/living/carbon/human/H = hood.loc
@@ -175,6 +175,7 @@
if(!helmettype)
return
if(!helmet)
+ to_chat(H, "The helmet's lightbulb seems to be damaged! You'll need a replacement bulb. ")
return
if(!helmet_on)
if(ishuman(src.loc))
diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm
index 60b2b511d325b..f89989b87caa1 100644
--- a/code/modules/clothing/suits/utility.dm
+++ b/code/modules/clothing/suits/utility.dm
@@ -32,7 +32,7 @@
/obj/item/powertool/jaws_of_life
)
slowdown = 1
- armor = list(MELEE = 15, BULLET = 5, LASER = 20, ENERGY = 10, BOMB = 20, BIO = 10, RAD = 20, FIRE = 100, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 15, BULLET = 5, LASER = 20, ENERGY = 10, BOMB = 20, BIO = 10, RAD = 20, FIRE = 100, ACID = 50, STAMINA = 10, BLEED = 25)
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
@@ -70,7 +70,7 @@
desc = "Use in case of bomb."
icon_state = "bombsuit"
clothing_flags = THICKMATERIAL | SNUG_FIT
- armor = list(MELEE = 20, BULLET = 0, LASER = 20, ENERGY = 10, BOMB = 100, BIO = 0, RAD = 0, FIRE = 80, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 20, BULLET = 0, LASER = 20, ENERGY = 10, BOMB = 100, BIO = 0, RAD = 0, FIRE = 80, ACID = 50, STAMINA = 10, BLEED = 25)
flags_inv = HIDEFACE|HIDEMASK|HIDEEARS|HIDEEYES|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
dynamic_hair_suffix = ""
dynamic_fhair_suffix = ""
@@ -95,7 +95,7 @@
clothing_flags = THICKMATERIAL
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
slowdown = 2
- armor = list(MELEE = 20, BULLET = 0, LASER = 20, ENERGY = 10, BOMB = 100, BIO = 0, RAD = 0, FIRE = 80, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 20, BULLET = 0, LASER = 20, ENERGY = 10, BOMB = 100, BIO = 0, RAD = 0, FIRE = 80, ACID = 50, STAMINA = 10, BLEED = 25)
flags_inv = HIDEJUMPSUIT
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT
@@ -133,7 +133,7 @@
desc = "A hood with radiation protective properties. The label reads, 'Made with lead. Please do not consume insulation.'"
clothing_flags = THICKMATERIAL | SNUG_FIT
flags_inv = HIDEMASK|HIDEEARS|HIDEFACE|HIDEEYES|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 60, RAD = 100, FIRE = 30, ACID = 30, STAMINA = 10)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 60, RAD = 100, FIRE = 30, ACID = 30, STAMINA = 10, BLEED = 15)
strip_delay = 60
equip_delay_other = 60
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
@@ -151,7 +151,7 @@
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/geiger_counter)
slowdown = 1.5
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 60, RAD = 100, FIRE = 30, ACID = 30, STAMINA = 10)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 60, RAD = 100, FIRE = 30, ACID = 30, STAMINA = 10, BLEED = 15)
strip_delay = 60
equip_delay_other = 60
flags_inv = HIDEJUMPSUIT
diff --git a/code/modules/clothing/suits/wintercoats.dm b/code/modules/clothing/suits/wintercoats.dm
index fb33b76761d58..c357091cca300 100644
--- a/code/modules/clothing/suits/wintercoats.dm
+++ b/code/modules/clothing/suits/wintercoats.dm
@@ -56,17 +56,19 @@
/obj/item/clothing/suit/hooded/wintercoat/security
name = "security winter coat"
+ desc = "A thick jacket made from a light, fire-resistant kevlar-like material which provides some protection to the user. It is particularly effective against energy-based threats due to its thickness and insulation."
icon_state = "coatsecurity"
item_state = "coatsecurity"
- armor = list(MELEE = 25, BULLET = 15, LASER = 30, ENERGY = 10, BOMB = 25, BIO = 0, RAD = 0, FIRE = 0, ACID = 45, STAMINA = 20)
hoodtype = /obj/item/clothing/head/hooded/winterhood/security
- slowdown = 0.05
+ armor = list(MELEE = 15, BULLET = 15, LASER = 40, ENERGY = 50, BOMB = 25, BIO = 0, RAD = 0, FIRE = 60, ACID = 45, STAMINA = 40)
+ slowdown = 0.04
/obj/item/clothing/suit/hooded/wintercoat/security/Initialize(mapload)
. = ..()
allowed = GLOB.security_wintercoat_allowed
/obj/item/clothing/head/hooded/winterhood/security
+ armor = list(MELEE = 15, BULLET = 15, LASER = 40, ENERGY = 50, BOMB = 25, BIO = 0, RAD = 0, FIRE = 60, ACID = 45, STAMINA = 40)
icon_state = "winterhood_security"
/obj/item/clothing/suit/hooded/wintercoat/detective
@@ -464,4 +466,21 @@
/obj/item/clothing/head/hooded/winterhood/cargo/old
icon_state = "old_winterhood_cargo"
-//end of winter coats
+//end of winter coats //uhhh... nuh uh
+
+// CentCom
+/obj/item/clothing/suit/hooded/wintercoat/centcom
+ name = "centcom winter coat"
+ desc = "A luxurious winter coat woven in the bright green and gold colours of Central Command. It has a small pin in the shape of the Nanotrasen logo for a zipper."
+ icon_state = "coatcentcom"
+ item_state = "coatcentcom"
+ armor = list(MELEE = 35, BULLET = 40, LASER = 40, ENERGY = 50, BOMB = 35, BIO = 10, RAD = 10, FIRE = 10, ACID = 60)
+ hoodtype = /obj/item/clothing/head/hooded/winterhood/centcom
+
+/obj/item/clothing/suit/hooded/wintercoat/centcom/Initialize(mapload)
+ . = ..()
+ allowed += GLOB.security_wintercoat_allowed
+
+/obj/item/clothing/head/hooded/winterhood/centcom
+ icon_state = "hood_centcom"
+ armor = list(MELEE = 35, BULLET = 40, LASER = 40, ENERGY = 50, BOMB = 35, BIO = 10, RAD = 10, FIRE = 10, ACID = 60)
diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm
index e7bca1b48511b..fb3781dbb0315 100644
--- a/code/modules/clothing/suits/wiz_robe.dm
+++ b/code/modules/clothing/suits/wiz_robe.dm
@@ -7,7 +7,7 @@
item_state = "wizhat"
gas_transfer_coefficient = 0.01 // IT'S MAGICAL OKAY JEEZ +1 TO NOT DIE
permeability_coefficient = 0.01
- armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 20, BIO = 20, RAD = 20, FIRE = 100, ACID = 100, STAMINA = 50)
+ armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 20, BIO = 20, RAD = 20, FIRE = 100, ACID = 100, STAMINA = 50, BLEED = 60)
strip_delay = 50
equip_delay_other = 50
clothing_flags = SNUG_FIT | THICKMATERIAL
@@ -38,7 +38,7 @@
icon_state = "wizard-fake"
gas_transfer_coefficient = 1
permeability_coefficient = 1
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0, BLEED = 0)
resistance_flags = FLAMMABLE
dog_fashion = /datum/dog_fashion/head/blue_wizard
clothing_flags = NONE
@@ -74,7 +74,7 @@
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01
body_parts_covered = CHEST|GROIN|ARMS|LEGS
- armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 20, BIO = 20, RAD = 20, FIRE = 100, ACID = 100, STAMINA = 50)
+ armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 20, BIO = 20, RAD = 20, FIRE = 100, ACID = 100, STAMINA = 50, BLEED = 60)
allowed = list(/obj/item/teleportation_scroll)
flags_inv = HIDEJUMPSUIT
strip_delay = 50
@@ -143,7 +143,7 @@
item_state = "wizrobe"
gas_transfer_coefficient = 1
permeability_coefficient = 1
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0, BLEED = 0)
resistance_flags = FLAMMABLE
clothing_flags = NONE
@@ -153,7 +153,7 @@
icon_state = "marisa"
gas_transfer_coefficient = 1
permeability_coefficient = 1
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0, BLEED = 0)
resistance_flags = FLAMMABLE
clothing_flags = NONE
@@ -164,7 +164,7 @@
item_state = "marisarobe"
gas_transfer_coefficient = 1
permeability_coefficient = 1
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0, BLEED = 0)
resistance_flags = FLAMMABLE
clothing_flags = NONE
@@ -210,16 +210,16 @@
desc = "Not all wizards are afraid of getting up close and personal."
icon_state = "battlemage"
item_state = "battlemage"
- recharge_delay = 0 // no auto-recharge
- max_charges = 15
- shield_icon = "shield-red"
min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT
max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard
- armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 20, BIO = 20, RAD = 20, FIRE = 100, ACID = 100, STAMINA = 70)
+ armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 20, BIO = 20, RAD = 20, FIRE = 100, ACID = 100, STAMINA = 70, BLEED = 70)
slowdown = 0
resistance_flags = FIRE_PROOF | ACID_PROOF
+/obj/item/clothing/suit/space/hardsuit/shielded/wizard/setup_shielding()
+ AddComponent(/datum/component/shielded, max_charges = 15, recharge_start_delay = 0 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, shield_icon = "shield-red")
+
/obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard
name = "battlemage helmet"
desc = "A suitably impressive helmet.."
@@ -227,7 +227,7 @@
item_state = "battlemage"
min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT
max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT
- armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 20, BIO = 20, RAD = 20, FIRE = 100, ACID = 100, STAMINA = 70)
+ armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 20, BIO = 20, RAD = 20, FIRE = 100, ACID = 100, STAMINA = 70, BLEED = 70)
actions_types = null //No inbuilt light
resistance_flags = FIRE_PROOF | ACID_PROOF
diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm
index 45d9ae724c1ae..b41fd05d11401 100644
--- a/code/modules/clothing/under/_under.dm
+++ b/code/modules/clothing/under/_under.dm
@@ -5,7 +5,7 @@
body_parts_covered = CHEST|GROIN|LEGS|ARMS
permeability_coefficient = 0.9
slot_flags = ITEM_SLOT_ICLOTHING
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10)
drop_sound = 'sound/items/handling/cloth_drop.ogg'
pickup_sound = 'sound/items/handling/cloth_pickup.ogg'
var/fitted = FEMALE_UNIFORM_FULL // For use in alternate clothing styles for women
diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm
index 22b024c42f02b..e980c273da0fa 100755
--- a/code/modules/clothing/under/accessories.dm
+++ b/code/modules/clothing/under/accessories.dm
@@ -228,7 +228,7 @@
desc = "An eccentric medal made of plasma."
icon_state = "plasma"
medaltype = "medal-plasma"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = -10, ACID = 0, STAMINA = 0) //It's made of plasma. Of course it's flammable.
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = -10, ACID = 0, STAMINA = 0, BLEED = 0) //It's made of plasma. Of course it's flammable.
custom_materials = list(/datum/material/plasma=1000)
/obj/item/clothing/accessory/medal/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
@@ -361,7 +361,7 @@
name = "bone talisman"
desc = "A hunter's talisman, some say the old gods smile on those who wear it."
icon_state = "talisman"
- armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 5, BOMB = 20, BIO = 20, RAD = 5, FIRE = 0, ACID = 25, STAMINA = 10)
+ armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 5, BOMB = 20, BIO = 20, RAD = 5, FIRE = 0, ACID = 25, STAMINA = 10, BLEED = 10)
attachment_slot = null
/obj/item/clothing/accessory/skullcodpiece
@@ -369,7 +369,7 @@
desc = "A skull shaped ornament, intended to protect the important things in life."
icon_state = "skull"
above_suit = TRUE
- armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 5, BOMB = 20, BIO = 20, RAD = 5, FIRE = 0, ACID = 25, STAMINA = 10)
+ armor = list(MELEE = 5, BULLET = 5, LASER = 5, ENERGY = 5, BOMB = 20, BIO = 20, RAD = 5, FIRE = 0, ACID = 25, STAMINA = 10, BLEED = 10)
attachment_slot = GROIN
/obj/item/clothing/accessory/holster
diff --git a/code/modules/clothing/under/color.dm b/code/modules/clothing/under/color.dm
index 1ee6779f7b248..255d85f5a182d 100644
--- a/code/modules/clothing/under/color.dm
+++ b/code/modules/clothing/under/color.dm
@@ -222,13 +222,13 @@
name = "durathread jumpsuit"
desc = "A jumpsuit made from durathread, its resilient fibres provide some protection to the wearer."
greyscale_colors = "#8291a1"
- armor = list(MELEE = 10, BULLET = 15, LASER = 10, FIRE = 40, ACID = 10, BOMB = 5, ENERGY = 20, STAMINA = 20)
+ armor = list(MELEE = 10, BULLET = 15, LASER = 10, FIRE = 40, ACID = 10, BOMB = 5, ENERGY = 20, STAMINA = 20, BLEED = 30)
/obj/item/clothing/under/color/jumpskirt/durathread
name = "durathread jumpskirt"
desc = "A jumpskirt made from durathread, its resilient fibres provide some protection to the wearer."
greyscale_colors = "#8291a1"
- armor = list(MELEE = 10, BULLET = 15, LASER = 10, FIRE = 40, ACID = 10, BOMB = 5, ENERGY = 20, STAMINA = 20)
+ armor = list(MELEE = 10, BULLET = 15, LASER = 10, FIRE = 40, ACID = 10, BOMB = 5, ENERGY = 20, STAMINA = 20, BLEED = 30)
/obj/item/clothing/under/color/rainbow
name = "rainbow jumpsuit"
diff --git a/code/modules/clothing/under/costume.dm b/code/modules/clothing/under/costume.dm
index 318d98d308cfa..9b040935b088a 100644
--- a/code/modules/clothing/under/costume.dm
+++ b/code/modules/clothing/under/costume.dm
@@ -257,7 +257,7 @@
item_state = null
worn_icon = 'icons/mob/clothing/under/security.dmi'
alt_covers_chest = TRUE
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 30, ACID = 30, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 30, ACID = 30, STAMINA = 10, BLEED = 15)
strip_delay = 50
alt_covers_chest = TRUE
sensor_mode = SENSOR_COORDS
diff --git a/code/modules/clothing/under/jobs/Plasmaman/engineering.dm b/code/modules/clothing/under/jobs/Plasmaman/engineering.dm
index 2b99630ba30e9..e50357a9e4749 100644
--- a/code/modules/clothing/under/jobs/Plasmaman/engineering.dm
+++ b/code/modules/clothing/under/jobs/Plasmaman/engineering.dm
@@ -3,7 +3,7 @@
desc = "An air-tight suit designed to be used by plasmamen exployed as engineers, the usual purple stripes being replaced by engineer's orange. It protects the user from fire and acid damage."
icon_state = "engineer_envirosuit"
item_state = "engineer_envirosuit"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 10, FIRE = 95, ACID = 95, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 10, FIRE = 95, ACID = 95, STAMINA = 0, BLEED = 10)
/obj/item/clothing/under/plasmaman/engineering/atmospherics
name = "atmospherics plasma envirosuit"
diff --git a/code/modules/clothing/under/jobs/Plasmaman/security.dm b/code/modules/clothing/under/jobs/Plasmaman/security.dm
index 8b737d2b16866..26282303438f1 100644
--- a/code/modules/clothing/under/jobs/Plasmaman/security.dm
+++ b/code/modules/clothing/under/jobs/Plasmaman/security.dm
@@ -3,7 +3,7 @@
desc = "A plasmaman containment suit designed for security officers, offering a limited amount of extra protection."
icon_state = "security_envirosuit"
item_state = "security_envirosuit"
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 95, ACID = 95, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 95, ACID = 95, STAMINA = 10, BLEED = 10)
sensor_mode = SENSOR_COORDS
random_sensor = FALSE
@@ -24,4 +24,4 @@
desc = "A plasmaman containment suit designed for brig physicians. It has a red cross emblasoned on the chest."
icon_state = "secmed_envirosuit"
item_state = "secmed_envirosuit"
- armor = list(MELEE = 5, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 95, ACID = 95, STAMINA = 10)
+ armor = list(MELEE = 5, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 95, ACID = 95, STAMINA = 10, BLEED = 10)
diff --git a/code/modules/clothing/under/jobs/centcom.dm b/code/modules/clothing/under/jobs/centcom.dm
index 253b73e8c6912..239e2af73d7b0 100644
--- a/code/modules/clothing/under/jobs/centcom.dm
+++ b/code/modules/clothing/under/jobs/centcom.dm
@@ -2,22 +2,51 @@
icon = 'icons/obj/clothing/under/centcom.dmi'
worn_icon = 'icons/mob/clothing/under/centcom.dmi'
-/obj/item/clothing/under/rank/centcom/officer
- name = "\improper CentCom officer's jumpsuit"
- desc = "It's a jumpsuit worn by CentCom Officers."
- icon_state = "officer"
- item_state = "g_suit"
- alt_covers_chest = TRUE
-
/obj/item/clothing/under/rank/centcom/commander
- name = "\improper CentCom officer's jumpsuit"
- desc = "It's a jumpsuit worn by CentCom's highest-tier Commanders."
+ name = "\improper CentCom commander's suit"
+ desc = "It's a suit worn by CentCom's highest-tier Commanders."
icon_state = "centcom"
item_state = "dg_suit"
+/obj/item/clothing/under/rank/centcom/official
+ name = "\improper CentCom official's suit"
+ desc = "A suit worn by CentCom Officials, with a silver belt buckle to indicate their rank from a glance."
+ icon_state = "official"
+ item_state = "dg_suit"
+
/obj/item/clothing/under/rank/centcom/intern
name = "\improper CentCom intern's jumpsuit"
desc = "It's a jumpsuit worn by those interning for CentCom. The top is styled after a polo shirt for easy identification."
icon_state = "intern"
- item_state = "g_suit"
+ item_state = "dg_suit"
can_adjust = FALSE
+
+/obj/item/clothing/under/rank/centcom/officer
+ name = "\improper CentCom turtleneck suit"
+ desc = "A casual, yet refined green turtleneck, used by CentCom Officers. It has a fragrance of aloe."
+ icon_state = "officer"
+ item_state = "dg_suit"
+ alt_covers_chest = TRUE
+
+/obj/item/clothing/under/rank/centcom/officer/replica
+ name = "\improper CentCom turtleneck replica"
+ desc = "A cheap copy of the CentCom turtleneck! A Donk Co. logo can be seen on the collar."
+
+/obj/item/clothing/under/rank/centcom/officer_skirt
+ name = "\improper CentCom turtleneck skirt"
+ desc = "A skirt version of the CentCom turtleneck, rarer and more sought after than the original."
+ icon_state = "officer_skirt"
+ item_state = "dg_suit"
+ alt_covers_chest = TRUE
+ body_parts_covered = CHEST|GROIN|ARMS
+
+/obj/item/clothing/under/rank/centcom/officer_skirt/replica
+ name = "\improper CentCom turtleneck skirt replica"
+ desc = "A cheap copy of the CentCom turtleneck skirt! A Donk Co. logo can be seen on the collar."
+
+/obj/item/clothing/under/rank/centcom/centcom_skirt
+ name = "\improper CentCom commander's suitskirt"
+ desc = "It's a suitskirt worn by CentCom's highest-tier Commanders."
+ icon_state = "centcom_skirt"
+ item_state = "dg_suit"
+ body_parts_covered = CHEST|GROIN|ARMS
diff --git a/code/modules/clothing/under/jobs/civilian/civilian.dm b/code/modules/clothing/under/jobs/civilian/civilian.dm
index 5b24c69e531bd..a3b979a75cef6 100644
--- a/code/modules/clothing/under/jobs/civilian/civilian.dm
+++ b/code/modules/clothing/under/jobs/civilian/civilian.dm
@@ -126,7 +126,7 @@
desc = "It's the official uniform of the station's janitor. It has minor protection from biohazards."
name = "janitor's jumpsuit"
icon_state = "janitor"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10)
/obj/item/clothing/under/rank/civilian/janitor/skirt
name = "janitor's jumpskirt"
diff --git a/code/modules/clothing/under/jobs/command.dm b/code/modules/clothing/under/jobs/command.dm
index d5029d8aa0a25..f915d5ea92f8b 100644
--- a/code/modules/clothing/under/jobs/command.dm
+++ b/code/modules/clothing/under/jobs/command.dm
@@ -3,7 +3,7 @@
name = "captain's jumpsuit"
icon_state = "captain"
item_state = "b_suit"
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 30, ACID = 30, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 30, ACID = 30, STAMINA = 10, BLEED = 10)
sensor_mode = SENSOR_COORDS
random_sensor = FALSE
icon = 'icons/obj/clothing/under/captain.dmi'
diff --git a/code/modules/clothing/under/jobs/engineering.dm b/code/modules/clothing/under/jobs/engineering.dm
index d9876536acf8d..88d6289238255 100644
--- a/code/modules/clothing/under/jobs/engineering.dm
+++ b/code/modules/clothing/under/jobs/engineering.dm
@@ -12,7 +12,7 @@
icon_state = "chiefengineer"
item_state = "gy_suit" //TODO replace it
worn_icon_state = "chiefengineer"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 10, FIRE = 80, ACID = 40, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 10, FIRE = 80, ACID = 40, STAMINA = 0, BLEED = 10)
resistance_flags = NONE
/obj/item/clothing/under/rank/engineering/chief_engineer/skirt
@@ -20,7 +20,7 @@
name = "chief engineer's jumpskirt"
icon_state = "chiefengineer_skirt"
item_state = "gy_suit"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 7, FIRE = 80, ACID = 40, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 7, FIRE = 80, ACID = 40, STAMINA = 0, BLEED = 10)
body_parts_covered = CHEST|GROIN|ARMS
can_adjust = FALSE
fitted = FEMALE_UNIFORM_TOP
@@ -50,7 +50,7 @@
name = "engineer's jumpsuit"
icon_state = "engine"
item_state = "engi_suit"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 10, FIRE = 60, ACID = 20, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 10, FIRE = 60, ACID = 20, STAMINA = 0, BLEED = 10)
resistance_flags = NONE
/obj/item/clothing/under/rank/engineering/engineer/hazard
diff --git a/code/modules/clothing/under/jobs/medical.dm b/code/modules/clothing/under/jobs/medical.dm
index 051cfdbb4dff2..996ce9e21a1e1 100644
--- a/code/modules/clothing/under/jobs/medical.dm
+++ b/code/modules/clothing/under/jobs/medical.dm
@@ -9,7 +9,7 @@
icon_state = "cmo"
item_state = "w_suit"
permeability_coefficient = 0.5
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10)
/obj/item/clothing/under/rank/medical/chief_medical_officer/skirt
name = "chief medical officer's jumpskirt"
@@ -28,7 +28,7 @@
icon_state = "genetics"
item_state = "w_suit"
permeability_coefficient = 0.5
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10)
/obj/item/clothing/under/rank/medical/geneticist/skirt
name = "geneticist's jumpskirt"
@@ -47,7 +47,7 @@
icon_state = "virology"
item_state = "w_suit"
permeability_coefficient = 0.5
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10)
/obj/item/clothing/under/rank/medical/virologist/skirt
name = "virologist's jumpskirt"
@@ -65,7 +65,7 @@
desc = "A standard jumpsuit used by paramedics onboard space stations. It's made of a special fiber that gives special protection against biohazards."
icon_state = "paramedic"
permeability_coefficient = 0.5
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10)
can_adjust = FALSE
/obj/item/clothing/under/rank/medical/paramedic/skirt
@@ -85,7 +85,7 @@
icon_state = "nursesuit"
item_state = "w_suit"
permeability_coefficient = 0.5
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10)
body_parts_covered = CHEST|GROIN|ARMS
fitted = NO_FEMALE_UNIFORM
can_adjust = FALSE
@@ -96,7 +96,7 @@
icon_state = "medical"
item_state = "w_suit"
permeability_coefficient = 0.5
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10)
/obj/item/clothing/under/rank/medical/doctor/skirt
name = "medical doctor's jumpskirt"
@@ -133,7 +133,7 @@
icon_state = "chemistry"
item_state = "w_suit"
permeability_coefficient = 0.5
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 50, ACID = 65, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 10, RAD = 0, FIRE = 50, ACID = 65, STAMINA = 0, BLEED = 10)
/obj/item/clothing/under/rank/medical/chemist/skirt
name = "chemist's jumpskirt"
diff --git a/code/modules/clothing/under/jobs/rnd.dm b/code/modules/clothing/under/jobs/rnd.dm
index f084ff1e700a7..7f17125c3112c 100644
--- a/code/modules/clothing/under/jobs/rnd.dm
+++ b/code/modules/clothing/under/jobs/rnd.dm
@@ -7,7 +7,7 @@
desc = "It's a jumpsuit worn by those with the know-how to achieve the position of \"Research Director\". Its fabric provides minor protection from biological contaminants."
icon_state = "director"
item_state = "w_suit"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 10, RAD = 0, FIRE = 0, ACID = 35, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 10, RAD = 0, FIRE = 0, ACID = 35, STAMINA = 0, BLEED = 10)
can_adjust = TRUE
alt_covers_chest = TRUE
@@ -27,7 +27,7 @@
name = "research director's tan suit"
icon_state = "rdwhimsy"
item_state = "rdwhimsy"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10)
can_adjust = TRUE
alt_covers_chest = TRUE
@@ -47,7 +47,7 @@
name = "research director's turtleneck"
icon_state = "rdturtle"
item_state = "p_suit"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 10, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10)
can_adjust = TRUE
alt_covers_chest = TRUE
@@ -76,7 +76,7 @@
item_state = "w_suit"
worn_icon_state = "toxinswhite"
permeability_coefficient = 0.5
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10)
/obj/item/clothing/under/rank/rnd/scientist/skirt
name = "scientist's jumpskirt"
diff --git a/code/modules/clothing/under/jobs/security.dm b/code/modules/clothing/under/jobs/security.dm
index 96038f4ada795..6dd3db43fc331 100644
--- a/code/modules/clothing/under/jobs/security.dm
+++ b/code/modules/clothing/under/jobs/security.dm
@@ -22,7 +22,7 @@
desc = "A tactical security jumpsuit for officers complete with Nanotrasen belt buckle."
icon_state = "rsecurity"
item_state = "r_suit"
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 30, ACID = 30, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 30, ACID = 30, STAMINA = 10, BLEED = 10)
alt_covers_chest = TRUE
/obj/item/clothing/under/rank/security/officer/white
@@ -71,6 +71,7 @@
desc = "A formal security suit for officers complete with Nanotrasen belt buckle."
icon_state = "rwarden"
item_state = "r_suit"
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 30, ACID = 30, STAMINA = 10, BLEED = 10)
/obj/item/clothing/under/rank/security/warden/white
name = "white security suit"
@@ -104,7 +105,7 @@
desc = "Someone who wears this means business."
icon_state = "detective"
item_state = "det"
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 30, ACID = 30, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 30, ACID = 30, STAMINA = 10, BLEED = 10)
strip_delay = 50
alt_covers_chest = TRUE
sensor_mode = SENSOR_COORDS
@@ -147,7 +148,7 @@
desc = "A security jumpsuit decorated for those few with the dedication to achieve the position of Head of Security."
icon_state = "rhos"
item_state = "r_suit"
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 50, STAMINA = 10, BLEED = 10)
strip_delay = 60
alt_covers_chest = TRUE
sensor_mode = SENSOR_COORDS
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index 5ebf1fe341e22..fe03c6e7e234a 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -40,7 +40,7 @@
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
- armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100)
+ armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100, BLEED = 100)
cold_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS
min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
diff --git a/code/modules/clothing/under/syndicate.dm b/code/modules/clothing/under/syndicate.dm
index f6f319679be9a..a599447bca044 100644
--- a/code/modules/clothing/under/syndicate.dm
+++ b/code/modules/clothing/under/syndicate.dm
@@ -4,7 +4,7 @@
icon_state = "syndicate"
item_state = "bl_suit"
has_sensor = NO_SENSORS
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 40, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 40, STAMINA = 10, BLEED = 25)
alt_covers_chest = TRUE
icon = 'icons/obj/clothing/under/syndicate.dmi'
worn_icon = 'icons/mob/clothing/under/syndicate.dmi'
@@ -14,7 +14,7 @@
desc = "Just looking at it makes you want to buy an SKS, go into the woods, and -operate-."
icon_state = "tactifool"
item_state = "bl_suit"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 40, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 40, STAMINA = 0, BLEED = 10)
/obj/item/clothing/under/syndicate/sniper
name = "Tactical turtleneck suit"
@@ -35,7 +35,7 @@
desc = "Badly translated labels tell you to clean this in Vodka. Great for squatting in."
icon_state = "trackpants"
can_adjust = FALSE
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 10, BLEED = 15)
resistance_flags = NONE
/obj/item/clothing/under/syndicate/combat
@@ -49,5 +49,5 @@
desc = "Military grade tracksuits for frontline squatting."
icon_state = "rus_under"
can_adjust = FALSE
- armor = list(MELEE = 5, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 10)
+ armor = list(MELEE = 5, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 10, BLEED = 15)
resistance_flags = NONE
diff --git a/code/modules/clothing/under/trek.dm b/code/modules/clothing/under/trek.dm
index 88055c88644f0..3e89917cdc11f 100644
--- a/code/modules/clothing/under/trek.dm
+++ b/code/modules/clothing/under/trek.dm
@@ -18,7 +18,7 @@
desc = "The uniform worn by engineering/security officers."
icon_state = "trek_engsec"
item_state = "r_suit"
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0) //more sec than eng, but w/e.
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 10) //more sec than eng, but w/e.
strip_delay = 50
/obj/item/clothing/under/trek/medsci
diff --git a/code/modules/events/anomaly_blood.dm b/code/modules/events/anomaly_blood.dm
new file mode 100644
index 0000000000000..59b914c3736a1
--- /dev/null
+++ b/code/modules/events/anomaly_blood.dm
@@ -0,0 +1,14 @@
+/datum/round_event_control/anomaly/blood
+ name = "Anomaly: Blood"
+ typepath = /datum/round_event/anomaly/blood
+
+ min_players = 15
+ max_occurrences = 2
+
+/datum/round_event/anomaly/blood
+ startWhen = 3
+ announceWhen = 10
+ anomaly_path = /obj/effect/anomaly/blood
+
+/datum/round_event/anomaly/blood/announce(fake)
+ priority_announce("Blood anomaly detected on long range scanners. Expected location: [impact_area.name].", "Anomaly Alert", SSstation.announcer.get_rand_alert_sound())
diff --git a/code/modules/events/asteroid_impact.dm b/code/modules/events/asteroid_impact.dm
index 0db2eb2892264..a303576af65c3 100644
--- a/code/modules/events/asteroid_impact.dm
+++ b/code/modules/events/asteroid_impact.dm
@@ -13,7 +13,7 @@
/datum/round_event/asteroid_impact/announce(fake)
priority_announce("A class-A asteroid has been detected on a collision course with the station. Destruction of the station is innevitable.", SSstation.announcer.get_rand_alert_sound())
if(!fake)
- set_security_level(SEC_LEVEL_DELTA)
+ SSsecurity_level.set_level(SEC_LEVEL_DELTA)
var/area/A = GLOB.areas_by_type[/area/centcom]
if(EMERGENCY_IDLE_OR_RECALLED)
SSshuttle.emergency.request(null, A, "Automatic Shuttle Call: Station destruction imminent.", TRUE)
diff --git a/code/modules/events/bureaucratic_error.dm b/code/modules/events/bureaucratic_error.dm
index d980f3ddc5f5c..087a9cbc232ea 100644
--- a/code/modules/events/bureaucratic_error.dm
+++ b/code/modules/events/bureaucratic_error.dm
@@ -6,7 +6,7 @@
/datum/round_event/bureaucratic_error
announceWhen = 1
- var/datum/job/chosen_job
+ var/chosen_job_title
/datum/round_event/bureaucratic_error/setup()
var/error_count = 10
@@ -14,13 +14,13 @@
var/datum/job/J = SSjob.GetJob(pick(get_all_jobs()))
if(!J || J.lock_flags)
continue
- chosen_job = J
+ chosen_job_title = J.title
break
- if(!chosen_job)
+ if(isnull(chosen_job_title))
return kill()
/datum/round_event/bureaucratic_error/announce(fake)
priority_announce("A recent bureaucratic error in the Organic Resources Department may result in personnel shortages in some departments and redundant staffing in others.", "Paperwork Mishap Alert", SSstation.announcer.get_rand_alert_sound())
/datum/round_event/bureaucratic_error/start()
- SSjob.set_overflow_role(chosen_job)
+ SSjob.set_overflow_role(chosen_job_title)
diff --git a/code/modules/events/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm
index fc8a5e39b0215..8a956238270b7 100644
--- a/code/modules/events/holiday/xmas.dm
+++ b/code/modules/events/holiday/xmas.dm
@@ -38,14 +38,14 @@
icon_state = "xmashat"
desc = "A crappy paper hat that you are REQUIRED to wear."
flags_inv = 0
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
/obj/item/clothing/head/costume/festive/Initialize(mapload)
//Merry christmas
if(CHRISTMAS in SSevents.holidays)
- armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 30, BIO = 30, RAD = 30, FIRE = 30, ACID = 30, STAMINA = 30)
+ armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 30, BIO = 30, RAD = 30, FIRE = 30, ACID = 30, STAMINA = 30, BLEED = 30)
else if(FESTIVE_SEASON in SSevents.holidays)
- armor = list(MELEE = 20, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 20, BIO = 20, RAD = 20, FIRE = 20, ACID = 20, STAMINA = 20)
+ armor = list(MELEE = 20, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 20, BIO = 20, RAD = 20, FIRE = 20, ACID = 20, STAMINA = 20, BLEED = 20)
return ..()
/obj/effect/spawner/xmastree
diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm
index eebf6f200c896..97236848b2e4e 100644
--- a/code/modules/events/immovable_rod.dm
+++ b/code/modules/events/immovable_rod.dm
@@ -132,7 +132,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
else if (isobj(clong))
if(clong.density)
var/obj/hit_obj = clong
- hit_obj.take_damage(hit_obj.obj_integrity, armour_penetration = 100)
+ hit_obj.take_damage(hit_obj.get_integrity(), armour_penetration = 100)
else if(isliving(clong))
penetrate(clong)
else if(istype(clong, type))
diff --git a/code/modules/events/mimite_infestation.dm b/code/modules/events/mimite_infestation.dm
new file mode 100644
index 0000000000000..dd99e6047d6c0
--- /dev/null
+++ b/code/modules/events/mimite_infestation.dm
@@ -0,0 +1,65 @@
+/datum/round_event_control/mimite_infestation
+ name = "Mimite Infestation"
+ typepath = /datum/round_event/mimite_infestation
+ weight = 10
+ min_players = 20
+
+
+/datum/round_event/mimite_infestation
+ announceWhen = 200
+ // 50% chance of being incremented by one
+ var/spawncount = 3
+ fakeable = TRUE
+
+/datum/round_event/mimite_infestation/setup()
+ announceWhen = rand(announceWhen, announceWhen + 50)
+ endWhen = 3600 //60 min
+ if(prob(50))
+ spawncount++
+
+/datum/round_event/mimite_infestation/announce(fake)
+ var/living_mimites = FALSE
+ for(var/mob/living/simple_animal/hostile/mimite/A)
+ if(A.stat != DEAD)
+ living_mimites = TRUE
+ if(living_mimites || fake)
+ priority_announce("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert", ANNOUNCER_ALIENS)
+
+/datum/round_event/mimite_infestation/start()
+ var/list/vents = list()
+ for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in GLOB.machines)
+ if(QDELETED(temp_vent))
+ continue
+ if(is_station_level(temp_vent.loc.z) && !temp_vent.welded)
+ var/datum/pipeline/temp_vent_parent = temp_vent.parents[1]
+ if(!temp_vent_parent)
+ continue//no parent vent
+ //Stops mimites getting stuck in small networks.
+ if(temp_vent_parent.other_atmosmch.len > 20)
+ vents += temp_vent
+ if(!vents.len)
+ message_admins("An event attempted to spawn mimites but no suitable vents were found. Shutting down.")
+ return MAP_ERROR
+ while(spawncount > 0 && vents.len)
+ var/obj/vent = pick_n_take(vents)
+ var/mob/living/simple_animal/hostile/mimite/new_mimite = new(vent.loc)
+ switch(length(GLOB.player_list))
+ if(0 to 20)
+ new_mimite.remaining_replications = 3
+ if(20 to 40)
+ new_mimite.remaining_replications = 4
+ else
+ new_mimite.remaining_replications = 5
+ spawncount--
+ announce_to_ghosts(new_mimite)
+ message_admins("[ADMIN_LOOKUPFLW(new_mimite)] has been spawned by an event.")
+ log_game("mimites where spawned by an event.")
+ return SUCCESSFUL_SPAWN
+
+
+/datum/round_event/mimite_infestation/end()
+ if(length(GLOB.all_mimites)) //If they're still around at the end of 60 min, turn of replication permanently
+ for(var/mob/living/simple_animal/hostile/mimite/M in GLOB.all_mimites)
+ M.eventongoing = FALSE
+ else
+ priority_announce("Sensors are no-longer detecting an outbreak of Mimites, well done crew!", "Lifesign Alert", SSstation.announcer.get_rand_alert_sound())
diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm
index 0f3a56cd1de40..b1e12c936440e 100644
--- a/code/modules/events/spacevine.dm
+++ b/code/modules/events/spacevine.dm
@@ -278,8 +278,7 @@
/datum/spacevine_mutation/woodening/on_grow(obj/structure/spacevine/holder)
if(holder.energy)
holder.set_density(TRUE)
- holder.max_integrity = 100
- holder.obj_integrity = holder.max_integrity
+ holder.modify_max_integrity(100)
/datum/spacevine_mutation/woodening/on_hit(obj/structure/spacevine/holder, mob/living/hitter, obj/item/I, expected_damage)
if(I?.is_sharp())
diff --git a/code/modules/fields/timestop.dm b/code/modules/fields/timestop.dm
index 7b27d3609fb2d..7efa781d7818b 100644
--- a/code/modules/fields/timestop.dm
+++ b/code/modules/fields/timestop.dm
@@ -146,7 +146,7 @@
/datum/proximity_monitor/advanced/timestop/process()
for(var/i in frozen_mobs)
var/mob/living/m = i
- m.Stun(20, 1, 1)
+ m.Stun(20, ignore_canstun = TRUE)
/datum/proximity_monitor/advanced/timestop/setup_field_turf(turf/T)
for(var/i in T.contents)
@@ -165,7 +165,7 @@
if(L.anti_magic_check(check_anti_magic, check_holy))
immune += L
return
- L.Stun(20, 1, 1)
+ L.Stun(20, ignore_canstun = TRUE)
SSmove_manager.stop_looping(src) //stops them mid pathing even if they're stunimmune //This is really dumb
if(isanimal(L))
var/mob/living/simple_animal/S = L
@@ -175,7 +175,7 @@
H.LoseTarget()
/datum/proximity_monitor/advanced/timestop/proc/unfreeze_mob(mob/living/L)
- L.AdjustStun(-20, 1, 1)
+ L.AdjustStun(-20, ignore_canstun = TRUE)
frozen_mobs -= L
if(isanimal(L))
var/mob/living/simple_animal/S = L
diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
index 6cd70bf1f8356..c169b897c6d70 100644
--- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
@@ -134,6 +134,7 @@
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("stabbed", "slashed", "attacked")
sharpness = IS_SHARP
+ bleed_force = BLEED_SURFACE
var/static/icon/broken_outline = icon('icons/obj/drinks.dmi', "broken")
/obj/item/broken_bottle/Initialize(mapload)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
index d06c44169f31b..47d2e91f9d062 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
@@ -57,7 +57,7 @@
/obj/machinery/gibber/container_resist(mob/living/user)
go_out()
-/obj/machinery/gibber/relaymove(mob/living/user)
+/obj/machinery/gibber/relaymove(mob/living/user, direction)
go_out()
/obj/machinery/gibber/attack_hand(mob/user)
diff --git a/code/modules/holoparasite/_holoparasite.dm b/code/modules/holoparasite/_holoparasite.dm
index 99fdb77fbe344..ab53ae325ae8c 100644
--- a/code/modules/holoparasite/_holoparasite.dm
+++ b/code/modules/holoparasite/_holoparasite.dm
@@ -140,6 +140,8 @@ GLOBAL_LIST_EMPTY_TYPED(holoparasites, /mob/living/simple_animal/hostile/holopar
if(mind && key && key != mind.key) // Ooh, new player!
first_time_show_popup = mind.has_antag_datum(/datum/antagonist/holoparasite)
. = ..()
+ if(!. || !client)
+ return FALSE
if(mind)
mind.name = "[real_name]"
if(QDELETED(summoner?.current))
diff --git a/code/modules/holoparasite/abilities/major/healing.dm b/code/modules/holoparasite/abilities/major/healing.dm
index 76b55b1ab7582..6806c36edbd67 100644
--- a/code/modules/holoparasite/abilities/major/healing.dm
+++ b/code/modules/holoparasite/abilities/major/healing.dm
@@ -139,7 +139,7 @@
carbon_target.blood_volume = min(carbon_target.blood_volume + actual_heal_amt, HOLOPARA_MAX_BLOOD_VOLUME_HEAL)
if(ishuman(carbon_target))
var/mob/living/carbon/human/human_target = carbon_target
- human_target.bleed_rate = max(human_target.bleed_rate - actual_heal_amt, 0)
+ human_target.cauterise_wounds(actual_heal_amt * 0.2)
if(purge_toxins)
var/list/reagents_purged = list()
@@ -188,12 +188,12 @@
* Heals an object.
*/
/datum/holoparasite_ability/major/healing/proc/heal_obj(obj/target)
- var/old_integrity = target.obj_integrity
- target.obj_integrity = min(target.obj_integrity + (target.max_integrity * 0.1), target.max_integrity)
- if(old_integrity > target.obj_integrity)
+ var/old_integrity = target.get_integrity()
+ target.repair_damage(target.get_integrity() + (target.max_integrity * 0.1), target.max_integrity)
+ if(old_integrity > target.get_integrity())
SSblackbox.record_feedback("associative", "holoparasite_obj_damage_healed", 1, list(
"target" = replacetext("[target.type]", "/obj/", ""),
- "amount" = max(old_integrity - target.obj_integrity, 0)
+ "amount" = max(old_integrity - target.get_integrity(), 0)
))
/**
diff --git a/code/modules/holoparasite/abilities/weapon/stab.dm b/code/modules/holoparasite/abilities/weapon/stab.dm
index e75c48086d210..a6cffc338f284 100644
--- a/code/modules/holoparasite/abilities/weapon/stab.dm
+++ b/code/modules/holoparasite/abilities/weapon/stab.dm
@@ -14,11 +14,9 @@
)
)
/**
- * The (maximum) amount of bleed damage with each hit.
- * This is premultiplied by 10, and then randomized between 50% and 100% of the value.
- * We need to pre-multiply by 10, as BYOND's rand() doesn't support decimal ranges, so we just multiply the final random value by 0.1.
+ * Randomised between 50% and 100%
*/
- var/premultiplied_bleed_rate = 40
+ var/bleed_level = BLEED_SURFACE
/datum/holoparasite_ability/weapon/blade/apply()
. = ..()
@@ -29,7 +27,7 @@
owner.attack_sound = 'sound/weapons/bladeslice.ogg'
owner.response_harm = "stabs"
owner.attacktext = "stabs"
- premultiplied_bleed_rate = master_stats.damage * 8
+ bleed_level = (master_stats.damage / 5) * (BLEED_DEEP_WOUND - BLEED_SURFACE) + BLEED_SURFACE
/datum/holoparasite_ability/weapon/blade/remove()
. = ..()
@@ -45,6 +43,4 @@
. = ..()
if(successful && ishuman(target))
var/mob/living/carbon/human/human_target = target
- if(human_target.bleed_rate < 15)
- var/randomized_bleed_rate = rand(round(premultiplied_bleed_rate * 0.5), premultiplied_bleed_rate) * 0.1
- human_target.bleed_rate = clamp(human_target.bleed_rate + randomized_bleed_rate, 0, 15)
+ human_target.add_bleeding((rand(500, 1000) / 1000) * bleed_level)
diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm
index a64befd731700..feb342f3196fc 100644
--- a/code/modules/hydroponics/hydroitemdefines.dm
+++ b/code/modules/hydroponics/hydroitemdefines.dm
@@ -86,6 +86,7 @@
attack_verb = list("chopped", "tore", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
/obj/item/hatchet/Initialize(mapload)
. = ..()
diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm
index 5482b9456cc8e..89814a413c64e 100644
--- a/code/modules/jobs/job_types/clown.dm
+++ b/code/modules/jobs/job_types/clown.dm
@@ -1,7 +1,7 @@
/datum/job/clown
title = JOB_NAME_CLOWN
description = "Be the life and soul of the station. Entertain the crew with your hilarious jokes and silly antics, including slipping, pie-ing and honking around. Remember your job is to keep things funny for others, not just yourself."
- department_for_prefs = DEPT_BITFLAG_CIV
+ department_for_prefs = DEPT_BITFLAG_SRV
department_head = list(JOB_NAME_HEADOFPERSONNEL)
supervisors = "the head of personnel"
faction = "Station"
diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm
index c14cfb10a0348..ea4076e5edcb0 100644
--- a/code/modules/jobs/job_types/mime.dm
+++ b/code/modules/jobs/job_types/mime.dm
@@ -1,7 +1,7 @@
/datum/job/mime
title = JOB_NAME_MIME
description = "Be the Clown's mute counterpart and arch nemesis. Conduct pantomimes and performances, create interesting situations with your mime powers. Remember your job is to keep things funny for others, not just yourself."
- department_for_prefs = DEPT_BITFLAG_CIV
+ department_for_prefs = DEPT_BITFLAG_SRV
department_head = list(JOB_NAME_HEADOFPERSONNEL)
supervisors = "the head of personnel"
faction = "Station"
diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm
index 0f3568111afef..a583a00d3c955 100644
--- a/code/modules/library/lib_items.dm
+++ b/code/modules/library/lib_items.dm
@@ -24,7 +24,7 @@
opacity = FALSE
resistance_flags = FLAMMABLE
max_integrity = 200
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 0, STAMINA = 0, CONSUME = 0, BLEED = 0)
var/state = BOOKCASE_UNANCHORED
var/list/allowed_books = list(/obj/item/book, /obj/item/spellbook, /obj/item/storage/book, /obj/item/codex_cicatrix) //Things allowed in the bookcase
/// When enabled, books_to_load number of random books will be generated for this bookcase when first interacted with.
diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm
index 0d7524b3811fd..01ba5e8c812c4 100644
--- a/code/modules/lighting/lighting_atom.dm
+++ b/code/modules/lighting/lighting_atom.dm
@@ -10,19 +10,24 @@
// The proc you should always use to set the light of this atom.
// Nonesensical value for l_color default, so we can detect if it gets set to null.
#define NONSENSICAL_VALUE -99999
-/atom/proc/set_light(var/l_range, var/l_power, var/l_color = NONSENSICAL_VALUE)
+/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE, l_on)
if(l_range > 0 && l_range < MINIMUM_USEFUL_LIGHT_RANGE)
- l_range = MINIMUM_USEFUL_LIGHT_RANGE //Brings the range up to 1.4, which is just barely brighter than the soft lighting that surrounds players.
- if (l_power != null)
- light_power = l_power
+ l_range = MINIMUM_USEFUL_LIGHT_RANGE //Brings the range up to 1.4, which is just barely brighter than the soft lighting that surrounds players.
- if (l_range != null)
- light_range = l_range
+ if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT, l_range, l_power, l_color, l_on) & COMPONENT_BLOCK_LIGHT_UPDATE)
+ return
+
+ if(!isnull(l_power))
+ set_light_power(l_power)
- if (l_color != NONSENSICAL_VALUE)
- light_color = l_color
+ if(!isnull(l_range))
+ set_light_range(l_range)
- SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT, l_range, l_power, l_color)
+ if(l_color != NONSENSICAL_VALUE)
+ set_light_color(l_color)
+
+ if(!isnull(l_on))
+ set_light_on(l_on)
update_light()
@@ -38,7 +43,7 @@
if(light_system != STATIC_LIGHT)
CRASH("update_light() for [src] with following light_system value: [light_system]")
- if (!light_power || !light_range) // We won't emit light anyways, destroy the light source.
+ if (!light_power || !light_range || !light_on) // We won't emit light anyways, destroy the light source.
QDEL_NULL(light)
else
if (!ismovable(loc)) // We choose what atom should be the top atom of the light here.
@@ -85,11 +90,8 @@
/atom/movable/Moved(atom/OldLoc, Dir)
. = ..()
- var/datum/light_source/L
- var/thing
- for (thing in light_sources) // Cycle through the light sources on this atom and tell them to update.
- L = thing
- L.source_atom.update_light()
+ for (var/datum/light_source/light as anything in light_sources) // Cycle through the light sources on this atom and tell them to update.
+ light.source_atom.update_light()
/atom/vv_edit_var(var_name, var_value)
switch (var_name)
@@ -120,66 +122,65 @@
return ..()
-/atom/proc/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION)
- return
-
-
-/turf/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION)
- if(!_duration)
- stack_trace("Lighting FX obj created on a turf without a duration")
- new /obj/effect/dummy/lighting_obj (src, _range, _power, _color, _duration)
-
-
-/obj/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION)
- if(!_duration)
- stack_trace("Lighting FX obj created on a obj without a duration")
- new /obj/effect/dummy/lighting_obj (get_turf(src), _range, _power, _color, _duration)
-
+/atom/proc/flash_lighting_fx(range = FLASH_LIGHT_RANGE, power = FLASH_LIGHT_POWER, color = COLOR_WHITE, duration = FLASH_LIGHT_DURATION, light_type = /obj/effect/dummy/lighting_obj)
+ if(!duration)
+ stack_trace("Lighting FX obj created on \[[type]\] without a duration")
+ var/obj/effect/dummy/light_obj = new light_type(get_turf(src), range, power, color, duration)
+ return light_obj
-/mob/living/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION)
- mob_light(_range, _power, _color, _duration)
+/mob/living/flash_lighting_fx(range = FLASH_LIGHT_RANGE, power = FLASH_LIGHT_POWER, color = COLOR_WHITE, duration = FLASH_LIGHT_DURATION, light_type = /obj/effect/dummy/lighting_obj/moblight)
+ return mob_light(range, power, color, duration)
-
-/mob/living/proc/mob_light(_range, _power, _color, _duration)
- var/obj/effect/dummy/lighting_obj/moblight/mob_light_obj = new (src, _range, _power, _color, _duration)
+/mob/living/proc/mob_light(range, power, color, duration, light_type = /obj/effect/dummy/lighting_obj/moblight)
+ var/obj/effect/dummy/lighting_obj/moblight/mob_light_obj = new light_type(src, range, power, color, duration)
return mob_light_obj
-
-/atom/proc/set_light_range(new_range)
- if(new_range == light_range)
- return
- SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_RANGE, new_range)
- . = light_range
- light_range = new_range
-
-
+/// Setter for the light power of this atom.
/atom/proc/set_light_power(new_power)
if(new_power == light_power)
return
- SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_POWER, new_power)
+ if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_POWER, new_power) & COMPONENT_BLOCK_LIGHT_UPDATE)
+ return
. = light_power
light_power = new_power
+ SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_POWER, .)
+/// Setter for the light range of this atom.
+/atom/proc/set_light_range(new_range)
+ if(new_range == light_range)
+ return
+ if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_RANGE, new_range) & COMPONENT_BLOCK_LIGHT_UPDATE)
+ return
+ . = light_range
+ light_range = new_range
+ SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_RANGE, .)
+/// Setter for the light color of this atom.
/atom/proc/set_light_color(new_color)
if(new_color == light_color)
return
- SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_COLOR, new_color)
+ if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_COLOR, new_color) & COMPONENT_BLOCK_LIGHT_UPDATE)
+ return
. = light_color
light_color = new_color
+ SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_COLOR, .)
-
+/// Setter for whether or not this atom's light is on.
/atom/proc/set_light_on(new_value)
if(new_value == light_on)
return
- SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_ON, new_value)
+ if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_ON, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE)
+ return
. = light_on
light_on = new_value
+ SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_ON, .)
-
+/// Setter for the light flags of this atom.
/atom/proc/set_light_flags(new_value)
if(new_value == light_flags)
return
- SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_FLAGS, new_value)
+ if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_FLAGS, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE)
+ return
. = light_flags
light_flags = new_value
+ SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_FLAGS, .)
diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm
index c8b48f2ac056f..fac6a30c9361e 100644
--- a/code/modules/mapping/mapping_helpers.dm
+++ b/code/modules/mapping/mapping_helpers.dm
@@ -321,6 +321,129 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
organ.organ_flags |= ORGAN_FROZEN
container.update_icon()
+/obj/effect/mapping_helpers/simple_pipes
+ name = "Simple Pipes"
+ late = TRUE
+ icon_state = "pipe-3"
+ alpha = 175
+ layer = GAS_PIPE_VISIBLE_LAYER
+ var/piping_layer = 3
+ var/pipe_color = ""
+ var/hide = FALSE
+
+ var/list/pipe_types = list(
+ /obj/machinery/atmospherics/pipe/simple/general/visible,
+ /obj/machinery/atmospherics/pipe/simple/general/visible,
+ /obj/machinery/atmospherics/pipe/manifold/general/visible,
+ /obj/machinery/atmospherics/pipe/manifold4w/general/visible
+ )
+
+/obj/effect/mapping_helpers/simple_pipes/Initialize()
+ preform_layer(piping_layer, pipe_color)
+ qdel(src)
+
+/obj/effect/mapping_helpers/simple_pipes/proc/preform_layer(override_layer, override_color, override_name = null)
+ var/list/connections = list( dir2text(NORTH) = FALSE, dir2text(SOUTH) = FALSE , dir2text(EAST) = FALSE , dir2text(WEST) = FALSE)
+ var/list/valid_connectors = typecacheof(/obj/machinery/atmospherics)
+ var/connection_num = 0
+ for(var/direction in connections)
+ var/turf/T = get_step(src, text2dir(direction))
+ for(var/thing in T.contents)
+ // If it is a mapping helper
+ if(istype(thing, /obj/effect/mapping_helpers/simple_pipes))
+ var/obj/effect/mapping_helpers/simple_pipes/found = thing
+
+ // If it is a supply_scrubber mapping helper
+ if(istype(found, /obj/effect/mapping_helpers/simple_pipes/supply_scrubber))
+ if(override_layer != 2 && override_layer != 4 && !istype(src, /obj/effect/mapping_helpers/simple_pipes/supply_scrubber))
+ continue // We allow it if we're also a supply_scrubber helper, otherwise we gotta be on layers 2 or 4.
+
+ // If it is a regular mapping helper
+ else
+ if(found.piping_layer != override_layer)
+ continue // We have to have the same layer to allow it.
+
+ connections[direction] = TRUE
+ connection_num++
+ break
+
+ if(!is_type_in_typecache(thing, valid_connectors))
+ continue
+
+ var/obj/machinery/atmospherics/AM = thing
+ if(AM.piping_layer != override_layer && !istype(AM, /obj/machinery/atmospherics/pipe/layer_manifold))
+ continue
+
+ if(angle2dir(dir2angle(text2dir(direction))+180) & AM.initialize_directions)
+ connections[direction] = TRUE
+ connection_num++
+ break
+
+ switch(connection_num)
+ if(1)
+ for(var/direction in connections)
+ if(connections[direction] != TRUE)
+ continue
+ spawn_pipe(direction, connection_num, override_layer, override_color, override_name)
+ return
+ if(2)
+ for(var/direction in connections)
+ if(connections[direction] != TRUE)
+ continue
+ //Detects straight pipes connected from east to west , north to south etc.
+ if(connections[dir2text(angle2dir(dir2angle(text2dir(direction))+180))] == TRUE)
+ spawn_pipe(direction, connection_num, override_layer, override_color, override_name)
+ return
+
+ for(var/direction2 in (connections - direction))
+ if(connections[direction2] != TRUE)
+ continue
+ spawn_pipe(dir2text(text2dir(direction)+text2dir(direction2)), connection_num, override_layer, override_color, override_name)
+ return
+ if(3)
+ for(var/direction in connections)
+ if(connections[direction] == FALSE)
+ spawn_pipe(direction, connection_num, override_layer, override_color, override_name)
+ return
+ if(4)
+ spawn_pipe(dir2text(NORTH), connection_num, override_layer, override_color, override_name)
+ return
+
+/// Spawn the pipe on the layer we specify
+/obj/effect/mapping_helpers/simple_pipes/proc/spawn_pipe(direction, connection_num, override_layer, override_color, override_name = null)
+ var/T = pipe_types[connection_num]
+ var/obj/machinery/atmospherics/pipe/pipe = new T(get_turf(src), TRUE, text2dir(direction))
+
+ if(!isnull(override_name))
+ pipe.name = override_name
+ pipe.piping_layer = override_layer
+ pipe.update_layer()
+ pipe.paint(override_color)
+ // prevents duplicates on the station blueprints mode since the effect is on
+ pipe.obj_flags &= ~ON_BLUEPRINTS
+
+/obj/effect/mapping_helpers/simple_pipes/supply_scrubber
+ name = "Simple Supply/Scrubber Pipes"
+ icon_state = "pipe-2-4"
+ color = rgb(128, 0, 128) // purple in-between pipe
+
+// Instead of using our current layer, we use
+/obj/effect/mapping_helpers/simple_pipes/supply_scrubber/Initialize()
+ preform_layer(2, rgb(0, 0, 255), override_name = "air supply pipe")
+ preform_layer(4, rgb(255, 0, 0), override_name = "scrubbers pipe")
+
+ qdel(src)
+
+/obj/effect/mapping_helpers/simple_pipes/supply_scrubber/hidden
+ name = "Hidden Simple Supply/Scrubber Pipes"
+ hide = TRUE
+ pipe_types = list(
+ /obj/machinery/atmospherics/pipe/simple/general/hidden,
+ /obj/machinery/atmospherics/pipe/simple/general/hidden,
+ /obj/machinery/atmospherics/pipe/manifold/general/hidden,
+ /obj/machinery/atmospherics/pipe/manifold4w/general/hidden
+ )
+
//Color correction helper - only use of these per area, it will convert the entire area
/obj/effect/mapping_helpers/color_correction
name = "color correction helper"
@@ -394,3 +517,176 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
qdel(src)
return
CRASH("Failed to find a portable atmospherics or a portables connector at [AREACOORD(src)]")
+
+// This will put directional windows to adjucant turfs if airs will likely be vaccuumed.
+// Putting this on a space turf is recommended. If you put this on an open tile, it will place directional windows anyway.
+// If a turf is not valid to put a tile, it will automatically make a turf for failsafe.
+// NOTE: This helper is specialised for space-proof, not just for standard mapping.
+/obj/effect/mapping_helpers/space_window_placer
+ name = "Placer: Spaceproof directional windows"
+ icon_state = "space_directional_window_placer"
+ late = TRUE
+
+ /** Mapper options **/
+ /// Determines which window type it will create
+ var/window_type = /obj/structure/window/reinforced
+
+ /** internal code variables - not for mappers **/
+ /// used to skip a direction on a turf
+ var/skip_direction
+ /// there are a few stuff that "CanAtmosPass()" is not reliable
+ var/static/list/unliable_atmos_blockers
+
+
+/obj/effect/mapping_helpers/space_window_placer/Initialize(mapload)
+ . = ..()
+ if(!unliable_atmos_blockers)
+ unliable_atmos_blockers = typecacheof(list(/obj/machinery/door))
+
+/obj/effect/mapping_helpers/space_window_placer/LateInitialize()
+ . = ..()
+ if(!z || !x || !y)
+ CRASH("It's not unable to place Spaceproof directional windoe placer - xyz is null.")
+
+ var/turf/my_turf = get_turf(src)
+ if(!my_turf)
+ CRASH("Spaceproof directional windoe placer failed to find a turf.")
+
+ // checks if turfs are fine to place a directional window
+ var/unliable_atmos_blocking
+ for(var/turf/each_turf in get_adjacent_open_turfs(my_turf))
+ if(isspaceturf(each_turf) || isopenspace(each_turf))
+ continue
+
+ if(!each_turf.CanAtmosPass(my_turf))
+ for(var/atom/movable/movable_content as anything in each_turf.contents)
+ if(is_type_in_typecache(movable_content, unliable_atmos_blockers))
+ unliable_atmos_blocking = TRUE
+ break
+ if(unliable_atmos_blocking)
+ break
+
+ var/list/nearby_turfs = list()
+ for(var/turf/each_turf in get_adjacent_open_turfs(my_turf))
+ if(unliable_atmos_blocking)
+ var/obj/effect/mapping_helpers/space_window_placer/nearby_placer = locate() in each_turf
+ if(nearby_placer) // we don't place windows there + give a value to skip directon
+ nearby_placer.skip_direction |= get_dir(each_turf, my_turf)
+ continue
+ if(skip_direction & get_dir(my_turf, each_turf))
+ continue
+ nearby_turfs += each_turf
+
+
+ // well, it's a bad idea to put a directional window here. Mapping failsafe process here.
+ if(unliable_atmos_blocking && (isspaceturf(my_turf) || isopenspace(my_turf)))
+ my_turf.PlaceOnTop(list(/turf/open/floor/plating, /turf/open/floor/iron), flags = CHANGETURF_INHERIT_AIR)
+ for(var/turf/each_turf in nearby_turfs)
+ if(isspaceturf(each_turf) || isopenspace(each_turf))
+ var/obj/d_glass = new window_type(my_turf)
+ d_glass.dir = get_dir(my_turf, each_turf)
+ else
+ var/improper_dir = get_dir(each_turf, my_turf)
+ for(var/obj/structure/window/d_glass in each_turf.contents)
+ if(d_glass.dir == improper_dir)
+ qdel(d_glass)
+ qdel(src)
+ return
+
+ // puts a directional window for each direction.
+ for(var/turf/each_turf in nearby_turfs)
+ if(!each_turf.CanAtmosPass(my_turf) || isspaceturf(each_turf) || isopenspace(each_turf))
+ continue
+
+ var/obj/d_glass = new window_type(each_turf)
+ d_glass.dir = get_dir(d_glass, my_turf)
+
+ qdel(src)
+
+/obj/effect/mapping_helpers/group_window_placer
+ name = "Placer: Grouped directional windows"
+ icon_state = "group_directional_window_placer"
+ late = TRUE
+
+ /** Mapper options **/
+ /// Determines which window type it will create.
+ /// Make a subtype of this mapping helper to change this value instead of manual change in DMM.
+ var/window_type = /obj/structure/window/reinforced
+ /// Directional window will not be placed to a direction from the adjacent turf where a fulltile glass exists.
+ /// If you set this TRUE, the windows will be placed.
+ var/place_onto_fulltile_window
+ /// Set TRUE to ignore group chain initialization
+ var/single
+
+ /** internal code variables - not for mappers **/
+ /// failsafe var to prevent it to run a code
+ var/to_be_initialized
+ /// a list of mappers that will be initialized together.
+ var/list/init_group
+
+/obj/effect/mapping_helpers/group_window_placer/LateInitialize()
+ . = ..()
+ if(to_be_initialized)
+ return
+
+ if(!z || !x || !y)
+ CRASH("It's not unable to use group_window_placer - xyz is null.")
+
+ var/turf/my_turf = get_turf(src)
+ if(!my_turf)
+ CRASH("group_window_placer failed to find a turf.")
+
+ if(single)
+ to_be_initialized = TRUE
+ finish_late_init(list(WEAKREF(src)))
+ return
+
+ init_group = list()
+ build_group(init_group)
+ finish_late_init()
+
+/obj/effect/mapping_helpers/group_window_placer/proc/build_group(list/chain_init_group)
+ if(to_be_initialized) // shouldn't reach here but just in case
+ return
+ to_be_initialized = TRUE
+ chain_init_group[WEAKREF(src)] = TRUE
+ for(var/turf/each_turf in get_adjacent_open_turfs(get_turf(src)))
+ var/obj/effect/mapping_helpers/group_window_placer/placer = locate() in each_turf
+ if(!placer || chain_init_group[WEAKREF(placer)] || placer.to_be_initialized)
+ continue
+ placer.build_group(chain_init_group)
+
+/obj/effect/mapping_helpers/group_window_placer/proc/finish_late_init()
+ for(var/datum/weakref/each_ref in init_group)
+ var/obj/effect/mapping_helpers/group_window_placer/each_placer = each_ref.resolve()
+ var/turf/my_turf = get_turf(each_placer)
+ var/list/nearby_turfs = list()
+ for(var/turf/each_turf in get_adjacent_open_turfs(my_turf))
+ if(each_turf.density)
+ continue
+ if(locate(/obj/effect/mapping_helpers/group_window_placer) in each_turf)
+ continue
+ // skip this - that direction should be connected
+ if(locate(/obj/effect/mapping_helpers/space_window_placer) in each_turf)
+ continue
+ // skip this - you won't want to have two directional window in the same directional spot.
+ // NOTE: this is "SPACE" window placer, not "GROUP"
+ if(place_onto_fulltile_window)
+ var/is_fulltile
+ for(var/obj/structure/window/window_on_turf in my_turf.contents)
+ if(window_on_turf.fulltile)
+ is_fulltile = TRUE
+ break
+ if(is_fulltile)
+ continue
+ nearby_turfs += each_turf
+
+ for(var/turf/each_turf in nearby_turfs)
+ var/obj/d_glass = new each_placer.window_type(my_turf)
+ d_glass.dir = get_dir(my_turf, each_turf)
+
+ for(var/datum/weakref/each_ref in init_group)
+ var/obj/effect/mapping_helpers/group_window_placer/each_placer = each_ref.resolve()
+ qdel(each_placer)
+ init_group.Cut()
+
diff --git a/code/modules/mapping/random_rooms.dm b/code/modules/mapping/random_rooms.dm
index 1e884ffbf0f9c..fc0559e960894 100644
--- a/code/modules/mapping/random_rooms.dm
+++ b/code/modules/mapping/random_rooms.dm
@@ -1509,6 +1509,15 @@
template_width = 5
weight = 2
+/datum/map_template/random_room/sk_rdm176
+ name = "Room with spaceproof windows"
+ room_id = "sk_rdm176_spacewindowroom"
+ mappath = "_maps/RandomRooms/10x10/sk_rdm176_spacewindowroom.dmm"
+ centerspawner = FALSE
+ template_height = 10
+ template_width = 10
+ weight = 1
+
//Flandstation Dedicated Random Room
/datum/map_template/random_room/sk_rdm_fln_01
diff --git a/code/modules/mentor/mentor.dm b/code/modules/mentor/mentor.dm
index 7b04a668ea90e..5e6525d1813c3 100644
--- a/code/modules/mentor/mentor.dm
+++ b/code/modules/mentor/mentor.dm
@@ -10,13 +10,8 @@
var/href_token
/// The Mentor Ticket Manager interface
var/datum/help_ui/mentor/mentor_interface
- /// If this mentor datum is inactive due to de-adminning.
- var/dementored = FALSE
- /// If this mentor datum was created due to someone being an admin, but not a mentor.
- /// This is used so that deadminning doesn't remove verbs if someone is both a mentor and an admin.
- var/for_admin = FALSE
-/datum/mentors/New(ckey, for_admin)
+/datum/mentors/New(ckey)
if(!ckey)
QDEL_IN(src, 0)
stack_trace("Mentor datum created without a ckey: [ckey]")
@@ -28,7 +23,6 @@
return
name = "[ckey]'s mentor datum"
href_token = GenerateToken()
- src.for_admin = for_admin
GLOB.mentor_datums[target] = src
// If they're logged in, let's assign their mentor datum now.
var/client/C = GLOB.directory[ckey]
@@ -43,10 +37,7 @@
return
owner = C
owner.mentor_datum = src
- if(for_admin)
- activate()
- else
- owner.add_mentor_verbs()
+ owner.add_mentor_verbs()
if(!check_rights_for(owner, R_ADMIN)) // add nonadmins to the mentor list.
GLOB.mentors |= owner
@@ -86,9 +77,6 @@
log_href_exploit(usr, " Tried to use the mentor panel without having the correct mentor datum.")
return
- if(dementored)
- return
-
if(!CheckMentorHREF(href, href_list))
return
@@ -102,25 +90,3 @@
else if(href_list["mhelp_tickets"])
GLOB.mhelp_tickets.BrowseTickets(usr)
-
-/datum/mentors/proc/activate()
- if(!for_admin)
- return
- if(IsAdminAdvancedProcCall())
- var/msg = " has tried to elevate permissions!"
- message_admins("[key_name_admin(usr)][msg]")
- log_admin("[key_name(usr)][msg]")
- return
- dementored = FALSE
- owner.add_mentor_verbs()
-
-/datum/mentors/proc/deactivate()
- if(!for_admin)
- return
- if(IsAdminAdvancedProcCall())
- var/msg = " has tried to elevate permissions!"
- message_admins("[key_name_admin(usr)][msg]")
- log_admin("[key_name(usr)][msg]")
- return
- dementored = TRUE
- owner.remove_mentor_verbs()
diff --git a/code/modules/mentor/mentor_loading.dm b/code/modules/mentor/mentor_loading.dm
index 4832bb4c27cc3..285ba82cc51c9 100644
--- a/code/modules/mentor/mentor_loading.dm
+++ b/code/modules/mentor/mentor_loading.dm
@@ -28,7 +28,7 @@
continue
if(findtextEx(line, "#", 1, 2))
continue
- new /datum/mentors(line, for_admin = FALSE)
+ new /datum/mentors(line)
return TRUE
/// Loads mentors from the ss13_mentors table
@@ -51,7 +51,7 @@
if(!ckey)
stack_trace("Invalid mentor row in database with null ckey with id: [id] and raw data: [raw_ckey]")
continue
- new /datum/mentors(ckey, for_admin = FALSE)
+ new /datum/mentors(ckey)
qdel(query_load_mentors)
return TRUE
@@ -69,6 +69,6 @@
return TRUE
// They're an admin, but not a mentor. Create them a mentor datum. This is automatically assigned.
else if(check_rights_for(src, R_ADMIN))
- new /datum/mentors(ckey, for_admin = TRUE)
+ new /datum/mentors(ckey)
return TRUE
return FALSE
diff --git a/code/modules/mining/aux_base.dm b/code/modules/mining/aux_base.dm
index 848a74e0b792c..dec029001110a 100644
--- a/code/modules/mining/aux_base.dm
+++ b/code/modules/mining/aux_base.dm
@@ -56,7 +56,7 @@ interface with the mining shuttle at the landing site if a mobile beacon is also
Unit | Condition | Status | Direction | Distance "
for(var/PDT in turrets)
var/obj/machinery/porta_turret/aux_base/T = PDT
- var/integrity = max((T.obj_integrity-T.integrity_failure * T.max_integrity)/(T.max_integrity-T.integrity_failure * max_integrity)*100, 0)
+ var/integrity = max((T.get_integrity()-T.integrity_failure * T.max_integrity)/(T.max_integrity-T.integrity_failure * max_integrity)*100, 0)
var/status
if(T.machine_stat & BROKEN)
status = "ERROR "
diff --git a/code/modules/mining/aux_base_camera.dm b/code/modules/mining/aux_base_camera.dm
index 186904ea06743..747fbe11bc53f 100644
--- a/code/modules/mining/aux_base_camera.dm
+++ b/code/modules/mining/aux_base_camera.dm
@@ -16,9 +16,10 @@
return ..()
//While players are only allowed to build in the base area, but consoles starting outside the base can move into the base area to begin work.
-/mob/camera/ai_eye/remote/base_construction/relaymove(mob/user, direct)
- dir = direct //This camera eye is visible as a drone, and needs to keep the dir updated
- ..()
+
+/mob/camera/ai_eye/remote/base_construction/relaymove(mob/living/user, direction)
+ dir = direction //This camera eye is visible as a drone, and needs to keep the dir updated
+ return ..()
/obj/item/construction/rcd/internal //Base console's internal RCD. Roundstart consoles are filled, rebuilt cosoles start empty.
name = "internal RCD"
diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm
index 997dc58a9d470..080ee5fad139e 100644
--- a/code/modules/mining/equipment/explorer_gear.dm
+++ b/code/modules/mining/equipment/explorer_gear.dm
@@ -12,7 +12,7 @@
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
heat_protection = CHEST|GROIN|LEGS|ARMS
hoodtype = /obj/item/clothing/head/hooded/explorer
- armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 50, BIO = 100, RAD = 50, FIRE = 50, ACID = 50, STAMINA = 20)
+ armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 50, BIO = 100, RAD = 50, FIRE = 50, ACID = 50, STAMINA = 20, BLEED = 30)
allowed = list(
/obj/item/flashlight,
/obj/item/tank/internals,
@@ -36,7 +36,7 @@
flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS
min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT
max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT
- armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 50, BIO = 100, RAD = 50, FIRE = 50, ACID = 50, STAMINA = 20)
+ armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 20, BOMB = 50, BIO = 100, RAD = 50, FIRE = 50, ACID = 50, STAMINA = 20, BLEED = 30)
resistance_flags = FIRE_PROOF
high_pressure_multiplier = 0.4
@@ -58,7 +58,7 @@
visor_flags_inv = HIDEFACIALHAIR
visor_flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH
actions_types = list(/datum/action/item_action/adjust)
- armor = list(MELEE = 10, BULLET = 5, LASER = 5, ENERGY = 5, BOMB = 0, BIO = 50, RAD = 0, FIRE = 20, ACID = 40, STAMINA = 10)
+ armor = list(MELEE = 10, BULLET = 5, LASER = 5, ENERGY = 5, BOMB = 0, BIO = 50, RAD = 0, FIRE = 20, ACID = 40, STAMINA = 10, BLEED = 10)
resistance_flags = FIRE_PROOF
/obj/item/clothing/mask/gas/explorer/attack_self(mob/user)
@@ -83,20 +83,16 @@
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | LAVA_PROOF
slowdown = 0
- armor = list(MELEE = 70, BULLET = 40, LASER = 20, ENERGY = 20, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 40)
+ armor = list(MELEE = 70, BULLET = 40, LASER = 20, ENERGY = 20, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 40, BLEED = 50)
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe)
high_pressure_multiplier = 0.6
/obj/item/clothing/suit/space/hostile_environment/Initialize(mapload)
. = ..()
AddComponent(/datum/component/spraycan_paintable)
- START_PROCESSING(SSobj, src)
-
-/obj/item/clothing/suit/space/hostile_environment/Destroy()
- STOP_PROCESSING(SSobj, src)
- return ..()
/obj/item/clothing/suit/space/hostile_environment/process(delta_time)
+ . = ..()
var/mob/living/carbon/C = loc
if(istype(C) && DT_PROB(1, delta_time)) //cursed by bubblegum
if(DT_PROB(7.5, delta_time))
@@ -115,7 +111,7 @@
w_class = WEIGHT_CLASS_NORMAL
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
clothing_flags = THICKMATERIAL // no space protection
- armor = list(MELEE = 70, BULLET = 40, LASER = 20, ENERGY = 20, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 40)
+ armor = list(MELEE = 70, BULLET = 40, LASER = 20, ENERGY = 20, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 40, BLEED = 50)
resistance_flags = FIRE_PROOF | LAVA_PROOF
high_pressure_multiplier = 0.6
diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm
index 58630fd6f4a77..bb1140c266ffe 100644
--- a/code/modules/mining/equipment/kinetic_crusher.dm
+++ b/code/modules/mining/equipment/kinetic_crusher.dm
@@ -18,6 +18,7 @@
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("smashed", "crushed", "cleaved", "chopped", "pulped")
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
actions_types = list(/datum/action/item_action/toggle_light)
light_system = MOVABLE_LIGHT
light_range = 5
diff --git a/code/modules/mining/equipment/marker_beacons.dm b/code/modules/mining/equipment/marker_beacons.dm
index fd33252851418..48285fc0e749e 100644
--- a/code/modules/mining/equipment/marker_beacons.dm
+++ b/code/modules/mining/equipment/marker_beacons.dm
@@ -74,7 +74,7 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sort_list(list(
icon = 'icons/obj/lighting.dmi'
icon_state = "markerrandom"
layer = BELOW_OPEN_DOOR_LAYER
- armor = list(MELEE = 50, BULLET = 75, LASER = 75, ENERGY = 75, BOMB = 25, BIO = 100, RAD = 100, FIRE = 25, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 75, LASER = 75, ENERGY = 75, BOMB = 25, BIO = 100, RAD = 100, FIRE = 25, ACID = 0, STAMINA = 0, BLEED = 0)
max_integrity = 50
anchored = TRUE
light_range = 2
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 01519dca33abd..8dfa2dd608204 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -418,6 +418,7 @@
damage_type = BRUTE
hitsound = 'sound/effects/splat.ogg'
knockdown = 30
+ bleed_force = BLEED_SURFACE
var/chain
/obj/projectile/hook/fire(setAngle)
@@ -654,7 +655,7 @@
to_chat(user, "You unfold the ladder. It extends much farther than you were expecting. ")
var/last_ladder = null
for(var/i in 1 to world.maxz)
- if(is_centcom_level(i) || is_reserved_level(i) || is_reebe(i) || is_away_level(i))
+ if(is_centcom_level(i) || is_reserved_level(i) || is_reebe(i) || is_away_level(i) || is_debug_level(i))
continue
var/turf/T2 = locate(ladder_x, ladder_y, i)
last_ladder = new /obj/structure/ladder/unbreakable/jacob(T2, null, last_ladder)
@@ -710,6 +711,7 @@
hitsound_on = 'sound/weapons/bladeslice.ogg'
w_class = WEIGHT_CLASS_BULKY
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
faction_bonus_force = 45
nemesis_factions = list("mining", "boss")
var/transform_cooldown
@@ -803,6 +805,7 @@
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
flags_1 = CONDUCT_1
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
w_class = WEIGHT_CLASS_BULKY
force = 1
throwforce = 1
diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm
index 19472c3c8438c..f3cc5773a56b3 100644
--- a/code/modules/mining/machine_processing.dm
+++ b/code/modules/mining/machine_processing.dm
@@ -218,7 +218,20 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/mineral/processing_unit_console)
/obj/machinery/mineral/processing_unit/Initialize(mapload)
. = ..()
proximity_monitor = new(src, 1)
- AddComponent(/datum/component/material_container, list(/datum/material/iron, /datum/material/glass, /datum/material/copper, /datum/material/silver, /datum/material/gold, /datum/material/diamond, /datum/material/plasma, /datum/material/uranium, /datum/material/bananium, /datum/material/titanium, /datum/material/bluespace), INFINITY, TRUE, /obj/item/stack)
+ var/list/allowed_materials = list(
+ /datum/material/iron,
+ /datum/material/glass,
+ /datum/material/copper,
+ /datum/material/silver,
+ /datum/material/gold,
+ /datum/material/diamond,
+ /datum/material/plasma,
+ /datum/material/uranium,
+ /datum/material/bananium,
+ /datum/material/titanium,
+ /datum/material/bluespace,
+ )
+ AddComponent(/datum/component/material_container, allowed_materials, INFINITY, MATCONTAINER_EXAMINE|BREAKDOWN_FLAGS_ORE_PROCESSOR, /obj/item/stack)
stored_research = new /datum/techweb/specialized/autounlocking/smelter
selected_material = SSmaterials.GetMaterialRef(/datum/material/iron)
@@ -280,13 +293,13 @@ c
if(QDELETED(O))
return
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
- var/material_amount = materials.get_item_material_amount(O)
+ var/material_amount = materials.get_item_material_amount(O, BREAKDOWN_FLAGS_ORE_PROCESSOR)
if(!materials.has_space(material_amount))
unload_mineral(O)
else
if(allow_point_redemption)
stored_points += O.points * O.amount * point_upgrade
- materials.insert_item(O)
+ materials.insert_item(O, breakdown_flags=BREAKDOWN_FLAGS_ORE_PROCESSOR)
qdel(O)
/obj/machinery/mineral/processing_unit/proc/get_machine_data()
diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm
index 7a0082a652e61..11b24c92a7249 100644
--- a/code/modules/mining/machine_redemption.dm
+++ b/code/modules/mining/machine_redemption.dm
@@ -27,7 +27,7 @@
/obj/machinery/mineral/ore_redemption/Initialize(mapload)
. = ..()
stored_research = new /datum/techweb/specialized/autounlocking/smelter
- materials = AddComponent(/datum/component/remote_materials, "orm", mapload)
+ materials = AddComponent(/datum/component/remote_materials, "orm", mapload, mat_container_flags=BREAKDOWN_FLAGS_ORM)
/obj/machinery/mineral/ore_redemption/Destroy()
QDEL_NULL(stored_research)
@@ -61,7 +61,7 @@
if(O.refined_type == null)
return
- var/material_amount = mat_container.get_item_material_amount(O)
+ var/material_amount = mat_container.get_item_material_amount(O, BREAKDOWN_FLAGS_ORM)
if(!material_amount)
qdel(O) //no materials, incinerate it
@@ -72,9 +72,10 @@
else
if(O?.refined_type)
stored_points += O.points * O.amount
- var/mats = O.custom_materials & mat_container.materials
+ var/list/stack_mats = O.get_material_composition(BREAKDOWN_FLAGS_ORM)
+ var/mats = stack_mats & mat_container.materials
var/amount = O.amount
- mat_container.insert_item(O, ore_multiplier) //insert it
+ mat_container.insert_item(O, ore_multiplier, breakdown_flags=BREAKDOWN_FLAGS_ORM) //insert it
materials.silo_log(src, "smelted", amount, "someone", mats)
qdel(O)
diff --git a/code/modules/mining/machine_silo.dm b/code/modules/mining/machine_silo.dm
index 33f2289dfb6a7..61eff7a8bb9ad 100644
--- a/code/modules/mining/machine_silo.dm
+++ b/code/modules/mining/machine_silo.dm
@@ -29,7 +29,7 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
/datum/material/bluespace,
/datum/material/plastic,
)
- AddComponent(/datum/component/material_container, materials_list, INFINITY, allowed_types=/obj/item/stack, _disable_attackby=TRUE)
+ AddComponent(/datum/component/material_container, materials_list, INFINITY, MATCONTAINER_NO_INSERT, /obj/item/stack)
if (!GLOB.ore_silo_default && mapload && is_station_level(z))
GLOB.ore_silo_default = src
@@ -49,9 +49,8 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
return ..()
-/obj/machinery/ore_silo/proc/remote_attackby(obj/machinery/M, mob/user, obj/item/stack/I)
+/obj/machinery/ore_silo/proc/remote_attackby(obj/machinery/M, mob/user, obj/item/stack/I, breakdown_flags=NONE)
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
-
// stolen from /datum/component/material_container/proc/OnAttackBy
if(user.a_intent != INTENT_HELP)
return
@@ -60,13 +59,13 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
if(!istype(I) || (I.flags_1 & HOLOGRAM_1) || (I.item_flags & NO_MAT_REDEMPTION))
to_chat(user, "[M] won't accept [I]! ")
return
- var/item_mats = I.custom_materials & materials.materials
+ var/item_mats = I.get_material_composition(breakdown_flags) & materials.materials
if(!length(item_mats))
to_chat(user, "[I] does not contain sufficient materials to be accepted by [M]. ")
return
// assumes unlimited space...
var/amount = I.amount
- materials.user_insert(I, user)
+ materials.user_insert(I, user, breakdown_flags)
silo_log(M, "deposited", amount, "sheets", item_mats)
return TRUE
diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm
index 235b7b8dd3ae0..9067617c458fa 100644
--- a/code/modules/mob/dead/dead.dm
+++ b/code/modules/mob/dead/dead.dm
@@ -102,6 +102,8 @@ INITIALIZE_IMMEDIATE(/mob/dead)
/mob/dead/Login()
. = ..()
+ if(!. || !client)
+ return FALSE
var/turf/T = get_turf(src)
if (isturf(T))
update_z(T.z)
diff --git a/code/modules/mob/dead/new_player/login.dm b/code/modules/mob/dead/new_player/login.dm
index ef150786f64c8..562377de00801 100644
--- a/code/modules/mob/dead/new_player/login.dm
+++ b/code/modules/mob/dead/new_player/login.dm
@@ -1,4 +1,6 @@
/mob/dead/new_player/Login()
+ if(!client)
+ return
if(CONFIG_GET(flag/use_exp_tracking))
client.set_exp_from_db()
if(!client) // client null during sleep
@@ -11,7 +13,9 @@
mind.active = TRUE
mind.set_current(src)
- ..()
+ . = ..()
+ if(!. || !client)
+ return FALSE
var/motd = global.config.motd
if(motd)
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index 5a7a0f96e91f9..fcb7218c8905c 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -403,7 +403,7 @@
"Science" = "#ffddff",
"Security" = "#ffdddd"
)
- var/static/list/department_list = list(GLOB.command_positions) + list(GLOB.engineering_positions) + list(GLOB.supply_positions) + list(GLOB.nonhuman_positions - "pAI") + list(GLOB.civilian_positions) + list(GLOB.gimmick_positions) + list(GLOB.medical_positions) + list(GLOB.science_positions) + list(GLOB.security_positions)
+ var/static/list/department_list = list(GLOB.command_positions) + list(GLOB.engineering_positions) + list(GLOB.supply_positions) + list(GLOB.nonhuman_positions - ROLE_PAI) + list(GLOB.civilian_positions) + list(GLOB.gimmick_positions) + list(GLOB.medical_positions) + list(GLOB.science_positions) + list(GLOB.security_positions)
var/list/dat = list("Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]
")
if(SSjob.prioritized_jobs.len > 0)
diff --git a/code/modules/mob/dead/new_player/sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories.dm
index 14a99ae643194..09d8fff6fb2bc 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories.dm
@@ -683,6 +683,10 @@
name = "Short Bangs"
icon_state = "hair_shortbangs"
+/datum/sprite_accessory/hair/shortbangs2
+ name = "Short Bangs 2"
+ icon_state = "hair_shortbangs2"
+
/datum/sprite_accessory/hair/short
name = "Short Hair"
icon_state = "hair_a"
diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm
index 9bb48f0c46380..b2c114412bfa2 100644
--- a/code/modules/mob/dead/observer/login.dm
+++ b/code/modules/mob/dead/observer/login.dm
@@ -1,5 +1,7 @@
/mob/dead/observer/Login()
- ..()
+ . = ..()
+ if(!. || !client)
+ return FALSE
ghost_accs = client.prefs.read_player_preference(/datum/preference/choiced/ghost_accessories)
ghost_others = client.prefs.read_player_preference(/datum/preference/choiced/ghost_others)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index b3b964a138941..4673766d135c7 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -842,7 +842,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
remove_verb(/mob/dead/observer/verb/boo)
remove_verb(/mob/dead/observer/verb/possess)
-/mob/dead/observer/reset_perspective(atom/A)
+/mob/dead/observer/reset_perspective(atom/new_eye)
if(client)
if(ismob(client.eye) && (client.eye != src))
var/mob/target = client.eye
@@ -873,7 +873,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/mob/mob_eye = creatures[eye_name]
//Istype so we filter out points of interest that are not mobs
if(client && mob_eye && istype(mob_eye))
- client.eye = mob_eye
+ client.set_eye(mob_eye)
if(mob_eye.hud_used)
client.screen = list()
LAZYINITLIST(mob_eye.observers)
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index 5b915187a9d76..88dfa4fe54c55 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -27,9 +27,9 @@
/mob/proc/get_item_for_held_index(i)
- if(!length(held_items))
- return null
- return held_items[i]
+ if(!length(held_items))
+ return null
+ return held_items[i]
//Odd = left. Even = right
/mob/proc/held_index_to_dir(i)
@@ -513,7 +513,7 @@
var/obj/item/bodypart/BP = new path ()
BP.owner = src
BP.held_index = i
- bodyparts += BP
+ add_bodypart(BP)
hand_bodyparts[i] = BP
..() //Don't redraw hands until we have organs for them
diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm
index 6faef22b7178b..e853c16df621a 100644
--- a/code/modules/mob/living/basic/basic.dm
+++ b/code/modules/mob/living/basic/basic.dm
@@ -134,14 +134,13 @@
// copied from simplemobs
/mob/living/basic/revive(full_heal = 0, admin_revive = 0)
- if(..()) //successfully ressuscitated from death
- icon = initial(icon)
- icon_state = icon_living
- set_density(initial(density))
- mobility_flags = MOBILITY_FLAGS_DEFAULT
- update_mobility()
- . = 1
- setMovetype(initial(movement_type))
+ . = ..()
+ if(!.)
+ return
+ icon = initial(icon)
+ icon_state = icon_living
+ density = initial(density)
+ setMovetype(initial(movement_type))
/mob/living/basic/proc/melee_attack(atom/target)
src.face_atom(target)
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index 83805475c7289..50aaa2aa16c09 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -2,31 +2,269 @@
/****************************************************
BLOOD SYSTEM
+
+https://www.desmos.com/calculator/vxrevmdvfx
+
+To calculate the blood loss rate, use the following formula:
+n = starting amount of blood in your mob
+b = bleed rate of your mob
+h = Rate at which bleeding decreases over time (0.02 constant, 0.08 for non-human mobs)
+
+This function calculates the amount of blood left in your system at time x
+q\left(x\right)=\left\{b<2.4:ne^{-\frac{1}{560}\left(bx-\frac{1}{2}x^{2}h\right)},ne^{-\frac{bx}{560}}\right\}
+
+Hide this function
+d\left(x\right)=\max\left(0,120-\frac{\left(120\cdot\max\left(0,\min\left(1,\frac{x-122}{560-122}\right)\right)\right)^{0.3}}{\left(120\right)^{-0.7}}\right)
+
+This function calculates the amount of health that your mob has at time x
+y=d\left(q\left(x\right)\right)
+
+**Notes for porting/search:**
+bleedsuppress has been replaced for is_bandaged(). Note that is_bleeding() returns if you are not bleeding, even if you have active bandages.
+
****************************************************/
-/mob/living/carbon/human/proc/suppress_bloodloss(amount)
- if(bleedsuppress)
+/datum/status_effect/bleeding
+ id = "bleeding"
+ status_type = STATUS_EFFECT_MERGE
+ alert_type = /atom/movable/screen/alert/status_effect/bleeding
+ tick_interval = 1 SECONDS
+
+ var/bandaged_bleeding = 0
+ var/bleed_rate = 0
+ var/time_applied = 0
+ var/bleed_heal_multiplier = 1
+
+/datum/status_effect/bleeding/merge(bleed_level)
+ src.bleed_rate = src.bleed_rate + max(min(bleed_level * bleed_level, sqrt(bleed_level)) / max(src.bleed_rate, 1), bleed_level - src.bleed_rate)
+ update_icon()
+
+/datum/status_effect/bleeding/on_creation(mob/living/new_owner, bleed_rate)
+ . = ..()
+ if (.)
+ src.bleed_rate = bleed_rate
+ linked_alert.maptext = MAPTEXT(owner.get_bleed_rate_string())
+
+/datum/status_effect/bleeding/tick()
+ if (HAS_TRAIT(owner, TRAIT_NO_BLOOD))
+ qdel(src)
+ return
+ time_applied += tick_interval
+ if (time_applied < 1 SECONDS)
+ if(bleed_rate >= BLEED_DEEP_WOUND)
+ owner.add_splatter_floor(owner.loc)
+ else
+ owner.add_splatter_floor(owner.loc, TRUE)
+ return
+ time_applied = 0
+ // Non-humans stop bleeding a lot quicker, even if it is not a minor cut
+ if (!ishuman(owner))
+ bleed_rate -= BLEED_HEAL_RATE_MINOR * 4 * bleed_heal_multiplier
+ // Make sure to update our icon
+ update_icon()
+ // Set the rate at which we process, so we bleed more on the ground when heavy bleeding
+ tick_interval = bleed_rate <= BLEED_RATE_MINOR ? 1 SECONDS : 0.2 SECONDS
+ // Reduce the actual rate of bleeding
+ if (ishuman(owner))
+ if (bleed_rate > 0 && bleed_rate < BLEED_RATE_MINOR)
+ bleed_rate -= BLEED_HEAL_RATE_MINOR * bleed_heal_multiplier
+ else
+ bandaged_bleeding -= BLEED_HEAL_RATE_MINOR * bleed_heal_multiplier
+ // We have finished bleeding
+ if (bleed_rate <= 0 && bandaged_bleeding <= 0)
+ qdel(src)
+ return
+ // The actual rate of bleeding, can be reduced by holding wounds
+ var/final_bleed_rate = bleed_rate
+ if (HAS_TRAIT(owner, TRAIT_BLEED_HELD))
+ final_bleed_rate = max(0, final_bleed_rate - BLEED_RATE_MINOR)
+ // We aren't actually bleeding
+ if (final_bleed_rate <= 0)
+ return
+ // Actually do the bleeding
+ owner.bleed(min(MAX_BLEED_RATE, final_bleed_rate))
+
+/datum/status_effect/bleeding/proc/update_icon()
+ // The actual rate of bleeding, can be reduced by holding wounds
+ // Calculate the message to show to the user
+ if (HAS_TRAIT(owner, TRAIT_BLEED_HELD))
+ linked_alert.name = "Bleeding (Held)"
+ if (bleed_rate > BLEED_RATE_MINOR)
+ linked_alert.desc = "You have serious wounds which are unlikely to heal themselves. You are applying pressure to them, slowing the rate of blood loss."
+ else
+ linked_alert.desc = "You are bleeding and are applying pressure to the wounds, preventing blood from pouring out."
+ linked_alert.icon_state = "bleed_held"
+ else if (bleed_rate == 0 && bandaged_bleeding > 0)
+ linked_alert.name = "Bleeding (Bandaged)"
+ linked_alert.desc = "You have bandages covering your wounds. They will heal slowly if they are not cauterized."
+ linked_alert.icon_state = "bleed_bandage"
+ else
+ if (bleed_rate < BLEED_RATE_MINOR)
+ linked_alert.name = "Bleeding (Light)"
+ linked_alert.desc = "You have some minor cuts that look like they will heal themselves if you don't run out of blood first.[ishuman(owner) ? " Click to apply pressure to the wounds." : ""]"
+ linked_alert.icon_state = "bleed"
+ else
+ linked_alert.name = "Bleeding (Heavy)"
+ linked_alert.desc = "Your wounds are bleeding heavily and are unlikely to heal themselves. Seek medical attention immediately![ishuman(owner) ? " Click to apply pressure to the wounds." : ""]"
+ linked_alert.icon_state = "bleed_heavy"
+
+ if (HAS_TRAIT(owner, TRAIT_NO_BLEEDING) || IS_IN_STASIS(owner))
+ linked_alert.maptext = MAPTEXT("[owner.get_bleed_rate_string()] ")
+ else
+ linked_alert.maptext = MAPTEXT(owner.get_bleed_rate_string())
+
+/datum/status_effect/bleeding/on_remove()
+ var/mob/living/carbon/human/human = owner
+ if (!istype(human))
return
+ // Not bleeding anymore, no need to hold wounds
+ human.stop_holding_wounds()
+
+/atom/movable/screen/alert/status_effect/bleeding
+ name = "Bleeding"
+ desc = "You are bleeding, find something to bandage the wound or you will die."
+ icon_state = "bleed"
+
+/atom/movable/screen/alert/status_effect/bleeding/Click(location, control, params)
+ var/mob/living/carbon/human/human = usr
+ if (!istype(human))
+ return
+ if (locate(/obj/item/offhand/bleeding_suppress) in human.held_items)
+ human.stop_holding_wounds()
+ else
+ human.hold_wounds()
+
+/mob/living/carbon/proc/is_bandaged()
+ if (HAS_TRAIT(src, TRAIT_NO_BLOOD))
+ return FALSE
+ var/datum/status_effect/bleeding/bleed = has_status_effect(STATUS_EFFECT_BLEED)
+ if (!bleed)
+ return FALSE
+ return bleed.bandaged_bleeding > 0
+
+/mob/living/carbon/proc/is_bleeding()
+ if (HAS_TRAIT(src, TRAIT_NO_BLOOD))
+ return FALSE
+ var/datum/status_effect/bleeding/bleed = has_status_effect(STATUS_EFFECT_BLEED)
+ if (!bleed)
+ return FALSE
+ return bleed.bleed_rate > 0
+
+/mob/living/carbon/proc/add_bleeding(bleed_level)
+ if (HAS_TRAIT(src, TRAIT_NO_BLOOD))
+ return
+ playsound(src, 'sound/surgery/blood_wound.ogg', 80, vary = TRUE)
+ apply_status_effect(dna?.species?.bleed_effect || STATUS_EFFECT_BLEED, bleed_level)
+ if (bleed_level >= BLEED_DEEP_WOUND)
+ blur_eyes(1)
+ to_chat(src, "Blood starts rushing out of the open wound! ")
+ if(bleed_level >= BLEED_CUT)
+ add_splatter_floor(src.loc)
else
- bleedsuppress = TRUE
- addtimer(CALLBACK(src, PROC_REF(resume_bleeding)), amount)
+ add_splatter_floor(src.loc, 1)
-/mob/living/carbon/human/proc/resume_bleeding()
- bleedsuppress = 0
- if(stat != DEAD && bleed_rate)
- to_chat(src, "The blood soaks through your bandage. ")
+/mob/living/carbon/human/add_bleeding(bleed_level)
+ if (NOBLOOD in dna.species.species_traits)
+ return
+ ..()
+
+/mob/living/carbon/proc/get_bleed_intensity()
+ var/datum/status_effect/bleeding/bleed = has_status_effect(STATUS_EFFECT_BLEED)
+ if (!bleed)
+ return 0
+ return 3 ** bleed.bleed_rate
+
+/mob/living/carbon/proc/get_bleed_rate()
+ var/datum/status_effect/bleeding/bleed = has_status_effect(STATUS_EFFECT_BLEED)
+ return bleed?.bleed_rate
+
+/// Can we heal bleeding using a welding tool?
+/mob/living/carbon/proc/has_mechanical_bleeding()
+ var/obj/item/bodypart/chest = get_bodypart(BODY_ZONE_CHEST)
+ return chest.bodytype & BODYTYPE_ROBOTIC
+
+/mob/living/proc/get_bleed_rate_string()
+ return "0.0/s"
+
+/mob/living/carbon/get_bleed_rate_string()
+ var/datum/status_effect/bleeding/bleed = has_status_effect(STATUS_EFFECT_BLEED)
+ if (!bleed)
+ return "0.0/s"
+ var/final_bleed_rate = bleed.bleed_rate
+ if (HAS_TRAIT(src, TRAIT_BLEED_HELD))
+ final_bleed_rate = max(0, final_bleed_rate - BLEED_RATE_MINOR)
+
+ // Set the text to the final bleed rate
+ final_bleed_rate = round(final_bleed_rate, 0.1)
+ if ((final_bleed_rate * 10) % 10 == 0)
+ return "[final_bleed_rate].0/s"
+ return "[final_bleed_rate]/s"
+
+/mob/living/carbon/proc/cauterise_wounds(amount = INFINITY)
+ var/datum/status_effect/bleeding/bleed = has_status_effect(STATUS_EFFECT_BLEED)
+ if (!bleed)
+ return FALSE
+ bleed.bleed_rate -= amount
+ if (bleed.bleed_rate <= 0)
+ remove_status_effect(STATUS_EFFECT_BLEED)
+ return TRUE
+
+/mob/living/carbon/proc/hold_wounds()
+ if (stat >= UNCONSCIOUS)
+ return
+ if (!is_bleeding())
+ if (is_bandaged())
+ balloon_alert(src, "Wounds already bandaged!")
+ else
+ balloon_alert(src, "You are not wounded!")
+ return
+ if (locate(/obj/item/offhand/bleeding_suppress) in held_items)
+ balloon_alert(src, "Already applying pressure!")
+ return
+ if (has_active_hand() && get_active_held_item())
+ balloon_alert(src, "Active hand is full!")
+ return
+ var/obj/item/offhand/bleeding_suppress/supressed_thing = new()
+ put_in_active_hand(supressed_thing)
+ balloon_alert(src, "You apply pressure to your wounds...")
+ var/datum/status_effect/bleeding/bleed = has_status_effect(STATUS_EFFECT_BLEED)
+ if (!bleed)
+ return
+ bleed.update_icon()
+
+/mob/living/carbon/proc/stop_holding_wounds()
+ var/located = FALSE
+ for (var/obj/item/offhand/bleeding_suppress/bleed_suppression in held_items)
+ qdel(bleed_suppression)
+ located = TRUE
+ if (located)
+ balloon_alert(src, "You stop applying pressure to your wounds...")
+ var/datum/status_effect/bleeding/bleed = has_status_effect(STATUS_EFFECT_BLEED)
+ if (!bleed)
+ return
+ bleed.update_icon()
+
+/mob/living/carbon/proc/suppress_bloodloss(amount)
+ var/datum/status_effect/bleeding/bleed = has_status_effect(STATUS_EFFECT_BLEED)
+ if (!bleed)
+ return
+ var/reduced_amount = min(bleed.bleed_rate, amount)
+ bleed.bleed_rate -= reduced_amount
+ bleed.bandaged_bleeding += reduced_amount
+ bleed.update_icon()
+ if (bleed.bleed_rate <= 0)
+ stop_holding_wounds()
// Takes care blood loss and regeneration
/mob/living/carbon/human/handle_blood()
- if(NOBLOOD in dna.species.species_traits)
- bleed_rate = 0
+ if((NOBLOOD in dna.species.species_traits) || HAS_TRAIT(src, TRAIT_NO_BLOOD))
+ cauterise_wounds()
return
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_HUSK))) //cryosleep or husked people do not pump the blood.
-
//Blood regeneration if there is some space
- if(blood_volume < BLOOD_VOLUME_NORMAL && !HAS_TRAIT(src, TRAIT_NOHUNGER) && !HAS_TRAIT(src, TRAIT_POWERHUNGRY))
+ if(!is_bleeding() && blood_volume < BLOOD_VOLUME_NORMAL && !HAS_TRAIT(src, TRAIT_NOHUNGER) && !HAS_TRAIT(src, TRAIT_POWERHUNGRY))
var/nutrition_ratio = 0
switch(nutrition)
if(0 to NUTRITION_LEVEL_STARVING)
@@ -46,69 +284,76 @@
//Effects of bloodloss
var/word = pick("dizzy","woozy","faint")
+
+ // How much oxyloss we want to be on
+ var/desired_damage = (getMaxHealth() * 1.2) * CLAMP01((blood_volume - BLOOD_VOLUME_SURVIVE) / (BLOOD_VOLUME_NORMAL - BLOOD_VOLUME_SURVIVE))
+ // Make it so we only go unconcious at 25% blood remaining
+ desired_damage = max(0, (getMaxHealth() * 1.2) - ((desired_damage ** 0.3) / ((getMaxHealth() * 1.2) ** (-0.7))))
+ if (desired_damage >= getMaxHealth() * 1.2)
+ desired_damage = getMaxHealth() * 2.0
+ if (HAS_TRAIT(src, TRAIT_BLOOD_COOLANT))
+ switch(blood_volume)
+ if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_SAFE)
+ if(prob(3))
+ to_chat(src, "Your sensors indicate [pick("overheating", "thermal throttling", "coolant issues")]. ")
+ if(-INFINITY to BLOOD_VOLUME_SURVIVE)
+ desired_damage = getMaxHealth() * 2.0
+ // Rapidly die with no saving you
+ adjustFireLoss(clamp(getMaxHealth() * 2.0 - getFireLoss(), 0, 10))
+ var/health_difference = clamp(desired_damage - getFireLoss(), 0, 5)
+ adjustFireLoss(health_difference)
+ return
switch(blood_volume)
if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE)
if(prob(5))
to_chat(src, "You feel [word]. ")
- adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1))
if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY)
- adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
if(prob(5))
blur_eyes(6)
to_chat(src, "You feel very [word]. ")
if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD)
- adjustOxyLoss(5)
- if(prob(15))
- Unconscious(rand(20,60))
+ if(prob(30))
+ blur_eyes(6)
+ Unconscious(rand(3,6))
to_chat(src, "You feel extremely [word]. ")
if(-INFINITY to BLOOD_VOLUME_SURVIVE)
- if(!HAS_TRAIT(src, TRAIT_NODEATH))
- death()
-
- var/temp_bleed = 0
- //Bleeding out
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
- var/brutedamage = BP.brute_dam
-
- //We want an accurate reading of .len
- list_clear_nulls(BP.embedded_objects)
- for(var/obj/item/embeddies in BP.embedded_objects)
- if(!embeddies.isEmbedHarmless())
- temp_bleed += 0.5
+ desired_damage = getMaxHealth() * 2.0
+ // Rapidly die with no saving you
+ adjustOxyLoss(clamp(getMaxHealth() * 2.0 - getOxyLoss(), 0, 10))
+ var/health_difference = clamp(desired_damage - getOxyLoss(), 0, 5)
+ adjustOxyLoss(health_difference)
- if(brutedamage >= 20)
- temp_bleed += (brutedamage * 0.013)
-
- bleed_rate = max(bleed_rate - 0.5, temp_bleed)//if no wounds, other bleed effects (heparin) naturally decreases
-
- if(bleed_rate && !bleedsuppress && !(HAS_TRAIT(src, TRAIT_FAKEDEATH)))
- bleed(bleed_rate)
+/mob/living/proc/bleed(amt)
+ add_splatter_floor(src.loc, 1)
//Makes a blood drop, leaking amt units of blood from the mob
-/mob/living/carbon/proc/bleed(amt)
- if(blood_volume)
- blood_volume = max(blood_volume - amt, 0)
- if (prob(sqrt(amt)*BLOOD_DRIP_RATE_MOD))
- if(isturf(src.loc)) //Blood loss still happens in locker, floor stays clean
- if(amt >= 10)
- add_splatter_floor(src.loc)
- else
- add_splatter_floor(src.loc, 1)
+/mob/living/carbon/bleed(amt)
+ if(blood_volume && !HAS_TRAIT(src, TRAIT_NO_BLOOD) && !HAS_TRAIT(src, TRAIT_NO_BLEEDING) && !IS_IN_STASIS(src))
+ // As you get less bloodloss, you bleed slower
+ // See the top of this file for desmos lines
+ var/decrease_multiplier = BLEED_RATE_MULTIPLIER
+ var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART)
+ if (!heart || !heart.beating)
+ decrease_multiplier = BLEED_RATE_MULTIPLIER_NO_HEART
+ var/blood_loss_amount = blood_volume - blood_volume * NUM_E ** (-(amt * decrease_multiplier)/BLOOD_VOLUME_NORMAL)
+ blood_volume = max(blood_volume - blood_loss_amount, 0)
+ if(isturf(src.loc) && prob(sqrt(blood_loss_amount)*BLOOD_DRIP_RATE_MOD)) //Blood loss still happens in locker, floor stays clean
+ if(blood_loss_amount >= 2)
+ add_splatter_floor(src.loc)
+ else
+ add_splatter_floor(src.loc, 1)
/mob/living/carbon/human/bleed(amt)
amt *= physiology.bleed_mod
if(!(NOBLOOD in dna.species.species_traits))
..()
-
-
/mob/living/proc/restore_blood()
blood_volume = initial(blood_volume)
/mob/living/carbon/human/restore_blood()
blood_volume = BLOOD_VOLUME_NORMAL
- bleed_rate = 0
+ cauterise_wounds()
/****************************************************
BLOOD TRANSFERS
@@ -233,6 +478,8 @@
//to add a splatter of blood or other mob liquid.
/mob/living/proc/add_splatter_floor(turf/T, small_drip)
+ if (HAS_TRAIT(src, TRAIT_NO_BLOOD) || HAS_TRAIT(src, TRAIT_NO_BLEEDING) || IS_IN_STASIS(src))
+ return
if(get_blood_id() != /datum/reagent/blood)
return
if(!T)
@@ -285,3 +532,21 @@
var/obj/effect/decal/cleanable/oil/B = locate() in T.contents
if(!B)
B = new(T)
+
+/**
+ * Item to represent the fact that we are covering a wound
+ */
+/obj/item/offhand/bleeding_suppress
+ name = "Applying pressure"
+ desc = "You are applying pressure to your wounds."
+ icon_state = "bleed_held"
+
+/obj/item/offhand/bleeding_suppress/equipped(mob/living/carbon/user, slot)
+ . = ..()
+ if (istype(user))
+ ADD_TRAIT(user, TRAIT_BLEED_HELD, ACTION_TRAIT)
+
+/obj/item/offhand/bleeding_suppress/dropped(mob/living/carbon/user, silent)
+ if (istype(user))
+ REMOVE_TRAIT(user, TRAIT_BLEED_HELD, ACTION_TRAIT)
+ return ..()
diff --git a/code/modules/mob/living/bloodcrawl.dm b/code/modules/mob/living/bloodcrawl.dm
index 9edaa6d1706db..d909cea4e0eb2 100644
--- a/code/modules/mob/living/bloodcrawl.dm
+++ b/code/modules/mob/living/bloodcrawl.dm
@@ -8,7 +8,7 @@
invisibility = 60
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
-/obj/effect/dummy/phased_mob/slaughter/relaymove(mob/user, direction)
+/obj/effect/dummy/phased_mob/slaughter/relaymove(mob/living/user, direction)
forceMove(get_step(src,direction))
/obj/effect/dummy/phased_mob/slaughter/ex_act()
@@ -167,7 +167,7 @@
if(!B)
return
forceMove(B.loc)
- src.client.eye = src
+ src.client.set_eye(src)
src.visible_message("[src] rises out of the pool of blood! ")
exit_blood_effect(B)
if(iscarbon(src))
diff --git a/code/modules/mob/living/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm
index 9856506f8e6f9..1cd2ac78d6863 100644
--- a/code/modules/mob/living/brain/MMI.dm
+++ b/code/modules/mob/living/brain/MMI.dm
@@ -24,7 +24,7 @@
if(iscyborg(loc))
var/mob/living/silicon/robot/borg = loc
borg.mmi = null
- mecha = null
+ set_mecha(null)
QDEL_NULL(brainmob)
QDEL_NULL(brain)
QDEL_NULL(radio)
@@ -68,7 +68,7 @@
log_attack("[key_name(user)] inserted [newbrain] into \the [src] at [AREACOORD(src)].")
SEND_SIGNAL(src, COMSIG_MMI_SET_BRAINMOB, newbrain.brainmob)
- brainmob = newbrain.brainmob
+ set_brainmob(newbrain.brainmob)
newbrain.brainmob = null
brainmob.forceMove(src)
brainmob.container = src
@@ -144,7 +144,7 @@
brain.organ_flags |= ORGAN_FROZEN
brain.transfer_identity(L)
- brainmob = brain.brainmob
+ set_brainmob(brain.brainmob)
brainmob.container = src
brain.name = "[L.real_name]'s brain"
@@ -152,6 +152,39 @@
update_icon()
return
+/// Proc to hook behavior associated to the change in value of the [/obj/item/mmi/var/brainmob] variable.
+/obj/item/mmi/proc/set_brainmob(mob/living/brain/new_brainmob)
+ if(brainmob == new_brainmob)
+ return FALSE
+ . = brainmob
+ brainmob = new_brainmob
+ if(new_brainmob)
+ if(mecha)
+ REMOVE_TRAIT(new_brainmob, TRAIT_IMMOBILIZED, BRAIN_UNAIDED)
+ REMOVE_TRAIT(new_brainmob, TRAIT_HANDS_BLOCKED, BRAIN_UNAIDED)
+ else
+ ADD_TRAIT(new_brainmob, TRAIT_IMMOBILIZED, BRAIN_UNAIDED)
+ ADD_TRAIT(new_brainmob, TRAIT_HANDS_BLOCKED, BRAIN_UNAIDED)
+ if(.)
+ var/mob/living/brain/old_brainmob = .
+ ADD_TRAIT(old_brainmob, TRAIT_IMMOBILIZED, BRAIN_UNAIDED)
+ ADD_TRAIT(old_brainmob, TRAIT_HANDS_BLOCKED, BRAIN_UNAIDED)
+
+
+/// Proc to hook behavior associated to the change in value of the [obj/vehicle/sealed/var/mecha] variable.
+/obj/item/mmi/proc/set_mecha(obj/vehicle/sealed/mecha/new_mecha)
+ if(mecha == new_mecha)
+ return FALSE
+ . = mecha
+ mecha = new_mecha
+ if(new_mecha)
+ if(!. && brainmob) // There was no mecha, there now is, and we have a brain mob that is no longer unaided.
+ REMOVE_TRAIT(brainmob, TRAIT_IMMOBILIZED, BRAIN_UNAIDED)
+ REMOVE_TRAIT(brainmob, TRAIT_HANDS_BLOCKED, BRAIN_UNAIDED)
+ else if(. && brainmob) // There was a mecha, there no longer is one, and there is a brain mob that is now again unaided.
+ ADD_TRAIT(brainmob, TRAIT_IMMOBILIZED, BRAIN_UNAIDED)
+ ADD_TRAIT(brainmob, TRAIT_HANDS_BLOCKED, BRAIN_UNAIDED)
+
/obj/item/mmi/proc/replacement_ai_name()
return brainmob.name
@@ -206,7 +239,7 @@
else
. += "The MMI indicates the brain is active. "
-/obj/item/mmi/relaymove(mob/user)
+/obj/item/mmi/relaymove(mob/living/user, direction)
return //so that the MMI won't get a warning about not being able to move if it tries to move
/obj/item/mmi/proc/brain_check(mob/user)
diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm
index 1bc31d5427f68..ef41226772bf9 100644
--- a/code/modules/mob/living/brain/brain.dm
+++ b/code/modules/mob/living/brain/brain.dm
@@ -16,6 +16,9 @@
var/obj/item/organ/brain/OB = new(loc) //we create a new brain organ for it.
OB.brainmob = src
forceMove(OB)
+ if(!container?.mecha) //Unless inside a mecha, brains are rather helpless.
+ ADD_TRAIT(src, TRAIT_IMMOBILIZED, BRAIN_UNAIDED)
+ ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, BRAIN_UNAIDED)
/mob/living/brain/proc/create_dna()
@@ -35,12 +38,6 @@
QDEL_NULL(stored_dna)
return ..()
-/mob/living/brain/update_mobility()
- if(in_contents_of(/obj/vehicle/sealed/mecha))
- mobility_flags = MOBILITY_FLAGS_DEFAULT
- else
- mobility_flags = NONE
-
/mob/living/brain/ex_act() //you cant blow up brainmobs because it makes transfer_to() freak out when borgs blow up.
return
diff --git a/code/modules/mob/living/brain/posibrain.dm b/code/modules/mob/living/brain/posibrain.dm
index 352a37cf114dc..a8e4655e2276e 100644
--- a/code/modules/mob/living/brain/posibrain.dm
+++ b/code/modules/mob/living/brain/posibrain.dm
@@ -9,9 +9,7 @@ GLOBAL_VAR(posibrain_notify_cooldown)
var/next_ask
var/askDelay = 600 //one minute
var/searching = FALSE
- brainmob = null
req_access = list(ACCESS_ROBOTICS)
- mecha = null//This does not appear to be used outside of reference in mecha.dm.
braintype = "Android"
var/autoping = TRUE //if it pings on creation immediately
var/begin_activation_message = "You carefully locate the manual activation switch and start the positronic brain's boot process. "
@@ -42,7 +40,7 @@ GLOBAL_VAR(posibrain_notify_cooldown)
/obj/item/mmi/posibrain/attack_self(mob/user)
if(!brainmob)
- brainmob = new(src)
+ set_brainmob(new /mob/living/brain(src))
if(!(GLOB.ghost_role_flags & GHOSTROLE_SILICONS))
to_chat(user, "Central Command has temporarily outlawed posibrain sentience in this sector... ")
return
@@ -171,7 +169,7 @@ GLOBAL_VAR(posibrain_notify_cooldown)
/obj/item/mmi/posibrain/Initialize(mapload)
. = ..()
- brainmob = new(src)
+ set_brainmob(new /mob/living/brain(src))
var/new_name
if(!LAZYLEN(possible_names))
new_name = pick(GLOB.posibrain_names)
@@ -184,6 +182,7 @@ GLOBAL_VAR(posibrain_notify_cooldown)
if(autoping)
ping_ghosts("created", TRUE)
+
/obj/item/mmi/posibrain/attackby(obj/item/O, mob/user)
return
diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm
index 9d9b23d55e1be..371c0c718de3e 100644
--- a/code/modules/mob/living/carbon/alien/alien.dm
+++ b/code/modules/mob/living/carbon/alien/alien.dm
@@ -25,7 +25,8 @@
/mob/living/carbon/alien/Initialize(mapload)
ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
add_verb(/mob/living/proc/mob_sleep)
- add_verb(/mob/living/proc/lay_down)
+ add_verb(/mob/living/proc/toggle_resting)
+
create_bodyparts() //initialize bodyparts
create_internal_organs()
return ..()
@@ -104,6 +105,8 @@ Des: Removes all infected images from the alien.
return
/mob/living/carbon/alien/canBeHandcuffed()
+ if(num_hands < 2)
+ return FALSE
return TRUE
/mob/living/carbon/alien/proc/alien_evolve(mob/living/carbon/alien/new_xeno)
@@ -119,3 +122,11 @@ Des: Removes all infected images from the alien.
/mob/living/carbon/alien/can_hold_items()
return has_fine_manipulation
+
+/mob/living/carbon/alien/on_lying_down(new_lying_angle)
+ . = ..()
+ update_icons()
+
+/mob/living/carbon/alien/on_standing_up()
+ . = ..()
+ update_icons()
diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
index 3a80e4617dadc..1b024ec6aa2b5 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
@@ -29,7 +29,7 @@
#define MAX_ALIEN_LEAP_DIST 7
/mob/living/carbon/alien/humanoid/hunter/proc/leap_at(atom/A)
- if((mobility_flags & (MOBILITY_MOVE | MOBILITY_STAND)) != (MOBILITY_MOVE | MOBILITY_STAND) || leaping)
+ if(body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_IMMOBILIZED) || leaping)
return
if(!(COOLDOWN_FINISHED(src, pounce_cooldown)))
@@ -77,17 +77,16 @@
sleep(0.2 SECONDS)//Runtime prevention (infinite bump() calls on hulks)
step_towards(src, L)
else
- Paralyze(40, 1, 1)
+ Paralyze(40, ignore_canstun = TRUE)
toggle_leap(FALSE)
else if(hit_atom.density && !hit_atom.CanPass(src, get_dir(hit_atom, src)))
visible_message("[src] smashes into [hit_atom]! ", "[src] smashes into [hit_atom]! ")
- Paralyze(40, 1, 1)
+ Paralyze(40, ignore_canstun = TRUE)
if(leaping) //check that toggles out of leaping mode if the alien gets hit or otherwise interrupted
leaping = FALSE
update_icons()
- update_mobility()
/mob/living/carbon/alien/humanoid/float(on)
if(leaping)
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
index 8fab76f902be7..1b19cd7eb2b4e 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
@@ -7,8 +7,14 @@
limb_destroyer = TRUE
hud_type = /datum/hud/alien
deathsound = 'sound/voice/hiss6.ogg'
- bodyparts = list(/obj/item/bodypart/chest/alien, /obj/item/bodypart/head/alien, /obj/item/bodypart/l_arm/alien,
- /obj/item/bodypart/r_arm/alien, /obj/item/bodypart/r_leg/alien, /obj/item/bodypart/l_leg/alien)
+ bodyparts = list(
+ /obj/item/bodypart/chest/alien,
+ /obj/item/bodypart/head/alien,
+ /obj/item/bodypart/l_arm/alien,
+ /obj/item/bodypart/r_arm/alien,
+ /obj/item/bodypart/r_leg/alien,
+ /obj/item/bodypart/l_leg/alien,
+ )
var/caste = ""
var/alt_icon = 'icons/mob/alienleap.dmi' //used to switch between the two alien icon files.
var/leap_on_click = FALSE
diff --git a/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm b/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm
index b21d8a356b2c1..42264f2534440 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm
@@ -17,7 +17,7 @@
else if(leap_on_click)
icon_state = "alien[caste]_pounce"
- else if(!(mobility_flags & MOBILITY_STAND))
+ else if(body_position == LYING_DOWN)
icon_state = "alien[caste]_sleep"
else if(mob_size == MOB_SIZE_LARGE)
icon_state = "alien[caste]"
diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm
index 0a1f7f00083a3..2702d366724b5 100644
--- a/code/modules/mob/living/carbon/alien/larva/larva.dm
+++ b/code/modules/mob/living/carbon/alien/larva/larva.dm
@@ -11,12 +11,22 @@
health = 25
hardcrit_threshold = HEALTH_THRESHOLD_CRIT
+ rotate_on_lying = FALSE
+
+ default_num_legs = 1
+ num_legs = 1 //Alien larvas always have a movable apendage.
+ usable_legs = 1 //Alien larvas always have a movable apendage.
+ default_num_hands = 0
+
+ bodyparts = list(
+ /obj/item/bodypart/chest/larva,
+ /obj/item/bodypart/head/larva,
+ )
+
var/amount_grown = 0
var/max_grown = 100
var/time_of_birth
- rotate_on_lying = 0
- bodyparts = list(/obj/item/bodypart/chest/larva, /obj/item/bodypart/head/larva)
flavor_text = FLAVOR_TEXT_EVIL
playable = TRUE
@@ -63,3 +73,6 @@
/mob/living/carbon/alien/larva/stripPanelEquip(obj/item/what, mob/who)
to_chat(src, "You don't have the dexterity to do this! ")
return
+
+/mob/living/carbon/alien/larva/canBeHandcuffed()
+ return TRUE
diff --git a/code/modules/mob/living/carbon/alien/larva/life.dm b/code/modules/mob/living/carbon/alien/larva/life.dm
index fe53dfa71772e..1eb88506709c9 100644
--- a/code/modules/mob/living/carbon/alien/larva/life.dm
+++ b/code/modules/mob/living/carbon/alien/larva/life.dm
@@ -24,6 +24,5 @@
if(stat == UNCONSCIOUS)
set_resting(FALSE)
set_stat(CONSCIOUS)
- update_mobility()
update_damage_hud()
update_health_hud()
diff --git a/code/modules/mob/living/carbon/alien/larva/update_icons.dm b/code/modules/mob/living/carbon/alien/larva/update_icons.dm
index 983544e8c72e9..24734a31851c5 100644
--- a/code/modules/mob/living/carbon/alien/larva/update_icons.dm
+++ b/code/modules/mob/living/carbon/alien/larva/update_icons.dm
@@ -14,10 +14,10 @@
icon_state = "larva[state]_dead"
else if(handcuffed || legcuffed) //This should be an overlay. Who made this an icon_state?
icon_state = "larva[state]_cuff"
- else if(!(mobility_flags & MOBILITY_STAND))
- icon_state = "larva[state]_sleep"
- else if(IsStun())
+ else if(HAS_TRAIT(src, TRAIT_INCAPACITATED))
icon_state = "larva[state]_stun"
+ else if(body_position == LYING_DOWN)
+ icon_state = "larva[state]_sleep"
else
icon_state = "larva[state]"
@@ -28,4 +28,5 @@
/mob/living/carbon/alien/larva/update_inv_handcuffed()
update_icons() //larva icon_state changes if cuffed/uncuffed.
-
+/mob/living/carbon/alien/larva/lying_angle_on_lying_down(new_lying_angle)
+ return // Larvas don't rotate on lying down, they have their own custom icons.
diff --git a/code/modules/mob/living/carbon/alien/login.dm b/code/modules/mob/living/carbon/alien/login.dm
index bb6eb084becca..13383568cfe9c 100644
--- a/code/modules/mob/living/carbon/alien/login.dm
+++ b/code/modules/mob/living/carbon/alien/login.dm
@@ -1,3 +1,5 @@
/mob/living/carbon/alien/Login()
. = ..()
+ if(!. || !client)
+ return FALSE
AddInfectionImages()
diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
index c7ff101a5236c..a54238d10635f 100644
--- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
@@ -102,17 +102,20 @@
var/mob/living/carbon/alien/larva/new_xeno = new(xeno_loc)
new_xeno.key = ghost.key
SEND_SOUND(new_xeno, sound('sound/voice/hiss5.ogg',0,0,0,100)) //To get the player's attention
- new_xeno.mobility_flags = NONE //so we don't move during the bursting animation
+ ADD_TRAIT(new_xeno, TRAIT_IMMOBILIZED, type) //so we don't move during the bursting animation
+ ADD_TRAIT(new_xeno, TRAIT_HANDS_BLOCKED, type)
new_xeno.notransform = 1
new_xeno.invisibility = INVISIBILITY_MAXIMUM
sleep(6)
if(QDELETED(src) || QDELETED(owner))
- return
+ qdel(new_xeno)
+ CRASH("AttemptGrow failed due to the early qdeletion of source or owner.")
if(new_xeno)
- new_xeno.mobility_flags = MOBILITY_FLAGS_DEFAULT
+ REMOVE_TRAIT(new_xeno, TRAIT_IMMOBILIZED, type)
+ REMOVE_TRAIT(new_xeno, TRAIT_HANDS_BLOCKED, type)
new_xeno.notransform = 0
new_xeno.invisibility = 0
diff --git a/code/modules/mob/living/carbon/alien/status_procs.dm b/code/modules/mob/living/carbon/alien/status_procs.dm
index 0affc187a12f0..cd8ada8bd7adf 100644
--- a/code/modules/mob/living/carbon/alien/status_procs.dm
+++ b/code/modules/mob/living/carbon/alien/status_procs.dm
@@ -4,17 +4,17 @@
/////////////////////////////////// STUN ////////////////////////////////////
-/mob/living/carbon/alien/Stun(amount, updating = 1, ignore_canstun = 0)
+/mob/living/carbon/alien/Stun(amount, ignore_canstun = FALSE)
. = ..()
if(!.)
move_delay_add = min(move_delay_add + round(amount / 2), 10) //a maximum delay of 10
-/mob/living/carbon/alien/SetStun(amount, updating = 1, ignore_canstun = 0)
+/mob/living/carbon/alien/SetStun(amount, ignore_canstun = FALSE)
. = ..()
if(!.)
move_delay_add = min(move_delay_add + round(amount / 2), 10)
-/mob/living/carbon/alien/AdjustStun(amount, updating = 1, ignore_canstun = 0)
+/mob/living/carbon/alien/AdjustStun(amount, ignore_canstun = FALSE)
. = ..()
if(!.)
move_delay_add = clamp(move_delay_add + round(amount/2), 0, 10)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 5586572af28b4..a86bbc3db8741 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -61,7 +61,7 @@
/mob/living/carbon/attackby(obj/item/I, mob/user, params)
for(var/datum/surgery/S in surgeries)
- if(!(mobility_flags & MOBILITY_STAND) || !S.lying_required)
+ if(body_position == LYING_DOWN || !S.lying_required)
if((S.self_operable || user != src) && (user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM))
if(S.next_step(user,user.a_intent))
return TRUE
@@ -218,7 +218,7 @@
if(HAS_TRAIT(src, TRAIT_RESTRAINED))
changeNext_move(CLICK_CD_BREAKOUT)
last_special = world.time + CLICK_CD_BREAKOUT
- var/buckle_cd = 600
+ var/buckle_cd = 60 SECONDS
if(handcuffed)
var/obj/item/restraints/O = src.get_item_by_slot(ITEM_SLOT_HANDCUFFED)
buckle_cd = O.breakouttime
@@ -236,7 +236,7 @@
/mob/living/carbon/resist_fire()
fire_stacks -= 5
- Paralyze(60, TRUE, TRUE)
+ Paralyze(60, ignore_canstun = TRUE)
spin(32,2)
visible_message("[src] rolls on the floor, trying to put [p_them()]self out! ", \
"You stop, drop, and roll! ")
@@ -326,21 +326,23 @@
/mob/living/carbon/proc/clear_cuffs(obj/item/I, cuff_break)
if(!I.loc || buckled)
- return
+ return FALSE
+ if(I != handcuffed && I != legcuffed)
+ return FALSE
visible_message("[src] manages to [cuff_break ? "break" : "remove"] [I]! ")
to_chat(src, "You successfully [cuff_break ? "break" : "remove"] [I]. ")
if(cuff_break)
. = !((I == handcuffed) || (I == legcuffed))
qdel(I)
- return
+ return TRUE
else
if(I == handcuffed)
handcuffed.forceMove(drop_location())
set_handcuffed(null)
I.dropped(src)
- if(buckled && buckled.buckle_requires_restraints)
+ if(buckled?.buckle_requires_restraints)
buckled.unbuckle_mob(src)
update_handcuffed()
return
@@ -349,10 +351,8 @@
legcuffed = null
I.dropped(src)
update_inv_legcuffed()
- return
- else
- dropItemToGround(I)
- return
+ return TRUE
+
/mob/living/carbon/proc/accident(obj/item/I)
if(!I || (I.item_flags & ABSTRACT) || HAS_TRAIT(I, TRAIT_NODROP))
@@ -474,9 +474,11 @@
if(dna)
dna.real_name = real_name
-/mob/living/carbon/update_mobility()
+/mob/living/carbon/set_body_position(new_value)
. = ..()
- if(!(mobility_flags & MOBILITY_STAND))
+ if(isnull(.))
+ return
+ if(new_value == LYING_DOWN)
add_movespeed_modifier(/datum/movespeed_modifier/carbon_crawling)
else
remove_movespeed_modifier(/datum/movespeed_modifier/carbon_crawling)
@@ -495,7 +497,6 @@
set_health(round(maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute, DAMAGE_PRECISION))
staminaloss = round(total_stamina, DAMAGE_PRECISION)
update_stat()
- update_mobility()
if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD*2) && stat == DEAD )
become_husk("burn")
med_hud_set_health()
@@ -509,7 +510,7 @@
/mob/living/carbon/update_stamina(extend_stam_crit = FALSE)
var/stam = getStaminaLoss()
if(stam >= DAMAGE_PRECISION && (maxHealth - stam) <= crit_threshold && !stat && !HAS_TRAIT(src, TRAIT_NOSTAMCRIT))
- if(extend_stam_crit || !HAS_TRAIT_FROM(src, TRAIT_INCAPACITATED, STAMINA))
+ if(!stat)
enter_stamcrit()
else if(HAS_TRAIT_FROM(src, TRAIT_INCAPACITATED, STAMINA))
REMOVE_TRAIT(src, TRAIT_INCAPACITATED, STAMINA)
@@ -728,9 +729,14 @@
hud_used.healths.icon_state = "health7"
/mob/living/carbon/proc/update_internals_hud_icon(internal_state = 0)
- if(hud_used && hud_used.internals)
+ if(hud_used?.internals)
hud_used.internals.icon_state = "internal[internal_state]"
+/mob/living/carbon/proc/update_spacesuit_hud_icon(cell_state = "empty")
+ if(hud_used?.spacesuit)
+ hud_used.spacesuit.icon_state = "spacesuit_[cell_state]"
+
+
/mob/living/carbon/set_health(new_value)
. = ..()
if(. > hardcrit_threshold)
@@ -763,7 +769,6 @@
if(!is_blind())
var/datum/component/blind_sense/B = GetComponent(/datum/component/blind_sense)
B?.RemoveComponent()
- update_mobility()
update_damage_hud()
update_health_hud()
med_hud_set_status()
@@ -781,7 +786,7 @@
update_action_buttons_icon() //some of our action buttons might be unusable when we're handcuffed.
update_inv_handcuffed()
update_hud_handcuffed()
- update_mobility()
+
/mob/living/carbon/heal_and_revive(heal_to = 75, revive_message)
// We can't heal them if they're missing a heart
@@ -868,29 +873,57 @@
/mob/living/carbon/proc/create_bodyparts()
var/l_arm_index_next = -1
var/r_arm_index_next = 0
- for(var/X in bodyparts)
- var/obj/item/bodypart/O = new X()
- O.owner = src
- bodyparts.Remove(X)
- bodyparts.Add(O)
- if(O.body_part == ARM_LEFT)
- l_arm_index_next += 2
- O.held_index = l_arm_index_next //1, 3, 5, 7...
- hand_bodyparts += O
- else if(O.body_part == ARM_RIGHT)
- r_arm_index_next += 2
- O.held_index = r_arm_index_next //2, 4, 6, 8...
- hand_bodyparts += O
+ for(var/bodypart_path in bodyparts)
+ var/obj/item/bodypart/bodypart_instance = new bodypart_path()
+ bodypart_instance.set_owner(src)
+ bodyparts.Remove(bodypart_path)
+ add_bodypart(bodypart_instance)
+ switch(bodypart_instance.body_part)
+ if(ARM_LEFT)
+ l_arm_index_next += 2
+ bodypart_instance.held_index = l_arm_index_next //1, 3, 5, 7...
+ hand_bodyparts += bodypart_instance
+ if(ARM_RIGHT)
+ r_arm_index_next += 2
+ bodypart_instance.held_index = r_arm_index_next //2, 4, 6, 8...
+ hand_bodyparts += bodypart_instance
+
+
+///Proc to hook behavior on bodypart additions.
+/mob/living/carbon/proc/add_bodypart(obj/item/bodypart/new_bodypart)
+ bodyparts += new_bodypart
+ new_bodypart.set_owner(src)
+
+ switch(new_bodypart.body_part)
+ if(LEG_LEFT, LEG_RIGHT)
+ set_num_legs(num_legs + 1)
+ if(!new_bodypart.bodypart_disabled)
+ set_usable_legs(usable_legs + 1)
+ if(ARM_LEFT, ARM_RIGHT)
+ set_num_hands(num_hands + 1)
+ if(!new_bodypart.bodypart_disabled)
+ set_usable_hands(usable_hands + 1)
+
+
+///Proc to hook behavior on bodypart removals.
+/mob/living/carbon/proc/remove_bodypart(obj/item/bodypart/old_bodypart)
+ bodyparts -= old_bodypart
+
+ switch(old_bodypart.body_part)
+ if(LEG_LEFT, LEG_RIGHT)
+ set_num_legs(num_legs - 1)
+ if(!old_bodypart.bodypart_disabled)
+ set_usable_legs(usable_legs - 1)
+ if(ARM_LEFT, ARM_RIGHT)
+ set_num_hands(num_hands - 1)
+ if(!old_bodypart.bodypart_disabled)
+ set_usable_hands(usable_hands - 1)
/mob/living/carbon/proc/create_internal_organs()
for(var/X in internal_organs)
var/obj/item/organ/I = X
I.Insert(src)
-/mob/living/carbon/proc/update_disabled_bodyparts()
- for(var/obj/item/bodypart/BP as() in bodyparts)
- BP.update_disabled()
-
/mob/living/carbon/vv_get_dropdown()
. = ..()
VV_DROPDOWN_OPTION("", "---------")
@@ -1146,7 +1179,19 @@
if(.)
if(!handcuffed)
REMOVE_TRAIT(src, TRAIT_RESTRAINED, HANDCUFFED_TRAIT)
- REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, HANDCUFFED_TRAIT)
else if(handcuffed)
ADD_TRAIT(src, TRAIT_RESTRAINED, HANDCUFFED_TRAIT)
- ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, HANDCUFFED_TRAIT)
+
+
+/mob/living/carbon/on_lying_down(new_lying_angle)
+ . = ..()
+ if(!buckled || buckled.buckle_lying != 0)
+ lying_angle_on_lying_down(new_lying_angle)
+
+
+/// Special carbon interaction on lying down, to transform its sprite by a rotation.
+/mob/living/carbon/proc/lying_angle_on_lying_down(new_lying_angle)
+ if(!new_lying_angle)
+ set_lying_angle(pick(90, 270))
+ else
+ set_lying_angle(new_lying_angle)
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 6ce7b15ea60b3..d7a117878f215 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -73,6 +73,10 @@
affecting = bodyparts[1]
SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
send_item_attack_message(I, user, parse_zone(affecting.body_zone))
+ if (I.bleed_force)
+ var/armour_block = run_armor_check(affecting, BLEED, armour_penetration = I.armour_penetration, silent = (I.force > 0))
+ var/hit_amount = (100 - armour_block) / 100
+ add_bleeding(I.bleed_force * hit_amount)
if(I.force)
var/armour_block = run_armor_check(affecting, MELEE, armour_penetration = I.armour_penetration)
apply_damage(I.force, I.damtype, affecting, armour_block)
@@ -93,6 +97,10 @@
if(head)
head.add_mob_blood(src)
update_inv_head()
+ else if (I.damtype == BURN && is_bleeding() && IS_ORGANIC_LIMB(affecting))
+ cauterise_wounds(AMOUNT_TO_BLEED_INTENSITY(I.force / 3))
+ to_chat(src, "The heat from [I] cauterizes your bleeding! ")
+ playsound(src, 'sound/surgery/cautery2.ogg', 70)
//dismemberment
var/dismemberthreshold = (((affecting.max_damage * 2) / max(I.is_sharp(), 0.5)) - (affecting.get_damage() + ((I.w_class - 3) * 10) + ((I.attack_weight - 1) * 15)))
@@ -128,7 +136,7 @@
ContactContractDisease(D)
for(var/datum/surgery/S in surgeries)
- if(!(mobility_flags & MOBILITY_STAND) || !S.lying_required)
+ if(body_position == LYING_DOWN || !S.lying_required)
if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)
if(S.next_step(user, user.a_intent))
return 1
@@ -198,6 +206,32 @@
return affecting.body_zone
return dam_zone
+/**
+ * Attempt to disarm the target mob.
+ * Will shove the target mob back, and drop them if they're in front of something dense
+ * or another carbon.
+*/
+/mob/living/carbon/proc/disarm(mob/living/carbon/target)
+ do_attack_animation(target, ATTACK_EFFECT_DISARM)
+ playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
+ if (ishuman(target))
+ var/mob/living/carbon/human/human_target = target
+ human_target.w_uniform?.add_fingerprint(src)
+
+ SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, src, get_combat_bodyzone(target))
+ target.disarm_effect(src)
+
+/mob/living/carbon/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this
+ for (var/obj/item/clothing/clothing in get_equipped_items())
+ if(clothing.blocks_shove_knockdown)
+ return TRUE
+ return FALSE
+
+/mob/living/carbon/proc/clear_shove_slowdown()
+ remove_movespeed_modifier(/datum/movespeed_modifier/shove)
+ var/active_item = get_active_held_item()
+ if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
+ visible_message("[name] regains their grip on \the [active_item]! ", "You regain your grip on \the [active_item]. ", null, COMBAT_MESSAGE_RANGE)
/mob/living/carbon/blob_act(obj/structure/blob/B)
if (stat == DEAD)
@@ -260,7 +294,7 @@
if(M == src && check_self_for_injuries())
return
- if(!(mobility_flags & MOBILITY_STAND))
+ if(body_position == LYING_DOWN)
if(buckled)
to_chat(M, "You need to unbuckle [src] first to do that!")
return
@@ -317,6 +351,8 @@
AdjustParalyzed(-60)
AdjustImmobilized(-60)
set_resting(FALSE)
+ if(body_position != STANDING_UP && !resting && !buckled && !HAS_TRAIT(src, TRAIT_FLOORED))
+ get_up(TRUE)
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
@@ -465,3 +501,56 @@
ADD_TRAIT(src, TRAIT_KNOCKEDOUT, OXYLOSS_TRAIT)
else if(getOxyLoss() <= 50)
REMOVE_TRAIT(src, TRAIT_KNOCKEDOUT, OXYLOSS_TRAIT)
+
+/mob/living/carbon/bullet_act(obj/projectile/P, def_zone, piercing_hit)
+ var/obj/item/bodypart/affecting = get_bodypart(check_zone(def_zone))
+ if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest)
+ affecting = bodyparts[1]
+ if (P.bleed_force)
+ var/armour_block = run_armor_check(affecting, BLEED, armour_penetration = P.armour_penetration, silent = TRUE)
+ var/hit_amount = (100 - armour_block) / 100
+ add_bleeding(P.bleed_force * hit_amount)
+ if (P.damage_type == BURN && is_bleeding() && IS_ORGANIC_LIMB(affecting))
+ cauterise_wounds(AMOUNT_TO_BLEED_INTENSITY(P.damage / 3))
+ playsound(src, 'sound/surgery/cautery2.ogg', 70)
+ to_chat(src, "The heat from [P] cauterizes your bleeding! ")
+
+ return ..()
+
+/mob/living/carbon/attack_basic_mob(mob/living/basic/user)
+ . = ..()
+ if(!.)
+ return
+ var/affected_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
+ var/dam_zone = dismembering_strike(user, affected_zone)
+ if(!dam_zone) //Dismemberment successful
+ return TRUE
+ var/obj/item/bodypart/affecting = get_bodypart(affected_zone)
+ if(!affecting)
+ affecting = get_bodypart(BODY_ZONE_CHEST)
+ var/armor = run_armor_check(affecting, MELEE, armour_penetration = user.armour_penetration)
+ apply_damage(user.melee_damage, user.melee_damage_type, affecting, armor)
+ // Apply bleeding
+ if (user.melee_damage_type == BRUTE)
+ var/armour_block = run_armor_check(dam_zone, BLEED, armour_penetration = user.armour_penetration, silent = TRUE)
+ var/hit_amount = (100 - armour_block) / 100
+ add_bleeding(user.melee_damage * 0.1 * hit_amount)
+
+/mob/living/carbon/attack_animal(mob/living/simple_animal/M)
+ . = ..()
+ if(!.)
+ return
+ var/affected_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
+ var/dam_zone = dismembering_strike(M, affected_zone)
+ if(!dam_zone) //Dismemberment successful
+ return TRUE
+ var/obj/item/bodypart/affecting = get_bodypart(affected_zone)
+ if(!affecting)
+ affecting = get_bodypart(BODY_ZONE_CHEST)
+ var/armor = run_armor_check(affecting, MELEE, armour_penetration = M.armour_penetration)
+ apply_damage(M.melee_damage, M.melee_damage_type, affecting, armor)
+ // Apply bleeding
+ if (M.melee_damage_type == BRUTE)
+ var/armour_block = run_armor_check(dam_zone, BLEED, armour_penetration = M.armour_penetration, silent = TRUE)
+ var/hit_amount = (100 - armour_block) / 100
+ add_bleeding(M.melee_damage * 0.1 * hit_amount)
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 6c0a149f894cc..f8b65dad3234a 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -5,6 +5,10 @@
hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,GLAND_HUD,NANITE_HUD,DIAG_NANITE_FULL_HUD)
has_limbs = 1
held_items = list(null, null)
+ num_legs = 0 //Populated on init through list/bodyparts
+ usable_legs = 0 //Populated on init through list/bodyparts
+ num_hands = 0 //Populated on init through list/bodyparts
+ usable_hands = 0 //Populated on init through list/bodyparts
var/list/internal_organs = list() //List of /obj/item/organ in the mob. They don't go in the contents for some reason I don't want to know.
var/list/internal_organs_slot= list() //Same as above, but stores "slot ID" - "organ" pairs for easy access.
var/silent = FALSE //Can't talk. Value goes down every life proc. //NOTE TO FUTURE CODERS: DO NOT INITIALIZE NUMERICAL VARS AS NULL OR I WILL MURDER YOU.
diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm
index ee3e69b02cafd..33b556e736336 100644
--- a/code/modules/mob/living/carbon/carbon_movement.dm
+++ b/code/modules/mob/living/carbon/carbon_movement.dm
@@ -28,3 +28,55 @@
adjust_nutrition(-(HUNGER_FACTOR/10))
if(m_intent == MOVE_INTENT_RUN)
adjust_nutrition(-(HUNGER_FACTOR/10))
+
+/mob/living/carbon/set_usable_legs(new_value)
+ . = ..()
+ if(isnull(.))
+ return
+ if(. == 0)
+ if(usable_legs != 0) //From having no usable legs to having some.
+ REMOVE_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+ REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+ else if(usable_legs == 0 && !(movement_type & (FLYING | FLOATING))) //From having usable legs to no longer having them.
+ ADD_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+ if(!usable_hands)
+ ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+
+
+/mob/living/carbon/set_usable_hands(new_value)
+ . = ..()
+ if(isnull(.))
+ return
+ if(. == 0)
+ REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, LACKING_MANIPULATION_APPENDAGES_TRAIT)
+ if(usable_hands != 0) //From having no usable hands to having some.
+ REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+ else if(usable_hands == 0 && default_num_hands > 0) //From having usable hands to no longer having them.
+ ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, LACKING_MANIPULATION_APPENDAGES_TRAIT)
+ if(!usable_legs && !(movement_type & (FLYING | FLOATING)))
+ ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+
+
+/mob/living/carbon/setMovetype(newval)
+ . = ..()
+ if(isnull(.))
+ return
+ if(!(. & (FLYING | FLOATING)))
+ if(movement_type & (FLYING | FLOATING)) //From not flying to flying.
+ remove_movespeed_modifier(/datum/movespeed_modifier/limbless)
+ REMOVE_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+ REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+ else if(!(movement_type & (FLYING | FLOATING))) //From flying to no longer flying.
+ var/limbless_slowdown = 0
+ if(usable_legs < default_num_legs)
+ limbless_slowdown += (default_num_legs - usable_legs) * 3
+ if(!usable_legs)
+ ADD_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+ if(usable_hands < default_num_hands)
+ limbless_slowdown += (default_num_hands - usable_hands) * 3
+ if(!usable_hands)
+ ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+ if(limbless_slowdown)
+ add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/limbless, multiplicative_slowdown = limbless_slowdown)
+ else
+ remove_movespeed_modifier(/datum/movespeed_modifier/limbless)
diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm
index 6d1d236fa8e86..5b817e0757e12 100644
--- a/code/modules/mob/living/carbon/examine.dm
+++ b/code/modules/mob/living/carbon/examine.dm
@@ -37,8 +37,8 @@
var/list/msg = list("")
var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
var/list/disabled = list()
- for(var/obj/item/bodypart/BP as() in bodyparts)
- if(BP.disabled)
+ for(var/obj/item/bodypart/BP as anything in bodyparts)
+ if(BP.bodypart_disabled)
disabled += BP
missing -= BP.body_zone
for(var/obj/item/I in BP.embedded_objects)
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 1ea81a906fee0..c755e27290862 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -59,9 +59,8 @@
if(gloves && !(obscured & ITEM_SLOT_GLOVES) && !(gloves.item_flags & EXAMINE_SKIP))
. += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands."
else if(FR && length(FR.blood_DNA))
- var/hand_number = get_num_arms(FALSE)
- if(hand_number)
- . += "[t_He] [t_has] [hand_number > 1 ? "" : "a"] blood-stained hand[hand_number > 1 ? "s" : ""]! "
+ if(num_hands)
+ . += "[t_He] [t_has] [num_hands > 1 ? "" : "a"] blood-stained hand[num_hands > 1 ? "s" : ""]! "
//belt
if(belt && !(belt.item_flags & EXAMINE_SKIP))
@@ -136,7 +135,7 @@
var/list/disabled = list()
for(var/obj/item/bodypart/BP as() in bodyparts)
- if(BP.disabled)
+ if(BP.bodypart_disabled)
disabled += BP
missing -= BP.body_zone
for(var/obj/item/I in BP.embedded_objects)
@@ -146,13 +145,17 @@
msg += "[t_He] [t_has] [icon2html(I, user)] \a [I] embedded in [t_his] [BP.name]! \n"
for(var/X in disabled)
- var/obj/item/bodypart/BP = X
+ var/obj/item/bodypart/body_part = X
var/damage_text
- if(!(BP.get_damage(include_stamina = FALSE) >= BP.max_damage)) //Stamina is disabling the limb
+ /*
+ if(HAS_TRAIT(body_part, TRAIT_DISABLED_BY_WOUND))
+ continue // skip if it's disabled by a wound (cuz we'll be able to see the bone sticking out!)
+ */
+ if(!(body_part.get_damage(include_stamina = FALSE) >= body_part.max_damage)) //we don't care if it's stamcritted
damage_text = "limp and lifeless"
else
- damage_text = (BP.brute_dam >= BP.burn_dam) ? BP.heavy_brute_msg : BP.heavy_burn_msg
- msg += "[capitalize(t_his)] [BP.name] is [damage_text]! \n"
+ damage_text = (body_part.brute_dam >= body_part.burn_dam) ? body_part.heavy_brute_msg : body_part.heavy_burn_msg
+ msg += "[capitalize(t_his)] [body_part.name] is [damage_text]! \n"
//stores missing limbs
var/l_limbs_missing = 0
@@ -189,6 +192,17 @@
burn_msg = burn_msg ? burn_msg : "burns"
bleed_msg = bleed_msg ? bleed_msg : "bleeding"
+ if (is_bleeding())
+ switch (get_bleed_rate())
+ if (BLEED_DEEP_WOUND to INFINITY)
+ msg += "[src] is [bleed_msg] extremely quickly. \n"
+ if (BLEED_RATE_MINOR to BLEED_DEEP_WOUND)
+ msg += "[src] is [bleed_msg] at a significant rate. \n"
+ else
+ msg += "[src] has some minor [bleed_msg] which look like it will stop soon. \n"
+ else if (is_bandaged())
+ msg += "[src] is [bleed_msg], but it is covered.\n"
+
if(!(user == src && src.hal_screwyhud == SCREWYHUD_HEALTHY)) //fake healthy
if(temp)
if(temp < 25)
@@ -244,14 +258,6 @@
if(blood_volume < BLOOD_VOLUME_SAFE)
msg += "[t_He] appear[p_s()] faint.\n"
- if(bleedsuppress)
- msg += "[t_He] [t_is] bandaged with something.\n"
- else if(bleed_rate)
- if(reagents.has_reagent(/datum/reagent/toxin/heparin, needs_metabolizing = TRUE))
- msg += "[t_He] [t_is] [bleed_msg] uncontrollably! \n"
- else
- msg += "[t_He] [t_is] [bleed_msg]! \n"
-
if(reagents.has_reagent(/datum/reagent/teslium, needs_metabolizing = TRUE))
msg += "[t_He] [t_is] emitting a gentle blue glow!\n"
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index e79f9616c0f73..c48601216475d 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -7,7 +7,7 @@
/mob/living/carbon/human/Initialize(mapload)
add_verb(/mob/living/proc/mob_sleep)
- add_verb(/mob/living/proc/lay_down)
+ add_verb(/mob/living/proc/toggle_resting)
icon_state = "" //Remove the inherent human icon that is visible on the map editor. We're rendering ourselves limb by limb, having it still be there results in a bug where the basic human icon appears below as south in all directions and generally looks nasty.
@@ -116,6 +116,10 @@
tab_data["Internal Atmosphere Info"] = GENERATE_STAT_TEXT("[target_tank.name]")
tab_data["Tank Pressure"] = GENERATE_STAT_TEXT("[target_tank.air_contents.return_pressure()]")
tab_data["Distribution Pressure"] = GENERATE_STAT_TEXT("[target_tank.distribute_pressure]")
+ if(istype(wear_suit, /obj/item/clothing/suit/space))
+ var/obj/item/clothing/suit/space/S = wear_suit
+ tab_data["Thermal Regulator"] = GENERATE_STAT_TEXT("[S.thermal_on ? "on" : "off"]")
+ tab_data["Cell Charge"] = GENERATE_STAT_TEXT("[S.cell ? "[round(S.cell.percent(), 0.1)]%" : "!invalid!"]")
if(mind)
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
@@ -943,10 +947,10 @@
. = ..()
if(ishuman(over))
var/mob/living/carbon/human/T = over // curbstomp, ported from PP with modifications
- if(!src.is_busy && (src.is_zone_selected(BODY_ZONE_HEAD) || src.is_zone_selected(BODY_ZONE_PRECISE_GROIN)) && get_turf(src) == get_turf(T) && !(T.mobility_flags & MOBILITY_STAND) && src.a_intent != INTENT_HELP && !HAS_TRAIT(src, TRAIT_PACIFISM)) //all the stars align, time to curbstomp
+ if(!src.is_busy && (src.is_zone_selected(BODY_ZONE_HEAD) || src.is_zone_selected(BODY_ZONE_PRECISE_GROIN)) && get_turf(src) == get_turf(T) && (T.body_position == LYING_DOWN) && src.a_intent != INTENT_HELP && !HAS_TRAIT(src, TRAIT_PACIFISM)) //all the stars align, time to curbstomp
src.is_busy = TRUE
- if (!do_after(src, 2.5 SECONDS, T) || get_turf(src) != get_turf(T) || (T.mobility_flags & MOBILITY_STAND) || src.a_intent == INTENT_HELP || src == T) //wait 30ds and make sure the stars still align (Body zone check removed after PR #958)
+ if (!do_after(src, 2.5 SECONDS, T) || get_turf(src) != get_turf(T) || (T.body_position == STANDING_UP) || src.a_intent == INTENT_HELP || src == T) //wait 30ds and make sure the stars still align (Body zone check removed after PR #958)
src.is_busy = FALSE
return
@@ -1023,10 +1027,10 @@
//src is the user that will be carrying, target is the mob to be carried
/mob/living/carbon/human/proc/can_piggyback(mob/living/carbon/target)
- return (istype(target) && target.stat == CONSCIOUS && (target.mobility_flags & MOBILITY_STAND))
+ return (istype(target) && target.stat == CONSCIOUS && target.body_position == STANDING_UP)
/mob/living/carbon/human/proc/can_be_firemanned(mob/living/carbon/target)
- return ((ishuman(target) || ismonkey(target)) && !(target.mobility_flags & MOBILITY_STAND))
+ return ((ishuman(target) || ismonkey(target)) && target.body_position == LYING_DOWN)
/mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target)
var/carrydelay = 50 //if you have latex you are faster at grabbing
@@ -1106,21 +1110,6 @@
riding_datum.restore_position(target)
to_chat(src, "You seem to be unable to carry [target]! ")
-/mob/living/carbon/human/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this
- var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor)
- for(var/bp in body_parts)
- if(isclothing(bp))
- var/obj/item/clothing/C = bp
- if(C.blocks_shove_knockdown)
- return TRUE
- return FALSE
-
-/mob/living/carbon/human/proc/clear_shove_slowdown()
- remove_movespeed_modifier(/datum/movespeed_modifier/shove)
- var/active_item = get_active_held_item()
- if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
- visible_message("[src.name] regains their grip on \the [active_item]! ", "You regain your grip on \the [active_item]. ", null, COMBAT_MESSAGE_RANGE)
-
/mob/living/carbon/human/updatehealth()
. = ..()
dna?.species.spec_updatehealth(src)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 0c1de85f79e81..eef368a8bc1b3 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -297,37 +297,6 @@
var/armor_block = run_armor_check(affecting, MELEE)
apply_damage(damage, BRUTE, affecting, armor_block)
-/mob/living/carbon/human/attack_basic_mob(mob/living/basic/user)
- . = ..()
- if(!.)
- return
- if(check_shields(user, user.melee_damage, "the [user.name]", MELEE_ATTACK, user.armour_penetration))
- return FALSE
- var/dam_zone = dismembering_strike(user, pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
- if(!dam_zone) //Dismemberment successful
- return TRUE
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
- if(!affecting)
- affecting = get_bodypart(BODY_ZONE_CHEST)
- var/armor = run_armor_check(affecting, MELEE, armour_penetration = user.armour_penetration)
- apply_damage(user.melee_damage, user.melee_damage_type, affecting, armor)
-
-/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M)
- . = ..()
- if(.)
- var/damage = M.melee_damage
- if(check_shields(M, damage, "the [M.name]", MELEE_ATTACK, M.armour_penetration))
- return FALSE
- var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
- if(!dam_zone) //Dismemberment successful
- return TRUE
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
- if(!affecting)
- affecting = get_bodypart(BODY_ZONE_CHEST)
- var/armor = run_armor_check(affecting, MELEE, armour_penetration = M.armour_penetration)
- apply_damage(damage, M.melee_damage_type, affecting, armor)
-
-
/mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M)
if(..()) //successful slime attack
var/damage = 20
@@ -678,6 +647,9 @@
missing -= LB.body_zone
if(LB.is_pseudopart) //don't show injury text for fake bodyparts; ie chainsaw arms or synthetic armblades
continue
+ var/self_aware = FALSE
+ if(HAS_TRAIT(src, TRAIT_SELF_AWARE))
+ self_aware = TRUE
var/limb_max_damage = LB.max_damage
var/status = ""
var/brutedamage = LB.brute_dam
@@ -715,7 +687,14 @@
var/no_damage
if(status == "OK" || status == "no damage")
no_damage = TRUE
- to_chat(src, "\t Your [LB.name] [HAS_TRAIT(src, TRAIT_SELF_AWARE) ? "has" : "is"] [status]. ")
+ var/isdisabled = " "
+ if(LB.bodypart_disabled)
+ isdisabled = " is disabled "
+ if(no_damage)
+ isdisabled += " but otherwise "
+ else
+ isdisabled += " and "
+ to_chat(src, "\t Your [LB.name][isdisabled][self_aware ? " has " : " is "][status]. ")
for(var/obj/item/I in LB.embedded_objects)
if(I.isEmbedHarmless())
@@ -726,8 +705,10 @@
for(var/t in missing)
to_chat(src, "Your [parse_zone(t)] is missing! ")
- if(bleed_rate)
+ if(is_bleeding())
to_chat(src, "You are [bleed_msg]! ")
+ else if (is_bandaged())
+ to_chat(src, "Your [bleed_msg] is bandaged! ")
if(getStaminaLoss())
if(getStaminaLoss() > 30)
to_chat(src, "You're completely exhausted. ")
@@ -874,3 +855,13 @@
ADD_TRAIT(src, TRAIT_NOBLOCK, type)
stoplag(50)
REMOVE_TRAIT(src, TRAIT_NOBLOCK, type)
+
+/mob/living/carbon/human/attack_basic_mob(mob/living/basic/user)
+ if(user.melee_damage != 0 && !HAS_TRAIT(user, TRAIT_PACIFISM) && check_shields(user, user.melee_damage, "the [user.name]", MELEE_ATTACK, user.armour_penetration))
+ return FALSE
+ return ..()
+
+/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M)
+ if(M.melee_damage != 0 && !HAS_TRAIT(M, TRAIT_PACIFISM) && check_shields(M, M.melee_damage, "the [M.name]", MELEE_ATTACK, M.armour_penetration))
+ return FALSE
+ return ..()
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 52da5dbbf7057..7bf419679f824 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -9,6 +9,7 @@
/// build_worn_icon is reponsible for building this, as each bodypart may be emissive and clothes
/// or other bodyparts may block the emissive elements of it.
blocks_emissive = FALSE
+
///Hair color
var/hair_color = "000"
///Hair style
@@ -46,7 +47,6 @@
var/special_voice = "" // For changing our voice. Used by a symptom.
var/bleed_rate = 0 //how much are we bleeding
- var/bleedsuppress = 0 //for stopping bloodloss, eventually this will be limb-based like bleeding
/// How many "units of blood" we have on our hands
var/blood_in_hands = 0
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 08d190c2f4999..f268c0dae5a83 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -1,8 +1,7 @@
/mob/living/carbon/human/canBeHandcuffed()
- if(get_num_arms(FALSE) >= 2)
- return TRUE
- else
+ if(num_hands < 2)
return FALSE
+ return TRUE
//gets assignment from ID or ID inside PDA or PDA itself
//Useful when player do something with computers
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index e6de200042cbb..6a4e59b5da79e 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -42,7 +42,7 @@
/mob/living/carbon/human/Move(NewLoc, direct)
. = ..()
- if(shoes && (mobility_flags & MOBILITY_STAND) && loc == NewLoc && has_gravity(loc))
+ if(shoes && body_position == STANDING_UP && loc == NewLoc && has_gravity(loc))
SEND_SIGNAL(shoes, COMSIG_SHOES_STEP_ACTION)
/mob/living/carbon/human/Process_Spacemove(movement_dir = 0) //Temporary laziness thing. Will change to handles by species reee.
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index fd0ce7c60b9a5..c235f766776a4 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -119,7 +119,6 @@
update_inv_w_uniform()
if(wear_suit.breakouttime) //when equipping a straightjacket
ADD_TRAIT(src, TRAIT_RESTRAINED, SUIT_TRAIT)
- ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, SUIT_TRAIT)
stop_pulling() //can't pull if restrained
update_action_buttons_icon() //certain action buttons will no longer be usable.
update_inv_wear_suit()
@@ -167,7 +166,6 @@
dropItemToGround(s_store, TRUE) //It makes no sense for your suit storage to stay on you if you drop your suit.
if(wear_suit.breakouttime) //when unequipping a straightjacket
REMOVE_TRAIT(src, TRAIT_RESTRAINED, SUIT_TRAIT)
- REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, SUIT_TRAIT)
drop_all_held_items() //suit is restraining
update_action_buttons_icon() //certain action buttons may be usable again.
wear_suit = null
diff --git a/code/modules/mob/living/carbon/human/physiology.dm b/code/modules/mob/living/carbon/human/physiology.dm
index 2a197b64ee29f..6a0511102408a 100644
--- a/code/modules/mob/living/carbon/human/physiology.dm
+++ b/code/modules/mob/living/carbon/human/physiology.dm
@@ -17,7 +17,8 @@
var/siemens_coeff = 1 // resistance to shocks
- var/stun_mod = 1 // % stun modifier
+ var/stun_add = 0 // % additive stun increaser
+ var/stun_mod = 1 // % multiplicitive stun multiplayer, applied after additive is applied
var/bleed_mod = 1 // % bleeding modifier
var/datum/armor/armor // internal armor datum
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 293aece90e759..c50e58357a037 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -94,6 +94,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
///What anim to use for gibbing
var/gib_anim = "gibbed-h"
+ var/list/required_organs = list()
var/obj/item/organ/brain/mutant_brain = /obj/item/organ/brain
var/obj/item/organ/heart/mutant_heart = /obj/item/organ/heart
var/obj/item/organ/eyes/mutanteyes = /obj/item/organ/eyes
@@ -129,6 +130,9 @@ GLOBAL_LIST_EMPTY(features_by_species)
///List of possible heights
var/list/species_height = SPECIES_HEIGHTS(BODY_SIZE_SHORT, BODY_SIZE_NORMAL, BODY_SIZE_TALL)
+ /// What bleed status effect should we apply?
+ var/bleed_effect = STATUS_EFFECT_BLEED
+
///List of results you get from knife-butchering. null means you cant butcher it. Associated by resulting type - value of amount
var/list/knife_butcher_results
@@ -263,13 +267,16 @@ GLOBAL_LIST_EMPTY(features_by_species)
if(heart && (!should_have_heart || replace_current))
heart.Remove(C,1)
+ required_organs -= /obj/item/organ/heart
QDEL_NULL(heart)
if(should_have_heart && !heart)
heart = new mutant_heart()
heart.Insert(C)
+ required_organs |= /obj/item/organ/heart
if(lungs && (!should_have_lungs || replace_current))
lungs.Remove(C,1)
+ required_organs -= /obj/item/organ/lungs
QDEL_NULL(lungs)
if(should_have_lungs && !lungs)
if(mutantlungs)
@@ -277,9 +284,11 @@ GLOBAL_LIST_EMPTY(features_by_species)
else
lungs = new()
lungs.Insert(C)
+ required_organs |= /obj/item/organ/lungs
if(liver && (!should_have_liver || replace_current))
liver.Remove(C,1)
+ required_organs -= /obj/item/organ/liver
QDEL_NULL(liver)
if(should_have_liver && !liver)
if(mutantliver)
@@ -287,9 +296,11 @@ GLOBAL_LIST_EMPTY(features_by_species)
else
liver = new()
liver.Insert(C)
+ required_organs |= /obj/item/organ/liver
if(stomach && (!should_have_stomach || replace_current))
stomach.Remove(C,1)
+ required_organs -= /obj/item/organ/stomach
QDEL_NULL(stomach)
if(should_have_stomach && !stomach)
if(mutantstomach)
@@ -297,16 +308,20 @@ GLOBAL_LIST_EMPTY(features_by_species)
else
stomach = new()
stomach.Insert(C)
+ required_organs |= /obj/item/organ/stomach
if(appendix && (!should_have_appendix || replace_current))
appendix.Remove(C,1)
+ required_organs -= /obj/item/organ/appendix
QDEL_NULL(appendix)
if(should_have_appendix && !appendix)
appendix = new()
appendix.Insert(C)
+ required_organs |= /obj/item/organ/appendix
if(tail && (!should_have_tail || replace_current))
tail.Remove(C,1)
+ required_organs -= /obj/item/organ/tail
QDEL_NULL(tail)
if(should_have_tail && !tail)
tail = new mutanttail()
@@ -316,9 +331,11 @@ GLOBAL_LIST_EMPTY(features_by_species)
lizard_tail.spines = C.dna.features["spines"]
tail = lizard_tail
tail.Insert(C)
+ required_organs |= /obj/item/organ/tail
if(wings && (!should_have_wings || replace_current))
wings.Remove(C,1)
+ required_organs -= /obj/item/organ/wings
QDEL_NULL(wings)
if(should_have_wings && !wings)
wings = new mutantwings()
@@ -328,47 +345,58 @@ GLOBAL_LIST_EMPTY(features_by_species)
if(locate(/datum/mutation/human/strongwings) in C.dna.mutations)
wings.flight_level = WINGS_FLYING
wings.Insert(C)
+ required_organs |= /obj/item/organ/wings
if(C.get_bodypart(BODY_ZONE_HEAD))
if(brain && (replace_current || !should_have_brain))
if(!brain.decoy_override)//Just keep it if it's fake
brain.Remove(C,TRUE,TRUE)
+ required_organs -= /obj/item/organ/brain
QDEL_NULL(brain)
if(should_have_brain && !brain)
brain = new mutant_brain()
brain.Insert(C, TRUE, TRUE)
+ required_organs |= /obj/item/organ/brain
if(eyes && (replace_current || !should_have_eyes))
eyes.Remove(C,1)
+ required_organs -= /obj/item/organ/eyes
QDEL_NULL(eyes)
if(should_have_eyes && !eyes)
eyes = new mutanteyes
eyes.Insert(C)
+ required_organs |= /obj/item/organ/eyes
if(ears && (replace_current || !should_have_ears))
ears.Remove(C,1)
+ required_organs -= /obj/item/organ/ears
QDEL_NULL(ears)
if(should_have_ears && !ears)
ears = new mutantears
ears.Insert(C)
+ required_organs |= /obj/item/organ/ears
if(tongue && (replace_current || !should_have_tongue))
tongue.Remove(C,1)
+ required_organs -= /obj/item/organ/tongue
QDEL_NULL(tongue)
if(should_have_tongue && !tongue)
tongue = new mutanttongue
tongue.Insert(C)
+ required_organs |= /obj/item/organ/tongue
if(old_species)
for(var/mutantorgan in old_species.mutant_organs)
var/obj/item/organ/I = C.getorgan(mutantorgan)
if(I)
I.Remove(C)
+ required_organs -= I.type
QDEL_NULL(I)
for(var/path in mutant_organs)
var/obj/item/organ/I = new path()
I.Insert(C)
+ required_organs |= I.type
/datum/species/proc/replace_body(mob/living/carbon/C, var/datum/species/new_species)
new_species ||= C.dna.species //If no new species is provided, assume its src.
@@ -811,7 +839,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
else
standing += mutable_appearance(undershirt.icon, undershirt.icon_state, CALCULATE_MOB_OVERLAY_LAYER(BODY_LAYER))
- if(H.socks && H.get_num_legs(FALSE) >= 2 && !(H.dna.species.bodytype & BODYTYPE_DIGITIGRADE) && !(NOSOCKS in species_traits))
+ if(H.socks && H.num_legs >= 2 && !(H.dna.species.bodytype & BODYTYPE_DIGITIGRADE) && !(NOSOCKS in species_traits))
var/datum/sprite_accessory/socks/socks = GLOB.socks_list[H.socks]
if(socks)
standing += mutable_appearance(socks.icon, socks.icon_state, CALCULATE_MOB_OVERLAY_LAYER(BODY_LAYER))
@@ -1123,8 +1151,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
if(I.species_restricted & H.dna?.species.bodyflag)
to_chat(H, "Your species cannot wear this item! ")
return FALSE
- var/num_arms = H.get_num_arms(FALSE)
- var/num_legs = H.get_num_legs(FALSE)
switch(slot)
if(ITEM_SLOT_HANDS)
@@ -1162,7 +1188,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_GLOVES) )
return FALSE
- if(num_arms < 2)
+ if(H.num_hands < 2)
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(ITEM_SLOT_FEET)
@@ -1170,7 +1196,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_FEET) )
return FALSE
- if(num_legs < 2)
+ if(H.num_legs < 2)
return FALSE
if((bodytype & BODYTYPE_DIGITIGRADE) && !(I.supports_variations & DIGITIGRADE_VARIATION))
if(!disable_warning)
@@ -1289,7 +1315,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
return FALSE
if(!istype(I, /obj/item/restraints/handcuffs))
return FALSE
- if(num_arms < 2)
+ if(H.num_legs < 2)
return FALSE
return TRUE
if(ITEM_SLOT_LEGCUFFED)
@@ -1297,7 +1323,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
return FALSE
if(!istype(I, /obj/item/restraints/legcuffs))
return FALSE
- if(num_legs < 2)
+ if(H.num_legs < 2)
return FALSE
return TRUE
if(ITEM_SLOT_BACKPACK)
@@ -1507,6 +1533,10 @@ GLOBAL_LIST_EMPTY(features_by_species)
to_chat(H, "Your hair starts to fall out in clumps. ")
addtimer(CALLBACK(src, PROC_REF(go_bald), H), 50)
+
+/datum/species/proc/handle_blood(mob/living/carbon/human/H)
+ return FALSE
+
/datum/species/proc/go_bald(mob/living/carbon/human/H)
if(QDELETED(H)) //may be called from a timer
return
@@ -1544,11 +1574,11 @@ GLOBAL_LIST_EMPTY(features_by_species)
return
/datum/species/proc/help(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
- if(!((target.health < 0 || HAS_TRAIT(target, TRAIT_FAKEDEATH)) && !(target.mobility_flags & MOBILITY_STAND)))
+ if(target.body_position == STANDING_UP || (target.health >= 0 && !HAS_TRAIT(target, TRAIT_FAKEDEATH)))
target.help_shake_act(user)
if(target != user)
log_combat(user, target, "shaken")
- return 1
+ return TRUE
else
var/we_breathe = !HAS_TRAIT(user, TRAIT_NOBREATH)
var/we_lung = user.getorganslot(ORGAN_SLOT_LUNGS)
@@ -1569,7 +1599,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
return TRUE
else
//Steal them shoes
- if(!(target.mobility_flags & MOBILITY_STAND) && (user.is_zone_selected(BODY_ZONE_L_LEG) || user.is_zone_selected(BODY_ZONE_R_LEG)) && user.a_intent == INTENT_GRAB && target.shoes)
+ if(target.body_position == LYING_DOWN && (user.is_zone_selected(BODY_ZONE_L_LEG) || user.is_zone_selected(BODY_ZONE_R_LEG)) && user.a_intent == INTENT_GRAB && target.shoes)
if(HAS_TRAIT(target.shoes, TRAIT_NODROP))
target.grabbedby(user)
return TRUE
@@ -1597,7 +1627,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
else
var/atk_verb = user.dna.species.attack_verb
- if(!(target.mobility_flags & MOBILITY_STAND))
+ if(target.body_position == LYING_DOWN)
atk_verb = ATTACK_EFFECT_KICK
switch(atk_verb)//this code is really stupid but some genius apparently made "claw" and "slash" two attack types but also the same one so it's needed i guess
@@ -1669,13 +1699,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
if(user.loc == target.loc)
return FALSE
else
- user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
- playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
-
- if(target.w_uniform)
- target.w_uniform.add_fingerprint(user)
- SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.get_combat_bodyzone(target))
- target.disarm_effect(user)
+ user.disarm(target)
/datum/species/proc/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
return
@@ -1733,44 +1757,16 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/weakness = H.check_weakness(I, user)
apply_damage(I.force * weakness, I.damtype, def_zone, armor_block, H)
- H.send_item_attack_message(I, user, hit_area)
-
- if(!I.force)
- return 0 //item force is zero
-
- //dismemberment
- var/dismemberthreshold = ((affecting.max_damage * 2) - affecting.get_damage()) //don't take the current hit into account.
- var/attackforce = (((I.w_class - 3) * 5) + ((I.attack_weight - 1) * 14) + ((I.is_sharp()-1) * 20)) //all the variables that go into ripping off a limb in one handy package. Force is absent because it's already been taken into account by the limb being damaged
- if(HAS_TRAIT(src, TRAIT_EASYDISMEMBER))
- dismemberthreshold -= 30
- if(I.is_sharp())
- attackforce = max(attackforce, I.force)
- if(attackforce >= dismemberthreshold && I.force >= 10)
- if(affecting.dismember(I.damtype))
- I.add_mob_blood(H)
- playsound(get_turf(H), I.get_dismember_sound(), 80, 1)
-
- var/bloody = 0
- if((I.damtype == BRUTE) && (I.force >= max(10, armor_block) || I.is_sharp()))
+ if (I.bleed_force)
+ var/armour_block = user.run_armor_check(affecting, BLEED, armour_penetration = I.armour_penetration, silent = (I.force > 0))
+ var/hit_amount = (100 - armour_block) / 100
+ H.add_bleeding(I.bleed_force * hit_amount)
if(IS_ORGANIC_LIMB(affecting))
I.add_mob_blood(H) //Make the weapon bloody, not the person.
- if(prob(I.force * 2)) //blood spatter!
- bloody = 1
- var/turf/location = H.loc
- if(istype(location))
- H.add_splatter_floor(location)
- if(get_dist(user, H) <= 1) //people with TK won't get smeared with blood
- user.add_mob_blood(H)
-
- switch(hit_area)
- if(BODY_ZONE_HEAD)
- if(!I.is_sharp())
- if(H.mind && H.stat == CONSCIOUS && H != user && (H.health - (I.force * I.attack_weight)) <= 0) // rev deconversion through blunt trauma.
- var/datum/antagonist/rev/rev = H.mind.has_antag_datum(/datum/antagonist/rev)
- if(rev)
- rev.remove_revolutionary(FALSE, user)
-
- if(bloody) //Apply blood
+ if(get_dist(user, H) <= 1) //people with TK won't get smeared with blood
+ user.add_mob_blood(H)
+ switch(hit_area)
+ if(BODY_ZONE_HEAD)
if(H.wear_mask)
H.wear_mask.add_mob_blood(H)
H.update_inv_wear_mask()
@@ -1781,8 +1777,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
H.glasses.add_mob_blood(H)
H.update_inv_glasses()
- if(BODY_ZONE_CHEST)
- if(bloody)
+ if(BODY_ZONE_CHEST)
if(H.wear_suit)
H.wear_suit.add_mob_blood(H)
H.update_inv_wear_suit()
@@ -1790,8 +1785,34 @@ GLOBAL_LIST_EMPTY(features_by_species)
H.w_uniform.add_mob_blood(H)
H.update_inv_w_uniform()
+ H.send_item_attack_message(I, user, hit_area)
+
+ if(!I.force)
+ return 0 //item force is zero
+
+ //dismemberment
+ var/dismemberthreshold = ((affecting.max_damage * 2) - affecting.get_damage()) //don't take the current hit into account.
+ var/attackforce = (((I.w_class - 3) * 5) + ((I.attack_weight - 1) * 14) + ((I.is_sharp()-1) * 20)) //all the variables that go into ripping off a limb in one handy package. Force is absent because it's already been taken into account by the limb being damaged
+ if(HAS_TRAIT(src, TRAIT_EASYDISMEMBER))
+ dismemberthreshold -= 30
+ if(I.is_sharp())
+ attackforce = max(attackforce, I.force)
+ if(attackforce >= dismemberthreshold && I.force >= 10)
+ if(affecting.dismember(I.damtype))
+ I.add_mob_blood(H)
+ playsound(get_turf(H), I.get_dismember_sound(), 80, 1)
+
+ if(I.damtype == BRUTE && (I.force >= max(10, armor_block) && hit_area == BODY_ZONE_HEAD))
+ if(!I.is_sharp() && H.mind && H.stat == CONSCIOUS && H != user && (H.health - (I.force * I.attack_weight)) <= 0) // rev deconversion through blunt trauma.
+ var/datum/antagonist/rev/rev = H.mind.has_antag_datum(/datum/antagonist/rev)
+ if(rev)
+ rev.remove_revolutionary(FALSE, user)
if(Iforce > 10 || Iforce >= 5 && prob(33))
H.force_say(user)
+ else if (I.damtype == BURN && H.is_bleeding())
+ H.cauterise_wounds(AMOUNT_TO_BLEED_INTENSITY(I.force / 3))
+ to_chat(user, "The heat from [I] cauterizes your bleeding! ")
+ playsound(src, 'sound/surgery/cautery2.ogg', 70)
return TRUE
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE)
@@ -1970,7 +1991,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
// Get the changes to the skin from the core temp
var/core_skin_diff = humi.coretemperature - humi.bodytemperature
// change rate of 0.08 to reflect temp back in to the core at the same rate as core to skin
- var/core_skin_change = (1 + thermal_protection) * get_temp_change_amount(core_skin_diff, 0.08)
+ var/core_skin_change = (1 + thermal_protection) * get_temp_change_amount(core_skin_diff, 0.09)
// We do not want to over shoot after using protection
if(core_skin_diff > 0)
@@ -2252,7 +2273,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
if(H.getorgan(/obj/item/organ/wings))
if(wings.flight_level >= WINGS_FLYING && H.movement_type & FLYING)
flyslip(H)
- . = stunmod * H.physiology.stun_mod * amount
+ . = max(stunmod + H.physiology.stun_add, 0) * H.physiology.stun_mod * amount
//////////////
//Space Move//
@@ -2299,7 +2320,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/obj/item/organ/wings/wings = H.getorganslot(ORGAN_SLOT_WINGS)
if(!H.getorgan(/obj/item/organ/wings))
return FALSE
- if(H.stat || !(H.mobility_flags & MOBILITY_STAND))
+ if(H.stat || H.body_position == LYING_DOWN)
return FALSE
var/turf/T = get_turf(H)
if(!T)
@@ -2341,7 +2362,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
H.setMovetype(H.movement_type | FLYING)
override_float = TRUE
H.pass_flags |= PASSTABLE
- H.update_mobility()
if(("wings" in H.dna.species.mutant_bodyparts) || ("moth_wings" in H.dna.species.mutant_bodyparts))
H.Togglewings()
else
diff --git a/code/modules/mob/living/carbon/human/species_types/IPC.dm b/code/modules/mob/living/carbon/human/species_types/IPC.dm
index c6b96c031aaed..db3b7dbf01b78 100644
--- a/code/modules/mob/living/carbon/human/species_types/IPC.dm
+++ b/code/modules/mob/living/carbon/human/species_types/IPC.dm
@@ -16,6 +16,7 @@
MUTCOLORS
)
inherent_traits = list(
+ TRAIT_BLOOD_COOLANT,
TRAIT_RESISTCOLD,
TRAIT_NOBREATH,
TRAIT_RADIMMUNE,
@@ -38,7 +39,6 @@
default_features = list("mcolor" = "#7D7D7D", "ipc_screen" = "Static", "ipc_antenna" = "None", "ipc_chassis" = "Morpheus Cyberkinetics (Custom)")
meat = /obj/item/stack/sheet/plasteel{amount = 5}
skinned_type = /obj/item/stack/sheet/iron{amount = 10}
- exotic_blood = /datum/reagent/oil
damage_overlay_type = "synth"
mutant_bodyparts = list("ipc_screen", "ipc_antenna", "ipc_chassis")
default_features = list("ipc_screen" = "BSOD", "ipc_antenna" = "None")
@@ -48,7 +48,6 @@
clonemod = 0
staminamod = 0.8
siemens_coeff = 1.5
- blood_color = "#000000"
reagent_tag = PROCESS_SYNTHETIC
species_gibs = GIB_TYPE_ROBOTIC
attack_sound = 'sound/items/trayhit1.ogg'
@@ -65,6 +64,10 @@
species_l_leg = /obj/item/bodypart/l_leg/ipc
species_r_leg = /obj/item/bodypart/r_leg/ipc
+ exotic_blood = /datum/reagent/oil
+ blood_color = "#000000"
+ bleed_effect = /datum/status_effect/bleeding/robotic
+
var/saved_screen //for saving the screen when they die
var/datum/action/innate/change_screen/change_screen
@@ -301,3 +304,37 @@
)
return to_add
+
+/datum/status_effect/bleeding/robotic
+ alert_type = /atom/movable/screen/alert/status_effect/bleeding/robotic
+ bleed_heal_multiplier = 0
+
+/datum/status_effect/bleeding/robotic/tick()
+ // Since we don't have flesh, we will instantly repair any sealed wounds
+ bandaged_bleeding = 0
+ ..()
+
+/datum/status_effect/bleeding/robotic/update_icon()
+ // The actual rate of bleeding, can be reduced by holding wounds
+ // Calculate the message to show to the user
+ if (HAS_TRAIT(owner, TRAIT_BLEED_HELD))
+ linked_alert.name = "Leaking (Held)"
+ if (bleed_rate > BLEED_RATE_MINOR)
+ linked_alert.desc = "Critical leaks have been detected in your system and require welding. Leak rate slowed by applied pressure."
+ else
+ linked_alert.desc = "Minor leaks have been detected in your system and require welding. Leak rate slowed by applied pressure."
+ else
+ if (bleed_rate < BLEED_RATE_MINOR)
+ linked_alert.name = "Leaking (Light)"
+ linked_alert.desc = "Minor leaks have been detected in your system and require welding."
+ else
+ linked_alert.name = "Leaking (Heavy)"
+ linked_alert.desc = "Critical leaks have been detected in your system and require welding."
+ linked_alert.icon_state = "bleed_robo"
+
+ linked_alert.maptext = MAPTEXT(owner.get_bleed_rate_string())
+
+/atom/movable/screen/alert/status_effect/bleeding/robotic
+ name = "Leaking"
+ desc = "You are leaking, weld the leaks back together or you will die."
+ icon_state = "bleed_robo"
diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
index 3ab82a79610c2..be59dc9e0cc70 100644
--- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
@@ -36,33 +36,29 @@
bodytemp_cold_damage_limit = (T20C - 10) // about 10c
var/current_color
- var/EMPeffect = FALSE
- var/emageffect = FALSE
+ //var/default_color
var/r1
var/g1
var/b1
var/static/r2 = 237
var/static/g2 = 164
var/static/b2 = 149
+ var/EMPeffect = FALSE
+ var/emageffect = FALSE
//this is shit but how do i fix it? no clue.
var/drain_time = 0 //used to keep ethereals from spam draining power sources
inert_mutation = OVERLOAD
var/obj/effect/dummy/lighting_obj/ethereal_light
-
/datum/species/ethereal/Destroy(force)
- if(ethereal_light)
- QDEL_NULL(ethereal_light)
+ QDEL_NULL(ethereal_light)
return ..()
-/datum/species/ethereal/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
- ethereal_light = C.mob_light()
-
+/datum/species/ethereal/on_species_gain(mob/living/carbon/new_ethereal, datum/species/old_species, pref_load)
. = ..()
-
- if(!ishuman(C))
+ if(!ishuman(new_ethereal))
return
- var/mob/living/carbon/human/ethereal = C
+ var/mob/living/carbon/human/ethereal = new_ethereal
default_color = "#[ethereal.dna.features["ethcolor"]]"
r1 = GETREDPART(default_color)
g1 = GETGREENPART(default_color)
@@ -70,15 +66,14 @@
RegisterSignal(ethereal, COMSIG_ATOM_SHOULD_EMAG, PROC_REF(should_emag))
RegisterSignal(ethereal, COMSIG_ATOM_ON_EMAG, PROC_REF(on_emag))
RegisterSignal(ethereal, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp_act))
-
+ ethereal_light = ethereal.mob_light(light_type = /obj/effect/dummy/lighting_obj/moblight/species)
spec_updatehealth(ethereal)
-
//The following code is literally only to make admin-spawned ethereals not be black.
- C.dna.features["mcolor"] = C.dna.features["ethcolor"] //Ethcolor and Mut color are both dogshit and will be replaced
- for(var/obj/item/bodypart/BP as() in C.bodyparts)
- if(BP.limb_id == SPECIES_ETHEREAL)
- BP.update_limb(is_creating = TRUE)
+ new_ethereal.dna.features["mcolor"] = new_ethereal.dna.features["ethcolor"] //Ethcolor and Mut color are both dogshit and will be replaced
+ for(var/obj/item/bodypart/limb as anything in new_ethereal.bodyparts)
+ if(limb.limb_id == SPECIES_ETHEREAL)
+ limb.update_limb(is_creating = TRUE)
/datum/species/ethereal/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load)
UnregisterSignal(C, COMSIG_ATOM_SHOULD_EMAG)
@@ -87,7 +82,6 @@
QDEL_NULL(ethereal_light)
return ..()
-
/datum/species/ethereal/random_name(gender, unique, lastname, attempts)
. = "[pick(GLOB.ethereal_names)] [random_capital_letter()]"
if(prob(65))
@@ -97,11 +91,12 @@
if(findname(.))
. = .(gender, TRUE, lastname, ++attempts)
-
-/datum/species/ethereal/spec_updatehealth(mob/living/carbon/human/H)
+/datum/species/ethereal/spec_updatehealth(mob/living/carbon/human/ethereal)
. = ..()
- if(H.stat != DEAD && !EMPeffect)
- var/healthpercent = max(H.health, 0) / 100
+ if(!ethereal_light)
+ return
+ if(ethereal.stat != DEAD && !EMPeffect)
+ var/healthpercent = max(ethereal.health, 0) / 100
if(!emageffect)
current_color = rgb(r2 + ((r1-r2)*healthpercent), g2 + ((g1-g2)*healthpercent), b2 + ((b1-b2)*healthpercent))
ethereal_light.set_light_range_power_color(1 + (2 * healthpercent), 1 + (1 * healthpercent), current_color)
@@ -110,11 +105,11 @@
else
ethereal_light.set_light_on(FALSE)
fixed_mut_color = rgb(128,128,128)
- H.update_body()
+ ethereal.update_body()
+ //ethereal.update_hair()
/datum/species/ethereal/proc/on_emp_act(mob/living/carbon/human/H, severity)
SIGNAL_HANDLER
-
EMPeffect = TRUE
spec_updatehealth(H)
to_chat(H, "You feel the light of your body leave you. ")
diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm
index d0cb954bb596b..acda8d150343a 100644
--- a/code/modules/mob/living/carbon/human/species_types/felinid.dm
+++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm
@@ -99,7 +99,7 @@
//Check to make sure legs are working
var/obj/item/bodypart/left_leg = H.get_bodypart(BODY_ZONE_L_LEG)
var/obj/item/bodypart/right_leg = H.get_bodypart(BODY_ZONE_R_LEG)
- if(!left_leg || !right_leg || left_leg.disabled || right_leg.disabled)
+ if(!left_leg || !right_leg || left_leg.bodypart_disabled || right_leg.bodypart_disabled)
return ..()
if(levels == 1)
//Nailed it!
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index a62c991428861..bd77efd9a3c36 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -858,7 +858,7 @@
name = "pile of bandages"
desc = "It emits a strange aura, as if there was still life within it..."
max_integrity = 50
- armor = list(MELEE = 90, BULLET = 90, LASER = 25, ENERGY = 80, BOMB = 50, BIO = 100, FIRE = -50, ACID = -50, STAMINA = 0)
+ armor = list(MELEE = 90, BULLET = 90, LASER = 25, ENERGY = 80, BOMB = 50, BIO = 100, FIRE = -50, ACID = -50, STAMINA = 0, BLEED = 0)
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "pile_bandages"
resistance_flags = FLAMMABLE
diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm
index 1e1a45b1d25c9..8b46658c88f6e 100644
--- a/code/modules/mob/living/carbon/human/species_types/humans.dm
+++ b/code/modules/mob/living/carbon/human/species_types/humans.dm
@@ -68,6 +68,12 @@
SPECIES_PERK_NAME = "Asimov Superiority",
SPECIES_PERK_DESC = "The AI and their cyborgs are often (but not always) subservient only \
to humans. As a human, silicons are required to both protect and obey you under the Asimov lawset.",
+ ),
+ list(
+ SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK,
+ SPECIES_PERK_ICON = "users",
+ SPECIES_PERK_NAME = "Indomitable Human Spirit",
+ SPECIES_PERK_DESC = "You're a human, you were born to inherit the stars!",
))
if(CONFIG_GET(flag/enforce_human_authority))
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index d9493fe6a43c0..7f4c9f3d5ec1c 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -309,7 +309,7 @@
plural_form = null
id = SPECIES_LUMINESCENT
var/glow_intensity = LUMINESCENT_DEFAULT_GLOW
- var/obj/effect/dummy/luminescent_glow/glow
+ var/obj/effect/dummy/lighting_obj/moblight/glow
var/obj/item/slime_extract/current_extract
var/datum/action/innate/integrate_extract/integrate_extract
var/datum/action/innate/use_extract/extract_minor
@@ -319,7 +319,7 @@
examine_limb_id = SPECIES_OOZELING
//Species datums don't normally implement destroy, but JELLIES SUCK ASS OUT OF A STEEL STRAW
-/datum/species/oozeling/luminescent/Destroy(force, ...)
+/datum/species/oozeling/luminescent/Destroy(force)
current_extract = null
QDEL_NULL(glow)
QDEL_NULL(integrate_extract)
@@ -327,27 +327,16 @@
QDEL_NULL(extract_minor)
return ..()
-
-/datum/species/oozeling/luminescent/on_species_loss(mob/living/carbon/C)
- ..()
- if(current_extract)
- current_extract.forceMove(C.drop_location())
- current_extract = null
- QDEL_NULL(glow)
- QDEL_NULL(integrate_extract)
- QDEL_NULL(extract_major)
- QDEL_NULL(extract_minor)
-
-/datum/species/oozeling/luminescent/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+/datum/species/oozeling/luminescent/on_species_gain(mob/living/carbon/new_jellyperson, datum/species/old_species)
..()
- glow = new(C)
- update_glow(C)
+ glow = new_jellyperson.mob_light(light_type = /obj/effect/dummy/lighting_obj/moblight/species)
+ update_glow(new_jellyperson)
integrate_extract = new(src)
- integrate_extract.Grant(C)
+ integrate_extract.Grant(new_jellyperson)
extract_minor = new(src)
- extract_minor.Grant(C)
+ extract_minor.Grant(new_jellyperson)
extract_major = new(src)
- extract_major.Grant(C)
+ extract_major.Grant(new_jellyperson)
/datum/species/oozeling/luminescent/proc/update_slime_actions()
integrate_extract.update_name()
@@ -355,25 +344,21 @@
extract_minor.UpdateButtonIcon()
extract_major.UpdateButtonIcon()
-/datum/species/oozeling/luminescent/proc/update_glow(mob/living/carbon/C, intensity)
- if(intensity)
- glow_intensity = intensity
- glow.set_light(glow_intensity, glow_intensity, C.dna.features["mcolor"])
-
-/obj/effect/dummy/luminescent_glow
- name = "luminescent glow"
- desc = "Tell a coder if you're seeing this."
- icon_state = "nothing"
- light_color = "#FFFFFF"
- light_range = LUMINESCENT_DEFAULT_GLOW
- light_system = MOVABLE_LIGHT
- light_power = 2.5
-
-/obj/effect/dummy/luminescent_glow/Initialize(mapload)
+/datum/species/oozeling/luminescent/on_species_loss(mob/living/carbon/C)
. = ..()
- if(!isliving(loc))
- return INITIALIZE_HINT_QDEL
+ if(current_extract)
+ current_extract.forceMove(C.drop_location())
+ current_extract = null
+ QDEL_NULL(glow)
+ QDEL_NULL(integrate_extract)
+ QDEL_NULL(extract_major)
+ QDEL_NULL(extract_minor)
+/// Updates the glow of our internal glow object
+/datum/species/oozeling/luminescent/proc/update_glow(mob/living/carbon/human/glowie, intensity)
+ if(intensity)
+ glow_intensity = intensity
+ glow.set_light_range_power_color(glow_intensity, glow_intensity, glowie.dna.features["mcolor"])
/datum/action/innate/integrate_extract
name = "Integrate Extract"
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index 3ffbcfa97eabb..b2db5f2212a10 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -97,3 +97,9 @@
species_language_holder = /datum/language_holder/lizard/ash
mutantlungs = /obj/item/organ/lungs/ashwalker
digitigrade_customization = DIGITIGRADE_FORCED
+
+/datum/species/lizard/ashwalker/spec_life(mob/living/carbon/human/H)
+ . = ..()
+ H.cauterise_wounds(0.1)
+ if (H.blood_volume < BLOOD_VOLUME_NORMAL && !H.is_bleeding())
+ H.blood_volume += 0.5
diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
index 1cea3c8950bf2..110e753ccd9cb 100644
--- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
@@ -225,6 +225,7 @@
item_flags = ABSTRACT | DROPDEL | ISWEAPON
w_class = WEIGHT_CLASS_HUGE
sharpness = IS_SHARP
+ bleed_force = BLEED_DEEP_WOUND
/obj/item/light_eater/Initialize(mapload)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/species_types/snail.dm b/code/modules/mob/living/carbon/human/species_types/snail.dm
index 4cce83b6a141e..85d8ccb9cd4a3 100644
--- a/code/modules/mob/living/carbon/human/species_types/snail.dm
+++ b/code/modules/mob/living/carbon/human/species_types/snail.dm
@@ -60,7 +60,7 @@
item_state = "snailshell"
lefthand_file = 'icons/mob/inhands/equipment/backpack_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/backpack_righthand.dmi'
- armor = list(MELEE = 20, BULLET = 10, LASER = 10, ENERGY = 10, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 20, BULLET = 10, LASER = 10, ENERGY = 10, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
max_integrity = 200
resistance_flags = FIRE_PROOF | ACID_PROOF
diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm
index f61f5e5ae8964..337cba0d5413e 100644
--- a/code/modules/mob/living/carbon/human/status_procs.dm
+++ b/code/modules/mob/living/carbon/human/status_procs.dm
@@ -1,27 +1,27 @@
-/mob/living/carbon/human/Stun(amount, updating = TRUE, ignore_canstun = FALSE)
+/mob/living/carbon/human/Stun(amount, ignore_canstun = FALSE)
amount = dna.species.spec_stun(src,amount)
return ..()
-/mob/living/carbon/human/Knockdown(amount, updating = TRUE, ignore_canstun = FALSE)
+/mob/living/carbon/human/Knockdown(amount, ignore_canstun = FALSE)
amount = dna.species.spec_stun(src,amount)
return ..()
-/mob/living/carbon/human/Paralyze(amount, updating = TRUE, ignore_canstun = FALSE)
+/mob/living/carbon/human/Paralyze(amount, ignore_canstun = FALSE)
amount = dna.species.spec_stun(src, amount)
return ..()
-/mob/living/carbon/human/Immobilize(amount, updating = TRUE, ignore_canstun = FALSE)
+/mob/living/carbon/human/Immobilize(amount, ignore_canstun = FALSE)
amount = dna.species.spec_stun(src, amount)
return ..()
-/mob/living/carbon/human/Unconscious(amount, updating = 1, ignore_canunconscious = 0)
+/mob/living/carbon/human/Unconscious(amount, ignore_canstun = FALSE)
amount = dna.species.spec_stun(src,amount)
if(HAS_TRAIT(src, TRAIT_HEAVY_SLEEPER))
amount *= rand(1.25, 1.3)
return ..()
-/mob/living/carbon/human/Sleeping(amount, updating = 1, ignore_sleepimmune = 0)
+/mob/living/carbon/human/Sleeping(amount)
if(HAS_TRAIT(src, TRAIT_HEAVY_SLEEPER))
amount *= rand(1.25, 1.3)
return ..()
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index d7db300834841..598a21d37743c 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -52,11 +52,9 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_hair()
dna.species.handle_hair(src)
-//used when putting/removing clothes that hide certain mutant body parts to just update those and not update the whole body.
/mob/living/carbon/human/proc/update_mutant_bodyparts()
dna.species.handle_mutant_bodyparts(src)
-
/mob/living/carbon/human/update_body()
remove_overlay(BODY_LAYER)
dna.species.handle_body(src)
@@ -218,7 +216,7 @@ There are several things that need to be remembered:
if(!gloves && blood_in_hands && !(NOBLOODOVERLAY in dna.species.species_traits))
var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands", -GLOVES_LAYER)
- if(get_num_arms(FALSE) < 2)
+ if(num_hands < 2)
if(has_left_hand(FALSE))
bloody_overlay.icon_state = "bloodyhands_left"
else if(has_right_hand(FALSE))
@@ -342,7 +340,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_shoes()
remove_overlay(SHOES_LAYER)
- if(get_num_legs(FALSE) <2)
+ if(num_legs < 2)
return
if(client && hud_used)
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index c36a916df082f..df98df3bc68ed 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -274,7 +274,8 @@
//Fourth and final link in a breath chain
/mob/living/carbon/proc/handle_breath_temperature(datum/gas_mixture/breath)
- return
+ // The air you breathe out should match your body temperature
+ breath.set_temperature(bodytemperature)
/// Attempts to take a breath from the external or internal air tank.
/mob/living/carbon/proc/get_breath_from_internal(volume_needed)
@@ -647,12 +648,12 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
/mob/living/carbon/proc/share_bodytemperature(mob/living/carbon/M)
var/temp_diff = bodytemperature - M.bodytemperature
if(temp_diff > 0) // you are warm share the heat of life
- M.adjust_bodytemperature(temp_diff, use_insulation=TRUE, use_steps=TRUE) // warm up the giver
- adjust_bodytemperature((temp_diff * -1), use_insulation=TRUE, use_steps=TRUE) // cool down the reciver
+ M.adjust_bodytemperature((temp_diff * 0.5), use_insulation=TRUE, use_steps=TRUE) // warm up the giver
+ adjust_bodytemperature((temp_diff * -0.5), use_insulation=TRUE, use_steps=TRUE) // cool down the reciver
else // they are warmer leech from them
- adjust_bodytemperature(temp_diff, use_insulation=TRUE, use_steps=TRUE) // warm up the reciver
- M.adjust_bodytemperature((temp_diff * -1), use_insulation=TRUE, use_steps=TRUE) // cool down the giver
+ adjust_bodytemperature((temp_diff * -0.5) , use_insulation=TRUE, use_steps=TRUE) // warm up the reciver
+ M.adjust_bodytemperature((temp_diff * 0.5), use_insulation=TRUE, use_steps=TRUE) // cool down the giver
/**
* Adjust the body temperature of a mob
@@ -664,21 +665,19 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
* * max_temp (optional) The maximum body temperature after adjustment
* * use_insulation (optional) modifies the amount based on the amount of insulation the mob has
* * use_steps (optional) Use the body temp divisors and max change rates
- * * hardsuit_fix (optional) num bodytemp_normal - H.bodytemperature Use hardsuit override until hardsuits fix is done...
+ * * capped (optional) default True used to cap step mode
*/
-/mob/living/carbon/adjust_bodytemperature(amount, min_temp=0, max_temp=INFINITY, use_insulation=FALSE, use_steps=FALSE, \
- hardsuit_fix=FALSE)
+/mob/living/carbon/adjust_bodytemperature(amount, min_temp=0, max_temp=INFINITY, use_insulation=FALSE, use_steps=FALSE, capped=TRUE)
// apply insulation to the amount of change
if(use_insulation)
amount *= (1 - get_insulation_protection(bodytemperature + amount))
- // Extra calculation for hardsuits to bleed off heat
- if(hardsuit_fix)
- amount += hardsuit_fix
-
// Use the bodytemp divisors to get the change step, with max step size
if(use_steps)
- amount = (amount > 0) ? min(amount / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX) : max(amount / BODYTEMP_COLD_DIVISOR, BODYTEMP_COOLING_MAX)
+ amount = (amount > 0) ? (amount / BODYTEMP_HEAT_DIVISOR) : (amount / BODYTEMP_COLD_DIVISOR)
+ // Clamp the results to the min and max step size
+ if(capped)
+ amount = (amount > 0) ? min(amount, BODYTEMP_HEATING_MAX) : max(amount, BODYTEMP_COOLING_MAX)
if(bodytemperature >= min_temp && bodytemperature <= max_temp)
bodytemperature = clamp(bodytemperature + amount, min_temp, max_temp)
diff --git a/code/modules/mob/living/carbon/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm
index e54a50bcfbc76..ae540b3b78506 100644
--- a/code/modules/mob/living/carbon/status_procs.dm
+++ b/code/modules/mob/living/carbon/status_procs.dm
@@ -16,7 +16,7 @@
ADD_TRAIT(src, TRAIT_INCAPACITATED, STAMINA)
ADD_TRAIT(src, TRAIT_IMMOBILIZED, STAMINA)
ADD_TRAIT(src, TRAIT_FLOORED, STAMINA)
- update_mobility()
+
/mob/living/carbon/adjust_drugginess(amount)
druggy = max(druggy+amount, 0)
diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm
index d644c52a83e5b..505201504141c 100644
--- a/code/modules/mob/living/carbon/update_icons.dm
+++ b/code/modules/mob/living/carbon/update_icons.dm
@@ -208,7 +208,6 @@
/obj/item/proc/worn_overlays(mutable_appearance/standing, isinhands = FALSE, icon_file, item_layer, atom/origin)
. = list()
-
/mob/living/carbon/update_body()
update_body_parts()
diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm
index 7737f0629daa1..78891afb06589 100644
--- a/code/modules/mob/living/death.dm
+++ b/code/modules/mob/living/death.dm
@@ -72,7 +72,6 @@
update_action_buttons_icon()
update_health_hud()
- update_mobility()
med_hud_set_health()
med_hud_set_status()
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index 2dbe321d48597..6908a0bbb88da 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -245,8 +245,8 @@
message_param = initial(message_param) // reset
if(ishuman(user) && intentional)
var/mob/living/carbon/human/H = user
- if(H.get_num_arms() == 0)
- if(H.get_num_legs() != 0)
+ if(H.usable_hands == 0)
+ if(H.usable_legs != 0)
message_param = "tries to point at %t with a leg, falling down in the process!"
H.Paralyze(20)
else
@@ -389,6 +389,9 @@
message = null
mob_type_blacklist_typecache = /mob/living/brain
+/datum/emote/living/custom/can_run_emote(mob/user, status_check, intentional)
+ . = ..() && intentional
+
/datum/emote/living/custom/proc/check_invalid(mob/user, input)
var/static/regex/stop_bad_mime = regex(@"says|exclaims|yells|asks")
if(stop_bad_mime.Find(input, 1, 1))
@@ -396,9 +399,6 @@
return TRUE
return FALSE
-/datum/emote/living/custom/can_run_emote(mob/user, status_check, intentional)
- . = ..() && intentional
-
/datum/emote/living/custom/run_emote(mob/user, params, type_override = null, intentional = FALSE)
if(!can_run_emote(user, TRUE, intentional))
return FALSE
diff --git a/code/modules/mob/living/inhand_holder.dm b/code/modules/mob/living/inhand_holder.dm
index 3181de18cd9c8..61a25fa4d2728 100644
--- a/code/modules/mob/living/inhand_holder.dm
+++ b/code/modules/mob/living/inhand_holder.dm
@@ -86,7 +86,7 @@
releasing = FALSE
return TRUE
-/obj/item/clothing/head/mob_holder/relaymove(mob/user)
+/obj/item/clothing/head/mob_holder/relaymove(mob/living/user, direction)
release()
/obj/item/clothing/head/mob_holder/container_resist()
diff --git a/code/modules/mob/living/init_signals.dm b/code/modules/mob/living/init_signals.dm
index 290c774b656a8..108570a584da3 100644
--- a/code/modules/mob/living/init_signals.dm
+++ b/code/modules/mob/living/init_signals.dm
@@ -9,12 +9,27 @@
RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_IMMOBILIZED), PROC_REF(on_immobilized_trait_gain))
RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_IMMOBILIZED), PROC_REF(on_immobilized_trait_loss))
+ RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_FLOORED), PROC_REF(on_floored_trait_gain))
+ RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_FLOORED), PROC_REF(on_floored_trait_loss))
+
+ //RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_FORCED_STANDING), PROC_REF(on_forced_standing_trait_gain))
+ //RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_FORCED_STANDING), PROC_REF(on_forced_standing_trait_loss))
+
RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_HANDS_BLOCKED), PROC_REF(on_handsblocked_trait_gain))
RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_HANDS_BLOCKED), PROC_REF(on_handsblocked_trait_loss))
+ RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_UI_BLOCKED), PROC_REF(on_ui_blocked_trait_gain))
+ RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_UI_BLOCKED), PROC_REF(on_ui_blocked_trait_loss))
+
+ RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_PULL_BLOCKED), PROC_REF(on_pull_blocked_trait_gain))
+ RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_PULL_BLOCKED), PROC_REF(on_pull_blocked_trait_loss))
+
RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_INCAPACITATED), PROC_REF(on_incapacitated_trait_gain))
RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_INCAPACITATED), PROC_REF(on_incapacitated_trait_loss))
+ RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_RESTRAINED), PROC_REF(on_restrained_trait_gain))
+ RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_RESTRAINED), PROC_REF(on_restrained_trait_loss))
+
RegisterSignals(src, list(
SIGNAL_ADDTRAIT(TRAIT_CRITICAL_CONDITION),
SIGNAL_REMOVETRAIT(TRAIT_CRITICAL_CONDITION),
@@ -35,7 +50,6 @@
if(stat <= UNCONSCIOUS)
update_stat()
-
///Called when TRAIT_DEATHCOMA is added to the mob.
/mob/living/proc/on_deathcoma_trait_gain(datum/source)
SIGNAL_HANDLER
@@ -51,42 +65,111 @@
/mob/living/proc/on_immobilized_trait_gain(datum/source)
SIGNAL_HANDLER
mobility_flags &= ~MOBILITY_MOVE
+ if(living_flags & MOVES_ON_ITS_OWN)
+ walk(src, 0) //stop mid walk
///Called when TRAIT_IMMOBILIZED is removed from the mob.
/mob/living/proc/on_immobilized_trait_loss(datum/source)
SIGNAL_HANDLER
mobility_flags |= MOBILITY_MOVE
-///Called when TRAIT_HANDS_BLOCKED is added to the mob.
+
+/// Called when [TRAIT_FLOORED] is added to the mob.
+/mob/living/proc/on_floored_trait_gain(datum/source)
+ SIGNAL_HANDLER
+ if(buckled && buckled.buckle_lying != NO_BUCKLE_LYING)
+ return // Handled by the buckle.
+ mobility_flags &= ~MOBILITY_STAND
+ on_floored_start()
+
+
+/// Called when [TRAIT_FLOORED] is removed from the mob.
+/mob/living/proc/on_floored_trait_loss(datum/source)
+ SIGNAL_HANDLER
+ mobility_flags |= MOBILITY_STAND
+ on_floored_end()
+
+
+/// Called when [TRAIT_HANDS_BLOCKED] is added to the mob.
/mob/living/proc/on_handsblocked_trait_gain(datum/source)
SIGNAL_HANDLER
mobility_flags &= ~(MOBILITY_USE | MOBILITY_PICKUP | MOBILITY_STORAGE)
- drop_all_held_items()
+ on_handsblocked_start()
if (active_storage)
active_storage.hide_from(src)
update_action_buttons_icon(TRUE)
-///Called when TRAIT_HANDS_BLOCKED is removed from the mob.
+/// Called when [TRAIT_HANDS_BLOCKED] is removed from the mob.
/mob/living/proc/on_handsblocked_trait_loss(datum/source)
SIGNAL_HANDLER
mobility_flags |= (MOBILITY_USE | MOBILITY_PICKUP | MOBILITY_STORAGE)
+ on_handsblocked_end()
update_action_buttons_icon(TRUE)
-/// Called when traits that alter succumbing are added/removed.
-/// Will show or hide the succumb alert prompt.
-/mob/living/proc/update_succumb_action()
+
+/// Called when [TRAIT_UI_BLOCKED] is added to the mob.
+/mob/living/proc/on_ui_blocked_trait_gain(datum/source)
SIGNAL_HANDLER
- if (CAN_SUCCUMB(src))
- throw_alert("succumb", /atom/movable/screen/alert/succumb)
- else
- clear_alert("succumb")
+ mobility_flags &= ~(MOBILITY_UI)
+ unset_machine()
+ update_action_buttons_icon()
+
+/// Called when [TRAIT_UI_BLOCKED] is removed from the mob.
+/mob/living/proc/on_ui_blocked_trait_loss(datum/source)
+ SIGNAL_HANDLER
+ mobility_flags |= MOBILITY_UI
+ update_action_buttons_icon()
+
+
+/// Called when [TRAIT_PULL_BLOCKED] is added to the mob.
+/mob/living/proc/on_pull_blocked_trait_gain(datum/source)
+ SIGNAL_HANDLER
+ mobility_flags &= ~(MOBILITY_PULL)
+ if(pulling)
+ stop_pulling()
+
+/// Called when [TRAIT_PULL_BLOCKED] is removed from the mob.
+/mob/living/proc/on_pull_blocked_trait_loss(datum/source)
+ SIGNAL_HANDLER
+ mobility_flags |= MOBILITY_PULL
+
-///Called when TRAIT_INCAPACITATED is added to the mob.
+/// Called when [TRAIT_INCAPACITATED] is added to the mob.
/mob/living/proc/on_incapacitated_trait_gain(datum/source)
SIGNAL_HANDLER
+ ADD_TRAIT(src, TRAIT_UI_BLOCKED, TRAIT_INCAPACITATED)
+ ADD_TRAIT(src, TRAIT_PULL_BLOCKED, TRAIT_INCAPACITATED)
+ update_icon()
update_action_buttons_icon(TRUE)
-///Called when TRAIT_INCAPACITATED is removed from the mob.
+/// Called when [TRAIT_INCAPACITATED] is removed from the mob.
/mob/living/proc/on_incapacitated_trait_loss(datum/source)
SIGNAL_HANDLER
+ REMOVE_TRAIT(src, TRAIT_UI_BLOCKED, TRAIT_INCAPACITATED)
+ REMOVE_TRAIT(src, TRAIT_PULL_BLOCKED, TRAIT_INCAPACITATED)
+ update_icon()
update_action_buttons_icon(TRUE)
+
+
+/// Called when [TRAIT_RESTRAINED] is added to the mob.
+/mob/living/proc/on_restrained_trait_gain(datum/source)
+ SIGNAL_HANDLER
+ ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_RESTRAINED)
+
+/// Called when [TRAIT_RESTRAINED] is removed from the mob.
+/mob/living/proc/on_restrained_trait_loss(datum/source)
+ SIGNAL_HANDLER
+ REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_RESTRAINED)
+
+
+/**
+ * Called when traits that alter succumbing are added/removed.
+ *
+ * Will show or hide the succumb alert prompt.
+ */
+/mob/living/proc/update_succumb_action()
+ SIGNAL_HANDLER
+ if (CAN_SUCCUMB(src))
+ throw_alert("succumb", /atom/movable/screen/alert/succumb)
+ else
+ clear_alert("succumb")
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 74c62324b6166..8400d117fdaa7 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -60,7 +60,7 @@
return
if(buckled || now_pushing)
return
- if(confused && stat == CONSCIOUS && (mobility_flags & MOBILITY_STAND) && m_intent == "run" && !ismovable(A) && !HAS_MOB_PROPERTY(src, PROP_CANTBUMPSLAM)) // ported from VORE, sue me
+ if(confused && stat == CONSCIOUS && body_position == STANDING_UP && m_intent == "run" && !ismovable(A) && !HAS_MOB_PROPERTY(src, PROP_CANTBUMPSLAM)) // ported from VORE, sue me //Suing you rn
APPLY_MOB_PROPERTY(src, PROP_CANTBUMPSLAM, src.type) //Bump() is called continuously so ratelimit the check to 20 seconds if it passes or 5 if it doesn't
if(prob(10))
playsound(get_turf(src), "punch", 25, 1, -1)
@@ -432,11 +432,11 @@
death()
/mob/living/incapacitated(ignore_restraints = FALSE, ignore_grab = FALSE, ignore_stasis = FALSE)
- if(stat || HAS_TRAIT(src, TRAIT_INCAPACITATED) || (!ignore_restraints && (HAS_TRAIT(src, TRAIT_RESTRAINED) || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE))) || (!ignore_stasis && IS_IN_STASIS(src)))
+ if(HAS_TRAIT(src, TRAIT_INCAPACITATED) || (!ignore_restraints && (HAS_TRAIT(src, TRAIT_RESTRAINED) || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_NECK))) || (!ignore_stasis && IS_IN_STASIS(src)))
return TRUE
/mob/living/canUseStorage()
- if (get_num_arms() <= 0)
+ if (usable_hands <= 0)
return FALSE
return TRUE
@@ -481,39 +481,95 @@
else
if(alert(src, "You sure you want to sleep for a while?", "Sleep", "Yes", "No") == "Yes")
SetSleeping(400) //Short nap
- update_mobility()
+
/mob/proc/get_contents()
-/mob/living/proc/lay_down()
+
+/mob/living/proc/toggle_resting()
set name = "Rest"
set category = "IC"
- if(!resting)
- set_resting(TRUE, FALSE)
- else
- if(do_after(src, 10, target = src, timed_action_flags = IGNORE_RESTRAINED | IGNORE_HELD_ITEM | IGNORE_USER_LOC_CHANGE))
- set_resting(FALSE, FALSE)
- else
- to_chat(src, "You fail to get up. ")
+ set_resting(!resting, FALSE)
+
///Proc to hook behavior to the change of value in the resting variable.
-/mob/living/proc/set_resting(rest, silent = TRUE)
- if(rest == resting)
+/mob/living/proc/set_resting(new_resting, silent = TRUE, instant = FALSE)
+ if(new_resting == resting)
return
- if(!silent)
- if(rest)
- to_chat(src, "You are now resting. ")
+ . = resting
+ resting = new_resting
+ if(new_resting)
+ if(body_position == LYING_DOWN)
+ if(!silent)
+ to_chat(src, "You will now try to stay lying down on the floor. ")
+ else if(buckled && buckled.buckle_lying != NO_BUCKLE_LYING)
+ if(!silent)
+ to_chat(src, "You will now lay down as soon as you are able to. ")
+ else
+ if(!silent)
+ to_chat(src, "You lay down. ")
+ set_lying_down()
+ else
+ if(body_position == STANDING_UP)
+ if(!silent)
+ to_chat(src, "You will now try to remain standing up. ")
+ else if(HAS_TRAIT(src, TRAIT_FLOORED) || (buckled && buckled.buckle_lying != NO_BUCKLE_LYING))
+ if(!silent)
+ to_chat(src, "You will now stand up as soon as you are able to. ")
else
- to_chat(src, "You get up. ")
- . = rest
- resting = rest
+ if(!silent)
+ to_chat(src, "You stand up. ")
+ get_up(instant)
+
update_resting()
+/// Proc to append and redefine behavior to the change of the [/mob/living/var/resting] variable.
/mob/living/proc/update_resting()
update_rest_hud_icon()
- update_mobility()
+ SEND_SIGNAL(src, COMSIG_LIVING_RESTING_UPDATED, resting)
+
+
+/mob/living/proc/get_up(instant = FALSE)
+ set waitfor = FALSE
+ if(!instant && !do_after(src, 1 SECONDS, src, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE|IGNORE_HELD_ITEM), extra_checks = CALLBACK(src, TYPE_PROC_REF(/mob/living, rest_checks_callback))))
+ return
+ if(resting || body_position == STANDING_UP || HAS_TRAIT(src, TRAIT_FLOORED))
+ return
+ set_body_position(STANDING_UP)
+ set_lying_angle(0)
+
+
+/mob/living/proc/rest_checks_callback()
+ if(resting || lying_angle == 0 || HAS_TRAIT(src, TRAIT_FLOORED))
+ return FALSE
+ return TRUE
+
+
+/// Change the [body_position] to [LYING_DOWN] and update associated behavior.
+/mob/living/proc/set_lying_down(new_lying_angle)
+ set_body_position(LYING_DOWN)
+
+
+/// Proc to append behavior related to lying down.
+/mob/living/proc/on_lying_down(new_lying_angle)
+ if(layer == initial(layer)) //to avoid things like hiding larvas.
+ layer = LYING_MOB_LAYER //so mob lying always appear behind standing mobs
+ ADD_TRAIT(src, TRAIT_UI_BLOCKED, LYING_DOWN_TRAIT)
+ ADD_TRAIT(src, TRAIT_PULL_BLOCKED, LYING_DOWN_TRAIT)
+ density = FALSE // We lose density and stop bumping passable dense things.
+ if(HAS_TRAIT(src, TRAIT_FLOORED) && !(dir & (NORTH|SOUTH)))
+ setDir(pick(NORTH, SOUTH)) // We are and look helpless.
+
+
+/// Proc to append behavior related to lying down.
+/mob/living/proc/on_standing_up()
+ if(layer == LYING_MOB_LAYER)
+ layer = initial(layer)
+ density = initial(density) // We were prone before, so we become dense and things can bump into us again.
+ REMOVE_TRAIT(src, TRAIT_UI_BLOCKED, LYING_DOWN_TRAIT)
+ REMOVE_TRAIT(src, TRAIT_PULL_BLOCKED, LYING_DOWN_TRAIT)
//Recursive function to find everything a mob is holding. Really shitty proc tbh.
@@ -571,7 +627,6 @@
set_suicide(FALSE)
set_stat(UNCONSCIOUS) //the mob starts unconscious,
updatehealth() //then we check if the mob should wake up.
- update_mobility()
update_sight()
clear_alert("not_enough_oxy")
reload_fullscreen()
@@ -625,16 +680,15 @@
return stat != DEAD
-/mob/living/proc/remove_CC(should_update_mobility = TRUE)
- SetStun(0, FALSE)
- SetKnockdown(0, FALSE)
- SetImmobilized(0, FALSE)
- SetParalyzed(0, FALSE)
- SetSleeping(0, FALSE)
+/mob/living/proc/remove_CC()
+ SetStun(0)
+ SetKnockdown(0)
+ SetImmobilized(0)
+ SetParalyzed(0)
+ SetSleeping(0)
setStaminaLoss(0)
- SetUnconscious(0, FALSE)
- if(should_update_mobility)
- update_mobility()
+ SetUnconscious(0)
+
//proc used to completely heal a mob.
/mob/living/proc/fully_heal(admin_revive = FALSE)
@@ -674,9 +728,9 @@
var/datum/component/mood/mood = GetComponent(/datum/component/mood)
if (mood)
mood.remove_temp_moods(admin_revive)
- update_mobility()
stop_sound_channel(CHANNEL_HEARTBEAT)
+
//proc called by revive(), to check if we can actually ressuscitate the mob (we don't want to revive him and have him instantly die again)
/mob/living/proc/can_be_revived()
. = 1
@@ -713,9 +767,10 @@
if(active_storage && !(CanReach(active_storage.parent,view_only = TRUE)))
active_storage.close(src)
- if(!(mobility_flags & MOBILITY_STAND) && !buckled && prob(getBruteLoss()*200/maxHealth))
+ if(body_position == LYING_DOWN && !buckled && prob(getBruteLoss()*200/maxHealth))
makeTrail(newloc, T, old_direction)
+
///Called by mob Move() when the lying_angle is different than zero, to better visually simulate crawling.
/mob/living/proc/lying_angle_on_movement(direct)
if(direct & EAST)
@@ -761,7 +816,7 @@
TH.color = spec_color
/mob/living/carbon/human/makeTrail(turf/T, turf/start, direction, spec_color)
- if((NOBLOOD in dna.species.species_traits) || !bleed_rate || bleedsuppress)
+ if((NOBLOOD in dna.species.species_traits) || !is_bleeding())
return
spec_color = dna.species.blood_color
..()
@@ -1198,65 +1253,8 @@
/mob/living/can_be_pulled()
return ..() && !(buckled && buckled.buckle_prevents_pull)
-//Updates canmove, lying and icons. Could perhaps do with a rename but I can't think of anything to describe it.
-//Robots, animals and brains have their own version so don't worry about them
-/mob/living/proc/update_mobility()
- var/has_legs = get_num_legs()
- var/has_arms = get_num_arms()
- var/ignore_legs = get_leg_ignore()
- var/canmove = !HAS_TRAIT(src, TRAIT_IMMOBILIZED) && (has_arms || ignore_legs || has_legs)
- if(canmove)
- mobility_flags |= MOBILITY_MOVE
- else
- mobility_flags &= ~MOBILITY_MOVE
- var/canstand_involuntary = !HAS_TRAIT(src, TRAIT_FLOORED) && (ignore_legs || has_legs)
- var/canstand = canstand_involuntary && !resting
-
- if(buckled && buckled.buckle_lying != -1)
- if(buckled.buckle_lying != 0)
- mobility_flags &= ~MOBILITY_STAND
- else
- mobility_flags |= MOBILITY_STAND
- set_lying_angle(buckled.buckle_lying)
- else if(!canstand)
- mobility_flags &= ~MOBILITY_STAND
- if(lying_angle == 0) //force them on the ground
- set_lying_angle(pick(90, 270))
- if(!canstand_involuntary)
- on_fall()
- else
- mobility_flags |= MOBILITY_STAND
- set_lying_angle(0)
-
- if(lying_angle != 0 || HAS_TRAIT(src, TRAIT_HANDS_BLOCKED) || incapacitated())
- mobility_flags &= ~(MOBILITY_UI|MOBILITY_PULL)
- else
- mobility_flags |= MOBILITY_UI|MOBILITY_PULL
-
- update_action_buttons_icon(TRUE)
-
- if(stat == UNCONSCIOUS)
- drop_all_held_items()
- if(!(mobility_flags & MOBILITY_PULL))
- if(pulling)
- stop_pulling()
- if(!(mobility_flags & MOBILITY_UI))
- unset_machine()
-
- // Movespeed mods based on arms/legs quantity
- if(!get_leg_ignore())
- var/limbless_slowdown = 0
- // These checks for <2 should be swapped out for something else if we ever end up with a species with more than 2
- if(has_legs < 2)
- limbless_slowdown += 6 - (has_legs * 3)
- if(!has_legs && has_arms < 2)
- limbless_slowdown += 6 - (has_arms * 3)
- if(limbless_slowdown)
- add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/limbless, multiplicative_slowdown = limbless_slowdown)
- else
- remove_movespeed_modifier(/datum/movespeed_modifier/limbless)
-///Called when mob changes from a standing position into a prone while lacking the ability to stand up at the moment, through update_mobility()
+/// Called when mob changes from a standing position into a prone while lacking the ability to stand up at the moment.
/mob/living/proc/on_fall()
return
@@ -1297,7 +1295,7 @@
if(.)
if(client)
reset_perspective()
- update_mobility() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
+
/mob/living/set_stat(new_stat)
. = ..()
@@ -1307,12 +1305,12 @@
if(CONSCIOUS)
if(stat >= UNCONSCIOUS)
ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT)
- ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_KNOCKEDOUT)
- ADD_TRAIT(src, TRAIT_FLOORED, UNCONSCIOUS_TRAIT)
+ ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, STAT_TRAIT)
+ ADD_TRAIT(src, TRAIT_INCAPACITATED, STAT_TRAIT)
+ ADD_TRAIT(src, TRAIT_FLOORED, STAT_TRAIT)
if(SOFT_CRIT)
if(stat >= UNCONSCIOUS)
ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) //adding trait sources should come before removing to avoid unnecessary updates
- ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_KNOCKEDOUT)
if(pulledby)
REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, PULLED_WHILE_SOFTCRIT_TRAIT)
if(UNCONSCIOUS)
@@ -1325,15 +1323,15 @@
if(CONSCIOUS)
if(. >= UNCONSCIOUS)
REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT)
- REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_KNOCKEDOUT)
- REMOVE_TRAIT(src, TRAIT_FLOORED, UNCONSCIOUS_TRAIT)
+ REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, STAT_TRAIT)
+ REMOVE_TRAIT(src, TRAIT_INCAPACITATED, STAT_TRAIT)
+ REMOVE_TRAIT(src, TRAIT_FLOORED, STAT_TRAIT)
REMOVE_TRAIT(src, TRAIT_CRITICAL_CONDITION, STAT_TRAIT)
if(SOFT_CRIT)
if(pulledby)
ADD_TRAIT(src, TRAIT_IMMOBILIZED, PULLED_WHILE_SOFTCRIT_TRAIT) //adding trait sources should come before removing to avoid unnecessary updates
if(. >= UNCONSCIOUS)
REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT)
- REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_KNOCKEDOUT)
ADD_TRAIT(src, TRAIT_CRITICAL_CONDITION, STAT_TRAIT)
if(UNCONSCIOUS)
if(. != HARD_CRIT)
@@ -1357,14 +1355,25 @@
. = buckled
buckled = new_buckled
if(buckled)
- if(!.)
- if(!HAS_TRAIT(buckled, TRAIT_NO_IMMOBILIZE)) //check if the object being buckled to that would normally immobilize has the NO_Immobilize trait, i.e. Wheelchairs. People buckled to wheelchairs obviously have more free movement that those buckled to stasis beds
- ADD_TRAIT(src, TRAIT_IMMOBILIZED, BUCKLED_TRAIT)
- if(buckled.buckle_lying)
+ ADD_TRAIT(src, TRAIT_IMMOBILIZED, BUCKLED_TRAIT)
+ switch(buckled.buckle_lying)
+ if(NO_BUCKLE_LYING) // The buckle doesn't force a lying angle.
+ REMOVE_TRAIT(src, TRAIT_FLOORED, BUCKLED_TRAIT)
+ if(0) // Forcing to a standing position.
+ REMOVE_TRAIT(src, TRAIT_FLOORED, BUCKLED_TRAIT)
+ set_body_position(STANDING_UP)
+ set_lying_angle(0)
+ else // Forcing to a lying position.
ADD_TRAIT(src, TRAIT_FLOORED, BUCKLED_TRAIT)
- else if(.)
+ set_body_position(LYING_DOWN)
+ set_lying_angle(buckled.buckle_lying)
+ else
REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, BUCKLED_TRAIT)
REMOVE_TRAIT(src, TRAIT_FLOORED, BUCKLED_TRAIT)
+ if(.) // We unbuckled from something.
+ var/atom/movable/old_buckled = .
+ if(old_buckled.buckle_lying == 0 && (resting || HAS_TRAIT(src, TRAIT_FLOORED))) // The buckle forced us to stay up (like a chair)
+ set_lying_down() // We want to rest or are otherwise floored, so let's drop on the ground.
/mob/living/set_pulledby(new_pulledby)
@@ -1453,15 +1462,16 @@
result += static_virus
return result
-/mob/living/reset_perspective(atom/A)
- if(..())
- update_sight()
- if(client.eye && client.eye != src)
- var/atom/AT = client.eye
- AT.get_remote_view_fullscreens(src)
- else
- clear_fullscreen("remote_view", 0)
- update_pipe_vision()
+/mob/living/reset_perspective(atom/new_eye)
+ if(!..())
+ return
+ update_sight()
+ if(client.eye && client.eye != src)
+ var/atom/AT = client.eye
+ AT.get_remote_view_fullscreens(src)
+ else
+ clear_fullscreen("remote_view", 0)
+ update_pipe_vision()
/mob/living/update_mouse_pointer()
..()
@@ -1538,16 +1548,6 @@
if(lying_angle != lying_prev)
update_transform()
lying_prev = lying_angle
- if(lying_angle != 0) //We are not standing up.
- if(layer == initial(layer)) //to avoid things like hiding larvas.
- layer = LYING_MOB_LAYER //so mob lying always appear behind standing mobs
- if(. == 0) //We became prone and were not before. We lose density and stop bumping passable dense things.
- density = FALSE
- else //We are prone.
- if(layer == LYING_MOB_LAYER)
- layer = initial(layer)
- if(.) //We weren't pone before, so we become dense and things can bump into us again.
- density = initial(density)
/**
* add_body_temperature_change Adds modifications to the body temperature
@@ -1605,3 +1605,96 @@
remove_client_colour(current_correction)
add_client_colour(entered.color_correction)
current_correction = entered.color_correction
+
+
+///Proc to modify the value of num_legs and hook behavior associated to this event.
+/mob/living/proc/set_num_legs(new_value)
+ if(num_legs == new_value)
+ return
+ . = num_legs
+ num_legs = new_value
+
+
+///Proc to modify the value of usable_legs and hook behavior associated to this event.
+/mob/living/proc/set_usable_legs(new_value)
+ if(usable_legs == new_value)
+ return
+ . = usable_legs
+ usable_legs = new_value
+
+ if(new_value > .) // Gained leg usage.
+ REMOVE_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+ REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+ else if(!(movement_type & (FLYING | FLOATING))) //Lost leg usage, not flying.
+ if(!usable_legs)
+ ADD_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+ if(!usable_hands)
+ ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+
+ if(usable_legs < default_num_legs)
+ var/limbless_slowdown = (default_num_legs - usable_legs) * 3
+ if(!usable_legs && usable_hands < default_num_hands)
+ limbless_slowdown += (default_num_hands - usable_hands) * 3
+ add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/limbless, multiplicative_slowdown = limbless_slowdown)
+ else
+ remove_movespeed_modifier(/datum/movespeed_modifier/limbless)
+
+
+///Proc to modify the value of num_hands and hook behavior associated to this event.
+/mob/living/proc/set_num_hands(new_value)
+ if(num_hands == new_value)
+ return
+ . = num_hands
+ num_hands = new_value
+
+
+///Proc to modify the value of usable_hands and hook behavior associated to this event.
+/mob/living/proc/set_usable_hands(new_value)
+ if(usable_hands == new_value)
+ return
+ . = usable_hands
+ usable_hands = new_value
+
+ if(new_value > .) // Gained hand usage.
+ REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+ else if(!(movement_type & (FLYING | FLOATING)) && !usable_hands && !usable_legs) //Lost a hand, not flying, no hands left, no legs.
+ ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT)
+
+
+/// Changes the value of the [living/body_position] variable.
+/mob/living/proc/set_body_position(new_value)
+ if(body_position == new_value)
+ return
+ . = body_position
+ body_position = new_value
+ if(new_value == LYING_DOWN) // From standing to lying down.
+ on_lying_down()
+ else // From lying down to standing up.
+ on_standing_up()
+
+
+/// Proc to append behavior to the condition of being floored. Called when the condition starts.
+/mob/living/proc/on_floored_start()
+ if(body_position == STANDING_UP) //force them on the ground
+ set_lying_angle(pick(90, 270))
+ set_body_position(LYING_DOWN)
+ on_fall()
+
+
+/// Proc to append behavior to the condition of being floored. Called when the condition ends.
+/mob/living/proc/on_floored_end()
+ if(!resting)
+ get_up()
+
+
+/// Proc to append behavior to the condition of being handsblocked. Called when the condition starts.
+/mob/living/proc/on_handsblocked_start()
+ drop_all_held_items()
+ ADD_TRAIT(src, TRAIT_UI_BLOCKED, TRAIT_HANDS_BLOCKED)
+ ADD_TRAIT(src, TRAIT_PULL_BLOCKED, TRAIT_HANDS_BLOCKED)
+
+
+/// Proc to append behavior to the condition of being handsblocked. Called when the condition ends.
+/mob/living/proc/on_handsblocked_end()
+ REMOVE_TRAIT(src, TRAIT_UI_BLOCKED, TRAIT_HANDS_BLOCKED)
+ REMOVE_TRAIT(src, TRAIT_PULL_BLOCKED, TRAIT_HANDS_BLOCKED)
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 87f4b1e7555a1..7e9efe18b5bc1 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -194,14 +194,12 @@
log_combat(user, src, "grabbed", addition="neck grab")
visible_message("[user] grabs [src] by the neck! ",\
"[user] grabs you by the neck! ")
- update_mobility() //we fall down
if(!buckled && !density)
Move(user.loc)
if(GRAB_KILL)
log_combat(user, src, "strangled", addition="kill grab")
visible_message("[user] is strangling [src]! ", \
"[user] is strangling you! ")
- update_mobility() //we fall down
if(!buckled && !density)
Move(user.loc)
user.set_pull_offsets(src, grab_state)
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 6a3b9557b4b63..920b0f651808c 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -26,12 +26,20 @@
///When the mob enters hard critical state and is fully incapacitated.
var/hardcrit_threshold = HEALTH_THRESHOLD_FULLCRIT
+ /// Generic bitflags for boolean conditions at the [/mob/living] level. Keep this for inherent traits of living types, instead of runtime-changeable ones.
+ var/living_flags = NONE
+
+ /// Flags that determine the potential of a mob to perform certain actions. Do not change this directly.
var/mobility_flags = MOBILITY_FLAGS_DEFAULT
var/resting = FALSE
- VAR_PROTECTED/lying_angle = 0 ///number of degrees. DO NOT USE THIS IN CHECKS. CHECK FOR MOBILITY FLAGS INSTEAD!!
- var/lying_prev = 0 //last value of lying on update_mobility
+ /// Variable to track the body position of a mob, regardless of the actual angle of rotation (usually matching it, but not necessarily).
+ var/body_position = STANDING_UP
+ /// Number of degrees of rotation of a mob. 0 means no rotation, up-side facing NORTH. 90 means up-side rotated to face EAST, and so on.
+ VAR_PROTECTED/lying_angle = 0
+ /// Value of lying lying_angle before last change. TODO: Remove the need for this.
+ var/lying_prev = 0
var/confused = 0 //Makes the mob move in random directions.
@@ -62,6 +70,20 @@
var/metabolism_efficiency = 1 //more or less efficiency to metabolize helpful/harmful reagents and regulate body temperature..
var/has_limbs = 0 //does the mob have distinct limbs?(arms,legs, chest,head)
+ ///How many legs does this mob have by default. This shouldn't change at runtime.
+ var/default_num_legs = 2
+ ///How many legs does this mob currently have. Should only be changed through set_num_legs()
+ var/num_legs = 2
+ ///How many usable legs this mob currently has. Should only be changed through set_usable_legs()
+ var/usable_legs = 2
+
+ ///How many hands does this mob have by default. This shouldn't change at runtime.
+ var/default_num_hands = 2
+ ///How many hands hands does this mob currently have. Should only be changed through set_num_hands()
+ var/num_hands = 2
+ ///How many usable hands does this mob currently have. Should only be changed through set_usable_hands()
+ var/usable_hands = 2
+
var/list/pipes_shown = list()
var/last_played_vent
@@ -134,6 +156,9 @@
var/icon/head_icon = 'icons/mob/pets_held.dmi'//what it looks like on your head
var/held_state = ""//icon state for the above
+ /// Is this mob allowed to be buckled/unbuckled to/from things?
+ var/can_buckle_to = TRUE
+
//is mob player controllable
var/playable = FALSE
var/flavor_text = FLAVOR_TEXT_NONE
diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm
index 24c834a72e20b..eaf9b84962334 100644
--- a/code/modules/mob/living/living_movement.dm
+++ b/code/modules/mob/living/living_movement.dm
@@ -3,17 +3,18 @@
update_turf_movespeed(loc)
update_looking_move()
+
/mob/living/CanAllowThrough(atom/movable/mover, border_dir)
. = ..()
if(.)
return
if(mover.throwing)
- return (!density || !(mobility_flags & MOBILITY_STAND) || (mover.throwing.thrower == src && !ismob(mover)))
+ return (!density || (body_position == LYING_DOWN) || (mover.throwing.thrower == src && !ismob(mover)))
if(buckled == mover)
return TRUE
if(ismob(mover) && (mover in buckled_mobs))
return TRUE
- return !mover.density || !(mobility_flags & MOBILITY_STAND)
+ return !mover.density || body_position == LYING_DOWN
/mob/living/toggle_move_intent()
. = ..()
@@ -32,11 +33,12 @@
else
remove_movespeed_modifier(/datum/movespeed_modifier/turf_slowdown)
+
/mob/living/proc/update_pull_movespeed()
if(pulling)
if(isliving(pulling))
var/mob/living/L = pulling
- if(!slowed_by_drag || (L.mobility_flags & MOBILITY_STAND) || L.buckled || grab_state >= GRAB_AGGRESSIVE)
+ if(!slowed_by_drag || L.body_position == STANDING_UP || L.buckled || grab_state >= GRAB_AGGRESSIVE)
remove_movespeed_modifier(/datum/movespeed_modifier/bulky_drag)
return
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/bulky_drag, multiplicative_slowdown = PULL_PRONE_SLOWDOWN)
diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm
index 43b1700fe8a2d..76e191a4d498d 100644
--- a/code/modules/mob/living/login.dm
+++ b/code/modules/mob/living/login.dm
@@ -1,5 +1,8 @@
/mob/living/Login()
- ..()
+ . = ..()
+ if(!. || !client)
+ return FALSE
+
//Mind updates
sync_mind()
mind.show_memory(src, 0)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 031b744162d00..f6ec743b5f95f 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -19,7 +19,6 @@
icon_state = "ai"
move_resist = MOVE_FORCE_VERY_STRONG
density = TRUE
- mobility_flags = ALL
status_flags = CANSTUN|CANPUSH
a_intent = INTENT_HARM //so we always get pushed instead of trying to swap
sight = SEE_TURFS | SEE_MOBS | SEE_OBJS
@@ -30,6 +29,7 @@
d_hud = DATA_HUD_DIAGNOSTIC_ADVANCED
mob_size = MOB_SIZE_LARGE
radio = /obj/item/radio/headset/silicon/ai
+ can_buckle_to = FALSE
var/battery = 200 //emergency power if the AI's APC is off
var/list/network = list("ss13")
var/list/connected_robots = list()
@@ -37,7 +37,7 @@
/// Station alert datum for showing alerts UI
var/datum/station_alert/alert_control
- var/aiRestorePowerRoutine = 0
+ var/aiRestorePowerRoutine = POWER_RESTORATION_OFF
var/requires_power = POWER_REQ_ALL
var/can_be_carded = TRUE
var/icon/holo_icon //Default is assigned when AI is created.
@@ -178,6 +178,9 @@
builtInCamera = new (src)
builtInCamera.network = list("ss13")
+ ADD_TRAIT(src, TRAIT_PULL_BLOCKED, ROUNDSTART_TRAIT)
+ ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, ROUNDSTART_TRAIT)
+
alert_control = new(src, list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER, ALARM_CAMERA, ALARM_BURGLAR, ALARM_MOTION), list(z), camera_view = TRUE)
RegisterSignal(alert_control.listener, COMSIG_ALARM_TRIGGERED, PROC_REF(alarm_triggered))
RegisterSignal(alert_control.listener, COMSIG_ALARM_CLEARED, PROC_REF(alarm_cleared))
@@ -398,12 +401,6 @@
if(ai_tracking_target)
ai_stop_tracking()
-/mob/living/silicon/ai/update_mobility() //If the AI dies, mobs won't go through it anymore
- if(stat != CONSCIOUS)
- mobility_flags = NONE
- else
- mobility_flags = ALL
-
/mob/living/silicon/ai/proc/ai_cancel_call()
set category = "Malfunction"
if(control_disabled)
@@ -794,13 +791,6 @@
to_chat(src, "You have been downloaded to a mobile storage device. Remote device connection severed.")
to_chat(user, "Transfer successful : [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.")
-/mob/living/silicon/ai/can_buckle()
- return 0
-
-/mob/living/silicon/ai/incapacitated(ignore_restraints = FALSE, ignore_grab = FALSE, ignore_stasis = FALSE)
- if(aiRestorePowerRoutine)
- return TRUE
- return ..()
/mob/living/silicon/ai/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE)
if(control_disabled || incapacitated())
@@ -909,33 +899,36 @@
malf_picker = new /datum/module_picker
-/mob/living/silicon/ai/reset_perspective(atom/A)
+/mob/living/silicon/ai/reset_perspective(atom/new_eye)
+ SHOULD_CALL_PARENT(FALSE) // AI needs to work as their own...
if(camera_light_on)
light_cameras()
- if(client)
- if(ismovable(A))
- if(A != GLOB.ai_camera_room_landmark)
- end_multicam()
- client.perspective = EYE_PERSPECTIVE
- client.eye = A
- else
+ if(!client)
+ return
+
+ if(ismovable(new_eye))
+ if(new_eye != GLOB.ai_camera_room_landmark)
end_multicam()
- if(isturf(loc))
- if(eyeobj)
- client.eye = eyeobj
- client.perspective = EYE_PERSPECTIVE
- else
- client.eye = client.mob
- client.perspective = MOB_PERSPECTIVE
- else
+ client.perspective = EYE_PERSPECTIVE
+ client.set_eye(new_eye)
+ else
+ end_multicam()
+ if(isturf(loc))
+ if(eyeobj)
+ client.set_eye(eyeobj)
client.perspective = EYE_PERSPECTIVE
- client.eye = loc
- update_sight()
- if(client.eye != src)
- var/atom/AT = client.eye
- AT.get_remote_view_fullscreens(src)
+ else
+ client.set_eye(client.mob)
+ client.perspective = MOB_PERSPECTIVE
else
- clear_fullscreen("remote_view", 0)
+ client.perspective = EYE_PERSPECTIVE
+ client.set_eye(loc)
+ update_sight()
+ if(client.eye != src)
+ var/atom/AT = client.eye
+ AT.get_remote_view_fullscreens(src)
+ else
+ clear_fullscreen("remote_view", 0)
/mob/living/silicon/ai/revive(full_heal = 0, admin_revive = 0)
. = ..()
@@ -1060,3 +1053,35 @@
/mob/living/silicon/ai/zMove(dir, feedback = FALSE, feedback_to = src)
. = eyeobj.zMove(dir, feedback, feedback_to)
+
+/// Proc to hook behavior to the changes of the value of [aiRestorePowerRoutine].
+/mob/living/silicon/ai/proc/setAiRestorePowerRoutine(new_value)
+ if(new_value == aiRestorePowerRoutine)
+ return
+ . = aiRestorePowerRoutine
+ aiRestorePowerRoutine = new_value
+ if(aiRestorePowerRoutine)
+ if(!.)
+ ADD_TRAIT(src, TRAIT_INCAPACITATED, POWER_LACK_TRAIT)
+ else if(.)
+ REMOVE_TRAIT(src, TRAIT_INCAPACITATED, POWER_LACK_TRAIT)
+
+
+/mob/living/silicon/on_handsblocked_start()
+ return // AIs have no hands
+
+/mob/living/silicon/on_handsblocked_end()
+ return // AIs have no hands
+
+/mob/living/silicon/ai/verb/change_photo_camera_radius()
+ set category = "AI Commands"
+ set name = "Adjust Camera Zoom"
+ set desc = "Change the zoom of your builtin camera."
+
+ if(incapacitated())
+ return
+ if(isnull(aicamera))
+ to_chat(usr, "You don't have a built-in camera! ")
+ return
+
+ aicamera.adjust_zoom(src)
diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm
index fa4346abb58f0..a9b65598d65e3 100644
--- a/code/modules/mob/living/silicon/ai/death.dm
+++ b/code/modules/mob/living/silicon/ai/death.dm
@@ -46,7 +46,7 @@
/mob/living/silicon/ai/proc/ShutOffDoomsdayDevice()
if(nuking)
- set_security_level("red")
+ SSsecurity_level.set_level(SEC_LEVEL_RED)
nuking = FALSE
for(var/obj/item/pinpointer/nuke/P in GLOB.pinpointer_list)
P.switch_mode_to(TRACK_NUKE_DISK) //Party's over, back to work, everyone
diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm
index 205396c452668..f19df8bec98f7 100644
--- a/code/modules/mob/living/silicon/ai/freelook/eye.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm
@@ -87,7 +87,7 @@
if(use_static)
ai.camera_visibility(src)
if(ai.client && !ai.multicam_on)
- ai.client.eye = src
+ ai.client.set_eye(src)
update_ai_detect_hud()
//Holopad
if(istype(ai.current_holopad, /obj/machinery/holopad))
diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm
index c7e70556d3d00..81e5ff91e12a8 100644
--- a/code/modules/mob/living/silicon/ai/life.dm
+++ b/code/modules/mob/living/silicon/ai/life.dm
@@ -1,8 +1,3 @@
-#define POWER_RESTORATION_OFF 0
-#define POWER_RESTORATION_START 1
-#define POWER_RESTORATION_SEARCH_APC 2
-#define POWER_RESTORATION_APC_FOUND 3
-
/mob/living/silicon/ai/Life(delta_time)
if (stat == DEAD)
return
@@ -112,7 +107,7 @@
T = get_turf(src)
if(isspaceturf(T))
to_chat(src, "Unable to verify! No power connection detected!")
- aiRestorePowerRoutine = POWER_RESTORATION_SEARCH_APC
+ setAiRestorePowerRoutine(POWER_RESTORATION_SEARCH_APC)
return
to_chat(src, "Connection verified. Searching for APC in power network.")
sleep(5 SECONDS)
@@ -130,7 +125,7 @@
to_chat(src, "Unable to locate APC!")
else
to_chat(src, "Lost connection with the APC!")
- aiRestorePowerRoutine = POWER_RESTORATION_SEARCH_APC
+ setAiRestorePowerRoutine(POWER_RESTORATION_SEARCH_APC)
return
if(AIarea.power_equip)
if(!isspaceturf(T))
@@ -151,7 +146,7 @@
to_chat(src, "APC ready for connection. ")
apc_override = theAPC
theAPC.ui_interact(src)
- aiRestorePowerRoutine = POWER_RESTORATION_APC_FOUND
+ setAiRestorePowerRoutine(POWER_RESTORATION_APC_FOUND)
sleep(5 SECONDS)
theAPC = null
@@ -163,20 +158,15 @@
to_chat(src, "APC Backdoor has been closed. ") //No change in behavior, just tells the AI why they have to rehack their APC and turn the power back on
else
to_chat(src, "Alert cancelled. Power has been restored without our assistance. ")
- aiRestorePowerRoutine = POWER_RESTORATION_OFF
+ setAiRestorePowerRoutine(POWER_RESTORATION_OFF)
set_blindness(0)
apc_override = null
update_sight()
/mob/living/silicon/ai/proc/ai_lose_power()
disconnect_shell()
- aiRestorePowerRoutine = POWER_RESTORATION_START
+ setAiRestorePowerRoutine(POWER_RESTORATION_START)
adjust_blindness(1)
update_sight()
to_chat(src, "You've lost power! ")
addtimer(CALLBACK(src, PROC_REF(start_RestorePowerRoutine)), 20)
-
-#undef POWER_RESTORATION_OFF
-#undef POWER_RESTORATION_START
-#undef POWER_RESTORATION_SEARCH_APC
-#undef POWER_RESTORATION_APC_FOUND
diff --git a/code/modules/mob/living/silicon/ai/login.dm b/code/modules/mob/living/silicon/ai/login.dm
index 2909b915bb888..ae8bcc4af66e5 100644
--- a/code/modules/mob/living/silicon/ai/login.dm
+++ b/code/modules/mob/living/silicon/ai/login.dm
@@ -1,5 +1,7 @@
/mob/living/silicon/ai/Login()
- ..()
+ . = ..()
+ if(!. || !client)
+ return FALSE
if(stat != DEAD)
if(lacks_power() && apc_override) //Placing this in Login() in case the AI doesn't have this link for whatever reason.
to_chat(usr, "Main power is unavailable, backup power in use. Diagnostics scan complete. Local APC ready for connection. ")
diff --git a/code/modules/mob/living/silicon/login.dm b/code/modules/mob/living/silicon/login.dm
index 541736da1a6a1..9b787a67797b2 100644
--- a/code/modules/mob/living/silicon/login.dm
+++ b/code/modules/mob/living/silicon/login.dm
@@ -4,7 +4,7 @@
var/datum/antagonist/rev/rev = mind.has_antag_datum(/datum/antagonist/rev)
if(rev)
rev.remove_revolutionary(TRUE)
- ..()
+ return ..()
/mob/living/silicon/auto_deadmin_on_login()
if(!client?.holder)
diff --git a/code/modules/mob/living/silicon/pai/death.dm b/code/modules/mob/living/silicon/pai/death.dm
index fd5e049e67fea..6adcb4949cd9d 100644
--- a/code/modules/mob/living/silicon/pai/death.dm
+++ b/code/modules/mob/living/silicon/pai/death.dm
@@ -2,7 +2,6 @@
if(stat == DEAD)
return
set_stat(DEAD)
- mobility_flags = NONE
update_sight()
clear_fullscreens()
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index dcd69571c5d4b..a3f4d8aac6c34 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -14,6 +14,7 @@
layer = BELOW_MOB_LAYER
can_be_held = TRUE
radio = /obj/item/radio/headset/silicon/pai
+ can_buckle_to = FALSE
move_force = 0
pull_force = 0
move_resist = 0
@@ -108,12 +109,6 @@
var/atom/movable/screen/ai/modpc/interface_button
-/mob/living/silicon/pai/can_unbuckle()
- return FALSE
-
-/mob/living/silicon/pai/can_buckle()
- return FALSE
-
/mob/living/silicon/pai/handle_atom_del(atom/A)
if(A == hacking_cable)
hacking_cable = null
@@ -175,6 +170,11 @@
emittersemicd = TRUE
addtimer(CALLBACK(src, PROC_REF(emittercool)), 600)
+
+ if(!holoform)
+ ADD_TRAIT(src, TRAIT_IMMOBILIZED, PAI_FOLDED)
+ ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, PAI_FOLDED)
+
return INITIALIZE_HINT_LATELOAD
@@ -214,15 +214,17 @@
return TRUE
/mob/living/silicon/pai/Login()
- ..()
+ . = ..()
+ if(!. || !client)
+ return FALSE
var/datum/asset/notes_assets = get_asset_datum(/datum/asset/simple/pAI)
mind.assigned_role = JOB_NAME_PAI
notes_assets.send(client)
client.perspective = EYE_PERSPECTIVE
if(holoform)
- client.eye = src
+ client.set_eye(src)
else
- client.eye = card
+ client.set_eye(card)
/mob/living/silicon/pai/get_stat_tab_status()
var/list/tab_data = ..()
@@ -296,7 +298,7 @@
/datum/action/innate/pai/rest/Trigger()
..()
- P.lay_down()
+ P.toggle_resting()
/datum/action/innate/pai/light
name = "Toggle Integrated Lights"
diff --git a/code/modules/mob/living/silicon/pai/pai_shell.dm b/code/modules/mob/living/silicon/pai/pai_shell.dm
index 7b50e517978db..f237bf6c1b078 100644
--- a/code/modules/mob/living/silicon/pai/pai_shell.dm
+++ b/code/modules/mob/living/silicon/pai/pai_shell.dm
@@ -18,7 +18,8 @@
emittersemicd = TRUE
addtimer(CALLBACK(src, PROC_REF(emittercool)), emittercd)
- mobility_flags = MOBILITY_FLAGS_DEFAULT
+ REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, PAI_FOLDED)
+ REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, PAI_FOLDED)
set_density(TRUE)
if(isliving(card.loc))
var/mob/living/L = card.loc
@@ -32,7 +33,7 @@
card.forceMove(src)
if(client)
client.perspective = EYE_PERSPECTIVE
- client.eye = src
+ client.set_eye(src)
set_light_on(FALSE)
icon_state = "[chassis]"
held_state = "[chassis]"
@@ -59,11 +60,12 @@
MH.release()
if(client)
client.perspective = EYE_PERSPECTIVE
- client.eye = card
+ client.set_eye(card)
var/turf/T = drop_location()
card.forceMove(T)
forceMove(card)
- mobility_flags = NONE
+ ADD_TRAIT(src, TRAIT_IMMOBILIZED, PAI_FOLDED)
+ ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, PAI_FOLDED)
set_density(FALSE)
set_light_on(FALSE)
holoform = FALSE
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index 7f4c27719abbf..193438412356a 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -98,11 +98,3 @@
else
cut_overlay(fire_overlay)
-/mob/living/silicon/robot/update_mobility()
- if(HAS_TRAIT(src, TRAIT_IMMOBILIZED))
- mobility_flags &= ~MOBILITY_MOVE
- else
- mobility_flags = MOBILITY_FLAGS_DEFAULT
- update_transform()
- update_action_buttons_icon()
-
diff --git a/code/modules/mob/living/silicon/robot/login.dm b/code/modules/mob/living/silicon/robot/login.dm
index 3856dd40d1564..86c3f731ea99c 100644
--- a/code/modules/mob/living/silicon/robot/login.dm
+++ b/code/modules/mob/living/silicon/robot/login.dm
@@ -1,5 +1,7 @@
/mob/living/silicon/robot/Login()
- ..()
+ . = ..()
+ if(!. || !client)
+ return FALSE
regenerate_icons()
show_laws(0)
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 38c9da02c973c..ad016dac78e52 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -7,12 +7,22 @@
health = 200
bubble_icon = "robot"
designation = "Default" //used for displaying the prefix & getting the current module of cyborg
- has_limbs = 1
+ has_limbs = TRUE
hud_type = /datum/hud/robot
+
radio = /obj/item/radio/borg
+
blocks_emissive = EMISSIVE_BLOCK_UNIQUE
- light_system = MOVABLE_LIGHT
+ light_system = MOVABLE_LIGHT_DIRECTIONAL
light_on = FALSE
+
+ //AI shell
+ var/shell = FALSE
+ var/deployed = FALSE
+ var/mob/living/silicon/ai/mainframe = null
+ var/datum/action/innate/undeployment/undeployment_action = new
+
+// ------------------------------------------ Parts
var/custom_name = ""
var/braintype = "Cyborg"
var/obj/item/robot_suit/robot_suit = null //Used for deconstruction to remember what the borg was constructed out of..
@@ -20,10 +30,6 @@
///The last time this mob was flashed. Used for flash cooldowns
var/last_flashed = 0
- var/shell = FALSE
- var/deployed = FALSE
- var/mob/living/silicon/ai/mainframe = null
- var/datum/action/innate/undeployment/undeployment_action = new
var/obj/item/clockwork/clockwork_slab/internal_clock_slab = null
var/ratvar = FALSE
@@ -164,7 +170,7 @@
mmi.brain.organ_flags |= ORGAN_FROZEN
mmi.brain.name = "[real_name]'s brain"
mmi.name = "[initial(mmi.name)]: [real_name]"
- mmi.brainmob = new(mmi)
+ mmi.set_brainmob(new /mob/living/brain(mmi))
mmi.brainmob.name = src.real_name
mmi.brainmob.real_name = src.real_name
mmi.brainmob.container = mmi
@@ -707,7 +713,6 @@
ADD_TRAIT(src, TRAIT_IMMOBILIZED, LOCKED_BORG_TRAIT)
else if(.)
REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LOCKED_BORG_TRAIT)
- update_mobility()
logevent("System lockdown [lockcharge?"triggered":"released"].")
@@ -1027,7 +1032,6 @@
set_stat(UNCONSCIOUS)
else
set_stat(CONSCIOUS)
- update_mobility()
diag_hud_set_status()
diag_hud_set_health()
diag_hud_set_aishell()
@@ -1231,9 +1235,9 @@
cell = null
/mob/living/silicon/robot/mouse_buckle_handling(mob/living/M, mob/living/user)
+ //Don't try buckling on INTENT_HARM so that silicons can search people's inventories without loading them
if(can_buckle && istype(M) && !(M in buckled_mobs) && ((user!=src)||(a_intent != INTENT_HARM)))
- if(buckle_mob(M))
- return TRUE
+ return user_buckle_mob(M, user, check_loc = FALSE)
/mob/living/silicon/robot/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
if(!is_type_in_typecache(M, can_ride_typecache))
@@ -1256,7 +1260,7 @@
M.visible_message("Unfortunately, [M] just can't seem to hold onto [src]! ")
return
if(iscarbon(M) && (!riding_datum.equip_buckle_inhands(M, 1)))
- if (M.get_num_arms() <= 0)
+ if(M.usable_hands == 0)
M.visible_message("[M] can't climb onto [src] because [M.p_they()] don't have any usable arms! ")
else
M.visible_message("[M] can't climb onto [src] because [M.p_their()] hands are full! ")
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index 4327ac64e5c91..be6024e1f743c 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -12,7 +12,7 @@
/mob/living/silicon/robot/attack_alien(mob/living/carbon/alien/humanoid/M)
if (M.a_intent == INTENT_DISARM)
- if(mobility_flags & MOBILITY_STAND)
+ if(body_position == STANDING_UP)
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
var/obj/item/I = get_active_held_item()
if(I)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 8c9f416283761..6a47c88edca87 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -469,6 +469,18 @@
/mob/living/silicon/hears_radio()
return FALSE
+/mob/living/silicon/on_floored_start()
+ return // Silicons are always standing by default.
+
+/mob/living/silicon/on_floored_end()
+ return // Silicons are always standing by default.
+
+/mob/living/silicon/on_lying_down()
+ return // Silicons are always standing by default.
+
+/mob/living/silicon/on_standing_up()
+ return // Silicons are always standing by default.
+
/**
* Records an IC event log entry in the cyborg's internal tablet.
*
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index cdc7c63d497ff..f4b33a44b3aed 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -138,7 +138,9 @@
booting = FALSE
on = TRUE
INVOKE_ASYNC(src, TYPE_PROC_REF(/atom/movable, say), "Boot sequence complete, [name] operational")
- update_mobility()
+ REMOVE_TRAIT(src, TRAIT_INCAPACITATED, POWER_LACK_TRAIT)
+ REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, POWER_LACK_TRAIT)
+ REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, POWER_LACK_TRAIT)
set_light_on(on)
update_icon()
diag_hud_set_botstat()
@@ -155,7 +157,9 @@
/mob/living/simple_animal/bot/proc/turn_off()
on = FALSE
- update_mobility()
+ ADD_TRAIT(src, TRAIT_INCAPACITATED, POWER_LACK_TRAIT)
+ ADD_TRAIT(src, TRAIT_IMMOBILIZED, POWER_LACK_TRAIT)
+ ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, POWER_LACK_TRAIT)
set_light_on(on)
bot_reset() //Resets an AI's call, should it exist.
update_icon()
@@ -194,11 +198,6 @@
RegisterSignal(src, COMSIG_ATOM_ON_EMAG, PROC_REF(on_emag))
RegisterSignal(src, COMSIG_ATOM_SHOULD_EMAG, PROC_REF(should_emag))
-/mob/living/simple_animal/bot/update_mobility()
- . = ..()
- if(!on)
- mobility_flags = NONE
-
/mob/living/simple_animal/bot/Destroy()
if(path_hud)
QDEL_NULL(path_hud)
@@ -1097,6 +1096,8 @@ Pass a positive integer as an argument to override a bot's default speed.
/mob/living/simple_animal/bot/Login()
. = ..()
+ if(!. || !client)
+ return FALSE
access_card.access |= player_access
diag_hud_set_botmode()
diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
index bd920202f842f..4ebba0bbabbf7 100644
--- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -92,7 +92,7 @@
/mob/living/simple_animal/bot/cleanbot/process_scan(atom/A)
if(iscarbon(A))
var/mob/living/carbon/C = A
- if(C.stat != DEAD && !(C.mobility_flags & MOBILITY_STAND))
+ if(C.stat != DEAD && C.body_position == LYING_DOWN)
return C
else if(is_type_in_typecache(A, target_types))
return A
diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
index 76e013ac35a1a..7ee271a9b8640 100644
--- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
@@ -225,7 +225,7 @@
targets += C
if(targets.len>0)
var/mob/living/carbon/t = pick(targets)
- if(t.stat != DEAD && (t.mobility_flags & MOBILITY_STAND) && !t.handcuffed) //we don't shoot people who are dead, cuffed or lying down.
+ if(t.stat != DEAD && t.body_position == STANDING_UP && !t.handcuffed) //we don't shoot people who are dead, cuffed or lying down.
shootAt(t)
switch(mode)
diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm
index b9fb425e6d425..aa01445a95c57 100644
--- a/code/modules/mob/living/simple_animal/bot/medbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/medbot.dm
@@ -91,7 +91,7 @@ GLOBAL_VAR(medibot_unique_id_gen)
if(!on)
icon_state = "medibot0"
return
- if(IsStun() || IsParalyzed())
+ if(HAS_TRAIT(src, TRAIT_INCAPACITATED))
icon_state = "medibota"
return
if(mode == BOT_HEALING)
@@ -129,10 +129,6 @@ GLOBAL_VAR(medibot_unique_id_gen)
medibot_counter = GLOB.medibot_unique_id_gen
GLOB.medibot_unique_id_gen++
-/mob/living/simple_animal/bot/medbot/update_mobility()
- . = ..()
- update_icon()
-
/mob/living/simple_animal/bot/medbot/bot_reset()
..()
set_patient(null)
@@ -337,7 +333,7 @@ GLOBAL_VAR(medibot_unique_id_gen)
return
/mob/living/simple_animal/bot/medbot/proc/tip_over(mob/user)
- mobility_flags &= ~MOBILITY_MOVE
+ ADD_TRAIT(src, TRAIT_IMMOBILIZED, BOT_TIPPED_OVER)
playsound(src, 'sound/machines/warning-buzzer.ogg', 50)
user.visible_message("[user] tips over [src]! ", "You tip [src] over! ")
tipped = TRUE
@@ -346,7 +342,7 @@ GLOBAL_VAR(medibot_unique_id_gen)
tipper_name = user.name
/mob/living/simple_animal/bot/medbot/proc/set_right(mob/user)
- mobility_flags &= MOBILITY_MOVE
+ REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, BOT_TIPPED_OVER)
var/list/messagevoice
if(user)
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index 5840d67551316..55c9fff6eb1e9 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -131,12 +131,6 @@
/mob/living/simple_animal/bot/mulebot/proc/has_power(bypass_open_check)
return (!open || bypass_open_check) && cell && cell.charge > 0 && (!wires.is_cut(WIRE_POWER1) && !wires.is_cut(WIRE_POWER2))
-/mob/living/simple_animal/bot/mulebot/update_mobility()
- . = ..()
- if(!on)
- mobility_flags |= MOBILITY_STAND //base bots removes all mobility flags when turned off, resulting in the bot becoming passable. we don't want this since it's a large device that should block things.
- update_action_buttons_icon(TRUE)
-
/mob/living/simple_animal/bot/mulebot/proc/set_id(new_id)
id = new_id
if(paicard)
@@ -442,7 +436,7 @@
if (!istype(L))
return
- if(user.incapacitated() || (istype(L) && !(L.mobility_flags & MOBILITY_STAND)))
+ if(user.incapacitated() || (istype(L) && L.body_position == LYING_DOWN))
return
if(!istype(AM) || isdead(AM) || iscameramob(AM) || istype(AM, /obj/effect/dummy/phased_mob))
@@ -800,7 +794,7 @@
bloodiness += 4
// player on mulebot attempted to move
-/mob/living/simple_animal/bot/mulebot/relaymove(mob/user)
+/mob/living/simple_animal/bot/mulebot/relaymove(mob/living/user, direction)
if(user.incapacitated())
return
if(load == user)
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index 067c92f2898cf..b85c5fd56f5ba 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -48,11 +48,8 @@
mobchatspan = "cultmobsay"
discovery_points = 1000
-/mob/living/simple_animal/hostile/construct/get_num_legs()
- return 0
-
-/mob/living/simple_animal/hostile/construct/get_num_arms()
- return 0
+ usable_legs = 0
+ usable_hands = 0
/mob/living/simple_animal/hostile/construct/Initialize(mapload)
. = ..()
@@ -81,7 +78,9 @@
return ..()
/mob/living/simple_animal/hostile/construct/Login()
- ..()
+ . = ..()
+ if(!. || !client)
+ return FALSE
to_chat(src, playstyle_string)
/mob/living/simple_animal/hostile/construct/examine(mob/user)
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index f2f25db2781a8..745c85461d56a 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -41,7 +41,7 @@
/mob/living/simple_animal/pet/cat/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
- add_verb(/mob/living/proc/lay_down)
+ add_verb(/mob/living/proc/toggle_resting)
/mob/living/simple_animal/pet/cat/space
name = "space cat"
@@ -182,34 +182,36 @@
/mob/living/simple_animal/pet/cat/update_resting()
. = ..()
- if(stat != DEAD)
- if (resting)
- icon_state = "[icon_living]_rest"
- collar_type = "[initial(collar_type)]_rest"
- else
- icon_state = "[icon_living]"
- collar_type = "[initial(collar_type)]"
+ if(stat == DEAD)
+ return
+ if (resting)
+ icon_state = "[icon_living]_rest"
+ collar_type = "[initial(collar_type)]_rest"
+ else
+ icon_state = "[icon_living]"
+ collar_type = "[initial(collar_type)]"
+ regenerate_icons()
+
/mob/living/simple_animal/pet/cat/Life()
if(!stat && !buckled && !client)
- if(prob(3))
- switch(rand(1, 3))
- if (1)
- INVOKE_ASYNC(src, TYPE_PROC_REF(/mob, emote), "me", 1, pick("stretches out for a belly rub.", "wags its tail.", "lies down."))
- set_resting(TRUE)
- if (2)
- INVOKE_ASYNC(src, TYPE_PROC_REF(/mob, emote), "me", 1, pick("sits down.", "crouches on its hind legs.", "looks alert."))
- set_resting(TRUE)
- icon_state = "[icon_living]_sit"
- collar_type = "[initial(collar_type)]_sit"
- if (3)
- if (resting)
- INVOKE_ASYNC(src, TYPE_PROC_REF(/mob, emote), "me", 1, pick("gets up and meows.", "walks around.", "stops resting."))
- set_resting(FALSE)
- else
- INVOKE_ASYNC(src, TYPE_PROC_REF(/mob, emote), "me", 1, pick("grooms its fur.", "twitches its whiskers.", "shakes out its coat."))
+ if(prob(1))
+ manual_emote(pick("stretches out for a belly rub.", "wags its tail.", "lies down."))
+ set_resting(TRUE)
+ else if (prob(1))
+ manual_emote(pick("sits down.", "crouches on its hind legs.", "looks alert."))
+ set_resting(TRUE)
+ icon_state = "[icon_living]_sit"
+ collar_type = "[initial(collar_type)]_sit"
+ else if (prob(1))
+ if (resting)
+ manual_emote(pick("gets up and meows.", "walks around.", "stops resting."))
+ set_resting(FALSE)
+ else
+ manual_emote(pick("grooms its fur.", "twitches its whiskers.", "shakes out its coat."))
..()
+
if(next_scan_time <= world.time)
make_babies()
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
index accaaa2787544..be86bc94c1cc4 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
@@ -133,7 +133,9 @@
return ..()
/mob/living/simple_animal/drone/Login()
- ..()
+ . = ..()
+ if(!. || !client)
+ return FALSE
check_laws()
if(flavortext)
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
index eef94e2393bb9..3b84f59d2d989 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
@@ -37,7 +37,9 @@
hidden_uplink.telecrystals = 10
/mob/living/simple_animal/drone/syndrone/Login()
- ..()
+ . = ..()
+ if(!. || !client)
+ return FALSE
to_chat(src, "You can kill and eat other drones to increase your health! " )
/mob/living/simple_animal/drone/syndrone/badass
diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm
index 136a813ca81df..e585d8143522f 100644
--- a/code/modules/mob/living/simple_animal/hostile/bear.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bear.dm
@@ -156,7 +156,7 @@
/mob/living/simple_animal/hostile/bear/butter/AttackingTarget() //Makes some attacks by the butter bear slip those who dare cross its path.
if(isliving(target))
var/mob/living/L = target
- if((L.mobility_flags & MOBILITY_STAND))
+ if((L.body_position == STANDING_UP))
L.Knockdown(20)
playsound(loc, 'sound/misc/slip.ogg', 15)
L.visible_message("[L] slips on butter! ")
diff --git a/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm b/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm
index a8a5d7da1a4de..501549c9cd813 100644
--- a/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm
+++ b/code/modules/mob/living/simple_animal/hostile/cat_butcher.dm
@@ -84,11 +84,11 @@
L.reagents.remove_reagent(/datum/reagent/toxin/chloralhydrate, 100)
if(L.blood_volume <= 500) //bandage them up and give em some blood if they're bleeding
L.blood_volume += 30
- L.suppress_bloodloss(1800)
+ L.suppress_bloodloss(BLEED_DEEP_WOUND)
if(L.getBruteLoss() >= 50)
var/healing = min(L.getBruteLoss(), 120)
L.adjustBruteLoss(-healing)
- L.suppress_bloodloss(1800)//bandage their ass
+ L.suppress_bloodloss(BLEED_DEEP_WOUND)//bandage their ass
FindTarget()
/mob/living/simple_animal/hostile/cat_butcherer/proc/newvictim(var/mob/living/carbon/human/L)
diff --git a/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm b/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm
index a3ac4a531dc78..d16cf8de121b3 100644
--- a/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm
+++ b/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm
@@ -192,14 +192,12 @@ GLOBAL_VAR_INIT(floor_cluwnes, 0)
/mob/living/simple_animal/hostile/floor_cluwne/proc/Manifest()//handles disappearing and appearance anim
if(manifested)
mobility_flags &= ~MOBILITY_MOVE
- update_mobility()
cluwnehole = new(src.loc)
addtimer(CALLBACK(src, TYPE_PROC_REF(/mob/living/simple_animal/hostile/floor_cluwne, Appear)), MANIFEST_DELAY)
else
invisibility = INVISIBILITY_SPIRIT
density = FALSE
mobility_flags |= MOBILITY_MOVE
- update_mobility()
if(cluwnehole)
qdel(cluwnehole)
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index 3afbc2f09a05b..54d1fda488dbc 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -95,7 +95,9 @@
return ..()
/mob/living/simple_animal/hostile/poison/giant_spider/Login()
- ..()
+ . = ..()
+ if(!. || !client)
+ return FALSE
SSmove_manager.stop_looping(src) // Just in case the AI's doing anything when we give them the mind
GLOB.spidermobs[src] = TRUE
diff --git a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm
index 48af70c824969..8c377c10caac9 100644
--- a/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mecha_pilot.dm
@@ -123,7 +123,7 @@
return FALSE
if(!M.has_charge(required_mecha_charge))
return FALSE
- if(M.obj_integrity < M.max_integrity*0.5)
+ if(M.get_integrity() < M.max_integrity*0.5)
return FALSE
return TRUE
@@ -217,7 +217,7 @@
return
//Too Much Damage - Eject
- if(mecha.obj_integrity < mecha.max_integrity*0.1)
+ if(mecha.get_integrity() < mecha.max_integrity*0.1)
exit_mecha(mecha)
return
@@ -228,7 +228,7 @@
action.Trigger()
//Heavy damage - Defense Power or Retreat
- if(mecha.obj_integrity < mecha.max_integrity*0.25)
+ if(mecha.get_integrity() < mecha.max_integrity*0.25)
if(prob(defense_mode_chance))
if(LAZYACCESSASSOC(mecha.occupant_actions, src, /datum/action/vehicle/sealed/mecha/mech_defense_mode) && !mecha.defense_mode)
var/datum/action/action = mecha.occupant_actions[src][/datum/action/vehicle/sealed/mecha/mech_defense_mode]
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index 9da9ce66d624b..52bd3f1bdfc30 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -308,13 +308,12 @@ Difficulty: Hard
return TRUE
return FALSE
+
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/be_aggressive()
if(BUBBLEGUM_IS_ENRAGED)
return TRUE
- if(isliving(target))
- var/mob/living/livingtarget = target
- return (livingtarget.stat != CONSCIOUS || !(livingtarget.mobility_flags & MOBILITY_STAND))
- return FALSE
+ return isliving(target) && HAS_TRAIT(target, TRAIT_INCAPACITATED)
+
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_retreat_distance()
return (be_aggressive() ? null : initial(retreat_distance))
diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm
index 472922fe2cd65..ece1e6f2915bd 100644
--- a/code/modules/mob/living/simple_animal/hostile/mimic.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm
@@ -123,7 +123,7 @@
..()
// death of this mob means the destruction of the original stuff of the copied mob.
if(istype(original_of_this, /obj/machinery/vending))
- original_of_this.take_damage(original_of_this.obj_integrity, BRUTE, 0, FALSE)
+ original_of_this.take_damage(original_of_this.max_integrity, BRUTE, 0, FALSE)
// currently do this to vending machines only.
// because the destruction of stuff (especially items) is annoying.
diff --git a/code/modules/mob/living/simple_animal/hostile/mimite.dm b/code/modules/mob/living/simple_animal/hostile/mimite.dm
new file mode 100644
index 0000000000000..4ad7b7b70b212
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/hostile/mimite.dm
@@ -0,0 +1,385 @@
+#define MIMITE_COOLDOWN 60
+#define MIMITE_VENT_COOLDOWN 100
+#define MIMITE_STUCK_THRESHOLD 10
+
+/mob/living/simple_animal/hostile/mimite
+ name = "Mimite"
+ desc = "A creature of unknown origin, it enjoys hiding in plain sight to ambush its prey"
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "mimite"
+ icon_living = "mimite"
+ pass_flags = PASSTABLE
+ ventcrawler = VENTCRAWLER_ALWAYS
+ a_intent = INTENT_HARM
+ melee_damage = 10
+ see_in_dark = 8
+ lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
+ deathmessage = "splatters into a pile of black gunk!"
+ del_on_death = TRUE
+ response_help = "touches"
+ response_disarm = "pushes"
+ response_harm = "hits"
+ speed = 3
+ maxHealth = 50
+ health = 50
+ gender = NEUTER
+ mob_biotypes = list(MOB_INORGANIC)
+ wander = FALSE
+
+ vision_range = 4
+ aggro_vision_range = 4
+ armour_penetration = 10
+ rapid_melee = 2
+ attacktext = "slashes"
+ attack_sound = 'sound/effects/meatslap.ogg'
+ emote_taunt = list("growls")
+ speak_emote = list("chitters")
+ taunt_chance = 30
+
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 0
+
+ faction = list("mimite")
+ move_to_delay = 3
+ gold_core_spawnable = NO_SPAWN
+ hardattacks = TRUE
+
+ discovery_points = 8000
+
+ var/static/list/blacklist_typecache = typecacheof(list(
+ /atom/movable/screen,
+ /obj/anomaly,
+ /obj/eldritch/narsie,
+ /obj/effect,
+ /obj/machinery,
+ /obj/structure,
+ /obj/item/radio/intercom,
+ /mob/camera,
+ /obj/item/storage/secure/safe,
+ /mob/living
+ ))
+ var/atom/movable/form = null
+ var/morphed = FALSE
+ var/mimite_time = 0
+ var/mimite_growth = 0
+ var/grow_as = null
+ var/obj/machinery/atmospherics/components/unary/vent_pump/entry_vent
+ var/travelling_in_vent = 0
+ var/replicate = TRUE
+ var/venthunt = TRUE
+ var/mimite_lastmove = null //Updates/Stores position of the mimite while it's moving
+ var/mimite_stuck = 0 //If mimite_lastmove hasn't changed, this will increment until it reaches mimite_stuck_threshold
+ var/attemptingventcrawl = FALSE
+ var/eventongoing = TRUE
+ var/remaining_replications = 4
+
+/mob/living/simple_animal/hostile/mimite/Initialize()
+ . = ..()
+ AddElement(/datum/element/point_of_interest)
+ GLOB.all_mimites += src
+ var/image/I = image(icon = 'icons/mob/hud.dmi', icon_state = "hudcultist", layer = DATA_HUD_PLANE, loc = src)
+ I.alpha = 200
+ I.appearance_flags = RESET_ALPHA
+ add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/mimites, "hudcultist", I)
+
+/mob/living/simple_animal/hostile/mimite/examine(mob/user)
+ if(morphed && replicate && venthunt)
+ . = form.examine(user)
+ if(get_dist(user,src)<=4)
+ . += "It doesn't look quite right... "
+ else
+ . = ..()
+
+/mob/living/simple_animal/hostile/mimite/med_hud_set_health()
+ if(morphed && !isliving(form))
+ var/image/holder = hud_list[HEALTH_HUD]
+ holder.icon_state = null
+ return //we hide medical hud while morphed
+ ..()
+
+/mob/living/simple_animal/hostile/mimite/med_hud_set_status()
+ if(morphed && !isliving(form))
+ var/image/holder = hud_list[STATUS_HUD]
+ holder.icon_state = null
+ return //we hide medical hud while morphed
+ ..()
+
+/mob/living/simple_animal/hostile/mimite/proc/allowed(atom/movable/A) // make it into property/proc ? not sure if worth it
+ return !is_type_in_typecache(A, blacklist_typecache) && (isobj(A) || ismob(A))
+
+/mob/living/simple_animal/hostile/mimite/ShiftClickOn(atom/movable/A)
+ if(mimite_time <= world.time && !stat)
+ if(A == src)
+ restore(TRUE)
+ return
+ if(allowed(A))
+ assume(A)
+ else
+ to_chat(src, "Your chameleon skin is still repairing itself! ")
+
+/mob/living/simple_animal/hostile/mimite/proc/assume(atom/movable/target)
+ morphed = TRUE
+ form = target
+
+ visible_message("[src] suddenly twists and changes shape, becoming a copy of [target]! ", \
+ "You twist your body and assume the form of [target]. ")
+ appearance = target.appearance
+ if(length(target.vis_contents))
+ add_overlay(target.vis_contents)
+ alpha = max(alpha, 150) //fucking chameleons
+ transform = initial(transform)
+ pixel_y = base_pixel_y
+ pixel_x = base_pixel_x
+ density = target.density
+ mobchatspan = initial(mobchatspan)
+
+ mimite_time = world.time + MIMITE_COOLDOWN
+ med_hud_set_health()
+ med_hud_set_status() //we're an object honest
+ vision_range = 1
+ aggro_vision_range = 1
+ return
+
+/mob/living/simple_animal/hostile/mimite/proc/restore(var/intentional = FALSE)
+ if(!morphed)
+ if(intentional)
+ to_chat(src, "You're already in your normal form! ")
+ return
+ morphed = FALSE
+ form = null
+ alpha = initial(alpha)
+ color = initial(color)
+ animate_movement = SLIDE_STEPS
+ maptext = null
+ density = initial(density)
+
+ visible_message("[src] suddenly collapses in on itself, turning into a strange shifting black mass! ", \
+ "You reform to your normal body. ")
+ name = initial(name)
+ icon = initial(icon)
+ icon_state = initial(icon_state)
+ vision_range = initial(vision_range)
+ aggro_vision_range = initial(aggro_vision_range)
+ cut_overlays()
+
+ //Baseline stats
+ melee_damage = initial(melee_damage)
+ set_varspeed(initial(speed))
+
+ mimite_time = world.time + MIMITE_COOLDOWN
+ med_hud_set_health()
+ med_hud_set_status() //we are not an object
+
+
+/mob/living/simple_animal/hostile/mimite/Aggro() // automated only
+ ..()
+ restore()
+
+/mob/living/simple_animal/hostile/mimite/AIShouldSleep(var/list/possible_targets)
+ . = ..()
+ if(.)
+ if(!morphed)
+ var/list/things = list()
+ for(var/atom/A as() in view(src))
+ if(allowed(A))
+ things += A
+ if(LAZYLEN(things) >= 1)
+ var/atom/movable/T = pick(things)
+ assume(T)
+ else
+ approachvent()
+
+/mob/living/simple_animal/hostile/mimite/can_track(mob/living/user)
+ if(morphed)
+ return FALSE
+ return ..()
+
+/mob/living/simple_animal/hostile/mimite/AttackingTarget()
+ if(morphed)
+ restore()
+ return ..()
+
+//Ambush attack
+/mob/living/simple_animal/hostile/mimite/attack_hand(mob/living/carbon/human/M)
+ if(morphed)
+ M.Knockdown(40)
+ M.reagents.add_reagent(/datum/reagent/toxin/morphvenom/mimite, 5)
+ to_chat(M, "[src] bites you! ")
+ visible_message("[src] violently bites [M]! ",\
+ "You ambush [M]! ", null, COMBAT_MESSAGE_RANGE)
+ restore()
+ else
+ ..()
+
+/mob/living/simple_animal/hostile/mimite/Life()
+ . = ..()
+ if(isturf(loc) && replicate)
+ mimite_growth += rand(1,6)
+ if(mimite_growth >= 350 && remaining_replications)
+ if(!grow_as)
+ grow_as = pick_weight(list(/mob/living/simple_animal/hostile/mimite = 50, /mob/living/simple_animal/hostile/mimite/ranged = 45, /mob/living/simple_animal/hostile/mimite/crate = 5))
+ var/mob/living/simple_animal/hostile/mimite/S = new grow_as(src.loc)
+ remaining_replications--
+ S.remaining_replications = remaining_replications
+ playsound(S.loc, 'sound/effects/meatslap.ogg', 60, TRUE)
+ mimite_growth = 0
+ approachvent()
+ if(AIStatus == AI_STATUS_OFF || client)
+ return
+ if(venthunt && !attemptingventcrawl && mimite_time <= world.time && prob(25))
+ approachvent()
+ if(attemptingventcrawl && entry_vent)
+ SSmove_manager.move_to(src, entry_vent, 1)
+ tryventcrawl()
+ if(isStuck())
+ SSmove_manager.stop_looping(src)
+
+/mob/living/simple_animal/hostile/mimite/proc/approachvent()
+ for(var/obj/machinery/atmospherics/components/unary/vent_pump/v in view(6,src))
+ if(!v.welded)
+ entry_vent = v
+ SSmove_manager.move_to(src, entry_vent, 1)
+ break
+ tryventcrawl()
+
+/mob/living/simple_animal/hostile/mimite/proc/tryventcrawl()
+ attemptingventcrawl = TRUE
+ mimite_time = world.time + MIMITE_VENT_COOLDOWN
+ if(QDELETED(entry_vent))
+ entry_vent = null
+ if(travelling_in_vent)
+ if(isturf(loc))
+ travelling_in_vent = 0
+ entry_vent = null
+ attemptingventcrawl = FALSE
+ else if(entry_vent)
+ if(get_dist(src, entry_vent) <= 3)
+ var/list/vents = list()
+ var/datum/pipeline/entry_vent_parent = entry_vent.parents[1]
+ for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in entry_vent_parent.other_atmosmch)
+ vents.Add(temp_vent)
+ if(!vents.len)
+ entry_vent = null
+ attemptingventcrawl = FALSE
+ return
+ var/obj/machinery/atmospherics/components/unary/vent_pump/exit_vent = pick(vents)
+ var/travel_time = round(get_dist(loc, exit_vent.loc) * 2)
+ travelling_in_vent = 1
+ spawn(travel_time)
+ if(!exit_vent || exit_vent.welded)
+ forceMove(entry_vent)
+ entry_vent = null
+ attemptingventcrawl = FALSE
+ travelling_in_vent = 0
+ return
+ else
+ visible_message("[src] scrambles into the ventilation ducts! ", \
+ "You hear something scampering through the ventilation ducts. ")
+ forceMove(exit_vent.loc)
+ entry_vent = null
+ attemptingventcrawl = FALSE
+ travelling_in_vent = 0
+ var/area/new_area = get_area(loc)
+ if(new_area)
+ new_area.Entered(src)
+ SSmove_manager.move_away(src, exit_vent, 4)
+ else
+ entry_vent = null
+ attemptingventcrawl = FALSE
+ travelling_in_vent = 0
+ return
+
+/mob/living/simple_animal/hostile/mimite/proc/isStuck()
+ //Check to see if the mimite is stuck due to things like windows or doors or windowdoors
+ if(mimite_lastmove)
+ if(mimite_lastmove == src.loc)
+ if(MIMITE_STUCK_THRESHOLD >= ++mimite_stuck)
+ mimite_stuck = 0
+ mimite_lastmove = null
+ return 1
+ else
+ mimite_lastmove = null
+ else
+ mimite_lastmove = src.loc
+ return 0
+
+/mob/living/simple_animal/hostile/mimite/death(gibbed)
+ new /obj/effect/decal/cleanable/oil(get_turf(src))
+ ..()
+
+/mob/living/simple_animal/hostile/mimite/Destroy()
+ GLOB.all_mimites -= src
+ ..()
+
+/mob/living/simple_animal/hostile/mimite/crate
+ name = "crate"
+ desc = "A rectangular steel crate."
+ icon = 'icons/obj/storage/crates.dmi'
+ icon_state = "crate"
+ icon_living = "crate"
+ attacktext = "bites"
+ speak_emote = list("clatters")
+ vision_range = 0
+ aggro_vision_range = 0
+ melee_damage = 15
+ speed = 4
+ move_to_delay = 4
+ venthunt = FALSE
+ morphed = TRUE
+
+/mob/living/simple_animal/hostile/mimite/crate/AttackingTarget()
+ cut_overlays()
+ if(prob(50))
+ add_overlay("[icon_state]_open")
+ else
+ add_overlay("[icon_state]_door")
+ return ..()
+
+/mob/living/simple_animal/hostile/mimite/crate/LoseTarget()
+ ..()
+ cut_overlays()
+ add_overlay("[icon_state]_door")
+
+/mob/living/simple_animal/hostile/mimite/crate/Initialize()
+ ..()
+ icon_state = pick("crate","weapon_crate","secgear_crate","private_crate")
+ icon_living = icon_state
+ add_overlay("[icon_state]_door")
+ med_hud_set_health()
+ med_hud_set_status()
+
+//Ambush attack does extra knockdown as crate mimite
+/mob/living/simple_animal/hostile/mimite/crate/attack_hand(mob/living/carbon/human/M)
+ morphed = FALSE
+ vision_range = 9
+ aggro_vision_range = 9
+ M.Knockdown(20)
+ M.reagents.add_reagent(/datum/reagent/toxin/morphvenom/mimite, 10)
+ to_chat(M, "[src] bites you! ")
+ visible_message("[src] violently bites [M]! ",\
+ "You ambush [M]! ", null, COMBAT_MESSAGE_RANGE)
+ cut_overlays()
+ add_overlay("[icon_state]_open")
+ ..()
+
+/mob/living/simple_animal/hostile/mimite/crate/assume(atom/movable/target)
+ return FALSE
+
+/mob/living/simple_animal/hostile/mimite/ranged
+ name = "Ranged mimite"
+ desc = "This mimite seems to be bursting with energy, beware of ranged shots!"
+ ranged = TRUE
+ vision_range = 7
+ aggro_vision_range = 7
+ speed = 7
+ move_to_delay = 7
+ rapid = 2
+ approaching_target = TRUE
+ minimum_distance = 1
+ melee_queue_distance = 1
+ projectiletype = /obj/projectile/beam/disabler
+
+
+#undef MIMITE_COOLDOWN
+#undef MIMITE_VENT_COOLDOWN
+#undef MIMITE_STUCK_THRESHOLD
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
index 4766f9269d10b..92353fa8a5813 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
@@ -114,7 +114,7 @@ While using this makes the system rely on OnFire, it still gives options for tim
/obj/structure/elite_tumor
name = "pulsing tumor"
desc = "An odd, pulsing tumor sticking out of the ground. You feel compelled to reach out and touch it..."
- armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
resistance_flags = INDESTRUCTIBLE
icon = 'icons/obj/lavaland/tumor.dmi'
icon_state = "tumor"
diff --git a/code/modules/mob/living/simple_animal/hostile/space_dragon.dm b/code/modules/mob/living/simple_animal/hostile/space_dragon.dm
index e59213910dd7b..67350051038bf 100644
--- a/code/modules/mob/living/simple_animal/hostile/space_dragon.dm
+++ b/code/modules/mob/living/simple_animal/hostile/space_dragon.dm
@@ -27,7 +27,7 @@
health = 350
spacewalk = TRUE
a_intent = INTENT_HARM
- damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0.5, OXY = 1)
+ damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
speed = 0
attacktext = "chomps"
attack_sound = 'sound/magic/demon_attack1.ogg'
@@ -60,7 +60,7 @@
/// A multiplier to how much each use of wing gust should add to the tiredness variable. Set to 5 if the current rift is destroyed.
var/tiredness_mult = 1
/// The distance Space Dragon's gust reaches
- var/gust_distance = 4
+ var/gust_distance = 3
/// The amount of tiredness to add to Space Dragon per use of gust
var/gust_tiredness = 30
/// Determines whether or not Space Dragon is in the middle of using wing gust. If set to true, prevents him from moving and doing certain actions.
@@ -414,13 +414,20 @@
overlay.appearance_flags = RESET_COLOR
add_overlay(overlay)
playsound(src, 'sound/effects/gravhit.ogg', 100, TRUE)
- for (var/mob/living/candidate in view(gust_distance, src))
- if(candidate == src || candidate.faction_check_mob(src))
+ var/list/candidates_flung = list()
+ for (var/turf/epicenter in view(1, usr.loc))
+ if(istype(epicenter, /turf/closed)) //Gusts dont go through walls.
continue
+ for (var/mob/living/mob in view(gust_distance, epicenter))
+ if(mob == src || mob.faction_check_mob(src))
+ continue
+ candidates_flung |= mob
+
+ for(var/mob/living/candidate in candidates_flung)
visible_message("[candidate] is knocked back by the gust! ")
to_chat(candidate, "You're knocked back by the gust! ")
var/dir_to_target = get_dir(get_turf(src), get_turf(candidate))
- var/throwtarget = get_edge_target_turf(target, dir_to_target)
+ var/throwtarget = get_edge_target_turf(candidate, dir_to_target)
candidate.safe_throw_at(throwtarget, 10, 1, src)
candidate.Paralyze(50)
addtimer(CALLBACK(src, PROC_REF(reset_status)), 4 + ((tiredness * tiredness_mult) / 10))
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 263d12722d678..c81712dff034d 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -4,7 +4,7 @@
health = 20
maxHealth = 20
gender = PLURAL //placeholder
-
+ living_flags = MOVES_ON_ITS_OWN
status_flags = CANPUSH
var/icon_living = ""
@@ -409,15 +409,15 @@
/mob/living/simple_animal/ExtinguishMob()
return
+
/mob/living/simple_animal/revive(full_heal = 0, admin_revive = 0)
- if(..()) //successfully ressuscitated from death
- icon = initial(icon)
- icon_state = icon_living
- set_density(initial(density))
- mobility_flags = MOBILITY_FLAGS_DEFAULT
- update_mobility()
- . = 1
- setMovetype(initial(movement_type))
+ . = ..()
+ if(!.)
+ return
+ icon = initial(icon)
+ icon_state = icon_living
+ density = initial(density)
+ setMovetype(initial(movement_type))
/mob/living/simple_animal/proc/make_babies() // <3 <3 <3
set waitfor = 0
@@ -476,23 +476,6 @@
REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, RESTING_TRAIT)
return ..()
-/mob/living/simple_animal/update_mobility(value_otherwise = TRUE)
- if(HAS_TRAIT_NOT_FROM(src, TRAIT_IMMOBILIZED, BUCKLED_TRAIT))
- drop_all_held_items()
- mobility_flags = NONE
- else if(buckled || IsImmobilized())
- mobility_flags = MOBILITY_FLAGS_INTERACTION
- else
- if(value_otherwise)
- mobility_flags = MOBILITY_FLAGS_DEFAULT
- else
- mobility_flags = NONE
- if(!(mobility_flags & MOBILITY_MOVE))
- SSmove_manager.stop_looping(src) //stop mid walk
-
- update_transform()
- update_action_buttons_icon()
-
/mob/living/simple_animal/update_transform()
var/matrix/ntransform = matrix(transform) //aka transform.Copy()
var/changed = FALSE
@@ -611,7 +594,7 @@
M.forceMove(get_turf(src))
return ..()
-/mob/living/simple_animal/relaymove(mob/user, direction)
+/mob/living/simple_animal/relaymove(mob/living/user, direction)
var/datum/component/riding/riding_datum = GetComponent(/datum/component/riding)
if(tame && riding_datum)
riding_datum.handle_ride(user, direction)
diff --git a/code/modules/mob/living/simple_animal/slime/life.dm b/code/modules/mob/living/simple_animal/slime/life.dm
index 7eb8018945080..5a1bb1e264b51 100644
--- a/code/modules/mob/living/simple_animal/slime/life.dm
+++ b/code/modules/mob/living/simple_animal/slime/life.dm
@@ -110,13 +110,11 @@
set_stat(UNCONSCIOUS)
powerlevel = 0
rabid = FALSE
- update_mobility()
regenerate_icons()
if(UNCONSCIOUS, HARD_CRIT)
if(!stasis)
to_chat(src, "You wake up from the stasis. ")
set_stat(CONSCIOUS)
- update_mobility()
regenerate_icons()
updatehealth()
@@ -220,8 +218,6 @@
powerlevel += gainpower
/mob/living/simple_animal/slime/proc/handle_targets()
- update_mobility()
-
if(attacked > 50)
attacked = 50
@@ -284,19 +280,19 @@
if (Leader)
if(holding_still)
holding_still = max(holding_still - 1, 0)
- else if((mobility_flags & MOBILITY_MOVE) && isturf(loc))
+ else if(!HAS_TRAIT(src, TRAIT_IMMOBILIZED) && isturf(loc))
step_to(src, Leader)
else if(hungry)
if (holding_still)
holding_still = max(holding_still - hungry, 0)
- else if((mobility_flags & MOBILITY_MOVE) && isturf(loc) && prob(50))
+ else if(!HAS_TRAIT(src, TRAIT_IMMOBILIZED) && isturf(loc) && prob(50))
step(src, pick(GLOB.cardinals))
else
if(holding_still)
holding_still = max(holding_still - 1, 0)
else if (docile && pulledby)
holding_still = 10
- else if((mobility_flags & MOBILITY_MOVE) && isturf(loc) && prob(33))
+ else if(!HAS_TRAIT(src, TRAIT_IMMOBILIZED) && isturf(loc) && prob(33))
step(src, pick(GLOB.cardinals))
else if(!special_process)
special_process = TRUE
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index bc1d2a2aeb008..5437e33abcd30 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -497,26 +497,19 @@
SStun = world.time + rand(20,60)
- mobility_flags &= ~MOBILITY_MOVE
+ Stun(3)
if(user)
step_away(src,user,15)
- addtimer(CALLBACK(src, PROC_REF(slime_move), user), 3)
+ addtimer(CALLBACK(src, PROC_REF(slime_move), user), 0.3 SECONDS)
/mob/living/simple_animal/slime/proc/slime_move(mob/user)
if(user)
step_away(src,user,15)
- update_mobility()
/mob/living/simple_animal/slime/pet
docile = 1
-/mob/living/simple_animal/slime/can_unbuckle()
- return 0
-
-/mob/living/simple_animal/slime/can_buckle()
- return 0
-
/mob/living/simple_animal/slime/get_mob_buckling_height(mob/seat)
if(..())
return 3
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index 1c4cfcaf20081..051b1e3ac7735 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -14,8 +14,8 @@
return S.duration - world.time
return 0
-/mob/living/proc/Stun(amount, updating = TRUE, ignore_canstun = FALSE) //Can't go below remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_STUN, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/Stun(amount, ignore_canstun = FALSE) //Can't go below remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_STUN, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANSTUN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
if(absorb_stun(amount, ignore_canstun))
@@ -24,11 +24,11 @@
if(S)
S.duration = max(world.time + amount, S.duration)
else if(amount > 0)
- S = apply_status_effect(STATUS_EFFECT_STUN, amount, updating)
+ S = apply_status_effect(STATUS_EFFECT_STUN, amount)
return S
-/mob/living/proc/SetStun(amount, updating = TRUE, ignore_canstun = FALSE) //Sets remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_STUN, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/SetStun(amount, ignore_canstun = FALSE) //Sets remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_STUN, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANSTUN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
var/datum/status_effect/incapacitating/stun/S = IsStun()
@@ -41,11 +41,11 @@
if(S)
S.duration = world.time + amount
else
- S = apply_status_effect(STATUS_EFFECT_STUN, amount, updating)
+ S = apply_status_effect(STATUS_EFFECT_STUN, amount)
return S
-/mob/living/proc/AdjustStun(amount, updating = TRUE, ignore_canstun = FALSE) //Adds to remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_STUN, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/AdjustStun(amount, ignore_canstun = FALSE) //Adds to remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_STUN, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANSTUN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
if(absorb_stun(amount, ignore_canstun))
@@ -54,7 +54,7 @@
if(S)
S.duration += amount
else if(amount > 0)
- S = apply_status_effect(STATUS_EFFECT_STUN, amount, updating)
+ S = apply_status_effect(STATUS_EFFECT_STUN, amount)
return S
///////////////////////////////// KNOCKDOWN /////////////////////////////////////
@@ -69,8 +69,8 @@
return K.duration - world.time
return 0
-/mob/living/proc/Knockdown(amount, updating = TRUE, ignore_canstun = FALSE) //Can't go below remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_KNOCKDOWN, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/Knockdown(amount, ignore_canstun = FALSE) //Can't go below remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_KNOCKDOWN, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANKNOCKDOWN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
if(absorb_stun(amount, ignore_canstun))
@@ -79,11 +79,11 @@
if(K)
K.duration = max(world.time + amount, K.duration)
else if(amount > 0)
- K = apply_status_effect(STATUS_EFFECT_KNOCKDOWN, amount, updating)
+ K = apply_status_effect(STATUS_EFFECT_KNOCKDOWN, amount)
return K
-/mob/living/proc/SetKnockdown(amount, updating = TRUE, ignore_canstun = FALSE) //Sets remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_KNOCKDOWN, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/SetKnockdown(amount, ignore_canstun = FALSE) //Sets remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_KNOCKDOWN, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANKNOCKDOWN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
var/datum/status_effect/incapacitating/knockdown/K = IsKnockdown()
@@ -96,11 +96,11 @@
if(K)
K.duration = world.time + amount
else
- K = apply_status_effect(STATUS_EFFECT_KNOCKDOWN, amount, updating)
+ K = apply_status_effect(STATUS_EFFECT_KNOCKDOWN, amount)
return K
-/mob/living/proc/AdjustKnockdown(amount, updating = TRUE, ignore_canstun = FALSE) //Adds to remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_KNOCKDOWN, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/AdjustKnockdown(amount, ignore_canstun = FALSE) //Adds to remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_KNOCKDOWN, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANKNOCKDOWN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
if(absorb_stun(amount, ignore_canstun))
@@ -109,7 +109,7 @@
if(K)
K.duration += amount
else if(amount > 0)
- K = apply_status_effect(STATUS_EFFECT_KNOCKDOWN, amount, updating)
+ K = apply_status_effect(STATUS_EFFECT_KNOCKDOWN, amount)
return K
///////////////////////////////// IMMOBILIZED ////////////////////////////////////
@@ -122,8 +122,8 @@
return I.duration - world.time
return 0
-/mob/living/proc/Immobilize(amount, updating = TRUE, ignore_canstun = FALSE) //Can't go below remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_IMMOBILIZE, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/Immobilize(amount, ignore_canstun = FALSE) //Can't go below remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_IMMOBILIZE, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANKNOCKDOWN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
if(absorb_stun(amount, ignore_canstun))
@@ -132,11 +132,11 @@
if(I)
I.duration = max(world.time + amount, I.duration)
else if(amount > 0)
- I = apply_status_effect(STATUS_EFFECT_IMMOBILIZED, amount, updating)
+ I = apply_status_effect(STATUS_EFFECT_IMMOBILIZED, amount)
return I
-/mob/living/proc/SetImmobilized(amount, updating = TRUE, ignore_canstun = FALSE) //Sets remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_IMMOBILIZE, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/SetImmobilized(amount, ignore_canstun = FALSE) //Sets remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_IMMOBILIZE, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANKNOCKDOWN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
var/datum/status_effect/incapacitating/immobilized/I = IsImmobilized()
@@ -149,11 +149,11 @@
if(I)
I.duration = world.time + amount
else
- I = apply_status_effect(STATUS_EFFECT_IMMOBILIZED, amount, updating)
+ I = apply_status_effect(STATUS_EFFECT_IMMOBILIZED, amount)
return I
-/mob/living/proc/AdjustImmobilized(amount, updating = TRUE, ignore_canstun = FALSE) //Adds to remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_IMMOBILIZE, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/AdjustImmobilized(amount, ignore_canstun = FALSE) //Adds to remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_IMMOBILIZE, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANKNOCKDOWN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
if(absorb_stun(amount, ignore_canstun))
@@ -162,7 +162,7 @@
if(I)
I.duration += amount
else if(amount > 0)
- I = apply_status_effect(STATUS_EFFECT_IMMOBILIZED, amount, updating)
+ I = apply_status_effect(STATUS_EFFECT_IMMOBILIZED, amount)
return I
///////////////////////////////// PARALYZED //////////////////////////////////
@@ -175,8 +175,8 @@
return P.duration - world.time
return 0
-/mob/living/proc/Paralyze(amount, updating = TRUE, ignore_canstun = FALSE) //Can't go below remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_PARALYZE, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/Paralyze(amount, ignore_canstun = FALSE) //Can't go below remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_PARALYZE, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANKNOCKDOWN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
if(absorb_stun(amount, ignore_canstun))
@@ -186,11 +186,11 @@
if(P)
P.duration = max(world.time + amount, P.duration)
else if(amount > 0)
- P = apply_status_effect(STATUS_EFFECT_PARALYZED, amount, updating)
+ P = apply_status_effect(STATUS_EFFECT_PARALYZED, amount)
return P
-/mob/living/proc/SetParalyzed(amount, updating = TRUE, ignore_canstun = FALSE) //Sets remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_PARALYZE, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/SetParalyzed(amount, ignore_canstun = FALSE) //Sets remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_PARALYZE, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANKNOCKDOWN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
var/datum/status_effect/incapacitating/paralyzed/P = IsParalyzed(FALSE)
@@ -203,11 +203,11 @@
if(P)
P.duration = world.time + amount
else
- P = apply_status_effect(STATUS_EFFECT_PARALYZED, amount, updating)
+ P = apply_status_effect(STATUS_EFFECT_PARALYZED, amount)
return P
-/mob/living/proc/AdjustParalyzed(amount, updating = TRUE, ignore_canstun = FALSE) //Adds to remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_PARALYZE, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/AdjustParalyzed(amount, ignore_canstun = FALSE) //Adds to remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_PARALYZE, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANKNOCKDOWN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
if(absorb_stun(amount, ignore_canstun))
@@ -216,33 +216,30 @@
if(P)
P.duration += amount
else if(amount > 0)
- P = apply_status_effect(STATUS_EFFECT_PARALYZED, amount, updating)
+ P = apply_status_effect(STATUS_EFFECT_PARALYZED, amount)
return P
//Blanket
-/mob/living/proc/AllImmobility(amount, updating)
- Paralyze(amount, FALSE)
- Knockdown(amount, FALSE)
- Stun(amount, FALSE)
- Immobilize(amount, FALSE)
- if(updating)
- update_mobility()
-
-/mob/living/proc/SetAllImmobility(amount, updating)
- SetParalyzed(amount, FALSE)
- SetKnockdown(amount, FALSE)
- SetStun(amount, FALSE)
- SetImmobilized(amount, FALSE)
- if(updating)
- update_mobility()
-
-/mob/living/proc/AdjustAllImmobility(amount, updating)
- AdjustParalyzed(amount, FALSE)
- AdjustKnockdown(amount, FALSE)
- AdjustStun(amount, FALSE)
- AdjustImmobilized(amount, FALSE)
- if(updating)
- update_mobility()
+/mob/living/proc/AllImmobility(amount)
+ Paralyze(amount)
+ Knockdown(amount)
+ Stun(amount)
+ Immobilize(amount)
+
+
+/mob/living/proc/SetAllImmobility(amount)
+ SetParalyzed(amount)
+ SetKnockdown(amount)
+ SetStun(amount)
+ SetImmobilized(amount)
+
+
+/mob/living/proc/AdjustAllImmobility(amount)
+ AdjustParalyzed(amount)
+ AdjustKnockdown(amount)
+ AdjustStun(amount)
+ AdjustImmobilized(amount)
+
//////////////////UNCONSCIOUS
/mob/living/proc/IsUnconscious() //If we're unconscious
@@ -254,19 +251,19 @@
return U.duration - world.time
return 0
-/mob/living/proc/Unconscious(amount, updating = TRUE, ignore_canstun = FALSE) //Can't go below remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_UNCONSCIOUS, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/Unconscious(amount, ignore_canstun = FALSE) //Can't go below remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_UNCONSCIOUS, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANUNCONSCIOUS) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
var/datum/status_effect/incapacitating/unconscious/U = IsUnconscious()
if(U)
U.duration = max(world.time + amount, U.duration)
else if(amount > 0)
- U = apply_status_effect(STATUS_EFFECT_UNCONSCIOUS, amount, updating)
+ U = apply_status_effect(STATUS_EFFECT_UNCONSCIOUS, amount)
return U
-/mob/living/proc/SetUnconscious(amount, updating = TRUE, ignore_canstun = FALSE) //Sets remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_UNCONSCIOUS, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/SetUnconscious(amount, ignore_canstun = FALSE) //Sets remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_UNCONSCIOUS, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANUNCONSCIOUS) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
var/datum/status_effect/incapacitating/unconscious/U = IsUnconscious()
@@ -276,18 +273,18 @@
else if(U)
U.duration = world.time + amount
else
- U = apply_status_effect(STATUS_EFFECT_UNCONSCIOUS, amount, updating)
+ U = apply_status_effect(STATUS_EFFECT_UNCONSCIOUS, amount)
return U
-/mob/living/proc/AdjustUnconscious(amount, updating = TRUE, ignore_canstun = FALSE) //Adds to remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_UNCONSCIOUS, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/AdjustUnconscious(amount, ignore_canstun = FALSE) //Adds to remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_UNCONSCIOUS, amount, ignore_canstun) & COMPONENT_NO_STUN)
return
if(((status_flags & CANUNCONSCIOUS) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canstun)
var/datum/status_effect/incapacitating/unconscious/U = IsUnconscious()
if(U)
U.duration += amount
else if(amount > 0)
- U = apply_status_effect(STATUS_EFFECT_UNCONSCIOUS, amount, updating)
+ U = apply_status_effect(STATUS_EFFECT_UNCONSCIOUS, amount)
return U
/////////////////////////////////// SLEEPING ////////////////////////////////////
@@ -301,41 +298,57 @@
return S.duration - world.time
return 0
-/mob/living/proc/Sleeping(amount, updating = TRUE, ignore_canstun = FALSE) //Can't go below remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_SLEEP, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/Sleeping(amount) //Can't go below remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_SLEEP, amount) & COMPONENT_NO_STUN)
return
- if((!HAS_TRAIT(src, TRAIT_SLEEPIMMUNE)) || ignore_canstun)
- var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
- if(S)
- S.duration = max(world.time + amount, S.duration)
- else if(amount > 0)
- S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount, updating)
- return S
-
-/mob/living/proc/SetSleeping(amount, updating = TRUE, ignore_canstun = FALSE) //Sets remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_SLEEP, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+ if(status_flags & GODMODE)
return
- if((!HAS_TRAIT(src, TRAIT_SLEEPIMMUNE)) || ignore_canstun)
- var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
- if(amount <= 0)
- if(S)
- qdel(S)
- else if(S)
- S.duration = world.time + amount
- else
- S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount, updating)
- return S
+ var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
+ if(S)
+ S.duration = max(world.time + amount, S.duration)
+ else if(amount > 0)
+ S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount)
+ return S
-/mob/living/proc/AdjustSleeping(amount, updating = TRUE, ignore_canstun = FALSE) //Adds to remaining duration
- if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_SLEEP, amount, updating, ignore_canstun) & COMPONENT_NO_STUN)
+/mob/living/proc/SetSleeping(amount) //Sets remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_SLEEP, amount) & COMPONENT_NO_STUN)
return
- if((!HAS_TRAIT(src, TRAIT_SLEEPIMMUNE)) || ignore_canstun)
- var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
+ if(status_flags & GODMODE)
+ return
+ var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
+ if(amount <= 0)
if(S)
- S.duration += amount
- else if(amount > 0)
- S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount, updating)
- return S
+ qdel(S)
+ else if(S)
+ S.duration = world.time + amount
+ else
+ S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount)
+ return S
+
+/mob/living/proc/AdjustSleeping(amount) //Adds to remaining duration
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_SLEEP, amount) & COMPONENT_NO_STUN)
+ return
+ if(status_flags & GODMODE)
+ return
+ var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
+ if(S)
+ S.duration += amount
+ else if(amount > 0)
+ S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount)
+ return S
+
+///Allows us to set a permanent sleep on a player (use with caution and remember to unset it with SetSleeping() after the effect is over)
+/mob/living/proc/PermaSleeping()
+ if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_SLEEP, -1) & COMPONENT_NO_STUN)
+ return
+ if(status_flags & GODMODE)
+ return
+ var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
+ if(S)
+ S.duration = -1
+ else
+ S = apply_status_effect(STATUS_EFFECT_SLEEPING, -1)
+ return S
///////////////////////////////// FROZEN /////////////////////////////////////
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index 00fa1790bd072..b1438706f2dae 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -2,6 +2,7 @@
* Run when a client is put in this mob or reconnets to byond and their client was on this mob
*
* Things it does:
+ * * call set_eye() to manually manage atom/list/eye_users
* * Adds player to player_list
* * sets lastKnownIP
* * sets computer_id
@@ -20,36 +21,50 @@
* * grant any actions the mob has to the client
* * calls [auto_deadmin_on_login](mob.html#proc/auto_deadmin_on_login)
* * send signal COMSIG_MOB_CLIENT_LOGIN
+ * * client can be deleted mid-execution of this proc, chiefly on parent calls, with lag
* * attaches the ash listener element so clients can hear weather
*/
/mob/Login()
+ if(!client)
+ return FALSE
+ // set_eye() is important here, because your eye doesn't know if you're using them as your eye
+ // FALSE when weakref doesn't exist, to prevent using their current eye
+ client.set_eye(client.eye, client.eye_weakref?.resolve() || FALSE)
add_to_player_list()
lastKnownIP = client.address
computer_id = client.computer_id
log_access("Mob Login: [key_name(src)] was assigned to a [type]")
world.update_status()
- client.screen = list() //remove hud items just in case
+ client.screen = list() //remove hud items just in case
client.images = list()
if(!hud_used)
- create_mob_hud()
+ create_mob_hud() // creating a hud will add it to the client's screen, which can process a disconnect
+ if(!client)
+ return FALSE
+
if(hud_used)
- hud_used.show_hud(hud_used.hud_version)
+ hud_used.show_hud(hud_used.hud_version) // see above, this can process a disconnect
+ if(!client)
+ return FALSE
hud_used.update_ui_style(ui_style2icon(client.prefs?.read_player_preference(/datum/preference/choiced/ui_style)))
next_move = 1
..()
- if (client && key != client.key)
+ if(!client)
+ return FALSE
+
+ SEND_SIGNAL(src, COMSIG_MOB_LOGIN)
+
+ if (key != client.key)
key = client.key
reset_perspective(loc)
if(loc)
loc.on_log(TRUE)
- SEND_SIGNAL(src, COMSIG_MOB_LOGIN)
-
//readd this mob's HUDs (antag, med, etc)
reload_huds()
@@ -96,10 +111,12 @@
log_message("Client [key_name(src)] has taken ownership of mob [src]([src.type])", LOG_OWNERSHIP)
SEND_SIGNAL(src, COMSIG_MOB_CLIENT_LOGIN, client)
- SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MOB_LOGGED_IN, src)
AddElement(/datum/element/weather_listener, /datum/weather/ash_storm, ZTRAIT_ASHSTORM, GLOB.ash_storm_sounds)
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MOB_LOGGED_IN, src)
+
+ return TRUE
/**
* Checks if the attached client is an admin and may deadmin them
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index e92f4b0283722..2fcac5d963f08 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -438,41 +438,44 @@
return B
/**
- * Reset the attached clients perspective (viewpoint)
- *
- * reset_perspective() set eye to common default : mob on turf, loc otherwise
- * reset_perspective(thing) set the eye to the thing (if it's equal to current default reset to mob perspective)
- */
-/mob/proc/reset_perspective(atom/A)
- if(client)
- if(A)
- if(ismovable(A))
- //Set the the thing unless it's us
- if(A != src)
- client.perspective = EYE_PERSPECTIVE
- client.eye = A
- else
- client.eye = client.mob
- client.perspective = MOB_PERSPECTIVE
- else if(isturf(A))
- //Set to the turf unless it's our current turf
- if(A != loc)
- client.perspective = EYE_PERSPECTIVE
- client.eye = A
- else
- client.eye = client.mob
- client.perspective = MOB_PERSPECTIVE
+ * Reset the attached clients perspective (viewpoint)
+ *
+ * reset_perspective(null) set eye to common default : mob on turf, loc otherwise
+ * reset_perspective(thing) set the eye to the thing (if it's equal to current default reset to mob perspective)
+ */
+/mob/proc/reset_perspective(atom/new_eye)
+ SHOULD_CALL_PARENT(TRUE)
+ if(!client)
+ return
+
+ if(new_eye)
+ if(ismovable(new_eye))
+ //Set the the thing unless it's us
+ if(new_eye != src)
+ client.perspective = EYE_PERSPECTIVE
+ client.set_eye(new_eye)
else
- //Do nothing
- else
- //Reset to common defaults: mob if on turf, otherwise current loc
- if(isturf(loc))
- client.eye = client.mob
+ client.set_eye(client.mob)
client.perspective = MOB_PERSPECTIVE
- else
+ else if(isturf(new_eye))
+ //Set to the turf unless it's our current turf
+ if(new_eye != loc)
client.perspective = EYE_PERSPECTIVE
- client.eye = loc
- return TRUE
+ client.set_eye(new_eye)
+ else
+ client.set_eye(client.mob)
+ client.perspective = MOB_PERSPECTIVE
+ else
+ //Do nothing
+ else
+ //Reset to common defaults: mob if on turf, otherwise current loc
+ if(isturf(loc))
+ client.set_eye(client.mob)
+ client.perspective = MOB_PERSPECTIVE
+ else
+ client.perspective = EYE_PERSPECTIVE
+ client.set_eye(loc)
+ return TRUE
/**
* Examine a mob
@@ -515,7 +518,7 @@
//you can only initiate exaimines if you have a hand, it's not disabled, and only as many examines as you have hands
/// our active hand, to check if it's disabled/detatched
var/obj/item/bodypart/active_hand = has_active_hand()? get_active_hand() : null
- if(!active_hand || active_hand.is_disabled() || LAZYLEN(do_afters) >= get_num_arms())
+ if(!active_hand || active_hand.bodypart_disabled || LAZYLEN(do_afters) >= usable_hands)
to_chat(src, "You don't have a free hand to examine this! ")
return FALSE
@@ -911,7 +914,7 @@
return src
/**
- * Buckle to another mob
+ * Buckle a living mob to this mob
*
* You can buckle on mobs if you're next to them since most are dense
*
@@ -949,14 +952,6 @@
return 0
return 9
-///can the mob be buckled to something by default?
-/mob/proc/can_buckle()
- return TRUE
-
-///can the mob be unbuckled from something by default?
-/mob/proc/can_unbuckle()
- return 1
-
///Can the mob interact() with an atom?
/mob/proc/can_interact_with(atom/A, treat_mob_as_adjacent)
if(IsAdminGhost(src))
@@ -1224,9 +1219,10 @@
/mob/proc/set_nutrition(var/change) //Seriously fuck you oldcoders.
nutrition = max(0, change)
-///Set the movement type of the mob and update it's movespeed
-/mob/setMovetype(newval)
+/mob/setMovetype(newval) //Set the movement type of the mob and update it's movespeed
. = ..()
+ if(isnull(.))
+ return
update_movespeed(FALSE)
/mob/proc/update_equipment_speed_mods()
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 0a39af6912142..97f9b47330cce 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -122,8 +122,6 @@
/// The atom that this mob is currently buckled to
var/atom/movable/buckled = null//Living
- /// The movable atom that we are currently in the process of buckling to, but haven't buckled with yet.
- var/atom/movable/buckling
//Hands
///What hand is the active hand
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index c542890c09a6a..82a8a22d0b334 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -453,11 +453,15 @@
dam = 1
else
dam = 0
- if((brute_heal > 0 && affecting.brute_dam > 0) || (burn_heal > 0 && affecting.burn_dam > 0))
+ if((brute_heal > 0 && (affecting.brute_dam > 0 || (H.is_bleeding() && H.has_mechanical_bleeding()))) || (burn_heal > 0 && affecting.burn_dam > 0))
if(affecting.heal_damage(brute_heal, burn_heal, 0, BODYTYPE_ROBOTIC))
H.update_damage_overlays()
- user.visible_message("[user] has fixed some of the [dam ? "dents on" : "burnt wires in"] [H]'s [parse_zone(affecting.body_zone)].", \
- "You fix some of the [dam ? "dents on" : "burnt wires in"] [H == user ? "your" : "[H]'s"] [parse_zone(affecting.body_zone)]. ")
+ if (brute_heal > 0 && H.is_bleeding() && H.has_mechanical_bleeding())
+ H.cauterise_wounds(0.4)
+ user.visible_message("[user] has fixed some of the dents on [H]'s [parse_zone(affecting.body_zone)], reducing [H.p_their()] leaking to [H.get_bleed_rate_string()].")
+ else
+ user.visible_message("[user] has fixed some of the [dam ? "dents on" : "burnt wires in"] [H]'s [parse_zone(affecting.body_zone)].", \
+ "You fix some of the [dam ? "dents on" : "burnt wires in"] [H == user ? "your" : "[H]'s"] [parse_zone(affecting.body_zone)]. ")
return TRUE //successful heal
else
to_chat(user, "[affecting] is already in good condition! ")
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index d7bbc303bffc1..51f84602cb15e 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -164,21 +164,23 @@
* Called by client/Move()
*/
/client/proc/Process_Grab()
- if(mob.pulledby)
- if((mob.pulledby == mob.pulling) && (mob.pulledby.grab_state == GRAB_PASSIVE)) //Don't autoresist passive grabs if we're grabbing them too.
- return
- if(mob.incapacitated(ignore_restraints = 1))
- move_delay = world.time + 10
- return TRUE
- else if(HAS_TRAIT(mob, TRAIT_RESTRAINED))
- move_delay = world.time + 10
- to_chat(src, "You're restrained! You can't move! ")
- return TRUE
- else if(mob.pulledby.grab_state == GRAB_AGGRESSIVE)
- move_delay = world.time + 10
- return TRUE
- else
- return mob.resist_grab(1)
+ if(!mob.pulledby)
+ return FALSE
+
+ if(mob.pulledby == mob.pulling && mob.pulledby.grab_state == GRAB_PASSIVE) //Don't autoresist passive grabs if we're grabbing them too.
+ return FALSE
+ if(mob.incapacitated(ignore_restraints = TRUE))
+ COOLDOWN_START(src, move_delay, 1 SECONDS)
+ return TRUE
+ else if(HAS_TRAIT(mob, TRAIT_RESTRAINED))
+ COOLDOWN_START(src, move_delay, 1 SECONDS)
+ to_chat(src, "You're restrained! You can't move! ")
+ return TRUE
+ else if(mob.pulledby.grab_state == GRAB_AGGRESSIVE)
+ COOLDOWN_START(src, move_delay, 1 SECONDS)
+ return TRUE
+ else
+ return mob.resist_grab(1)
/**
* Allows mobs to ignore density and phase through objects
diff --git a/code/modules/mob/mob_stat.dm b/code/modules/mob/mob_stat.dm
index c9200140700a5..73e365a2620fd 100644
--- a/code/modules/mob/mob_stat.dm
+++ b/code/modules/mob/mob_stat.dm
@@ -238,7 +238,7 @@
else
tab_data["Players Playing/Connected"] = GENERATE_STAT_TEXT("[get_active_player_count()]/[GLOB.clients.len]")
if(SSticker.round_start_time)
- tab_data["Security Level"] = GENERATE_STAT_TEXT("[capitalize(get_security_level())]")
+ tab_data["Security Level"] = GENERATE_STAT_TEXT("[capitalize(SSsecurity_level.get_current_level_as_text())]")
tab_data["divider_3"] = GENERATE_STAT_DIVIDER
if(SSshuttle.emergency)
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 99afd08579668..c6be5066ad246 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -63,6 +63,8 @@
if(notransform)
return TRUE
notransform = TRUE
+ ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_GENERIC)
+ ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, TRAIT_GENERIC)
Paralyze(1, ignore_canstun = TRUE)
if(delete_items)
diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm
index b8613a74f5337..a4ef011cd21ff 100644
--- a/code/modules/modular_computers/computers/item/computer.dm
+++ b/code/modules/modular_computers/computers/item/computer.dm
@@ -8,7 +8,7 @@ GLOBAL_LIST_EMPTY(TabletMessengers) // a list of all active messengers, similar
desc = "A small portable microcomputer."
icon = 'icons/obj/computer.dmi'
icon_state = "laptop"
- light_system = MOVABLE_LIGHT
+ light_system = MOVABLE_LIGHT_DIRECTIONAL
light_range = 3
light_power = 0.6
light_color = "#FFFFFF"
@@ -56,7 +56,7 @@ GLOBAL_LIST_EMPTY(TabletMessengers) // a list of all active messengers, similar
integrity_failure = 0.5
max_integrity = 100
- armor = list(MELEE = 0, BULLET = 20, LASER = 20, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 0, ACID = 0, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 20, LASER = 20, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
/// List of "connection ports" in this computer and the components with which they are plugged
var/list/all_components = list()
diff --git a/code/modules/modular_computers/computers/item/processor.dm b/code/modules/modular_computers/computers/item/processor.dm
index 8ca04d3ce357d..c01d014d6e9c7 100644
--- a/code/modules/modular_computers/computers/item/processor.dm
+++ b/code/modules/modular_computers/computers/item/processor.dm
@@ -32,7 +32,7 @@
hardware_flag = machinery_computer.hardware_flag
max_hardware_size = machinery_computer.max_hardware_size
steel_sheet_cost = machinery_computer.steel_sheet_cost
- obj_integrity = machinery_computer.obj_integrity
+ update_integrity(machinery_computer.get_integrity())
max_integrity = machinery_computer.max_integrity
integrity_failure = machinery_computer.integrity_failure
base_active_power_usage = machinery_computer.base_active_power_usage
diff --git a/code/modules/modular_computers/computers/machinery/modular_computer.dm b/code/modules/modular_computers/computers/machinery/modular_computer.dm
index 4c358a2718c50..16fe3c9b40c64 100644
--- a/code/modules/modular_computers/computers/machinery/modular_computer.dm
+++ b/code/modules/modular_computers/computers/machinery/modular_computer.dm
@@ -72,7 +72,7 @@
else
add_overlay(screen_icon_state_menu)
- if(cpu && cpu.obj_integrity <= cpu.integrity_failure * cpu.max_integrity)
+ if(cpu && cpu.get_integrity() <= cpu.integrity_failure * cpu.max_integrity)
add_overlay("bsod")
add_overlay("broken")
diff --git a/code/modules/modular_computers/file_system/programs/borg_self_monitor.dm b/code/modules/modular_computers/file_system/programs/borg_self_monitor.dm
index dda9a6c99d9ed..38f50f6184885 100644
--- a/code/modules/modular_computers/file_system/programs/borg_self_monitor.dm
+++ b/code/modules/modular_computers/file_system/programs/borg_self_monitor.dm
@@ -53,6 +53,7 @@
data["printerPictures"] = borgo.connected_ai ? length(borgo.connected_ai.aicamera?.stored) : length(borgo.aicamera?.stored) //Number of pictures taken, synced to AI if available
data["printerToner"] = borgo.toner //amount of toner
data["printerTonerMax"] = borgo.tonermax //It's a variable, might as well use it
+ data["cameraRadius"] = isnull(borgo.aicamera) ? 1 : borgo.aicamera.picture_size_x // picture_size_x and picture_size_y should always be the same.
data["thrustersInstalled"] = borgo.ionpulse //If we have a thruster uprade
data["thrustersStatus"] = "[borgo.ionpulse_on?"ACTIVE":"DISABLED"]" //Feedback for thruster status
data["selfDestructAble"] = (borgo.emagged || istype(borgo, /mob/living/silicon/robot/modules/syndicate))
@@ -133,6 +134,20 @@
borgo.lamp_intensity = clamp(text2num(params["ref"]), 1, 5)
borgo.toggle_headlamp(FALSE, TRUE)
+ if("cameraRadius")
+ var/obj/item/camera/siliconcam/robot_camera/borgcam = borgo.aicamera
+ if(isnull(borgcam))
+ CRASH("Cyborg embedded AI camera is null somehow, was it qdeleted?")
+ var/desired_radius = text2num(params["ref"])
+ if(isnull(desired_radius))
+ return
+ // respect the limits
+ if(desired_radius > borgcam.picture_size_x_max || desired_radius < borgcam.picture_size_x_min)
+ log_href_exploit(usr, " attempted to select an invalid borg camera size '[desired_radius]'.")
+ return
+ borgcam.picture_size_x = desired_radius
+ borgcam.picture_size_y = desired_radius
+
if("selfDestruct")
if(borgo.stat || borgo.lockcharge) //No detonation while stunned or locked down
return
diff --git a/code/modules/modular_computers/file_system/programs/ntmessenger.dm b/code/modules/modular_computers/file_system/programs/ntmessenger.dm
index 27349cdb3fe06..4ba422c8782bf 100644
--- a/code/modules/modular_computers/file_system/programs/ntmessenger.dm
+++ b/code/modules/modular_computers/file_system/programs/ntmessenger.dm
@@ -186,6 +186,14 @@
computer.saved_image = null
photo_path = null
return TRUE
+ if("PDA_viewPhotos")
+ if(!issilicon(usr))
+ return
+ var/mob/living/silicon/user = usr
+ var/obj/item/camera/siliconcam/aicamera = user.aicamera
+ if(isnull(aicamera))
+ return
+ aicamera.viewpictures(user)
if("PDA_selectPhoto")
if(!issilicon(usr))
return
diff --git a/code/modules/movespeed/_movespeed_modifier.dm b/code/modules/movespeed/_movespeed_modifier.dm
index 92f6b6b00f161..27609e9f410bc 100644
--- a/code/modules/movespeed/_movespeed_modifier.dm
+++ b/code/modules/movespeed/_movespeed_modifier.dm
@@ -200,6 +200,7 @@ GLOBAL_LIST_EMPTY(movespeed_modification_cache)
continue
. += amt
cached_multiplicative_slowdown = .
+ SEND_SIGNAL(src, COMSIG_MOB_MOVESPEED_UPDATED)
/// Get the move speed modifiers list of the mob
/mob/proc/get_movespeed_modifiers()
diff --git a/code/modules/multiz/movement/mob/living_zfall.dm b/code/modules/multiz/movement/mob/living_zfall.dm
index 45f2daa43f03f..9599a1f5bdcfc 100644
--- a/code/modules/multiz/movement/mob/living_zfall.dm
+++ b/code/modules/multiz/movement/mob/living_zfall.dm
@@ -33,10 +33,10 @@
var/total_damage_percent_left = 1
var/obj/item/bodypart/left_leg = get_bodypart(BODY_ZONE_L_LEG)
var/obj/item/bodypart/right_leg = get_bodypart(BODY_ZONE_R_LEG)
- if(left_leg && !left_leg.disabled)
+ if(left_leg && !left_leg.bodypart_disabled)
total_damage_percent_left -= 0.45
apply_damage(amount_total * 0.45, BRUTE, BODY_ZONE_L_LEG)
- if(right_leg && !right_leg.disabled)
+ if(right_leg && !right_leg.bodypart_disabled)
total_damage_percent_left -= 0.45
apply_damage(amount_total * 0.45, BRUTE, BODY_ZONE_R_LEG)
adjustBruteLoss(amount_total * total_damage_percent_left)
diff --git a/code/modules/ninja/energy_katana.dm b/code/modules/ninja/energy_katana.dm
index 31859ccdf9523..dc0972777808a 100644
--- a/code/modules/ninja/energy_katana.dm
+++ b/code/modules/ninja/energy_katana.dm
@@ -18,6 +18,7 @@
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "tore", "ripped", "diced", "cut")
slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_BELT
sharpness = IS_SHARP
+ bleed_force = BLEED_DEEP_WOUND
max_integrity = 200
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE
var/datum/effect_system/spark_spread/spark_system
diff --git a/code/modules/ninja/suit/head.dm b/code/modules/ninja/suit/head.dm
index 448cfc7586f1d..b02d10df78048 100644
--- a/code/modules/ninja/suit/head.dm
+++ b/code/modules/ninja/suit/head.dm
@@ -3,7 +3,7 @@
name = "ninja hood"
icon_state = "s-ninja"
item_state = "s-ninja_mask"
- armor = list(MELEE = 60, BULLET = 50, LASER = 30, ENERGY = 15, BOMB = 30, BIO = 30, RAD = 25, FIRE = 100, ACID = 100, STAMINA = 60)
+ armor = list(MELEE = 60, BULLET = 50, LASER = 30, ENERGY = 15, BOMB = 30, BIO = 30, RAD = 25, FIRE = 100, ACID = 100, STAMINA = 60, BLEED = 60)
strip_delay = 12
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
blockTracking = TRUE//Roughly the only unique thing about this helmet.
diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm
index 9cd1dafa1db60..aee33924f9453 100644
--- a/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm
@@ -11,7 +11,6 @@
H.SetParalyzed(0)
H.adjustStaminaLoss(-75)
H.stuttering = 0
- H.update_mobility()
H.reagents.add_reagent(/datum/reagent/medicine/amphetamine, 5)
H.say(pick("A CORNERED FOX IS MORE DANGEROUS THAN A JACKAL!","HURT ME MOOORRREEE!","IMPRESSIVE!"), forced = "ninjaboost")
a_boost--
diff --git a/code/modules/ninja/suit/shoes.dm b/code/modules/ninja/suit/shoes.dm
index cd9536822a4cc..6a0b16e6667c3 100644
--- a/code/modules/ninja/suit/shoes.dm
+++ b/code/modules/ninja/suit/shoes.dm
@@ -7,7 +7,7 @@
permeability_coefficient = 0.01
clothing_flags = NOSLIP
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
- armor = list(MELEE = 60, BULLET = 50, LASER = 30, ENERGY = 15, BOMB = 30, BIO = 30, RAD = 30, FIRE = 100, ACID = 100, STAMINA = 60)
+ armor = list(MELEE = 60, BULLET = 50, LASER = 30, ENERGY = 15, BOMB = 30, BIO = 30, RAD = 30, FIRE = 100, ACID = 100, STAMINA = 60, BLEED = 60)
strip_delay = 120
cold_protection = FEET
min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT
diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm
index 85a77b3c93a75..5734d60ec467c 100644
--- a/code/modules/ninja/suit/suit.dm
+++ b/code/modules/ninja/suit/suit.dm
@@ -19,25 +19,36 @@ Contents:
allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/stock_parts/cell)
slowdown = 1
resistance_flags = LAVA_PROOF | ACID_PROOF
- armor = list(MELEE = 60, BULLET = 50, LASER = 30, ENERGY = 15, BOMB = 30, BIO = 30, RAD = 30, FIRE = 100, ACID = 100, STAMINA = 60)
+ armor = list(MELEE = 60, BULLET = 50, LASER = 30, ENERGY = 15, BOMB = 30, BIO = 30, RAD = 30, FIRE = 100, ACID = 100, STAMINA = 60, BLEED = 60)
strip_delay = 12
-
- actions_types = list(/datum/action/item_action/initialize_ninja_suit, /datum/action/item_action/ninjasmoke, /datum/action/item_action/ninjaboost, /datum/action/item_action/ninjapulse, /datum/action/item_action/ninjastar, /datum/action/item_action/ninjanet, /datum/action/item_action/ninja_sword_recall, /datum/action/item_action/ninja_stealth, /datum/action/item_action/toggle_glove)
-
- //Important parts of the suit.
+ min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
+ cell = null
+ show_hud = FALSE
+ actions_types = list(
+ /datum/action/item_action/initialize_ninja_suit,
+ /datum/action/item_action/ninjasmoke,
+ /datum/action/item_action/ninjaboost,
+ /datum/action/item_action/ninjapulse,
+ /datum/action/item_action/ninjastar,
+ /datum/action/item_action/ninjanet,
+ /datum/action/item_action/ninja_sword_recall,
+ /datum/action/item_action/ninja_stealth,
+ /datum/action/item_action/toggle_glove
+ )
+
+ //Important parts of the suit.
var/mob/living/carbon/human/affecting = null
- var/obj/item/stock_parts/cell/cell
var/datum/effect_system/spark_spread/spark_system
var/datum/techweb/stored_research
var/obj/item/disk/tech_disk/t_disk//To copy design onto disk.
var/obj/item/energy_katana/energyKatana //For teleporting the katana back to the ninja (It's an ability)
- //Other articles of ninja gear worn together, used to easily reference them after initializing.
+ //Other articles of ninja gear worn together, used to easily reference them after initializing.
var/obj/item/clothing/head/helmet/space/space_ninja/n_hood
var/obj/item/clothing/shoes/space_ninja/n_shoes
var/obj/item/clothing/gloves/space_ninja/n_gloves
- //Main function variables.
+ //Main function variables.
var/s_initialized = 0//Suit starts off.
var/s_coold = 0//If the suit is on cooldown. Can be used to attach different cooldowns to abilities. Ticks down every second based on suit ntick().
var/s_cost = 2.5//Base energy cost each ntick.
@@ -55,9 +66,14 @@ Contents:
var/s_bombs = 10//Number of smoke bombs.
var/a_boost = 3//Number of adrenaline boosters.
-
-/obj/item/clothing/suit/space/space_ninja/get_cell()
- return cell
+/obj/item/clothing/suit/space/space_ninja/examine(mob/user)
+ . = .()
+ if(s_initialized)
+ if(user == affecting)
+ . += "All systems operational. Current energy capacity: [display_energy(cell.charge)] .\n"+\
+ "The CLOAK-tech device is [stealth?"active":"inactive"] .\n"+\
+ "There are [s_bombs] smoke bomb\s remaining.\n"+\
+ "There are [a_boost] adrenaline booster\s remaining."
/obj/item/clothing/suit/space/space_ninja/Initialize(mapload)
. = ..()
@@ -76,6 +92,17 @@ Contents:
cell.name = "black power cell"
cell.icon_state = "bscell"
+// seal the cell in the ninja outfit
+/obj/item/clothing/suit/space/space_ninja/toggle_spacesuit_cell(mob/user)
+ return
+
+// Space Suit temperature regulation and power usage
+/obj/item/clothing/suit/space/space_ninja/process()
+ var/mob/living/carbon/human/user = src.loc
+ if(!user || !ishuman(user) || !(user.wear_suit == src))
+ return
+ user.adjust_bodytemperature(BODYTEMP_NORMAL - user.bodytemperature)
+
/obj/item/clothing/suit/space/space_ninja/Destroy()
QDEL_NULL(spark_system)
QDEL_NULL(cell)
@@ -167,16 +194,6 @@ Contents:
n_gloves.candrain = FALSE
n_gloves.draining = FALSE
-
-/obj/item/clothing/suit/space/space_ninja/examine(mob/user)
- . = .()
- if(s_initialized)
- if(user == affecting)
- . += "All systems operational. Current energy capacity: [display_energy(cell.charge)] .\n"+\
- "The CLOAK-tech device is [stealth?"active":"inactive"] .\n"+\
- "There are [s_bombs] smoke bomb\s remaining.\n"+\
- "There are [a_boost] adrenaline booster\s remaining."
-
/obj/item/clothing/suit/space/space_ninja/ui_action_click(mob/user, action)
if(istype(action, /datum/action/item_action/initialize_ninja_suit))
toggle_on_off()
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 4dee583111c01..1d805ce7bb3ad 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -162,14 +162,16 @@
* * text - The text to append to the paper.
* * font - The font to use.
* * color - The font color to use.
- * * bold - Whether this text should be rendered completely bold.
+ * * bold - Whether this text should be rendered completely bold
+ * * advanced_html - Boolean that is true when the writer has R_FUN permission, which sanitizes less HTML (such as images) from the new paper_input.
*/
-/obj/item/paper/proc/add_raw_text(text, font, color, bold)
+/obj/item/paper/proc/add_raw_text(text, font, color, bold, advanced_html)
var/new_input_datum = new /datum/paper_input(
text,
font,
color,
bold,
+ advanced_html,
)
input_field_count += get_input_field_count(text)
@@ -569,7 +571,7 @@
// Safe to assume there are writing implement details as user.can_write(...) fails with an invalid writing implement.
var/writing_implement_data = holding.get_writing_implement_details()
- add_raw_text(paper_input, writing_implement_data["font"], writing_implement_data["color"], writing_implement_data["use_bold"])
+ add_raw_text(paper_input, writing_implement_data["font"], writing_implement_data["color"], writing_implement_data["use_bold"], check_rights_for(user?.client, R_FUN))
log_paper("[key_name(user)] wrote to [name]: \"[paper_input]\"")
to_chat(user, "You have added to your paper masterpiece!");
@@ -653,15 +655,18 @@
var/colour = ""
/// Whether to render the font bold or not.
var/bold = FALSE
+ /// Whether the creator has R_FUN permission, which allows for less sanitised HTML.
+ var/advanced_html = FALSE
-/datum/paper_input/New(_raw_text, _font, _colour, _bold)
+/datum/paper_input/New(_raw_text, _font, _colour, _bold, _advanced_html)
raw_text = _raw_text
font = _font
colour = _colour
bold = _bold
+ advanced_html = _advanced_html
/datum/paper_input/proc/make_copy()
- return new /datum/paper_input(raw_text, font, colour, bold);
+ return new /datum/paper_input(raw_text, font, colour, bold, advanced_html);
/datum/paper_input/proc/to_list()
return list(
@@ -669,6 +674,7 @@
font = font,
color = colour,
bold = bold,
+ advanced_html = advanced_html,
)
/// A single instance of a saved stamp on paper.
diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm
index 532da0097b2e3..d55c0b67a9999 100644
--- a/code/modules/paperwork/paperbin.dm
+++ b/code/modules/paperwork/paperbin.dm
@@ -147,6 +147,10 @@
papertype = /obj/item/paper/natural
resistance_flags = FLAMMABLE
+/obj/item/paper_bin/bundlenatural/examine()
+ . = ..()
+ . += "You can cut the cord on this with a sharp implement, freeing all 30 sheets at once. "
+
/obj/item/paper_bin/bundlenatural/attack_hand(mob/user)
..()
if(total_paper < 1)
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index f82d9debd47aa..14fa0b9507970 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -103,6 +103,7 @@
colour = "crimson"
custom_materials = list(/datum/material/gold = 750)
sharpness = IS_SHARP
+ bleed_force = BLEED_SURFACE
resistance_flags = FIRE_PROOF
unique_reskin_icon = list("Oak" = "pen-fountain-o",
"Gold" = "pen-fountain-g",
@@ -243,6 +244,7 @@
embedding = list(embed_chance = EMBED_CHANCE, armour_block = 30)
throwforce = initial(throwforce)
sharpness = initial(sharpness)
+ bleed_force = initial(bleed_force)
playsound(user, 'sound/weapons/saberoff.ogg', 5, 1)
to_chat(user, "[src] can now be concealed. ")
else
@@ -255,6 +257,7 @@
embedding = list(embed_chance = 200, max_damage_mult = 15, armour_block = 40) //rule of cool
throwforce = 35
sharpness = IS_SHARP
+ bleed_force = BLEED_CUT
playsound(user, 'sound/weapons/saberon.ogg', 5, 1)
to_chat(user, "[src] is now active. ")
updateEmbedding()
diff --git a/code/modules/photography/photos/frame.dm b/code/modules/photography/photos/frame.dm
index 0660c0fb637de..0be0b0ffea9e6 100644
--- a/code/modules/photography/photos/frame.dm
+++ b/code/modules/photography/photos/frame.dm
@@ -10,6 +10,7 @@
result_path = /obj/structure/sign/picture_frame
pixel_shift = -32
var/obj/item/photo/displayed
+ pixel_shift = 30
/obj/item/wallframe/picture/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/photo))
diff --git a/code/modules/plumbing/plumbers/bottle_dispenser.dm b/code/modules/plumbing/plumbers/bottle_dispenser.dm
index 0ed32ee8714bb..0fbd93a536994 100644
--- a/code/modules/plumbing/plumbers/bottle_dispenser.dm
+++ b/code/modules/plumbing/plumbers/bottle_dispenser.dm
@@ -1,71 +1,24 @@
///We take a constant input of reagents, and produce a bottle once a set volume is reached
/obj/machinery/plumbing/bottle_dispenser
- name = "bottle dispenser"
- desc = "A dispenser that dispenses bottles."
+ name = "bottle filler"
+ desc = "A dispenser that fills bottles from a tap."
icon_state = "pill_press" //TODO SPRITE IT !!!!!!
- var/bottle_name = "factory bottle"
- var/bottle_size = 30
- ///the icon_state number for the bottle.
- var/list/stored_bottles = list()
- var/max_stored_bottles = 3
- ///max amount of bottles allowed on our tile before we start storing them instead
- var/max_floor_bottles = 10
-
-
-
/obj/machinery/plumbing/bottle_dispenser/examine(mob/user)
. = ..()
- . += "The [name] currently has [stored_bottles.len] stored. There needs to be less than [max_floor_bottles] on the floor to continue dispensing. "
+ . += "Use an open container on it to fill it up! "
/obj/machinery/plumbing/bottle_dispenser/Initialize(mapload, bolt)
. = ..()
AddComponent(/datum/component/plumbing/simple_demand, bolt)
update_appearance() //so the input/output pipes will overlay properly during init
-/obj/machinery/plumbing/bottle_dispenser/process()
- if(machine_stat & NOPOWER)
- return
- if((reagents.total_volume >= bottle_size) && (stored_bottles.len < max_stored_bottles))
- var/obj/item/reagent_containers/glass/bottle/P = new(src)
- reagents.trans_to(P, bottle_size)
- P.name = bottle_name
- stored_bottles += P
- if(stored_bottles.len)
- var/bottle_amount = 0
- for(var/obj/item/reagent_containers/glass/bottle/P in loc)
- bottle_amount++
- if(bottle_amount >= max_floor_bottles) //too much so just stop
- break
- if(bottle_amount < max_floor_bottles)
- var/atom/movable/AM = stored_bottles[1] //AM because forceMove is all we need
- stored_bottles -= AM
- AM.forceMove(drop_location())
-
-
-/obj/machinery/plumbing/bottle_dispenser/ui_state(mob/user)
- return GLOB.default_state
-
-/obj/machinery/plumbing/bottle_dispenser/ui_interact(mob/user, datum/tgui/ui)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "BottleDispenser")
- ui.open()
-
-/obj/machinery/plumbing/bottle_dispenser/ui_data(mob/user)
- var/list/data = list()
- data["bottle_size"] = bottle_size
- data["bottle_name"] = bottle_name
- return data
-
-/obj/machinery/plumbing/bottle_dispenser/ui_act(action, params)
- if(..())
- return
- switch(action)
- if("change_bottle_size")
- bottle_size = clamp(text2num(params["volume"]), 0, 30)
- . = TRUE
- if("change_bottle_name")
- var/new_name = stripped_input(usr, "Enter a bottle name.", name, bottle_name)
- bottle_name = new_name + " bottle"
- . = TRUE
+/obj/machinery/plumbing/bottle_dispenser/attackby(obj/item/C, mob/user)
+ var/datum/reagents/container = C.reagents
+ if (!container)
+ return ..()
+ if (!(container.flags & OPENCONTAINER))
+ user.balloon_alert("[C] is not fillable!")
+ return FALSE
+ reagents.trans_to(container, min(reagents.total_volume, container.maximum_volume - container.total_volume), transfered_by = user)
+ return FALSE
diff --git a/code/modules/plumbing/plumbers/patch_dispenser.dm b/code/modules/plumbing/plumbers/patch_dispenser.dm
deleted file mode 100644
index 0f21f9027d68d..0000000000000
--- a/code/modules/plumbing/plumbers/patch_dispenser.dm
+++ /dev/null
@@ -1,73 +0,0 @@
-///We take a constant input of reagents, and produce a patch once a set volume is reached
-/obj/machinery/plumbing/patch_dispenser
- name = "patch dispenser"
- desc = "A dispenser that dispenses patches."
- icon_state = "pill_press" //TODO SPRITE IT !!!!!!
- active_power_usage = 80
-
- var/patch_name = "factory patch"
- var/patch_size = 40
- ///the icon_state number for the patch.
- var/list/stored_patches = list()
- var/max_stored_patches = 3
- ///max amount of patches allowed on our tile before we start storing them instead
- var/max_floor_patches = 10
-
-
-
-
-/obj/machinery/plumbing/patch_dispenser/examine(mob/user)
- . = ..()
- . += "The [name] currently has [stored_patches.len] stored. There needs to be less than [max_floor_patches] on the floor to continue dispensing. "
-
-/obj/machinery/plumbing/patch_dispenser/Initialize(mapload, bolt)
- . = ..()
- AddComponent(/datum/component/plumbing/simple_demand, bolt)
- update_appearance() //so the input/output pipes will overlay properly during init
-
-/obj/machinery/plumbing/patch_dispenser/process()
- if(machine_stat & NOPOWER)
- return
- if((reagents.total_volume >= patch_size) && (stored_patches.len < max_stored_patches))
- var/obj/item/reagent_containers/pill/patch/P = new(src)
- reagents.trans_to(P, patch_size)
- P.name = patch_name
- stored_patches += P
- if(stored_patches.len)
- var/patch_amount = 0
- for(var/obj/item/reagent_containers/pill/patch/P in loc)
- patch_amount++
- if(patch_amount >= max_floor_patches) //too much so just stop
- break
- if(patch_amount < max_floor_patches)
- var/atom/movable/AM = stored_patches[1] //AM because forceMove is all we need
- stored_patches -= AM
- AM.forceMove(drop_location())
-
-
-/obj/machinery/plumbing/patch_dispenser/ui_state(mob/user)
- return GLOB.default_state
-
-/obj/machinery/plumbing/patch_dispenser/ui_interact(mob/user, datum/tgui/ui)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "PatchDispenser")
- ui.open()
-
-/obj/machinery/plumbing/patch_dispenser/ui_data(mob/user)
- var/list/data = list()
- data["patch_size"] = patch_size
- data["patch_name"] = patch_name
- return data
-
-/obj/machinery/plumbing/patch_dispenser/ui_act(action, params)
- if(..())
- return
- switch(action)
- if("change_patch_size")
- patch_size = clamp(text2num(params["volume"]), 0, 40)
- . = TRUE
- if("change_patch_name")
- var/new_name = stripped_input(usr, "Enter a patch name.", name, patch_name)
- patch_name = new_name + " patch"
- . = TRUE
diff --git a/code/modules/plumbing/plumbers/pill_press.dm b/code/modules/plumbing/plumbers/pill_press.dm
deleted file mode 100644
index 979979f4cbd07..0000000000000
--- a/code/modules/plumbing/plumbers/pill_press.dm
+++ /dev/null
@@ -1,109 +0,0 @@
-///We take a constant input of reagents, and produce a pill once a set volume is reached
-/obj/machinery/plumbing/pill_press
- name = "pill press"
- desc = "A press that presses pills."
- icon_state = "pill_press"
- active_power_usage = 100
- ///the minimum size a pill can be
- var/minimum_pill = 5
- ///the maximum size a pill can be
- var/maximum_pill = 50
- ///the size of the pill
- var/pill_size = 10
- ///pill name
- var/pill_name = "factory pill"
- ///the icon_state number for the pill.
- var/chosen_pill_style = "pill_shape_capsule_purple_pink"
- ///list of id's and icons for the pill selection of the ui
- var/static/list/pill_styles = list()
- ///list of pills stored in the machine, so we dont have 610 pills on one tile
- var/list/stored_pills = list()
- var/max_stored_pills = 3
- ///max amount of pills allowed on our tile before we start storing them instead
- var/max_floor_pills = 10
-
-
-
-
-/obj/machinery/plumbing/pill_press/examine(mob/user)
- . = ..()
- . += "The [name] currently has [stored_pills.len] stored. There needs to be less than [max_floor_pills] on the floor to continue dispensing. "
-
-/obj/machinery/plumbing/pill_press/Initialize(mapload, bolt)
- . = ..()
- AddComponent(/datum/component/plumbing/simple_demand, bolt)
-
- //expertly copypasted from chemmasters
- if(!length(pill_styles))
- for (var/each_pill_shape in PILL_SHAPE_LIST_WITH_DUMMY)
- var/list/style_list = list()
- style_list["id"] = each_pill_shape
- style_list["pill_icon_name"] = each_pill_shape
- pill_styles += list(style_list)
- update_appearance() //so the input/output pipes will overlay properly during init
-
-/obj/machinery/plumbing/pill_press/process()
- if(machine_stat & NOPOWER)
- return
- if((reagents.total_volume >= pill_size) && (stored_pills.len < max_stored_pills))
- var/obj/item/reagent_containers/pill/P = new(src)
- reagents.trans_to(P, pill_size)
- P.name = pill_name
- stored_pills += P
- if(chosen_pill_style == "pill_random_dummy")
- P.icon_state = pick(PILL_SHAPE_LIST)
- else
- P.icon_state = chosen_pill_style
- if(P.icon_state == "pill_shape_capsule_bloodred") //mirrored from chem masters
- P.desc = "A tablet or capsule, but not just any, a red one, one taken by the ones not scared of knowledge, freedom, uncertainty and the brutal truths of reality."
- if(stored_pills.len)
- var/pill_amount = 0
- for(var/obj/item/reagent_containers/pill/P in loc)
- pill_amount++
- if(pill_amount >= max_floor_pills) //too much so just stop
- break
- if(pill_amount < max_floor_pills)
- var/atom/movable/AM = stored_pills[1] //AM because forceMove is all we need
- stored_pills -= AM
- AM.forceMove(drop_location())
-
-/obj/machinery/plumbing/pill_press/ui_assets(mob/user)
- return list(
- get_asset_datum(/datum/asset/spritesheet_batched/medicine_containers),
- )
-
-
-/obj/machinery/plumbing/pill_press/ui_state(mob/user)
- return GLOB.default_state
-
-/obj/machinery/plumbing/pill_press/ui_interact(mob/user, datum/tgui/ui)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "ChemPress")
- ui.open()
-
-/obj/machinery/plumbing/pill_press/ui_data(mob/user)
- var/list/data = list()
- data["pill_size"] = pill_size
- data["pill_name"] = pill_name
- data["chosen_pill_style"] = chosen_pill_style
- data["pill_styles"] = pill_styles
- return data
-
-/obj/machinery/plumbing/pill_press/ui_act(action, params)
- if(..())
- return
- switch(action)
- if("change_pill_style")
- chosen_pill_style = "[params["id"]]"
- . = TRUE
- if("change_pill_size")
- pill_size = clamp(text2num(params["volume"]), minimum_pill, maximum_pill)
- . = TRUE
- if("change_pill_name")
- var/new_name = stripped_input(usr, "Enter a pill name.", name, pill_name)
- if(findtext(new_name, "pill")) //names like pillatron and Pilliam are thus valid
- pill_name = new_name
- else
- pill_name = new_name + " pill"
- . = TRUE
diff --git a/code/modules/plumbing/plumbers/synthesizer.dm b/code/modules/plumbing/plumbers/synthesizer.dm
index 47fafe4f2cea8..045eccf507d95 100644
--- a/code/modules/plumbing/plumbers/synthesizer.dm
+++ b/code/modules/plumbing/plumbers/synthesizer.dm
@@ -19,10 +19,6 @@
var/datum/reagent/reagent_id = null
///reagent overlay. its the colored pipe thingies. we track this because overlays.Cut() is bad
var/image/r_overlay
- ///The amount of reagent dispensable before requiring a refill from a compressed matter cartridge.
- var/volume_left = 0
- ///The maximum amount of precursor in a synthesizer.
- var/max_volume = 1000
///straight up copied from chem dispenser. Being a subtype would be extremely tedious and making it global would restrict potential subtypes using different dispensable_reagents
var/list/dispensable_reagents = list(
/datum/reagent/aluminium,
@@ -66,34 +62,11 @@
return
if(reagents.total_volume >= amount*delta_time*0.5) //otherwise we get leftovers, and we need this to be precise
return
- if(volume_left < amount) //Empty
- return
reagents.add_reagent(reagent_id, amount*delta_time*0.5)
- volume_left = max(volume_left - amount*delta_time*0.5, 0)
-
-/obj/machinery/plumbing/synthesizer/attackby(obj/item/O, mob/user, params)
- if(!istype(O, /obj/item/rcd_ammo))
- return ..()
- var/obj/item/rcd_ammo/R = O
- if(!R.ammoamt)
- to_chat(user, "The [R.name] doesn't have any reagent left! ")
- return ..()
- var/added_volume = -volume_left //For the difference calculation
- volume_left = min(volume_left+R.ammoamt*10, src.max_volume) //400 per cartridge
- added_volume = added_volume+volume_left
- R.ammoamt -= added_volume/10
- if(R.ammoamt <= 0) //Emptied
- to_chat(user, "You refill the chemical synthesizer with the [R.name], emptying it completely! ")
- qdel(R)
- return
- if(added_volume == 0) //No change
- to_chat(user, "The chemical synthesizer is full! ")
- return
- to_chat(user, "You refill the chemical synthesizer with the [R.name], leaving [R.ammoamt*10] units in it. ")
/obj/machinery/plumbing/synthesizer/examine(mob/user)
. = ..()
- . += "A display says it currently holds [volume_left] units of precursor before requiring a refill. "
+ . += "A display says it is currently producing [initial(reagent_id.name)]. "
/obj/machinery/plumbing/synthesizer/ui_state(mob/user)
return GLOB.default_state
diff --git a/code/modules/pool/components/swimming.dm b/code/modules/pool/components/swimming.dm
index b5cb1b6358747..8211e87e97794 100644
--- a/code/modules/pool/components/swimming.dm
+++ b/code/modules/pool/components/swimming.dm
@@ -33,7 +33,7 @@
if(lengths > lengths_for_bonus)
var/mob/living/L = parent
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "exercise", /datum/mood_event/exercise)
- L.apply_status_effect(STATUS_EFFECT_EXERCISED) //Swimming is really good excercise!
+ L.apply_status_effect(STATUS_EFFECT_EXERCISED, 20) //Swimming is really good excercise!
lengths = 0
//Damn edge cases
@@ -120,7 +120,7 @@
var/obj/item/pool/helditem = victim.get_active_held_item()
if(istype(helditem) && ISWIELDED(helditem))
return
- return ((!(victim.mobility_flags & MOBILITY_STAND)) && (!HAS_TRAIT(victim, TRAIT_NOBREATH)))
+ return ((victim.body_position == LYING_DOWN) && (!HAS_TRAIT(victim, TRAIT_NOBREATH)))
/datum/component/swimming/proc/drown(mob/living/victim)
if(victim.losebreath < 1)
diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm
index cada253c82ce5..c37ce0d32285f 100644
--- a/code/modules/power/apc/apc_main.dm
+++ b/code/modules/power/apc/apc_main.dm
@@ -68,8 +68,6 @@
///Is the AI locked from using the APC
var/aidisabled = 0
- var/tdir = null
-
///Reference to our cable terminal
var/obj/machinery/power/terminal/terminal = null
///Amount of power used by the lighting channel
@@ -135,35 +133,11 @@
if (!req_access)
req_access = list(ACCESS_ENGINE_EQUIP)
if (!armor)
- armor = list(MELEE = 20, BULLET = 20, LASER = 10, ENERGY = 100, BOMB = 30, BIO = 100, RAD = 100, FIRE = 90, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 20, BULLET = 20, LASER = 10, ENERGY = 100, BOMB = 30, BIO = 100, RAD = 100, FIRE = 90, ACID = 50, STAMINA = 0, BLEED = 0)
..()
GLOB.apcs_list += src
wires = new /datum/wires/apc(src)
- // offset 24 pixels in direction of dir
- // this allows the APC to be embedded in a wall, yet still inside an area
- if (building)
- setDir(ndir)
- tdir = dir // to fix Vars bug
- setDir(SOUTH)
-
- switch(tdir)
- if(NORTH)
- if((pixel_y != initial(pixel_y)) && (pixel_y != 23))
- log_mapping("APC: ([src]) at [AREACOORD(src)] with dir ([tdir] | [uppertext(dir2text(tdir))]) has pixel_y value ([pixel_y] - should be 23.)")
- pixel_y = 23
- if(SOUTH)
- if((pixel_y != initial(pixel_y)) && (pixel_y != -23))
- log_mapping("APC: ([src]) at [AREACOORD(src)] with dir ([tdir] | [uppertext(dir2text(tdir))]) has pixel_y value ([pixel_y] - should be -23.)")
- pixel_y = -23
- if(EAST)
- if((pixel_y != initial(pixel_x)) && (pixel_x != 24))
- log_mapping("APC: ([src]) at [AREACOORD(src)] with dir ([tdir] | [uppertext(dir2text(tdir))]) has pixel_x value ([pixel_x] - should be 24.)")
- pixel_x = 24
- if(WEST)
- if((pixel_y != initial(pixel_x)) && (pixel_x != -25))
- log_mapping("APC: ([src]) at [AREACOORD(src)] with dir ([tdir] | [uppertext(dir2text(tdir))]) has pixel_x value ([pixel_x] - should be -25.)")
- pixel_x = -25
if (building)
area = get_area(src)
opened = APC_COVER_OPENED
@@ -172,6 +146,26 @@
set_machine_stat(machine_stat | MAINT)
update_appearance()
addtimer(CALLBACK(src, PROC_REF(update)), 5)
+ dir = ndir
+
+ // offset APC_PIXEL_OFFSET pixels in direction of dir
+ // this allows the APC to be embedded in a wall, yet still inside an area
+ var/offset_old
+ switch(dir)
+ if(NORTH)
+ offset_old = pixel_y
+ pixel_y = APC_PIXEL_OFFSET
+ if(SOUTH)
+ offset_old = pixel_y
+ pixel_y = -APC_PIXEL_OFFSET
+ if(EAST)
+ offset_old = pixel_x
+ pixel_x = APC_PIXEL_OFFSET
+ if(WEST)
+ offset_old = pixel_x
+ pixel_x = -APC_PIXEL_OFFSET
+ if(offset_old != APC_PIXEL_OFFSET && !building)
+ log_mapping("APC: ([src]) at [AREACOORD(src)] with dir ([dir] | [uppertext(dir2text(dir))]) has pixel_[dir & (WEST|EAST) ? "x" : "y"] value [offset_old] - should be [dir & (SOUTH|EAST) ? "-" : ""][APC_PIXEL_OFFSET]. Use the directional/ helpers!")
/obj/machinery/power/apc/Destroy()
GLOB.apcs_list -= src
diff --git a/code/modules/power/apc/apc_mapping.dm b/code/modules/power/apc/apc_mapping.dm
index e132cf6d86dcf..7bfb7a8bf6bed 100644
--- a/code/modules/power/apc/apc_mapping.dm
+++ b/code/modules/power/apc/apc_mapping.dm
@@ -19,18 +19,4 @@
/obj/machinery/power/apc/auto_name
auto_name = TRUE
-/obj/machinery/power/apc/auto_name/north //Pixel offsets get overwritten on New()
- dir = NORTH
- pixel_y = 23
-
-/obj/machinery/power/apc/auto_name/south
- dir = SOUTH
- pixel_y = -23
-
-/obj/machinery/power/apc/auto_name/east
- dir = EAST
- pixel_x = 24
-
-/obj/machinery/power/apc/auto_name/west
- dir = WEST
- pixel_x = -25
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/power/apc/auto_name, APC_PIXEL_OFFSET)
diff --git a/code/modules/power/apc/apc_power_proc.dm b/code/modules/power/apc/apc_power_proc.dm
index 13ea299ff2e43..29eeaf55daf04 100644
--- a/code/modules/power/apc/apc_power_proc.dm
+++ b/code/modules/power/apc/apc_power_proc.dm
@@ -11,7 +11,7 @@
// create a terminal object at the same position as original turf loc
// wires will attach to this
terminal = new/obj/machinery/power/terminal(loc)
- terminal.setDir(tdir)
+ terminal.setDir(dir)
terminal.master = src
/obj/machinery/power/apc/disconnect_terminal()
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index f74a7c721ca34..06d87c838a6e4 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -11,7 +11,7 @@
throw_speed = 2
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
- /// note %age conveted to actual charge in New
+ /// note %age converted to actual charge in New
var/charge = 0
var/maxcharge = 1000
custom_materials = list(/datum/material/iron=700, /datum/material/glass=50)
@@ -42,7 +42,7 @@
charge = maxcharge
if(ratingdesc)
desc += " This one has a rating of [display_energy(maxcharge)], and you should not swallow it."
- update_icon()
+ update_appearance()
/obj/item/stock_parts/cell/Destroy()
STOP_PROCESSING(SSobj, src)
@@ -65,18 +65,18 @@
else
return PROCESS_KILL
-/obj/item/stock_parts/cell/update_icon()
- cut_overlays()
+/obj/item/stock_parts/cell/update_overlays()
+ . = ..()
if(grown_battery)
- add_overlay(image('icons/obj/power.dmi',"grown_wires"))
+ . += mutable_appearance('icons/obj/power.dmi', "grown_wires")
if(charge < 0.01)
return
else if(charge/maxcharge >=0.995)
- add_overlay("cell-o2")
+ . += "cell-o2"
else
- add_overlay("cell-o1")
+ . += "cell-o1"
-/obj/item/stock_parts/cell/proc/percent() // return % charge of cell
+/obj/item/stock_parts/cell/proc/percent() // return % charge of cell
return maxcharge ? 100 * charge / maxcharge : 0 //Division by 0 protection
// use power from a cell
@@ -233,7 +233,7 @@
/obj/item/stock_parts/cell/crap/empty/Initialize(mapload)
. = ..()
charge = 0
- update_icon()
+ update_appearance()
/obj/item/stock_parts/cell/upgraded
name = "upgraded power cell"
@@ -255,7 +255,7 @@
/obj/item/stock_parts/cell/secborg/empty/Initialize(mapload)
. = ..()
charge = 0
- update_icon()
+ update_appearance()
/obj/item/stock_parts/cell/pulse //200 pulse shots
name = "pulse rifle power cell"
@@ -288,7 +288,7 @@
/obj/item/stock_parts/cell/high/empty/Initialize(mapload)
. = ..()
charge = 0
- update_icon()
+ update_appearance()
/obj/item/stock_parts/cell/super
name = "super-capacity power cell"
@@ -301,7 +301,7 @@
/obj/item/stock_parts/cell/super/empty/Initialize(mapload)
. = ..()
charge = 0
- update_icon()
+ update_appearance()
/obj/item/stock_parts/cell/hyper
name = "hyper-capacity power cell"
@@ -314,7 +314,7 @@
/obj/item/stock_parts/cell/hyper/empty/Initialize(mapload)
. = ..()
charge = 0
- update_icon()
+ update_appearance()
/obj/item/stock_parts/cell/bluespace
name = "bluespace power cell"
@@ -328,7 +328,7 @@
/obj/item/stock_parts/cell/bluespace/empty/Initialize(mapload)
. = ..()
charge = 0
- update_icon()
+ update_appearance()
/obj/item/stock_parts/cell/infinite
name = "infinite-capacity power cell!"
@@ -349,8 +349,9 @@
maxcharge = 50000
ratingdesc = FALSE
-/obj/item/stock_parts/cell/infinite/abductor/update_icon()
- return
+/obj/item/stock_parts/cell/infinite/abductor/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/update_icon_blocker)
/obj/item/stock_parts/cell/potato
@@ -383,7 +384,7 @@
/obj/item/stock_parts/cell/emproof/empty/Initialize(mapload)
. = ..()
charge = 0
- update_icon()
+ update_appearance()
/obj/item/stock_parts/cell/emproof/empty/ComponentInitialize()
. = ..()
diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm
index eb877225f0701..d761ec5a1d4e3 100644
--- a/code/modules/power/lighting/light.dm
+++ b/code/modules/power/lighting/light.dm
@@ -56,48 +56,11 @@
var/turning_on = FALSE
var/roundstart_smoothing = FALSE
-/obj/machinery/light/broken
- status = LIGHT_BROKEN
- icon_state = "tube-broken"
-
-// the smaller bulb light fixture
-
-/obj/machinery/light/small
- icon_state = "bulb"
- base_state = "bulb"
- fitting = "bulb"
- brightness = 6
- desc = "A small lighting fixture."
- bulb_colour = "#FFE6CC" //little less cozy, bit more industrial, but still cozy.. -qwerty
- light_type = /obj/item/light/bulb
-
-/obj/machinery/light/small/broken
- status = LIGHT_BROKEN
- icon_state = "bulb-broken"
-
/obj/machinery/light/Move()
if(status != LIGHT_BROKEN)
break_light_tube(1)
return ..()
-/obj/machinery/light/built
- icon_state = "tube-empty"
- start_with_cell = FALSE
-
-/obj/machinery/light/built/Initialize(mapload)
- . = ..()
- status = LIGHT_EMPTY
- update(FALSE, TRUE)
-
-/obj/machinery/light/small/built
- icon_state = "bulb-empty"
- start_with_cell = FALSE
-
-/obj/machinery/light/small/built/Initialize(mapload)
- . = ..()
- status = LIGHT_EMPTY
- update(FALSE, TRUE)
-
/obj/machinery/light/proc/store_cell(new_cell)
if(cell)
UnregisterSignal(cell, COMSIG_PARENT_QDELETING)
@@ -290,7 +253,7 @@
update()
/obj/machinery/light/proc/broken_sparks(start_only=FALSE)
- if(!QDELETED(src) && status == LIGHT_BROKEN && has_power() && Master.current_runlevel)
+ if(!QDELETED(src) && status == LIGHT_BROKEN && has_power() && MC_RUNNING())
if(!start_only)
do_sparks(3, TRUE, src)
var/delay = rand(BROKEN_SPARKS_MIN, BROKEN_SPARKS_MAX)
@@ -417,7 +380,7 @@
newlight.setDir(src.dir)
newlight.stage = cur_stage
if(!disassembled)
- newlight.obj_integrity = newlight.max_integrity * 0.5
+ newlight.take_damage(newlight.max_integrity * 0.5, sound_effect=FALSE)
if(status != LIGHT_BROKEN)
break_light_tube()
if(status != LIGHT_EMPTY)
diff --git a/code/modules/power/lighting/light_construct.dm b/code/modules/power/lighting/light_construct.dm
index 96c23c8e7aaf4..47584ee0d1fe6 100644
--- a/code/modules/power/lighting/light_construct.dm
+++ b/code/modules/power/lighting/light_construct.dm
@@ -6,7 +6,7 @@
anchored = TRUE
layer = WALL_OBJ_LAYER
max_integrity = 200
- armor = list(MELEE = 50, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 50, STAMINA = 0, BLEED = 0)
var/stage = 1
var/fixture_type = "tube"
diff --git a/code/modules/power/lighting/light_mapping_helpers.dm b/code/modules/power/lighting/light_mapping_helpers.dm
new file mode 100644
index 0000000000000..d8ef644e5223d
--- /dev/null
+++ b/code/modules/power/lighting/light_mapping_helpers.dm
@@ -0,0 +1,121 @@
+/obj/machinery/light/broken
+ status = LIGHT_BROKEN
+ icon_state = "tube-broken"
+
+/obj/machinery/light/built
+ icon_state = "tube-empty"
+ start_with_cell = FALSE
+
+/obj/machinery/light/built/Initialize(mapload)
+ . = ..()
+ status = LIGHT_EMPTY
+ update(FALSE, TRUE)
+
+/obj/machinery/light/no_nightlight
+ nightshift_enabled = FALSE
+
+/obj/machinery/light/warm
+ bulb_colour = "#fae5c1"
+
+/obj/machinery/light/warm/no_nightlight
+ nightshift_allowed = FALSE
+
+/obj/machinery/light/cold
+ bulb_colour = "#deefff"
+ nightshift_light_color = "#deefff"
+
+/obj/machinery/light/cold/no_nightlight
+ nightshift_allowed = FALSE
+
+/obj/machinery/light/red/dim
+ brightness = 4
+ bulb_power = 0.7
+
+/obj/machinery/light/blacklight
+ bulb_colour = "#A700FF"
+ nightshift_allowed = FALSE
+ brightness = 8
+
+/obj/machinery/light/dim
+ nightshift_allowed = FALSE
+ bulb_colour = "#FFDDCC"
+ bulb_power = 0.6
+
+// the smaller bulb light fixture
+
+/obj/machinery/light/small
+ icon_state = "bulb"
+ base_state = "bulb"
+ fitting = "bulb"
+ brightness = 6
+ desc = "A small lighting fixture."
+ bulb_colour = "#FFE6CC" //little less cozy, bit more industrial, but still cozy.. -qwerty
+ light_type = /obj/item/light/bulb
+
+/obj/machinery/light/small/broken
+ status = LIGHT_BROKEN
+ icon_state = "bulb-broken"
+
+/obj/machinery/light/small/built
+ icon_state = "bulb-empty"
+ start_with_cell = FALSE
+
+/obj/machinery/light/small/built/Initialize(mapload)
+ . = ..()
+ status = LIGHT_EMPTY
+ update(FALSE, TRUE)
+
+/obj/machinery/light/small/blacklight
+ bulb_colour = "#A700FF"
+ nightshift_allowed = FALSE
+ brightness = 4
+
+// -------- Directional presets
+// The directions are backwards on the lights we have now
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light, 0)
+
+// ---- Broken tube
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light/broken, 0)
+
+// ---- Tube construct
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/light_construct, 0)
+
+// ---- Tube frames
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light/built, 0)
+
+// ---- No nightlight tubes
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light/no_nightlight, 0)
+
+// ---- Warm light tubes
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light/warm, 0)
+
+// ---- No nightlight warm light tubes
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light/warm/no_nightlight, 0)
+
+// ---- Cold light tubes
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light/cold, 0)
+
+// ---- No nightlight cold light tubes
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light/cold/no_nightlight, 0)
+
+// ---- Blacklight tubes
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light/blacklight, 0)
+
+// ---- Dim tubes
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light/dim, 0)
+
+
+// -------- Bulb lights
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light/small, 0)
+
+// ---- Bulb construct
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/light_construct/small, 0)
+
+// ---- Bulb frames
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light/small/built, 0)
+
+// ---- Broken bulbs
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light/small/broken, 0)
+
+// ---- Blacklight bulbs
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light/small/blacklight, 0)
diff --git a/code/modules/power/lighting/light_wallframes.dm b/code/modules/power/lighting/light_wallframes.dm
index 8189ca6caa75d..0e3c9ae3433d3 100644
--- a/code/modules/power/lighting/light_wallframes.dm
+++ b/code/modules/power/lighting/light_wallframes.dm
@@ -5,7 +5,7 @@
icon = 'icons/obj/lighting.dmi'
icon_state = "tube-construct-item"
result_path = /obj/structure/light_construct
- inverse = TRUE
+ wall_external = TRUE
/obj/item/wallframe/light_fixture/small
name = "small light fixture frame"
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index 6bef2d1f561e4..95c50ffb478cc 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -379,7 +379,7 @@
icon_state_on = "protoemitter_+a"
icon_state_underpowered = "protoemitter_+u"
can_buckle = TRUE
- buckle_lying = FALSE
+ buckle_lying = 0
///Sets the view size for the user
var/view_range = 4.5
///Grants the buckled mob the action button
diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm
index f05ed4eedfe24..ec26aa3603883 100644
--- a/code/modules/power/singularity/field_generator.dm
+++ b/code/modules/power/singularity/field_generator.dm
@@ -33,7 +33,7 @@ field_generator power level display
use_power = NO_POWER_USE
max_integrity = 500
//100% immune to lasers and energy projectiles since it absorbs their energy.
- armor = list(MELEE = 25, BULLET = 10, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 70, STAMINA = 0)
+ armor = list(MELEE = 25, BULLET = 10, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 70, STAMINA = 0, BLEED = 0)
var/power_level = 0
var/active = FG_OFFLINE
var/power = 20 // Current amount of power
diff --git a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm
index d09f453d60054..24feb2fc3d024 100644
--- a/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm
+++ b/code/modules/power/singularity/particle_accelerator/particle_accelerator.dm
@@ -27,7 +27,7 @@
anchored = FALSE
density = TRUE
max_integrity = 500
- armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 90, ACID = 80, STAMINA = 0)
+ armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 90, ACID = 80, STAMINA = 0, BLEED = 0)
var/obj/machinery/particle_accelerator/control_box/master = null
var/construction_state = PA_CONSTRUCTION_UNSECURED
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index e26fb9848c3cd..e8e9755a8a4bc 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -638,18 +638,19 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
qdel(src)
return gain
-/obj/machinery/power/supermatter_crystal/blob_act(obj/structure/blob/B)
- if(B && !isspaceturf(loc)) //does nothing in space
- playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
- damage += B.obj_integrity * 0.5 //take damage equal to 50% of remaining blob health before it tried to eat us
- if(B.obj_integrity > 100)
- B.visible_message("\The [B] strikes at \the [src] and flinches away! ",\
- "You hear a loud crack as you are washed with a wave of heat. ")
- B.take_damage(100, BURN)
- else
- B.visible_message("\The [B] strikes at \the [src] and rapidly flashes to ash. ",\
- "You hear a loud crack as you are washed with a wave of heat. ")
- Consume(B)
+/obj/machinery/power/supermatter_crystal/blob_act(obj/structure/blob/blob)
+ if(!blob || isspaceturf(loc)) //does nothing in space
+ return
+ playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, TRUE)
+ damage += blob.get_integrity() * 0.5 //take damage equal to 50% of remaining blob health before it tried to eat us
+ if(blob.get_integrity() > 100)
+ blob.visible_message("\The [blob] strikes at \the [src] and flinches away! ",\
+ "You hear a loud crack as you are washed with a wave of heat. ")
+ blob.take_damage(100, BURN)
+ else
+ blob.visible_message("\The [blob] strikes at \the [src] and rapidly flashes to ash. ",\
+ "You hear a loud crack as you are washed with a wave of heat. ")
+ Consume(blob)
/obj/machinery/power/supermatter_crystal/attack_tk(mob/user)
if(!iscarbon(user))
@@ -880,15 +881,15 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
icon_state = "darkmatter"
/obj/machinery/power/supermatter_crystal/proc/supermatter_pull(turf/center, pull_range = 10)
- playsound(src.loc, 'sound/weapons/marauder.ogg', 100, 1, extrarange = 7)
+ playsound(src.loc, 'sound/weapons/marauder.ogg', 100, TRUE, extrarange = 7)
for(var/atom/movable/P in orange(pull_range,center))
if(P.anchored || P.move_resist >= MOVE_FORCE_EXTREMELY_STRONG) //move resist memes.
return
if(ishuman(P))
var/mob/living/carbon/human/H = P
- if(H.incapacitated() || !(H.mobility_flags & MOBILITY_STAND) || H.mob_negates_gravity())
+ if(H.incapacitated() || H.body_position == LYING_DOWN || H.mob_negates_gravity())
return //You can't knock down someone who is already knocked down or has immunity to gravity
- H.visible_message("[H] is suddenly knocked down, as if [H.p_their()] [(H.get_num_legs() == 1) ? "leg had" : "legs have"] been pulled out from underneath [H.p_them()]! ",\
+ H.visible_message("[H] is suddenly knocked down, as if [H.p_their()] [(H.usable_legs == 1) ? "leg had" : "legs have"] been pulled out from underneath [H.p_them()]! ",\
"A sudden gravitational pulse knocks you down! ",\
"You hear a thud. ")
H.apply_effect(40, EFFECT_PARALYZE, 0)
diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm
index 36b59e9c5bf46..786eefeac8095 100644
--- a/code/modules/projectiles/guns/energy/energy_gun.dm
+++ b/code/modules/projectiles/guns/energy/energy_gun.dm
@@ -87,6 +87,13 @@
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
investigate_flags = ADMIN_INVESTIGATE_TARGET
+/obj/item/gun/energy/e_gun/hos/contents_explosion(severity, target)
+ if (!ammo_type || !cell)
+ name = "\improper Broken X-01 MultiPhase Energy Gun"
+ desc = "This is an expensive, modern recreation of an antique laser gun. This gun had several unique firemodes, but lacked the ability to recharge over time. Seems too be damaged to the point of not functioning, but still valuable."
+ icon_state = "hoslaser_broken"
+ update_icon()
+
/obj/item/gun/energy/e_gun/dragnet
name = "\improper DRAGnet"
desc = "The \"Dynamic Rapid-Apprehension of the Guilty\" net is a revolution in law enforcement technology."
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index b8f8f9623b95b..88c8716c6bd68 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -45,6 +45,13 @@
weapon_weight = WEAPON_LIGHT
investigate_flags = ADMIN_INVESTIGATE_TARGET
+/obj/item/gun/energy/laser/captain/contents_explosion(severity, target)
+ if (!ammo_type || !cell)
+ name = "\improper broken antique laser gun"
+ desc = "This is an antique laser gun. All craftsmanship is of the highest quality. It was decorated with leather and chrome. Seems too be damaged to the point of not functioning, but still valuable."
+ icon_state = "caplaser_broken"
+ update_icon()
+
/obj/item/gun/energy/laser/captain/scattershot
name = "scatter shot laser rifle"
icon_state = "lasercannon"
@@ -52,6 +59,10 @@
desc = "An industrial-grade heavy-duty laser rifle with a modified laser lens to scatter its shot into multiple smaller lasers. The inner-core can self-charge for theoretically infinite use."
ammo_type = list(/obj/item/ammo_casing/energy/laser/scatter, /obj/item/ammo_casing/energy/laser)
shaded_charge = FALSE
+ flags_1 = PREVENT_CONTENTS_EXPLOSION_1
+
+/obj/item/gun/energy/laser/captain/scattershot/contents_explosion(severity, target)
+ return
/obj/item/gun/energy/laser/cyborg
can_charge = FALSE
diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm
index 5d6cd84719890..be44f0a4c10da 100644
--- a/code/modules/projectiles/guns/magic/staff.dm
+++ b/code/modules/projectiles/guns/magic/staff.dm
@@ -92,6 +92,7 @@
armour_penetration = 75
block_flags = BLOCKING_ACTIVE | BLOCKING_NASTY | BLOCKING_PROJECTILE
sharpness = IS_SHARP
+ bleed_force = BLEED_DEEP_WOUND
max_charges = 4
/obj/item/gun/magic/staff/spellblade/Initialize(mapload)
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 72fe814ef336c..2248ac3b96fd8 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -504,12 +504,12 @@
if(!L.density)
// If you are moving, then bullets will hit you even if you are lying.
// This is to counter abuse in space where you can be moving via inertia while lying #11020
- if (!(L.mobility_flags & MOBILITY_STAND) && L.last_move_time + max(L.inertia_move_delay, CRAWLING_ADD_SLOWDOWN + CONFIG_GET(number/movedelay/run_delay)) > world.time)
+ if ((L.body_position == LYING_DOWN) && L.last_move_time + max(L.inertia_move_delay, CRAWLING_ADD_SLOWDOWN + CONFIG_GET(number/movedelay/run_delay)) > world.time)
return TRUE
return FALSE
- if (L.mobility_flags & MOBILITY_STAND)// if you stand, it returns true and you get hit. If you arent standing(i.e. resting), it returns false and you dont get hit. Such stupid code.
+ if(L.body_position != LYING_DOWN)// if you stand, it returns true and you get hit. If you arent standing(i.e. resting), it returns false and you dont get hit. Such stupid code.
return TRUE
- var/stunned = !CHECK_BITFIELD(L.mobility_flags, MOBILITY_USE | MOBILITY_STAND | MOBILITY_MOVE)
+ var/stunned = HAS_TRAIT(L, TRAIT_IMMOBILIZED) && HAS_TRAIT(L, TRAIT_FLOORED) && HAS_TRAIT(L, TRAIT_HANDS_BLOCKED)
return !stunned || hit_stunned_targets
return TRUE
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index 0f0f4d90dc35a..b1d8739124380 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -7,3 +7,4 @@
armor_flag = BULLET
hitsound_wall = "ricochet"
impact_effect_type = /obj/effect/temp_visual/impact_effect
+ bleed_force = BLEED_DEEP_WOUND
diff --git a/code/modules/projectiles/projectile/bullets/dart_syringe.dm b/code/modules/projectiles/projectile/bullets/dart_syringe.dm
index 2220d599a334e..22538dff1cff9 100644
--- a/code/modules/projectiles/projectile/bullets/dart_syringe.dm
+++ b/code/modules/projectiles/projectile/bullets/dart_syringe.dm
@@ -2,6 +2,7 @@
name = "dart"
icon_state = "cbbolt"
damage = 6
+ bleed_force = BLEED_SURFACE
var/piercing = FALSE
var/obj/item/reagent_containers/syringe/syringe = null
diff --git a/code/modules/projectiles/projectile/bullets/dnainjector.dm b/code/modules/projectiles/projectile/bullets/dnainjector.dm
index 081e7f22edb25..3872527018119 100644
--- a/code/modules/projectiles/projectile/bullets/dnainjector.dm
+++ b/code/modules/projectiles/projectile/bullets/dnainjector.dm
@@ -1,6 +1,7 @@
/obj/projectile/bullet/dnainjector
name = "\improper DNA injector"
icon_state = "syringeproj"
+ bleed_force = BLEED_SURFACE
var/obj/item/dnainjector/injector
damage = 5
hitsound_wall = "shatter"
diff --git a/code/modules/projectiles/projectile/bullets/grenade.dm b/code/modules/projectiles/projectile/bullets/grenade.dm
index 254594eaaf99f..16fa4a12e46ee 100644
--- a/code/modules/projectiles/projectile/bullets/grenade.dm
+++ b/code/modules/projectiles/projectile/bullets/grenade.dm
@@ -5,6 +5,7 @@
desc = "USE A WEEL GUN"
icon_state= "bolter"
damage = 60
+ bleed_force = 0
/obj/projectile/bullet/a40mm/on_hit(atom/target, blocked = FALSE)
..()
diff --git a/code/modules/projectiles/projectile/bullets/revolver.dm b/code/modules/projectiles/projectile/bullets/revolver.dm
index 270e760067d94..85ceca64e6a12 100644
--- a/code/modules/projectiles/projectile/bullets/revolver.dm
+++ b/code/modules/projectiles/projectile/bullets/revolver.dm
@@ -35,6 +35,7 @@
name = ".38 Bouncy Rubber bullet"
damage = 7
stamina = 27
+ bleed_force = BLEED_SCRATCH
ricochets_max = 5
ricochet_incidence_leeway = 70
ricochet_chance = 130
@@ -109,6 +110,7 @@
damage = 0
nodamage = TRUE
martial_arts_no_deflect = TRUE
+ bleed_force = 0
/obj/projectile/bullet/c38/mime/on_hit(atom/target, blocked = FALSE)
if(isliving(target))
diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm
index 66d3b56da9f91..86a443b61519b 100644
--- a/code/modules/projectiles/projectile/bullets/shotgun.dm
+++ b/code/modules/projectiles/projectile/bullets/shotgun.dm
@@ -8,6 +8,7 @@
damage = 10
stamina = 50
armour_penetration = -20
+ bleed_force = BLEED_TINY
/obj/projectile/bullet/incendiary/shotgun
name = "incendiary slug"
@@ -62,6 +63,7 @@
ricochets_max = 1
ricochet_chance = 50
ricochet_decay_chance = 0.9
+ bleed_force = BLEED_SCRATCH
/obj/projectile/bullet/pellet/shotgun_buckshot
name = "buckshot pellet"
@@ -80,6 +82,7 @@
ricochet_incidence_leeway = 60
ricochet_decay_chance = 0.75
armour_penetration = -20
+ bleed_force = BLEED_TINY
/obj/projectile/bullet/pellet/shotgun_rubbershot/Range()
if(damage <= 0 && tile_dropoff_s == 0)
@@ -131,6 +134,7 @@
/obj/projectile/bullet/scattershot
damage = 18
+ bleed_force = BLEED_SURFACE
//Breaching Ammo
@@ -139,6 +143,7 @@
desc = "A breaching round designed to destroy airlocks and windows with only a few shots, but is ineffective against other targets."
hitsound = 'sound/weapons/sonic_jackhammer.ogg'
damage = 10 //does shit damage to everything except doors and windows
+ bleed_force = BLEED_SURFACE
/obj/projectile/bullet/shotgun_breaching/on_hit(atom/target)
if(istype(target, /obj/structure/window) || istype(target, /obj/structure/grille) || istype(target, /obj/machinery/door) || istype(target, /obj/structure/door_assembly))
diff --git a/code/modules/projectiles/projectile/bullets/smg.dm b/code/modules/projectiles/projectile/bullets/smg.dm
index a307ee3d36c2d..71b244598c3a3 100644
--- a/code/modules/projectiles/projectile/bullets/smg.dm
+++ b/code/modules/projectiles/projectile/bullets/smg.dm
@@ -31,3 +31,4 @@
ricochet_decay_chance = 0.8
ricochet_decay_damage = 0.85
armour_penetration = -15
+ bleed_force = BLEED_SCRATCH
diff --git a/code/modules/projectiles/projectile/bullets/special.dm b/code/modules/projectiles/projectile/bullets/special.dm
index dc89a8e566667..6da5eb1a233c1 100644
--- a/code/modules/projectiles/projectile/bullets/special.dm
+++ b/code/modules/projectiles/projectile/bullets/special.dm
@@ -3,6 +3,7 @@
/obj/projectile/bullet/honker
name = "banana"
damage = 0
+ bleed_force = 0
paralyze = 60
movement_type = FLYING
projectile_piercing = ALL
@@ -11,6 +12,7 @@
icon = 'icons/obj/hydroponics/harvest.dmi'
icon_state = "banana"
range = 200
+ bleed_force = 0
/obj/projectile/bullet/honker/Initialize(mapload)
. = ..()
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index e141025b7c368..7aa387f08fa1d 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -160,7 +160,8 @@
return
M.notransform = TRUE
- M.mobility_flags = NONE
+ ADD_TRAIT(M, TRAIT_IMMOBILIZED, MAGIC_TRAIT)
+ ADD_TRAIT(M, TRAIT_HANDS_BLOCKED, MAGIC_TRAIT)
M.icon = null
M.cut_overlays()
M.invisibility = INVISIBILITY_ABSTRACT
diff --git a/code/modules/projectiles/projectile/reusable/foam_dart.dm b/code/modules/projectiles/projectile/reusable/foam_dart.dm
index 40bda2bd608ef..2401e2a77405b 100644
--- a/code/modules/projectiles/projectile/reusable/foam_dart.dm
+++ b/code/modules/projectiles/projectile/reusable/foam_dart.dm
@@ -9,6 +9,7 @@
ammo_type = /obj/item/ammo_casing/caseless/foam_dart
range = 10
martial_arts_no_deflect = TRUE
+ bleed_force = 0
var/modified = FALSE
var/obj/item/pen/pen = null
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index 806e446cffdff..a22ded82d5407 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -380,7 +380,6 @@
addiction_tick++
if(C && need_mob_update) //some of the metabolized reagents had effects on the mob that requires some updates.
C.updatehealth()
- C.update_mobility()
C.update_stamina()
update_total()
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index fbf05aae1dad2..6b483e41f06d7 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -162,7 +162,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/kahlua/on_mob_life(mob/living/carbon/M)
M.dizziness = max(0,M.dizziness-5)
M.drowsyness = max(0,M.drowsyness-3)
- M.AdjustSleeping(-40, FALSE)
+ M.AdjustSleeping(-40)
if(!HAS_TRAIT(M, TRAIT_ALCOHOL_TOLERANCE))
M.Jitter(5)
..()
@@ -1352,10 +1352,10 @@ All effects don't start immediately, but rather get worse over time; the rate is
M.slurring += 3
switch(current_cycle)
if(51 to 200)
- M.Sleeping(100, FALSE)
+ M.Sleeping(100)
. = 1
if(201 to INFINITY)
- M.AdjustSleeping(40, FALSE)
+ M.AdjustSleeping(40)
M.adjustToxLoss(2, 0)
. = 1
..()
diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index a38a27bb81b8b..4d67bdd2f423d 100644
--- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -319,7 +319,7 @@
/datum/reagent/consumable/coffee/on_mob_life(mob/living/carbon/M)
M.dizziness = max(0,M.dizziness-5)
M.drowsyness = max(0,M.drowsyness-3)
- M.AdjustSleeping(-40, FALSE)
+ M.AdjustSleeping(-40)
//310.15 is the normal bodytemp.
M.adjust_bodytemperature(25 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL)
if(holder.has_reagent(/datum/reagent/consumable/frostoil))
@@ -393,7 +393,7 @@
/datum/reagent/consumable/icecoffee/on_mob_life(mob/living/carbon/M)
M.dizziness = max(0,M.dizziness-5)
M.drowsyness = max(0,M.drowsyness-3)
- M.AdjustSleeping(-40, FALSE)
+ M.AdjustSleeping(-40)
M.adjust_bodytemperature(10 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, M.get_body_temp_normal())
M.Jitter(5)
..()
@@ -413,7 +413,7 @@
/datum/reagent/consumable/icetea/on_mob_life(mob/living/carbon/M)
M.dizziness = max(0,M.dizziness-2)
M.drowsyness = max(0,M.drowsyness-1)
- M.AdjustSleeping(-40, FALSE)
+ M.AdjustSleeping(-40)
if(M.getToxLoss() && prob(20))
M.adjustToxLoss(-1, 0)
M.adjust_bodytemperature(10 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, M.get_body_temp_normal())
@@ -459,7 +459,7 @@
M.set_drugginess(30)
M.dizziness += 1.5
M.drowsyness = 0
- M.AdjustSleeping(-40, FALSE)
+ M.AdjustSleeping(-40)
M.adjust_bodytemperature(10 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, M.get_body_temp_normal())
M.radiation += 4
..()
@@ -488,7 +488,7 @@
M.Jitter(20)
M.dizziness +=1
M.drowsyness = 0
- M.AdjustSleeping(-40, FALSE)
+ M.AdjustSleeping(-40)
M.adjust_bodytemperature(10 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, M.get_body_temp_normal())
..()
@@ -611,7 +611,7 @@
/datum/reagent/consumable/tonic/on_mob_life(mob/living/carbon/M)
M.dizziness = max(0,M.dizziness-5)
M.drowsyness = max(0,M.drowsyness-3)
- M.AdjustSleeping(-40, FALSE)
+ M.AdjustSleeping(-40)
M.adjust_bodytemperature(10 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, M.get_body_temp_normal())
..()
. = 1
@@ -630,7 +630,7 @@
M.Jitter(20)
M.dizziness +=1
M.drowsyness = 0
- M.AdjustSleeping(-40, FALSE)
+ M.AdjustSleeping(-40)
M.adjust_bodytemperature(10 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, M.get_body_temp_normal())
..()
@@ -672,7 +672,7 @@
/datum/reagent/consumable/soy_latte/on_mob_life(mob/living/carbon/M)
M.dizziness = max(0,M.dizziness-5)
M.drowsyness = max(0,M.drowsyness-3)
- M.SetSleeping(0, FALSE)
+ M.SetSleeping(0)
M.adjust_bodytemperature(5 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL)
M.Jitter(5)
if(M.getBruteLoss() && prob(20))
@@ -694,7 +694,7 @@
/datum/reagent/consumable/cafe_latte/on_mob_life(mob/living/carbon/M)
M.dizziness = max(0,M.dizziness-5)
M.drowsyness = max(0,M.drowsyness-3)
- M.SetSleeping(0, FALSE)
+ M.SetSleeping(0)
M.adjust_bodytemperature(5 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL)
M.Jitter(5)
if(M.getBruteLoss() && prob(20))
diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
index a17407ad18330..612ccc4b8f744 100644
--- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
@@ -19,7 +19,7 @@
/datum/reagent/drug/space_drugs/on_mob_life(mob/living/carbon/M)
M.set_drugginess(15)
if(isturf(M.loc) && !isspaceturf(M.loc))
- if(M.mobility_flags & MOBILITY_MOVE)
+ if(!HAS_TRAIT(M, TRAIT_IMMOBILIZED))
if(prob(10))
step(M, pick(GLOB.cardinals))
if(prob(7))
@@ -52,11 +52,11 @@
var/smoke_message = pick("You feel relaxed.", "You feel calmed.","You feel alert.","You feel rugged.")
to_chat(M, "[smoke_message] ")
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "smoked", /datum/mood_event/smoked, name)
- M.AdjustStun(-5, FALSE)
- M.AdjustKnockdown(-5, FALSE)
- M.AdjustUnconscious(-5, FALSE)
- M.AdjustParalyzed(-5, FALSE)
- M.AdjustImmobilized(-5, FALSE)
+ M.AdjustStun(-5)
+ M.AdjustKnockdown(-5)
+ M.AdjustUnconscious(-5)
+ M.AdjustParalyzed(-5)
+ M.AdjustImmobilized(-5)
..()
. = 1
@@ -91,13 +91,13 @@
M.adjustBruteLoss(rand(1,4))
M.Stun(5, 0)
to_chat(M, "You stop to furiously scratch at your skin. ")
- M.AdjustStun(-20, FALSE)
- M.AdjustKnockdown(-20, FALSE)
- M.AdjustUnconscious(-20, FALSE)
- M.AdjustImmobilized(-20, FALSE)
- M.AdjustParalyzed(-20, FALSE)
- M.adjustToxLoss(0.75, 0)
- M.adjustStaminaLoss(-18, 0)
+ M.AdjustStun(-20)
+ M.AdjustKnockdown(-20)
+ M.AdjustUnconscious(-20)
+ M.AdjustImmobilized(-20)
+ M.AdjustParalyzed(-20)
+ M.adjustToxLoss(0.75)
+ M.adjustStaminaLoss(-18)
..()
. = 1
@@ -214,12 +214,12 @@
var/high_message = pick("You feel hyper.", "You feel like you need to go faster.", "You feel like you can run the world.")
if(prob(5))
to_chat(M, "[high_message] ")
- M.AdjustStun(-40, FALSE)
- M.AdjustKnockdown(-40, FALSE)
- M.AdjustUnconscious(-40, FALSE)
- M.AdjustParalyzed(-40, FALSE)
- M.AdjustImmobilized(-40, FALSE)
- M.adjustStaminaLoss(-40, 0)
+ M.AdjustStun(-40)
+ M.AdjustKnockdown(-40)
+ M.AdjustUnconscious(-40)
+ M.AdjustParalyzed(-40)
+ M.AdjustImmobilized(-40)
+ M.adjustStaminaLoss(-40)
M.drowsyness = max(0,M.drowsyness-30)
M.Jitter(2)
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1)
@@ -229,7 +229,7 @@
. = 1
/datum/reagent/drug/methamphetamine/overdose_process(mob/living/M)
- if((M.mobility_flags & MOBILITY_MOVE) && !ismovable(M.loc))
+ if(!HAS_TRAIT(M, TRAIT_IMMOBILIZED) && !ismovable(M.loc))
for(var/i in 1 to 4)
step(M, pick(GLOB.cardinals))
if(prob(20))
@@ -256,7 +256,7 @@
..()
/datum/reagent/drug/methamphetamine/addiction_act_stage3(mob/living/M)
- if((M.mobility_flags & MOBILITY_MOVE) && !ismovable(M.loc))
+ if(!HAS_TRAIT(M, TRAIT_IMMOBILIZED) && !ismovable(M.loc))
for(var/i = 0, i < 4, i++)
step(M, pick(GLOB.cardinals))
M.Jitter(15)
@@ -266,7 +266,7 @@
..()
/datum/reagent/drug/methamphetamine/addiction_act_stage4(mob/living/carbon/human/M)
- if((M.mobility_flags & MOBILITY_MOVE) && !ismovable(M.loc))
+ if(!HAS_TRAIT(M, TRAIT_IMMOBILIZED) && !ismovable(M.loc))
for(var/i = 0, i < 8, i++)
step(M, pick(GLOB.cardinals))
M.Jitter(20)
@@ -318,7 +318,7 @@
M.adjustStaminaLoss(-5, 0)
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 4)
M.hallucination += 5
- if((M.mobility_flags & MOBILITY_MOVE) && !ismovable(M.loc))
+ if(!HAS_TRAIT(M, TRAIT_IMMOBILIZED) && !ismovable(M.loc))
step(M, pick(GLOB.cardinals))
step(M, pick(GLOB.cardinals))
..()
@@ -326,7 +326,7 @@
/datum/reagent/drug/bath_salts/overdose_process(mob/living/M)
M.hallucination += 5
- if((M.mobility_flags & MOBILITY_MOVE) && !ismovable(M.loc))
+ if(!HAS_TRAIT(M, TRAIT_IMMOBILIZED) && !ismovable(M.loc))
for(var/i in 1 to 8)
step(M, pick(GLOB.cardinals))
if(prob(20))
@@ -337,7 +337,7 @@
/datum/reagent/drug/bath_salts/addiction_act_stage1(mob/living/M)
M.hallucination += 10
- if((M.mobility_flags & MOBILITY_MOVE) && !ismovable(M.loc))
+ if(!HAS_TRAIT(M, TRAIT_IMMOBILIZED) && !ismovable(M.loc))
for(var/i = 0, i < 8, i++)
step(M, pick(GLOB.cardinals))
M.Jitter(5)
@@ -348,7 +348,7 @@
/datum/reagent/drug/bath_salts/addiction_act_stage2(mob/living/M)
M.hallucination += 20
- if((M.mobility_flags & MOBILITY_MOVE) && !ismovable(M.loc))
+ if(!HAS_TRAIT(M, TRAIT_IMMOBILIZED) && !ismovable(M.loc))
for(var/i = 0, i < 8, i++)
step(M, pick(GLOB.cardinals))
M.Jitter(10)
@@ -360,7 +360,7 @@
/datum/reagent/drug/bath_salts/addiction_act_stage3(mob/living/M)
M.hallucination += 30
- if((M.mobility_flags & MOBILITY_MOVE) && !ismovable(M.loc))
+ if(!HAS_TRAIT(M, TRAIT_IMMOBILIZED) && !ismovable(M.loc))
for(var/i = 0, i < 12, i++)
step(M, pick(GLOB.cardinals))
M.Jitter(15)
@@ -372,7 +372,7 @@
/datum/reagent/drug/bath_salts/addiction_act_stage4(mob/living/carbon/human/M)
M.hallucination += 30
- if((M.mobility_flags & MOBILITY_MOVE) && !ismovable(M.loc))
+ if(!HAS_TRAIT(M, TRAIT_IMMOBILIZED) && !ismovable(M.loc))
for(var/i = 0, i < 16, i++)
step(M, pick(GLOB.cardinals))
M.Jitter(50)
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index 64eb9f0e7aceb..ed94c4991864a 100755
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -183,11 +183,11 @@
/datum/reagent/consumable/sugar/overdose_start(mob/living/M)
to_chat(M, "You go into hyperglycaemic shock! Lay off the twinkies! ")
- M.AdjustSleeping(600, FALSE)
+ M.AdjustSleeping(600)
. = 1
/datum/reagent/consumable/sugar/overdose_process(mob/living/M)
- M.AdjustSleeping(40, FALSE)
+ M.AdjustSleeping(40)
..()
. = 1
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index c7ce0a2806bbc..c38ccc49a781d 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -63,11 +63,11 @@
REMOVE_TRAITS_NOT_IN(M, list(SPECIES_TRAIT, ROUNDSTART_TRAIT, ORGAN_TRAIT, TRAIT_GENERIC))
M.set_blurriness(0)
M.set_blindness(0)
- M.SetKnockdown(0, FALSE)
- M.SetStun(0, FALSE)
- M.SetUnconscious(0, FALSE)
- M.SetParalyzed(0, FALSE)
- M.SetImmobilized(0, FALSE)
+ M.SetKnockdown(0)
+ M.SetStun(0)
+ M.SetUnconscious(0)
+ M.SetParalyzed(0)
+ M.SetImmobilized(0)
M.silent = FALSE
M.dizziness = 0
M.disgust = 0
@@ -105,11 +105,11 @@
/datum/reagent/medicine/synaptizine/on_mob_life(mob/living/carbon/M)
M.drowsyness = max(M.drowsyness-5, 0)
- M.AdjustStun(-20, FALSE)
- M.AdjustKnockdown(-20, FALSE)
- M.AdjustUnconscious(-20, FALSE)
- M.AdjustImmobilized(-20, FALSE)
- M.AdjustParalyzed(-20, FALSE)
+ M.AdjustStun(-20)
+ M.AdjustKnockdown(-20)
+ M.AdjustUnconscious(-20)
+ M.AdjustImmobilized(-20)
+ M.AdjustParalyzed(-20)
if(holder.has_reagent(/datum/reagent/toxin/mindbreaker))
holder.remove_reagent(/datum/reagent/toxin/mindbreaker, 5)
M.hallucination = max(0, M.hallucination - 10)
@@ -682,7 +682,7 @@
to_chat(M, "Your hands spaz out and you drop what you were holding! ")
M.Jitter(10)
- M.AdjustAllImmobility(-20, FALSE)
+ M.AdjustAllImmobility(-20)
M.adjustStaminaLoss(-10*REM, FALSE)
..()
return TRUE
@@ -791,7 +791,7 @@
if(12 to 24)
M.drowsyness += 1
if(24 to INFINITY)
- M.Sleeping(40, 0)
+ M.Sleeping(40)
. = 1
..()
@@ -926,7 +926,7 @@
M.adjustStaminaLoss(-0.5*REM, 0)
. = 1
if(prob(20))
- M.AdjustAllImmobility(-20, FALSE)
+ M.AdjustAllImmobility(-20)
..()
/datum/reagent/medicine/epinephrine/overdose_process(mob/living/M)
@@ -1069,7 +1069,7 @@
M.adjustToxLoss(-1*REM, 0)
M.adjustBruteLoss(-1*REM, 0)
M.adjustFireLoss(-1*REM, 0)
- M.AdjustAllImmobility(-60, FALSE)
+ M.AdjustAllImmobility(-60)
M.adjustStaminaLoss(-35*REM, 0)
..()
. = 1
@@ -1129,7 +1129,7 @@
metabolization_rate = 0.5 * REAGENTS_METABOLISM
/datum/reagent/medicine/insulin/on_mob_life(mob/living/carbon/M)
- if(M.AdjustSleeping(-20, FALSE))
+ if(M.AdjustSleeping(-20))
. = 1
M.reagents.remove_reagent(/datum/reagent/consumable/sugar, 3)
..()
@@ -1386,6 +1386,8 @@
M.adjustToxLoss(-5*REM, 0)
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, -15*REM)
M.adjustCloneLoss(-3*REM, 0)
+ if (M.blood_volume < BLOOD_VOLUME_NORMAL)
+ M.blood_volume = max(M.blood_volume, min(M.blood_volume + 4, BLOOD_VOLUME_NORMAL))
..()
. = 1
@@ -1472,7 +1474,7 @@
overdose_threshold = 30
/datum/reagent/medicine/changelingadrenaline/on_mob_life(mob/living/carbon/M as mob)
- M.AdjustAllImmobility(-20, FALSE)
+ M.AdjustAllImmobility(-20)
M.adjustStaminaLoss(-20, 0)
..()
return TRUE
@@ -1565,7 +1567,7 @@
/datum/reagent/medicine/modafinil/on_mob_life(mob/living/carbon/M)
if(!overdosed) // We do not want any effects on OD
overdose_threshold = overdose_threshold + rand(-10,10)/10 // for extra fun
- M.AdjustAllImmobility(-20, FALSE)
+ M.AdjustAllImmobility(-20)
M.adjustStaminaLoss(-15*REM, 0)
M.Jitter(1)
metabolization_rate = 0.01 * REAGENTS_METABOLISM * rand(5,20) // randomizes metabolism between 0.02 and 0.08 per tick
@@ -1596,13 +1598,13 @@
if(prob(20))
to_chat(M, "You have a sudden fit!")
M.emote("moan")
- M.Paralyze(20, 1, 0) // you should be in a bad spot at this point unless epipen has been used
+ M.Paralyze(20) // you should be in a bad spot at this point unless epipen has been used
if(81)
to_chat(M, "You feel too exhausted to continue!") // at this point you will eventually die unless you get charcoal
M.adjustOxyLoss(0.1*REM, 0)
M.adjustStaminaLoss(0.1*REM, 0)
if(82 to INFINITY)
- M.Sleeping(100, 0, TRUE)
+ M.Sleeping(100)
M.adjustOxyLoss(1.5*REM, 0)
M.adjustStaminaLoss(1.5*REM, 0)
..()
@@ -1672,7 +1674,7 @@
/datum/reagent/medicine/polypyr //This is intended to be an ingredient in advanced chems.
name = "Polypyrylium Oligomers"
- description = "A purple mixture of short polyelectrolyte chains not easily synthesized in the laboratory. It is valued as an intermediate in the synthesis of the cutting edge pharmaceuticals."
+ description = "A purple mixture of short polyelectrolyte chains not easily synthesized in the laboratory. It is a powerful pharmaceutical drug which provides minor healing and prevents bloodloss, making it incredibly useful for the synthesis of other drugs."
reagent_state = SOLID
color = "#9423FF"
chem_flags = CHEMICAL_RNG_GENERAL | CHEMICAL_RNG_FUN | CHEMICAL_RNG_BOTANY | CHEMICAL_GOAL_BOTANIST_HARVEST
@@ -1683,10 +1685,9 @@
/datum/reagent/medicine/polypyr/on_mob_life(mob/living/carbon/M) //I wanted a collection of small positive effects, this is as hard to obtain as coniine after all.
M.adjustOrganLoss(ORGAN_SLOT_LUNGS, -0.25)
M.adjustBruteLoss(-0.35, 0)
- if(prob(50))
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- H.bleed_rate = max(H.bleed_rate - 1, 0)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ H.cauterise_wounds(0.1)
..()
. = 1
@@ -1705,7 +1706,7 @@
/datum/reagent/medicine/stabilizing_nanites
name = "Stabilizing nanites"
- description = "Rapidly heals a patient out of crit by regenerating damaged cells. Nanites distribution in the blood makes them ineffective against moderately healthy targets."
+ description = "Rapidly heals a patient out of crit by regenerating damaged cells and causing blood to clot, preventing bleeding. Nanites distribution in the blood makes them ineffective against moderately healthy targets."
reagent_state = LIQUID
color = "#000000"
chem_flags = CHEMICAL_NOT_SYNTH | CHEMICAL_RNG_GENERAL | CHEMICAL_RNG_FUN | CHEMICAL_RNG_BOTANY
@@ -1722,4 +1723,12 @@
if(prob(20))
M.Jitter(5)
M.losebreath = 0
+ if (M.blood_volume < BLOOD_VOLUME_SAFE)
+ M.blood_volume = max(M.blood_volume, min(M.blood_volume + 4, BLOOD_VOLUME_SAFE))
..()
+
+/datum/reagent/medicine/stabilizing_nanites/on_mob_metabolize(mob/living/L)
+ ADD_TRAIT(L, TRAIT_NO_BLEEDING, type)
+
+/datum/reagent/medicine/stabilizing_nanites/on_mob_end_metabolize(mob/living/L)
+ REMOVE_TRAIT(L, TRAIT_NO_BLEEDING, type)
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index cd5a95bbe2d52..ed255d284557b 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -320,10 +320,16 @@
return
return ..()
+/datum/reagent/fuel/unholywater/on_mob_metabolize(mob/living/L)
+ ADD_TRAIT(L, TRAIT_NO_BLEEDING, type)
+
+/datum/reagent/fuel/unholywater/on_mob_end_metabolize(mob/living/L)
+ REMOVE_TRAIT(L, TRAIT_NO_BLEEDING, type)
+
/datum/reagent/fuel/unholywater/on_mob_life(mob/living/carbon/M)
if(iscultist(M))
M.drowsyness = max(M.drowsyness-5, 0)
- M.AdjustAllImmobility(-40, FALSE)
+ M.AdjustAllImmobility(-40)
M.adjustStaminaLoss(-10, 0)
M.adjustToxLoss(-2, 0)
M.adjustOxyLoss(-2, 0)
@@ -847,7 +853,7 @@
taste_mult = 0 // apparently tasteless.
/datum/reagent/mercury/on_mob_life(mob/living/carbon/M)
- if((M.mobility_flags & MOBILITY_MOVE) && !isspaceturf(M.loc))
+ if(!HAS_TRAIT(src, TRAIT_IMMOBILIZED) && !isspaceturf(M.loc))
step(M, pick(GLOB.cardinals))
if(prob(5))
M.emote(pick("twitch","drool","moan"))
@@ -928,7 +934,7 @@
taste_description = "metal"
/datum/reagent/lithium/on_mob_life(mob/living/carbon/M)
- if((M.mobility_flags & MOBILITY_MOVE) && !isspaceturf(M.loc) && isturf(M.loc))
+ if(!HAS_TRAIT(M, TRAIT_IMMOBILIZED) && !isspaceturf(M.loc) && isturf(M.loc))
step(M, pick(GLOB.cardinals))
if(prob(5))
M.emote(pick("twitch","drool","moan"))
@@ -2160,7 +2166,7 @@
/datum/reagent/eldritch/on_mob_life(mob/living/carbon/M)
if(IS_HERETIC(M))
M.drowsyness = max(M.drowsyness-5, 0)
- M.AdjustAllImmobility(-40, FALSE)
+ M.AdjustAllImmobility(-40)
M.adjustStaminaLoss(-10, FALSE)
M.adjustToxLoss(-2, FALSE)
M.adjustOxyLoss(-2, FALSE)
diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
index 3d8aa24424613..c22f01d136836 100644
--- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
@@ -283,7 +283,7 @@
/datum/reagent/teslium/energized_jelly/on_mob_life(mob/living/carbon/M)
if(isoozeling(M))
shock_timer = 0 //immune to shocks
- M.AdjustAllImmobility(-40, FALSE)
+ M.AdjustAllImmobility(-40)
M.adjustStaminaLoss(-2, 0)
if(isluminescent(M))
var/mob/living/carbon/human/H = M
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index 26a654c2e792d..567fc0d499958 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -288,10 +288,10 @@
M.confused += 2
M.drowsyness += 2
if(10 to 50)
- M.Sleeping(40, 0)
+ M.Sleeping(40)
. = 1
if(51 to INFINITY)
- M.Sleeping(40, 0)
+ M.Sleeping(40)
M.adjustToxLoss((current_cycle - 50)*REM, 0)
. = 1
..()
@@ -310,9 +310,9 @@
/datum/reagent/toxin/fakebeer/on_mob_life(mob/living/carbon/M)
switch(current_cycle)
if(1 to 50)
- M.Sleeping(40, 0)
+ M.Sleeping(40)
if(51 to INFINITY)
- M.Sleeping(40, 0)
+ M.Sleeping(40)
M.adjustToxLoss((current_cycle - 50)*REM, 0)
return ..()
@@ -486,7 +486,7 @@
if(M.toxloss <= 60)
M.adjustToxLoss(1*REM, 0)
if(current_cycle >= 18)
- M.Sleeping(40, 0)
+ M.Sleeping(40)
..()
return TRUE
@@ -504,7 +504,7 @@
M.losebreath += 1
if(prob(8))
to_chat(M, "You feel horrendously weak!")
- M.Stun(40, 0)
+ M.Stun(40)
M.adjustToxLoss(2*REM, 0)
return ..()
@@ -566,7 +566,7 @@
var/picked_option = rand(1,3)
switch(picked_option)
if(1)
- C.Paralyze(60, 0)
+ C.Paralyze(60)
. = TRUE
if(2)
C.losebreath += 10
@@ -596,7 +596,7 @@
/datum/reagent/toxin/pancuronium/on_mob_life(mob/living/carbon/M)
if(current_cycle >= 10)
- M.Stun(40, 0)
+ M.Stun(40)
. = TRUE
if(prob(20))
M.losebreath += 4
@@ -614,7 +614,7 @@
/datum/reagent/toxin/sodium_thiopental/on_mob_life(mob/living/carbon/M)
if(current_cycle >= 10)
- M.Sleeping(40, 0)
+ M.Sleeping(40)
M.adjustStaminaLoss(10*REM, 0)
..()
return TRUE
@@ -631,7 +631,7 @@
/datum/reagent/toxin/sulfonal/on_mob_life(mob/living/carbon/M)
if(current_cycle >= 22)
- M.Sleeping(40, 0)
+ M.Sleeping(40)
return ..()
/datum/reagent/toxin/amanitin
@@ -718,7 +718,7 @@
/datum/reagent/toxin/curare/on_mob_life(mob/living/carbon/M)
if(current_cycle >= 11)
- M.Paralyze(60, 0)
+ M.Paralyze(60)
M.adjustOxyLoss(1*REM, 0)
. = 1
..()
@@ -736,7 +736,8 @@
/datum/reagent/toxin/heparin/on_mob_life(mob/living/carbon/M)
if(ishuman(M))
var/mob/living/carbon/human/H = M
- H.bleed_rate = min(H.bleed_rate + 2, 8)
+ if (!H.is_bleeding())
+ H.add_bleeding(BLEED_SURFACE)
H.adjustBruteLoss(1, 0) //Brute damage increases with the amount they're bleeding
. = 1
return ..() || .
@@ -855,7 +856,7 @@
holder.remove_reagent(type, actual_metaboliztion_rate * M.metabolism_efficiency)
M.adjustToxLoss(actual_toxpwr*REM, 0)
if(prob(10))
- M.Paralyze(20, 0)
+ M.Paralyze(20)
. = 1
..()
@@ -969,3 +970,8 @@
M.silent = max(M.silent, 3)
M.confused = max(M.confused, 3)
..()
+
+/datum/reagent/toxin/morphvenom/mimite
+ name = "Mimite venom"
+ description = "Deadly venom of a shapeshifting creature."
+ color = "#330063"
diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
index c881dd1653ea5..77afff5240b00 100644
--- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
+++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
@@ -267,7 +267,7 @@
var/range = created_volume/3
if(isatom(holder.my_atom))
var/atom/A = holder.my_atom
- A.flash_lighting_fx(_range = (range + 2))
+ A.flash_lighting_fx(range = (range + 2))
for(var/mob/living/carbon/C in hearers(range, location))
if(C.flash_act())
if(get_dist(C, location) < 4)
@@ -288,7 +288,7 @@
var/range = created_volume/10
if(isatom(holder.my_atom))
var/atom/A = holder.my_atom
- A.flash_lighting_fx(_range = (range + 2))
+ A.flash_lighting_fx(range = (range + 2))
for(var/mob/living/carbon/C in hearers(range, location))
if(C.flash_act())
if(get_dist(C, location) < 4)
diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm
index e284a050710c7..37cb861f31e3b 100644
--- a/code/modules/reagents/reagent_containers/blood_pack.dm
+++ b/code/modules/reagents/reagent_containers/blood_pack.dm
@@ -3,17 +3,17 @@
desc = "Contains blood used for transfusion. Must be attached to an IV drip."
icon = 'icons/obj/bloodpack.dmi'
icon_state = "bloodpack"
- volume = 200
+ volume = 400
var/blood_type = null
var/unique_blood = null
var/labelled = 0
reagent_flags = TRANSPARENT | ABSOLUTELY_GRINDABLE
- fill_icon_thresholds = list(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
+ fill_icon_thresholds = list(10, 40, 60, 80, 100, 120, 140, 160, 180, 200)
/obj/item/reagent_containers/blood/Initialize(mapload)
. = ..()
if(blood_type != null)
- reagents.add_reagent(unique_blood ? unique_blood : /datum/reagent/blood, 200, list("viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null))
+ reagents.add_reagent(unique_blood ? unique_blood : /datum/reagent/blood, 400, list("viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null))
update_icon()
/obj/item/reagent_containers/blood/examine(mob/user)
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index c4f06eec402b9..91eae09b1b5e3 100755
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -245,7 +245,7 @@
flags_inv = HIDEHAIR
slot_flags = ITEM_SLOT_HEAD
resistance_flags = NONE
- armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 75, ACID = 50, STAMINA = 0) //Weak melee protection, because you can wear it on your head
+ armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 75, ACID = 50, STAMINA = 0, BLEED = 0) //Weak melee protection, because you can wear it on your head
slot_equipment_priority = list( \
ITEM_SLOT_BACK, ITEM_SLOT_ID,\
ITEM_SLOT_ICLOTHING, ITEM_SLOT_OCLOTHING,\
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index 457950ed9a53c..ae636947e99ae 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -62,7 +62,9 @@
/obj/item/reagent_containers/spray/proc/spray(atom/A, mob/user)
var/range = max(min(current_range, get_dist(src, A)), 1)
+
var/obj/effect/decal/chempuff/D = new /obj/effect/decal/chempuff(get_turf(src))
+
D.create_reagents(amount_per_transfer_from_this)
var/puff_reagent_left = range //how many turf, mob or dense objet we can react with before we consider the chem puff consumed
if(stream_mode)
@@ -72,6 +74,7 @@
reagents.trans_to(D, amount_per_transfer_from_this, 1/range)
D.color = mix_color_from_reagents(D.reagents.reagent_list)
var/wait_step = max(round(2+3/range), 2)
+
do_spray(A, wait_step, D, range, puff_reagent_left, user)
/obj/item/reagent_containers/spray/proc/do_spray(atom/A, wait_step, obj/effect/decal/chempuff/D, range, puff_reagent_left, mob/user)
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index f3ea9bee68909..2d275eb4daed0 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -126,6 +126,8 @@
layer = ABOVE_WINDOW_LAYER
reagent_id = /datum/reagent/consumable/condensedcapsaicin
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/peppertank, 30)
+
/obj/structure/reagent_dispensers/peppertank/Initialize(mapload)
. = ..()
if(prob(1))
@@ -182,6 +184,7 @@
layer = ABOVE_WINDOW_LAYER
reagent_id = /datum/reagent/consumable/virus_food
+MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/virusfood, 30)
/obj/structure/reagent_dispensers/cooking_oil
name = "vat of cooking oil"
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index 361e884d78e20..412a5fb6cb05c 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -5,7 +5,7 @@
/obj/machinery/disposal
icon = 'icons/obj/atmospherics/pipes/disposal.dmi'
density = TRUE
- armor = list(MELEE = 25, BULLET = 10, LASER = 10, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 90, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 25, BULLET = 10, LASER = 10, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 90, ACID = 30, STAMINA = 0, BLEED = 0)
max_integrity = 200
resistance_flags = FIRE_PROOF
interaction_flags_machine = INTERACT_MACHINE_OPEN | INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON
@@ -144,7 +144,7 @@
. = TRUE
update_appearance()
-/obj/machinery/disposal/relaymove(mob/user)
+/obj/machinery/disposal/relaymove(mob/living/user, direction)
attempt_escape(user)
// resist to escape the bin
diff --git a/code/modules/recycling/disposal/holder.dm b/code/modules/recycling/disposal/holder.dm
index 159024937c109..4ff466db0f06c 100644
--- a/code/modules/recycling/disposal/holder.dm
+++ b/code/modules/recycling/disposal/holder.dm
@@ -135,7 +135,7 @@
// called when player tries to move while in a pipe
-/obj/structure/disposalholder/relaymove(mob/user)
+/obj/structure/disposalholder/relaymove(mob/living/user, direction)
if(user.incapacitated())
return
for(var/mob/M as() in hearers(5, get_turf(src)))
diff --git a/code/modules/recycling/disposal/pipe.dm b/code/modules/recycling/disposal/pipe.dm
index d3bf772f83c36..79c16ade1c3c1 100644
--- a/code/modules/recycling/disposal/pipe.dm
+++ b/code/modules/recycling/disposal/pipe.dm
@@ -9,7 +9,7 @@
obj_flags = CAN_BE_HIT | ON_BLUEPRINTS
dir = NONE // dir will contain dominant direction for junction pipes
max_integrity = 200
- armor = list(MELEE = 25, BULLET = 10, LASER = 10, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 90, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 25, BULLET = 10, LASER = 10, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 90, ACID = 30, STAMINA = 0, BLEED = 0)
layer = DISPOSAL_PIPE_LAYER // slightly lower than wires and other pipes
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
var/dpdir = NONE // bitmask of pipe directions
diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm
index f388dbfb71a8f..b1bfcdfa293d8 100644
--- a/code/modules/research/designs/machine_designs.dm
+++ b/code/modules/research/designs/machine_designs.dm
@@ -274,14 +274,6 @@
category = list("Research Machinery")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
-/datum/design/board/experimentor
- name = "Machine Design (E.X.P.E.R.I-MENTOR Board)"
- desc = "The circuit board for an E.X.P.E.R.I-MENTOR."
- id = "experimentor"
- build_path = /obj/item/circuitboard/machine/experimentor
- category = list("Research Machinery")
- departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
-
/datum/design/board/protolathe
name = "Machine Design (Protolathe Board)"
desc = "The circuit board for a protolathe."
diff --git a/code/modules/research/designs/wiremod_designs.dm b/code/modules/research/designs/wiremod_designs.dm
index f4dd9043ceb0f..abcf2ef825bb1 100644
--- a/code/modules/research/designs/wiremod_designs.dm
+++ b/code/modules/research/designs/wiremod_designs.dm
@@ -425,7 +425,7 @@
name = "Compact Remote Shell"
desc = "A handheld shell with one big button."
id = "compact_remote_shell"
- build_path = /obj/item/compact_remote
+ build_path = /obj/item/shell/compact_remote
materials = list(/datum/material/glass = 2000, /datum/material/iron = 5000)
build_type = PROTOLATHE | COMPONENT_PRINTER
category = list(WIREMOD_CIRCUITRY, WIREMOD_SHELLS)
@@ -434,7 +434,7 @@
name = "Controller Shell"
desc = "A handheld shell with several buttons."
id = "controller_shell"
- build_path = /obj/item/controller
+ build_path = /obj/item/shell/controller
build_type = PROTOLATHE | COMPONENT_PRINTER
materials = list(/datum/material/glass = 2000, /datum/material/iron = 7000)
category = list(WIREMOD_CIRCUITRY, WIREMOD_SHELLS)
@@ -443,7 +443,7 @@
name = "Scanner Shell"
desc = "A handheld scanner shell that can scan entities."
id = "scanner_shell"
- build_path = /obj/item/wiremod_scanner
+ build_path = /obj/item/shell/wiremod_scanner
build_type = PROTOLATHE | COMPONENT_PRINTER
materials = list(/datum/material/glass = 4000, /datum/material/iron = 5000)
category = list(WIREMOD_CIRCUITRY, WIREMOD_SHELLS)
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
deleted file mode 100644
index a64e6ec972681..0000000000000
--- a/code/modules/research/experimentor.dm
+++ /dev/null
@@ -1,672 +0,0 @@
-//this is designed to replace the destructive analyzer
-
-//NEEDS MAJOR CODE CLEANUP
-
-#define SCANTYPE_POKE 1
-#define SCANTYPE_IRRADIATE 2
-#define SCANTYPE_GAS 3
-#define SCANTYPE_HEAT 4
-#define SCANTYPE_COLD 5
-#define SCANTYPE_OBLITERATE 6
-#define SCANTYPE_DISCOVER 7
-
-#define EFFECT_PROB_VERYLOW 20
-#define EFFECT_PROB_LOW 35
-#define EFFECT_PROB_MEDIUM 50
-#define EFFECT_PROB_HIGH 75
-#define EFFECT_PROB_VERYHIGH 95
-
-#define FAIL 8
-/obj/machinery/rnd/experimentor
- name = "\improper E.X.P.E.R.I-MENTOR"
- desc = "A \"replacement\" for the destructive analyzer with a slight tendency to catastrophically fail."
- icon = 'icons/obj/machines/heavy_lathe.dmi'
- icon_state = "h_lathe"
- density = TRUE
- use_power = IDLE_POWER_USE
- circuit = /obj/item/circuitboard/machine/experimentor
- var/recentlyExperimented = 0
- var/mob/trackedIan
- var/mob/trackedRuntime
- var/badThingCoeff = 0
- var/resetTime = 15
- var/cloneMode = FALSE
- var/list/item_reactions = list()
- var/static/list/valid_items = list() //valid items for special reactions like transforming
- var/list/critical_items_typecache //items that can cause critical reactions
- var/banned_typecache // items that won't be produced
-
-/obj/machinery/rnd/experimentor/proc/ConvertReqString2List(list/source_list)
- var/list/temp_list = params2list(source_list)
- for(var/O in temp_list)
- temp_list[O] = text2num(temp_list[O])
- return temp_list
-
-/obj/machinery/rnd/experimentor/proc/valid_items()
- if (!isnull(valid_items))
- return valid_items
- var/static/list/banned_typecache = typecacheof(list(
- /obj/item/stock_parts/cell/infinite,
- /obj/item/grenade/chem_grenade/tuberculosis
- ))
-
- valid_items = list()
-
- for(var/I in typesof(/obj/item))
- if(ispath(I, /obj/item/relic))
- item_reactions["[I]"] = SCANTYPE_DISCOVER
- else
- item_reactions["[I]"] = pick(SCANTYPE_POKE,SCANTYPE_IRRADIATE,SCANTYPE_GAS,SCANTYPE_HEAT,SCANTYPE_COLD,SCANTYPE_OBLITERATE)
-
- if(is_type_in_typecache(I, banned_typecache))
- continue
-
- if(ispath(I, /obj/item/stock_parts) || ispath(I, /obj/item/grenade/chem_grenade) || ispath(I, /obj/item/kitchen))
- var/obj/item/tempCheck = I
- if(initial(tempCheck.icon_state) != null) //check it's an actual usable item, in a hacky way
- valid_items["[I]"] += 15
-
- if(ispath(I, /obj/item/reagent_containers/food))
- var/obj/item/tempCheck = I
- if(initial(tempCheck.icon_state) != null) //check it's an actual usable item, in a hacky way
- valid_items["[I]"] += rand(1,4)
- return valid_items
-
-/obj/machinery/rnd/experimentor/Initialize(mapload)
- . = ..()
-
- trackedIan = locate(/mob/living/simple_animal/pet/dog/corgi/Ian) in GLOB.mob_living_list
- trackedRuntime = locate(/mob/living/simple_animal/pet/cat/Runtime) in GLOB.mob_living_list
-
- critical_items_typecache = typecacheof(list(
- /obj/item/construction/rcd,
- /obj/item/grenade,
- /obj/item/aicard,
- /obj/item/storage/backpack/holding,
- /obj/item/slime_extract,
- /obj/item/transfer_valve))
-
-/obj/machinery/rnd/experimentor/RefreshParts()
- for(var/obj/item/stock_parts/manipulator/M in component_parts)
- if(resetTime > 0 && (resetTime - M.rating) >= 1)
- resetTime -= M.rating
- for(var/obj/item/stock_parts/scanning_module/M in component_parts)
- badThingCoeff += M.rating*2
- for(var/obj/item/stock_parts/micro_laser/M in component_parts)
- badThingCoeff += M.rating
-
-/obj/machinery/rnd/experimentor/examine(mob/user)
- . = ..()
- if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Malfunction probability reduced by [badThingCoeff]% . Cooldown interval between experiments at [resetTime*0.1] seconds. "
-
-/obj/machinery/rnd/experimentor/proc/checkCircumstances(obj/item/O)
- //snowflake check to only take "made" bombs
- if(istype(O, /obj/item/transfer_valve))
- var/obj/item/transfer_valve/T = O
- if(!T.tank_one || !T.tank_two || !T.attached_device)
- return FALSE
- return TRUE
-
-/obj/machinery/rnd/experimentor/Insert_Item(obj/item/O, mob/user)
- if(user.a_intent != INTENT_HARM)
- . = 1
- if(!is_insertion_ready(user))
- return
- if(!user.transferItemToLoc(O, src))
- return
- loaded_item = O
- to_chat(user, "You add [O] to the machine. ")
- flick("h_lathe_load", src)
-
-/obj/machinery/rnd/experimentor/default_deconstruction_crowbar(obj/item/O)
- ejectItem()
- . = ..(O)
-
-/obj/machinery/rnd/experimentor/ui_interact(mob/user)
- var/list/dat = list("")
- if(!linked_console)
- dat += "Scan for R&D Console "
- if(loaded_item)
- dat += "Loaded Item: [loaded_item]"
-
- dat += ""
- if(istype(loaded_item,/obj/item/relic))
- dat += "Discover "
- dat += "Eject "
- var/list/listin = SSresearch.techweb_boost_items
- if(listin)
- var/list/output = list("Research Boost Data: ")
- var/list/res = list("Already researched: ")
- var/list/boosted = list("Already boosted: ")
- for(var/node_id in listin)
- var/datum/techweb_node/N = SSresearch.techweb_node_by_id(node_id)
- var/str = "[N.display_name] : [listin[N]] points. "
- if(SSresearch.science_tech.researched_nodes[N.id])
- res += str
- else if(SSresearch.science_tech.boosted_nodes[N.id])
- boosted += str
- if(SSresearch.science_tech.visible_nodes[N.id]) //JOY OF DISCOVERY!
- output += str
- output += boosted + res
- dat += output
- else
- dat += "Nothing loaded. "
- dat += "Refresh "
- dat += "Close "
- var/datum/browser/popup = new(user, "experimentor","Experimentor", 700, 400, src)
- popup.set_content(dat.Join(" "))
- popup.open()
- onclose(user, "experimentor")
-
-/obj/machinery/rnd/experimentor/Topic(href, href_list)
- if(..())
- return
- usr.set_machine(src)
-
- var/scantype = href_list["function"]
- var/obj/item/process = locate(href_list["item"]) in src
-
- if(href_list["close"])
- usr << browse(null, "window=experimentor")
- return
- if(scantype == "search")
- var/obj/machinery/computer/rdconsole/D = locate(/obj/machinery/computer/rdconsole) in oview(5,src)
- if(D)
- linked_console = D
- else if(scantype == "eject")
- ejectItem()
- else if(scantype == "refresh")
- updateUsrDialog()
- else
- if(recentlyExperimented)
- to_chat(usr, "[src] has been used too recently! ")
- else if(!loaded_item)
- to_chat(usr, "[src] is not currently loaded! ")
- else if(!process || process != loaded_item) //Interface exploit protection (such as hrefs or swapping items with interface set to old item)
- to_chat(usr, "Interface failure detected in [src]. Please try again. ")
- else
- var/dotype
- if(text2num(scantype) == SCANTYPE_DISCOVER)
- dotype = SCANTYPE_DISCOVER
- else
- dotype = matchReaction(process,scantype)
- experiment(dotype,process)
- use_power(750)
- if(dotype != FAIL)
- var/list/nodes = techweb_item_boost_check(process)
- var/picked = pick_weight(nodes) //This should work.
- if(linked_console)
- linked_console.stored_research.boost_with_path(SSresearch.techweb_node_by_id(picked), process.type)
- updateUsrDialog()
-
-/obj/machinery/rnd/experimentor/proc/matchReaction(matching,reaction)
- var/obj/item/D = matching
- if(D)
- if(item_reactions.Find("[D.type]"))
- var/tor = item_reactions["[D.type]"]
- if(tor == text2num(reaction))
- return tor
- else
- return FAIL
- else
- return FAIL
- else
- return FAIL
-
-/obj/machinery/rnd/experimentor/proc/ejectItem(delete=FALSE)
- if(loaded_item)
- if(cloneMode)
- visible_message("A duplicate [loaded_item] pops out! ")
- var/type_to_make = loaded_item.type
- new type_to_make(get_turf(pick(oview(1,src))))
- cloneMode = FALSE
- return
- var/turf/dropturf = get_turf(pick(view(1,src)))
- if(!dropturf) //Failsafe to prevent the object being lost in the void forever.
- dropturf = drop_location()
- loaded_item.forceMove(dropturf)
- if(delete)
- qdel(loaded_item)
- loaded_item = null
-
-/obj/machinery/rnd/experimentor/proc/throwSmoke(turf/where)
- var/datum/effect_system/smoke_spread/smoke = new
- smoke.set_up(0, where)
- smoke.start()
-
-
-/obj/machinery/rnd/experimentor/proc/experiment(exp,obj/item/exp_on)
- recentlyExperimented = 1
- icon_state = "h_lathe_wloop"
- var/chosenchem
- var/criticalReaction = is_type_in_typecache(exp_on, critical_items_typecache)
- ////////////////////////////////////////////////////////////////////////////////////////////////
- if(exp == SCANTYPE_POKE)
- visible_message("[src] prods at [exp_on] with mechanical arms.")
- if(prob(EFFECT_PROB_LOW) && criticalReaction)
- visible_message("[exp_on] is gripped in just the right way, enhancing its focus.")
- badThingCoeff++
- else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
- visible_message("[src] malfunctions and destroys [exp_on], lashing its arms out at nearby people! ")
- for(var/mob/living/m in ohearers(1, src))
- m.apply_damage(15, BRUTE, pick(BODY_ZONE_HEAD,BODY_ZONE_CHEST,BODY_ZONE_PRECISE_GROIN))
- investigate_log("Experimentor dealt minor brute to [m].", INVESTIGATE_EXPERIMENTOR)
- ejectItem(TRUE)
- else if(prob(EFFECT_PROB_LOW-badThingCoeff))
- visible_message("[src] malfunctions! ")
- exp = SCANTYPE_OBLITERATE
- else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
- visible_message("[src] malfunctions, throwing the [exp_on]! ")
- var/mob/living/target = locate(/mob/living) in ohearers(7,src)
- if(target)
- var/obj/item/throwing = loaded_item
- investigate_log("Experimentor has thrown [loaded_item] at [key_name(target)]", INVESTIGATE_EXPERIMENTOR)
- ejectItem()
- if(throwing)
- throwing.throw_at(target, 10, 1)
- ////////////////////////////////////////////////////////////////////////////////////////////////
- if(exp == SCANTYPE_IRRADIATE)
- visible_message("[src] reflects radioactive rays at [exp_on]! ")
- if(prob(EFFECT_PROB_LOW) && criticalReaction)
- visible_message("[exp_on] has activated an unknown subroutine!")
- cloneMode = TRUE
- investigate_log("Experimentor has made a clone of [exp_on]", INVESTIGATE_EXPERIMENTOR)
- ejectItem()
- else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
- visible_message("[src] malfunctions, melting [exp_on] and leaking radiation! ")
- radiation_pulse(src, 500)
- ejectItem(TRUE)
- else if(prob(EFFECT_PROB_LOW-badThingCoeff))
- visible_message("[src] malfunctions, spewing toxic waste! ")
- for(var/turf/T in oview(1, src))
- if(!T.density)
- if(prob(EFFECT_PROB_VERYHIGH) && !(locate(/obj/effect/decal/cleanable/greenglow) in T))
- var/obj/effect/decal/cleanable/reagentdecal = new/obj/effect/decal/cleanable/greenglow(T)
- reagentdecal.reagents.add_reagent(/datum/reagent/uranium/radium, 7)
- else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
- var/savedName = "[exp_on]"
- ejectItem(TRUE)
- var/newPath = text2path(pick_weight(valid_items()))
- loaded_item = new newPath(src)
- visible_message("[src] malfunctions, transforming [savedName] into [loaded_item]! ")
- investigate_log("Experimentor has transformed [savedName] into [loaded_item]", INVESTIGATE_EXPERIMENTOR)
- if(istype(loaded_item, /obj/item/grenade/chem_grenade))
- var/obj/item/grenade/chem_grenade/CG = loaded_item
- CG.prime()
- ejectItem()
- ////////////////////////////////////////////////////////////////////////////////////////////////
- if(exp == SCANTYPE_GAS)
- visible_message("[src] fills its chamber with gas, [exp_on] included. ")
- if(prob(EFFECT_PROB_LOW) && criticalReaction)
- visible_message("[exp_on] achieves the perfect mix!")
- new /obj/item/stack/sheet/mineral/plasma(get_turf(pick(oview(1,src))))
- else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
- visible_message("[src] destroys [exp_on], leaking dangerous gas! ")
- chosenchem = pick(/datum/reagent/carbon,/datum/reagent/uranium/radium,/datum/reagent/toxin,/datum/reagent/consumable/condensedcapsaicin,/datum/reagent/drug/mushroomhallucinogen,/datum/reagent/drug/space_drugs,/datum/reagent/consumable/ethanol,/datum/reagent/consumable/ethanol/beepsky_smash)
- var/datum/reagents/R = new/datum/reagents(50)
- R.my_atom = src
- R.add_reagent(chosenchem , 50)
- investigate_log("Experimentor has released [chosenchem] smoke.", INVESTIGATE_EXPERIMENTOR)
- var/datum/effect_system/smoke_spread/chem/smoke = new
- smoke.set_up(R, 0, src, silent = TRUE)
- playsound(src, 'sound/effects/smoke.ogg', 50, 1, -3)
- smoke.start()
- qdel(R)
- ejectItem(TRUE)
- else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
- visible_message("[src]'s chemical chamber has sprung a leak! ")
- chosenchem = pick(/datum/reagent/mutationtoxin/classic,/datum/reagent/nanomachines,/datum/reagent/toxin/acid)
- var/datum/reagents/R = new/datum/reagents(50)
- R.my_atom = src
- R.add_reagent(chosenchem , 50)
- var/datum/effect_system/smoke_spread/chem/smoke = new
- smoke.set_up(R, 0, src, silent = TRUE)
- playsound(src, 'sound/effects/smoke.ogg', 50, 1, -3)
- smoke.start()
- qdel(R)
- ejectItem(TRUE)
- warn_admins(usr, "[chosenchem] smoke")
- investigate_log("Experimentor has released [chosenchem] smoke!", INVESTIGATE_EXPERIMENTOR)
- else if(prob(EFFECT_PROB_LOW-badThingCoeff))
- visible_message("[src] malfunctions, spewing harmless gas.")
- throwSmoke(loc)
- else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
- visible_message("[src] melts [exp_on], ionizing the air around it! ")
- empulse(loc, 4, 6)
- investigate_log("Experimentor has generated an Electromagnetic Pulse.", INVESTIGATE_EXPERIMENTOR)
- ejectItem(TRUE)
- ////////////////////////////////////////////////////////////////////////////////////////////////
- if(exp == SCANTYPE_HEAT)
- visible_message("[src] raises [exp_on]'s temperature.")
- if(prob(EFFECT_PROB_LOW) && criticalReaction)
- visible_message("[src]'s emergency coolant system gives off a small ding! ")
- playsound(src, 'sound/machines/ding.ogg', 50, 1)
- var/obj/item/reagent_containers/food/drinks/coffee/C = new /obj/item/reagent_containers/food/drinks/coffee(get_turf(pick(oview(1,src))))
- chosenchem = pick(/datum/reagent/toxin/plasma,/datum/reagent/consumable/capsaicin,/datum/reagent/consumable/ethanol)
- C.reagents.remove_any(25)
- C.reagents.add_reagent(chosenchem , 50)
- C.name = "Cup of Suspicious Liquid"
- C.desc = "It has a large hazard symbol printed on the side in fading ink."
- investigate_log("Experimentor has made a cup of [chosenchem] coffee.", INVESTIGATE_EXPERIMENTOR)
- else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
- var/turf/start = get_turf(src)
- var/mob/M = locate(/mob/living) in view(3, src)
- var/turf/MT = get_turf(M)
- if(MT)
- visible_message("[src] dangerously overheats, launching a flaming fuel orb! ")
- investigate_log("Experimentor has launched a fireball at [M]!", INVESTIGATE_EXPERIMENTOR)
- var/obj/projectile/magic/fireball/FB = new /obj/projectile/magic/fireball(start)
- FB.preparePixelProjectile(MT, start)
- FB.fire()
- else if(prob(EFFECT_PROB_LOW-badThingCoeff))
- visible_message("[src] malfunctions, melting [exp_on] and releasing a burst of flame! ")
- explosion(loc, -1, 0, 0, 0, 0, flame_range = 2)
- investigate_log("Experimentor started a fire.", INVESTIGATE_EXPERIMENTOR)
- ejectItem(TRUE)
- else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
- visible_message("[src] malfunctions, melting [exp_on] and leaking hot air! ")
- var/datum/gas_mixture/env = loc.return_air()
- env.adjust_heat(100000)
- air_update_turf()
- investigate_log("Experimentor has released hot air.", INVESTIGATE_EXPERIMENTOR)
- ejectItem(TRUE)
- else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
- visible_message("[src] malfunctions, activating its emergency coolant systems! ")
- throwSmoke(loc)
- for(var/mob/living/m in ohearers(1, src))
- m.apply_damage(5, BURN, pick(BODY_ZONE_HEAD,BODY_ZONE_CHEST,BODY_ZONE_PRECISE_GROIN))
- investigate_log("Experimentor has dealt minor burn damage to [key_name(m)]", INVESTIGATE_EXPERIMENTOR)
- ejectItem()
- ////////////////////////////////////////////////////////////////////////////////////////////////
- if(exp == SCANTYPE_COLD)
- visible_message("[src] lowers [exp_on]'s temperature.")
- if(prob(EFFECT_PROB_LOW) && criticalReaction)
- visible_message("[src]'s emergency coolant system gives off a small ding! ")
- var/obj/item/reagent_containers/food/drinks/coffee/C = new /obj/item/reagent_containers/food/drinks/coffee(get_turf(pick(oview(1,src))))
- playsound(src, 'sound/machines/ding.ogg', 50, 1) //Ding! Your death coffee is ready!
- chosenchem = pick(/datum/reagent/uranium,/datum/reagent/consumable/frostoil,/datum/reagent/medicine/ephedrine)
- C.reagents.remove_any(25)
- C.reagents.add_reagent(chosenchem , 50)
- C.name = "Cup of Suspicious Liquid"
- C.desc = "It has a large hazard symbol printed on the side in fading ink."
- investigate_log("Experimentor has made a cup of [chosenchem] coffee.", INVESTIGATE_EXPERIMENTOR)
- else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
- visible_message("[src] malfunctions, shattering [exp_on] and releasing a dangerous cloud of coolant! ")
- var/datum/reagents/R = new/datum/reagents(50)
- R.my_atom = src
- R.add_reagent(/datum/reagent/consumable/frostoil , 50)
- investigate_log("Experimentor has released frostoil gas.", INVESTIGATE_EXPERIMENTOR)
- var/datum/effect_system/smoke_spread/chem/smoke = new
- smoke.set_up(R, 0, src, silent = TRUE)
- playsound(src, 'sound/effects/smoke.ogg', 50, 1, -3)
- smoke.start()
- qdel(R)
- ejectItem(TRUE)
- else if(prob(EFFECT_PROB_LOW-badThingCoeff))
- visible_message("[src] malfunctions, shattering [exp_on] and leaking cold air! ")
- var/datum/gas_mixture/env = loc.return_air()
- env.adjust_heat(-75000)
- air_update_turf()
- investigate_log("Experimentor has released cold air.", INVESTIGATE_EXPERIMENTOR)
- ejectItem(TRUE)
- else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
- visible_message("[src] malfunctions, releasing a flurry of chilly air as [exp_on] pops out! ")
- var/datum/effect_system/smoke_spread/smoke = new
- smoke.set_up(0, loc)
- smoke.start()
- ejectItem()
- ////////////////////////////////////////////////////////////////////////////////////////////////
- if(exp == SCANTYPE_OBLITERATE)
- visible_message("[exp_on] activates the crushing mechanism, [exp_on] is destroyed! ")
- if(linked_console.linked_lathe)
- var/datum/component/material_container/linked_materials = linked_console.linked_lathe.GetComponent(/datum/component/material_container)
- for(var/material in exp_on.custom_materials)
- linked_materials.insert_amount_mat( min((linked_materials.max_amount - linked_materials.total_amount), (exp_on.custom_materials[material])), material)
- if(prob(EFFECT_PROB_LOW) && criticalReaction)
- visible_message("[src]'s crushing mechanism slowly and smoothly descends, flattening the [exp_on]! ")
- new /obj/item/stack/sheet/plasteel(get_turf(pick(oview(1,src))))
- else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
- visible_message("[src]'s crusher goes way too many levels too high, crushing right through space-time! ")
- playsound(src, 'sound/effects/supermatter.ogg', 50, 1, -3)
- investigate_log("Experimentor has triggered the 'throw things' reaction.", INVESTIGATE_EXPERIMENTOR)
- for(var/atom/movable/AM in oview(7,src))
- if(!AM.anchored)
- AM.throw_at(src,10,1)
- else if(prob(EFFECT_PROB_LOW-badThingCoeff))
- visible_message("[src]'s crusher goes one level too high, crushing right into space-time! ")
- playsound(src, 'sound/effects/supermatter.ogg', 50, 1, -3)
- investigate_log("Experimentor has triggered the 'minor throw things' reaction.", INVESTIGATE_EXPERIMENTOR)
- var/list/throwAt = list()
- for(var/atom/movable/AM in oview(7,src))
- if(!AM.anchored)
- throwAt.Add(AM)
- for(var/counter = 1, counter < throwAt.len, ++counter)
- var/atom/movable/cast = throwAt[counter]
- cast.throw_at(pick(throwAt),10,1)
- ejectItem(TRUE)
- ////////////////////////////////////////////////////////////////////////////////////////////////
- if(exp == FAIL)
- var/a = pick("rumbles","shakes","vibrates","shudders")
- var/b = pick("crushes","spins","viscerates","smashes","insults")
- visible_message("[exp_on] [a], and [b], the experiment was a failure. ")
-
- if(exp == SCANTYPE_DISCOVER)
- visible_message("[src] scans the [exp_on], revealing its true nature!")
- playsound(src, 'sound/effects/supermatter.ogg', 50, 3, -1)
- var/obj/item/relic/R = loaded_item
- R.reveal(linked_console.stored_research)
- investigate_log("Experimentor has revealed a relic with [R.realProc] effect.", INVESTIGATE_EXPERIMENTOR)
- ejectItem()
-
- //Global reactions
- if(prob(EFFECT_PROB_VERYLOW-badThingCoeff) && loaded_item)
- var/globalMalf = rand(1,100)
- if(globalMalf < 15)
- visible_message("[src]'s onboard detection system has malfunctioned! ")
- item_reactions["[exp_on.type]"] = pick(SCANTYPE_POKE,SCANTYPE_IRRADIATE,SCANTYPE_GAS,SCANTYPE_HEAT,SCANTYPE_COLD,SCANTYPE_OBLITERATE)
- ejectItem()
- if(globalMalf > 16 && globalMalf < 35)
- visible_message("[src] melts [exp_on], ian-izing the air around it! ")
- throwSmoke(loc)
- if(trackedIan)
- throwSmoke(trackedIan.loc)
- trackedIan.forceMove(loc)
- investigate_log("Experimentor has stolen Ian!", INVESTIGATE_EXPERIMENTOR) //...if anyone ever fixes it...
- else
- new /mob/living/simple_animal/pet/dog/corgi(loc)
- investigate_log("Experimentor has spawned a new corgi.", INVESTIGATE_EXPERIMENTOR)
- ejectItem(TRUE)
- if(globalMalf > 36 && globalMalf < 50)
- visible_message("Experimentor draws the life essence of those nearby! ")
- for(var/mob/living/m in hearers(4,src))
- to_chat(m, "You feel your flesh being torn from you, mists of blood drifting to [src]! ")
- m.apply_damage(50, BRUTE, BODY_ZONE_CHEST)
- investigate_log("Experimentor has taken 50 brute a blood sacrifice from [m]", INVESTIGATE_EXPERIMENTOR)
- if(globalMalf > 51 && globalMalf < 75)
- visible_message("[src] encounters a run-time error! ")
- throwSmoke(loc)
- if(trackedRuntime)
- throwSmoke(trackedRuntime.loc)
- trackedRuntime.forceMove(drop_location())
- investigate_log("Experimentor has stolen Runtime!", INVESTIGATE_EXPERIMENTOR)
- else
- new /mob/living/simple_animal/pet/cat(loc)
- investigate_log("Experimentor failed to steal runtime, and instead spawned a new cat.", INVESTIGATE_EXPERIMENTOR)
- ejectItem(TRUE)
- if(globalMalf > 76)
- visible_message("[src] begins to smoke and hiss, shaking violently! ")
- use_power(500000)
- investigate_log("Experimentor has drained power from its APC", INVESTIGATE_EXPERIMENTOR)
-
- addtimer(CALLBACK(src, PROC_REF(reset_exp)), resetTime)
-
-/obj/machinery/rnd/experimentor/proc/reset_exp()
- update_icon()
- recentlyExperimented = FALSE
-
-/obj/machinery/rnd/experimentor/update_icon()
- icon_state = "h_lathe"
-
-/obj/machinery/rnd/experimentor/proc/warn_admins(user, ReactionName)
- var/turf/T = get_turf(user)
- message_admins("Experimentor reaction: [ReactionName] generated by [ADMIN_LOOKUPFLW(user)] at [ADMIN_VERBOSEJMP(T)]")
- log_game("Experimentor reaction: [ReactionName] generated by [key_name(user)] in [AREACOORD(T)]")
-
-#undef SCANTYPE_POKE
-#undef SCANTYPE_IRRADIATE
-#undef SCANTYPE_GAS
-#undef SCANTYPE_HEAT
-#undef SCANTYPE_COLD
-#undef SCANTYPE_OBLITERATE
-#undef SCANTYPE_DISCOVER
-
-#undef EFFECT_PROB_VERYLOW
-#undef EFFECT_PROB_LOW
-#undef EFFECT_PROB_MEDIUM
-#undef EFFECT_PROB_HIGH
-#undef EFFECT_PROB_VERYHIGH
-
-#undef FAIL
-
-
-//////////////////////////////////SPECIAL ITEMS////////////////////////////////////////
-
-/obj/item/relic
- name = "strange object"
- desc = "What mysteries could this hold?"
- icon = 'icons/obj/assemblies.dmi'
- var/realName = "defined object"
- var/revealed = FALSE
- var/realProc
- var/cooldownMax = 60
- var/cooldown
-
-/obj/item/relic/Initialize(mapload)
- . = ..()
- icon_state = pick("shock_kit","armor-igniter-analyzer","infra-igniter0","infra-igniter1","radio-multitool","prox-radio1","radio-radio","timer-multitool0","radio-igniter-tank")
- realName = "[pick("broken","twisted","spun","improved","silly","regular","badly made")] [pick("device","object","toy","illegal tech","weapon")]"
-
-
-/obj/item/relic/proc/reveal(datum/techweb/techweb)
- if(revealed) //Re-rolling your relics seems a bit overpowered, yes?
- return
- revealed = TRUE
- name = realName
- cooldownMax = rand(60,300)
- realProc = pick("teleport","explode","rapidDupe","petSpray","flash","clean","corgicannon")
- //Give science research
- techweb.add_point_type(TECHWEB_POINT_TYPE_DISCOVERY, 2000)
-
-/obj/item/relic/attack_self(mob/user)
- if(revealed)
- if(cooldown)
- to_chat(user, "[src] does not react! ")
- return
- else if(loc == user)
- cooldown = TRUE
- call(src,realProc)(user)
- if(!QDELETED(src))
- addtimer(CALLBACK(src, PROC_REF(cd)), cooldownMax)
- else
- to_chat(user, "You aren't quite sure what to do with this yet. ")
-
-/obj/item/relic/proc/cd()
- cooldown = FALSE
-
-//////////////// RELIC PROCS /////////////////////////////
-
-/obj/item/relic/proc/throwSmoke(turf/where)
- var/datum/effect_system/smoke_spread/smoke = new
- smoke.set_up(0, get_turf(where))
- smoke.start()
-
-/obj/item/relic/proc/corgicannon(mob/user)
- playsound(src, "sparks", rand(25,50), 1)
- var/mob/living/simple_animal/pet/dog/corgi/C = new/mob/living/simple_animal/pet/dog/corgi(get_turf(user))
- C.throw_at(pick(oview(10,user)), 10, rand(3,8), callback = CALLBACK(src, PROC_REF(throwSmoke), C))
- warn_admins(user, "Corgi Cannon", 0)
-
-/obj/item/relic/proc/clean(mob/user)
- playsound(src, "sparks", rand(25,50), 1)
- var/obj/item/grenade/chem_grenade/cleaner/CL = new/obj/item/grenade/chem_grenade/cleaner(get_turf(user))
- CL.prime()
- warn_admins(user, "Foam", 0)
-
-/obj/item/relic/proc/flash(mob/user)
- playsound(src, "sparks", rand(25,50), 1)
- var/obj/item/grenade/flashbang/CB = new/obj/item/grenade/flashbang(user.loc)
- CB.prime()
- warn_admins(user, "Flash")
-
-/obj/item/relic/proc/petSpray(mob/user)
- var/message = "[src] begins to shake, and in the distance the sound of rampaging animals arises! "
- visible_message(message)
- to_chat(user, message)
- var/animals = rand(1,25)
- var/counter
- var/list/valid_animals = list(/mob/living/simple_animal/parrot, /mob/living/simple_animal/butterfly, /mob/living/simple_animal/pet/cat, /mob/living/simple_animal/pet/dog/corgi, /mob/living/simple_animal/crab, /mob/living/simple_animal/pet/fox, /mob/living/simple_animal/hostile/lizard, /mob/living/simple_animal/mouse, /mob/living/simple_animal/pet/dog/pug, /mob/living/simple_animal/hostile/bear, /mob/living/simple_animal/hostile/poison/bees, /mob/living/simple_animal/hostile/carp)
- for(counter = 1; counter < animals; counter++)
- var/mobType = pick(valid_animals)
- new mobType(get_turf(src))
- warn_admins(user, "Mass Mob Spawn")
- if(prob(60))
- to_chat(user, "[src] falls apart! ")
- qdel(src)
-
-/obj/item/relic/proc/rapidDupe(mob/user)
- audible_message("[src] emits a loud pop!")
- var/list/dupes = list()
- var/counter
- var/max = rand(5,10)
- for(counter = 1; counter < max; counter++)
- var/obj/item/relic/R = new type(get_turf(src))
- R.name = name
- R.desc = desc
- R.realName = realName
- R.realProc = realProc
- R.revealed = TRUE
- dupes |= R
- R.throw_at(pick(oview(7,get_turf(src))),10,1)
- counter = 0
- QDEL_LIST_IN(dupes, rand(10, 100))
- warn_admins(user, "Rapid duplicator", 0)
-
-/obj/item/relic/proc/explode(mob/user)
- to_chat(user, "[src] begins to heat up! ")
- addtimer(CALLBACK(src, PROC_REF(do_explode), user), rand(35, 100))
-
-/obj/item/relic/proc/do_explode(mob/user)
- if(loc == user)
- visible_message("\The [src]'s top opens, releasing a powerful blast! ")
- explosion(user.loc, 0, rand(1,5), rand(1,5), rand(1,5), rand(1,5), flame_range = 2)
- warn_admins(user, "Explosion")
- qdel(src) //Comment this line to produce a light grenade (the bomb that keeps on exploding when used)!!
-
-/obj/item/relic/proc/teleport(mob/user)
- to_chat(user, "[src] begins to vibrate! ")
- addtimer(CALLBACK(src, PROC_REF(do_the_teleport), user), rand(10, 30))
-
-/obj/item/relic/proc/do_the_teleport(mob/user)
- var/turf/userturf = get_turf(user)
- if(loc == user && !is_centcom_level(userturf.z)) //Because Nuke Ops bringing this back on their shuttle, then looting the ERT area is 2fun4you!
- visible_message("[src] twists and bends, relocating itself! ")
- throwSmoke(userturf)
- do_teleport(user, userturf, 8, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
- throwSmoke(get_turf(user))
- warn_admins(user, "Teleport", 0)
-
-//Admin Warning proc for relics
-/obj/item/relic/proc/warn_admins(mob/user, RelicType, priority = 1)
- var/turf/T = get_turf(src)
- var/log_msg = "[RelicType] relic used by [key_name(user)] in [AREACOORD(T)]"
- if(priority) //For truly dangerous relics that may need an admin's attention. BWOINK!
- message_admins("[RelicType] relic activated by [ADMIN_LOOKUPFLW(user)] in [ADMIN_VERBOSEJMP(T)]")
- log_game(log_msg)
- investigate_log(log_msg, "experimentor")
diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm
index 8869194da7400..d87bfce4f12fb 100644
--- a/code/modules/research/machinery/_production.dm
+++ b/code/modules/research/machinery/_production.dm
@@ -41,7 +41,7 @@
stored_research = new
host_research = SSresearch.science_tech
update_research()
- materials = AddComponent(/datum/component/remote_materials, "lathe", mapload)
+ materials = AddComponent(/datum/component/remote_materials, "lathe", mapload, mat_container_flags=BREAKDOWN_FLAGS_LATHE)
RefreshParts()
RegisterSignal(src, COMSIG_MATERIAL_CONTAINER_CHANGED, PROC_REF(on_materials_changed))
RegisterSignal(src, COMSIG_REMOTE_MATERIALS_CHANGED, PROC_REF(on_materials_changed))
diff --git a/code/modules/research/nanites/nanite_chamber.dm b/code/modules/research/nanites/nanite_chamber.dm
index 112b178a58aec..966c9dc4207b8 100644
--- a/code/modules/research/nanites/nanite_chamber.dm
+++ b/code/modules/research/nanites/nanite_chamber.dm
@@ -187,7 +187,7 @@
return TRUE
-/obj/machinery/nanite_chamber/relaymove(mob/user as mob)
+/obj/machinery/nanite_chamber/relaymove(mob/living/user, direction)
if(user.stat || locked)
if(message_cooldown <= world.time)
message_cooldown = world.time + 50
diff --git a/code/modules/research/nanites/nanite_programs/buffing.dm b/code/modules/research/nanites/nanite_programs/buffing.dm
index 3a3e0c357cc2c..eb11675deeff4 100644
--- a/code/modules/research/nanites/nanite_programs/buffing.dm
+++ b/code/modules/research/nanites/nanite_programs/buffing.dm
@@ -31,7 +31,6 @@
host_mob.SetAllImmobility(0)
host_mob.adjustStaminaLoss(-75)
host_mob.set_resting(FALSE)
- host_mob.update_mobility()
/datum/nanite_program/hardening
name = "Dermal Hardening"
diff --git a/code/modules/research/nanites/public_chamber.dm b/code/modules/research/nanites/public_chamber.dm
index 527ca9c96339b..a1aa67d48c595 100644
--- a/code/modules/research/nanites/public_chamber.dm
+++ b/code/modules/research/nanites/public_chamber.dm
@@ -183,7 +183,7 @@
return TRUE
-/obj/machinery/public_nanite_chamber/relaymove(mob/user as mob)
+/obj/machinery/public_nanite_chamber/relaymove(mob/living/user, direction)
if(user.stat || locked)
if(message_cooldown <= world.time)
message_cooldown = world.time + 50
diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm
index 15e0e98aabfc5..ea9985ed23488 100644
--- a/code/modules/research/rdconsole.dm
+++ b/code/modules/research/rdconsole.dm
@@ -536,10 +536,6 @@ Nothing else in the console has ID requirements.
/obj/machinery/computer/rdconsole/core
name = "Core R&D Console"
-/obj/machinery/computer/rdconsole/experiment
- name = "E.X.P.E.R.I-MENTOR R&D Console"
-
-
/obj/machinery/computer/rdconsole/vv_get_dropdown()
. = ..()
VV_DROPDOWN_OPTION("", "---------")
diff --git a/code/modules/research/rdmachines.dm b/code/modules/research/rdmachines.dm
index 93e3cc4c83ade..765d6091bc6ed 100644
--- a/code/modules/research/rdmachines.dm
+++ b/code/modules/research/rdmachines.dm
@@ -13,7 +13,7 @@
var/requires_console = TRUE
var/disabled = FALSE
var/obj/machinery/computer/rdconsole/linked_console
- var/obj/item/loaded_item = null //the item loaded inside the machine (currently only used by experimentor and destructive analyzer)
+ var/obj/item/loaded_item = null //the item loaded inside the machine (currently only used by the destructive analyzer)
/obj/machinery/rnd/proc/reset_busy()
busy = FALSE
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 2ca411d40e28b..73a0bb54dcfb7 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -22,7 +22,6 @@
"design_disk",
"dest_tagger",
"destructive_analyzer",
- "experimentor",
"fax",
"glasses_prescription",
"handlabel",
diff --git a/code/modules/research/xenobiology/crossbreeding/_misc.dm b/code/modules/research/xenobiology/crossbreeding/_misc.dm
index 758439b839a68..8fee94597f33f 100644
--- a/code/modules/research/xenobiology/crossbreeding/_misc.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_misc.dm
@@ -147,7 +147,7 @@ Slimecrossing Items
icon_state = "frozen"
density = TRUE
max_integrity = 100
- armor = list(MELEE = 30, BULLET = 50, LASER = -50, ENERGY = -50, BOMB = 0, BIO = 100, RAD = 100, FIRE = -80, ACID = 30, STAMINA = 0)
+ armor = list(MELEE = 30, BULLET = 50, LASER = -50, ENERGY = -50, BOMB = 0, BIO = 100, RAD = 100, FIRE = -80, ACID = 30, STAMINA = 0, BLEED = 0)
/obj/structure/ice_stasis/Initialize(mapload)
. = ..()
diff --git a/code/modules/research/xenobiology/crossbreeding/_potions.dm b/code/modules/research/xenobiology/crossbreeding/_potions.dm
index 618af07fc0c8b..c08f9b0a620a9 100644
--- a/code/modules/research/xenobiology/crossbreeding/_potions.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_potions.dm
@@ -118,6 +118,9 @@ Slimecrossing Potions
if(!istype(C))
to_chat(user, "The potion can only be used on clothing! ")
return
+ if(istype(C, /obj/item/clothing/suit/space))
+ to_chat(user, "The [C] is already pressure-resistant! ")
+ return ..()
if(C.min_cold_protection_temperature == SPACE_SUIT_MIN_TEMP_PROTECT && C.clothing_flags & STOPSPRESSUREDAMAGE)
to_chat(user, "The [C] is already pressure-resistant! ")
return ..()
diff --git a/code/modules/research/xenobiology/crossbreeding/_structures.dm b/code/modules/research/xenobiology/crossbreeding/_structures.dm
index 59f3ee41b483c..b4cee124d51e4 100644
--- a/code/modules/research/xenobiology/crossbreeding/_structures.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_structures.dm
@@ -398,7 +398,7 @@ GLOBAL_LIST_EMPTY(bluespace_slime_crystals)
/obj/structure/slime_crystal/cerulean/Initialize(mapload)
. = ..()
- while(crystals < 3)
+ for (var/i in 1 to 10) // doesn't guarantee 3 but it's a good effort
spawn_crystal()
/obj/structure/slime_crystal/cerulean/proc/spawn_crystal()
diff --git a/code/modules/research/xenobiology/crossbreeding/_weapons.dm b/code/modules/research/xenobiology/crossbreeding/_weapons.dm
index 377677262d579..d52370b12d505 100644
--- a/code/modules/research/xenobiology/crossbreeding/_weapons.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_weapons.dm
@@ -62,7 +62,7 @@ Slimecrossing Weapons
icon_state = "adamshield"
item_state = "adamshield"
w_class = WEIGHT_CLASS_HUGE
- armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 80, ACID = 70, STAMINA = 70)
+ armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 80, ACID = 70, STAMINA = 70, BLEED = 0)
slot_flags = ITEM_SLOT_BACK
attack_weight = 2
block_power = 75
diff --git a/code/modules/research/xenobiology/crossbreeding/warping.dm b/code/modules/research/xenobiology/crossbreeding/warping.dm
index 1bb76532b3ce2..b19063456081d 100644
--- a/code/modules/research/xenobiology/crossbreeding/warping.dm
+++ b/code/modules/research/xenobiology/crossbreeding/warping.dm
@@ -379,7 +379,7 @@ GLOBAL_DATUM(blue_storage, /obj/item/storage/backpack/holding/bluespace)
/obj/item/storage/backpack/holding/bluespace
name = "warped rune"
anchored = TRUE
- armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100)
+ armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 100, BLEED = 0)
invisibility = INVISIBILITY_ABSTRACT
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
@@ -604,6 +604,7 @@ GLOBAL_DATUM(blue_storage, /obj/item/storage/backpack/holding/bluespace)
/obj/item/toy/plush/gondola,
/obj/item/toy/plush/flushed = 2,
/obj/item/toy/plush/flushed/rainbow,
+ /obj/item/toy/plush/shark,
/obj/item/toy/eightball/haunted,
/obj/item/toy/foamblade,
/obj/item/toy/katana,
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 684aa2997a534..27e2a8d97735c 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -264,9 +264,9 @@
to_chat(user, "You start glowing brighter. ")
return 60 SECONDS
else
- var/obj/effect/dummy/luminescent_glow/glowth = new(user) //copied from glowy mutation, copied from luminescents
- glowth.set_light(2.5, 2.5, user.dna.features["mcolor"]) //Weaker than regular luminescents
- QDEL_IN(glowth, 600)
+ var/obj/effect/dummy/lighting_obj/moblight/glow = new(user) //copied from glowy mutation, copied from luminescents
+ glow.set_light(2.5, 2.5, user.dna.features["mcolor"]) //Weaker than regular luminescents
+ QDEL_IN(glow, 600)
return 60 SECONDS
if(SLIME_ACTIVATE_MAJOR)
diff --git a/code/modules/ruins/lavalandruin_code/puzzle.dm b/code/modules/ruins/lavalandruin_code/puzzle.dm
index d2ad5f06fdf73..0c2557c16398a 100644
--- a/code/modules/ruins/lavalandruin_code/puzzle.dm
+++ b/code/modules/ruins/lavalandruin_code/puzzle.dm
@@ -296,9 +296,9 @@
//Some armor so it's harder to kill someone by mistake.
/obj/structure/puzzle_element/prison
- armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 50, RAD = 50, FIRE = 50, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 50, RAD = 50, FIRE = 50, ACID = 50, STAMINA = 0, BLEED = 0)
-/obj/structure/puzzle_element/prison/relaymove(mob/user)
+/obj/structure/puzzle_element/prison/relaymove(mob/living/user, direction)
return
/obj/item/prisoncube
diff --git a/code/modules/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/ruins/spaceruin_code/hilbertshotel.dm
index d99a5678b07f0..ccfc1768b2995 100644
--- a/code/modules/ruins/spaceruin_code/hilbertshotel.dm
+++ b/code/modules/ruins/spaceruin_code/hilbertshotel.dm
@@ -257,7 +257,7 @@ GLOBAL_VAR_INIT(hhmysteryRoomNumber, 1337)
tugged_on = 0
return
if(alert(user, "Hilbert's Hotel would like to remind you that while we will do everything we can to protect the belongings you leave behind, we make no guarantees of their safety while you're gone, especially that of the health of any living creatures. With that in mind, are you ready to leave?", "Exit", "Leave", "Stay") == "Leave")
- if(!(user.mobility_flags & MOBILITY_MOVE) || (get_dist(get_turf(src), get_turf(user)) > 1)) //no teleporting around if they're dead or moved away during the prompt.
+ if(HAS_TRAIT(user, TRAIT_IMMOBILIZED) || (get_dist(get_turf(src), get_turf(user)) > 1)) //no teleporting around if they're dead or moved away during the prompt.
return
user.forceMove(get_turf(parentSphere))
do_sparks(3, FALSE, get_turf(user))
diff --git a/code/modules/security/genpop.dm b/code/modules/security/genpop.dm
index 366a0372b83a9..307b984cff784 100644
--- a/code/modules/security/genpop.dm
+++ b/code/modules/security/genpop.dm
@@ -10,7 +10,6 @@
power_channel = AREA_USAGE_ENVIRON
density = TRUE
pass_flags_self = PASSTRANSPARENT | PASSGRILLE | PASSSTRUCTURE
- obj_integrity = 600
max_integrity = 600
integrity_failure = 0.35
//Robust! It'll be tough to break...
@@ -364,7 +363,6 @@
icon = 'icons/obj/machines/genpop_display.dmi'
icon_state = "frame"
pixel_shift = 32
- inverse = 1
result_path = /obj/machinery/genpop_interface
/obj/item/electronics/genpop_interface
diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm
index a9042d327dd23..89c92e3f140e6 100644
--- a/code/modules/security_levels/keycard_authentication.dm
+++ b/code/modules/security_levels/keycard_authentication.dm
@@ -25,6 +25,8 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new)
var/mob/triggerer = null
var/waiting = 0
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26)
+
/obj/machinery/keycard_auth/Initialize(mapload)
. = ..()
ev = GLOB.keycard_events.addEvent("triggerEvent", CALLBACK(src, PROC_REF(triggerEvent)))
@@ -49,7 +51,7 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new)
var/list/data = list()
data["waiting"] = waiting
data["auth_required"] = event_source ? event_source.event : 0
- data["red_alert"] = (seclevel2num(get_security_level()) >= SEC_LEVEL_RED) ? 1 : 0
+ data["red_alert"] = (SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED) ? 1 : 0
data["emergency_maint"] = GLOB.emergency_access
data["bsa_unlock"] = GLOB.bsa_unlock
return data
@@ -78,12 +80,28 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new)
if(event_source)
event_source.trigger_event(usr)
event_source = null
+ update_appearance()
. = TRUE
if("bsa_unlock")
if(!event_source)
sendEvent(KEYCARD_BSA_UNLOCK)
. = TRUE
+/obj/machinery/keycard_auth/update_appearance(updates)
+ . = ..()
+
+ if(event_source && !(machine_stat & (NOPOWER|BROKEN)))
+ set_light(1.4, 0.7, "#5668E1")
+ else
+ set_light(0)
+
+/obj/machinery/keycard_auth/update_overlays()
+ . = ..()
+
+ if(event_source && !(machine_stat & (NOPOWER|BROKEN)))
+ . += mutable_appearance(icon, "auth_on")
+ . += emissive_appearance(icon, "auth_on", alpha = src.alpha)
+
/obj/machinery/keycard_auth/proc/sendEvent(event_type)
triggerer = usr
event = event_type
@@ -97,13 +115,13 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new)
waiting = 0
/obj/machinery/keycard_auth/proc/triggerEvent(source)
- icon_state = "auth_on"
event_source = source
+ update_appearance()
addtimer(CALLBACK(src, PROC_REF(eventTriggered)), 20)
/obj/machinery/keycard_auth/proc/eventTriggered()
- icon_state = "auth_off"
event_source = null
+ update_appearance()
/obj/machinery/keycard_auth/proc/trigger_event(confirmer)
log_game("[key_name(triggerer)] triggered and [key_name(confirmer)] confirmed event [event]")
@@ -116,7 +134,7 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new)
deadchat_broadcast("[confirmer] confirmed [event] at [A2.name] . ", confirmer)
switch(event)
if(KEYCARD_RED_ALERT)
- set_security_level(SEC_LEVEL_RED)
+ SSsecurity_level.set_level(SEC_LEVEL_RED)
if(KEYCARD_EMERGENCY_MAINTENANCE_ACCESS)
make_maint_all_access()
if(KEYCARD_BSA_UNLOCK)
diff --git a/code/modules/security_levels/security_level_datums.dm b/code/modules/security_levels/security_level_datums.dm
new file mode 100644
index 0000000000000..4737e21e41d0d
--- /dev/null
+++ b/code/modules/security_levels/security_level_datums.dm
@@ -0,0 +1,86 @@
+/**
+ * Security levels
+ *
+ * These are used by the security level subsystem. Each one of these represents a security level that a player can set.
+ *
+ * Base type is abstract
+ */
+
+/datum/security_level
+ /// The name of this security level.
+ var/name = "not set"
+ /// The numerical level of this security level, see defines for more information.
+ var/number_level = -1
+ /// The sound that we will play when this security level is set
+ var/sound
+ /// The looping sound that will be played while the security level is set
+ var/looping_sound
+ /// The looping sound interval
+ var/looping_sound_interval
+ /// The shuttle call time modification of this security level
+ var/shuttle_call_time_mod = 0
+ /// Our announcement when lowering to this level
+ var/lowering_to_announcement
+ /// Our announcement when elevating to this level
+ var/elevating_to_announcemnt
+ /// Our configuration key for lowering to text, if set, will override the default lowering to announcement.
+ var/lowering_to_configuration_key
+ /// Our configuration key for elevating to text, if set, will override the default elevating to announcement.
+ var/elevating_to_configuration_key
+
+/datum/security_level/New()
+ . = ..()
+ if(lowering_to_configuration_key) // I'm not sure about you, but isn't there an easier way to do this?
+ lowering_to_announcement = global.config.Get(lowering_to_configuration_key)
+ if(elevating_to_configuration_key)
+ elevating_to_announcemnt = global.config.Get(elevating_to_configuration_key)
+
+/**
+ * GREEN
+ *
+ * No threats
+ */
+/datum/security_level/green
+ name = "green"
+ sound = 'sound/misc/notice2.ogg' // Friendly beep
+ number_level = SEC_LEVEL_GREEN
+ lowering_to_configuration_key = /datum/config_entry/string/alert_green
+ shuttle_call_time_mod = ALERT_COEFF_GREEN
+
+/**
+ * BLUE
+ *
+ * Caution advised
+ */
+/datum/security_level/blue
+ name = "blue"
+ sound = 'sound/misc/notice1.ogg' // Angry alarm
+ number_level = SEC_LEVEL_BLUE
+ lowering_to_configuration_key = /datum/config_entry/string/alert_blue_downto
+ elevating_to_configuration_key = /datum/config_entry/string/alert_blue_upto
+ shuttle_call_time_mod = ALERT_COEFF_BLUE
+
+/**
+ * RED
+ *
+ * Hostile threats
+ */
+/datum/security_level/red
+ name = "red"
+ sound = 'sound/misc/notice1.ogg' // The same angry alarm
+ number_level = SEC_LEVEL_RED
+ lowering_to_configuration_key = /datum/config_entry/string/alert_red_downto
+ elevating_to_configuration_key = /datum/config_entry/string/alert_red_upto
+ shuttle_call_time_mod = ALERT_COEFF_RED
+
+/**
+ * DELTA
+ *
+ * Station destruction is imminent
+ */
+/datum/security_level/delta
+ name = "delta"
+ sound = 'sound/misc/notice1.ogg' // The same angry alarm, again
+ number_level = SEC_LEVEL_DELTA
+ elevating_to_configuration_key = /datum/config_entry/string/alert_delta
+ shuttle_call_time_mod = ALERT_COEFF_DELTA
diff --git a/code/modules/security_levels/security_levels.dm b/code/modules/security_levels/security_levels.dm
deleted file mode 100644
index 95398906c4da7..0000000000000
--- a/code/modules/security_levels/security_levels.dm
+++ /dev/null
@@ -1,97 +0,0 @@
-GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN)
-//SEC_LEVEL_GREEN = code green
-//SEC_LEVEL_BLUE = code blue
-//SEC_LEVEL_RED = code red
-//SEC_LEVEL_DELTA = code delta
-
-//config.alert_desc_blue_downto
-
-/proc/set_security_level(level)
- switch(level)
- if("green")
- level = SEC_LEVEL_GREEN
- if("blue")
- level = SEC_LEVEL_BLUE
- if("red")
- level = SEC_LEVEL_RED
- if("delta")
- level = SEC_LEVEL_DELTA
-
- //Will not be announced if you try to set to the same level as it already is
- if(level < SEC_LEVEL_GREEN || level > SEC_LEVEL_DELTA || level == GLOB.security_level)
- return
- switch(level)
- if(SEC_LEVEL_GREEN)
- minor_announce(CONFIG_GET(string/alert_green), "Attention! Security level lowered to green:")
- if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL)
- if(GLOB.security_level >= SEC_LEVEL_RED)
- SSshuttle.emergency.modTimer(4)
- else
- SSshuttle.emergency.modTimer(2)
-
- if(SEC_LEVEL_BLUE)
- if(GLOB.security_level < SEC_LEVEL_BLUE)
- minor_announce(CONFIG_GET(string/alert_blue_upto), "Attention! Security level elevated to blue:",1)
- if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL)
- SSshuttle.emergency.modTimer(0.5)
- else
- minor_announce(CONFIG_GET(string/alert_blue_downto), "Attention! Security level lowered to blue:")
- if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL)
- SSshuttle.emergency.modTimer(2)
-
- if(SEC_LEVEL_RED)
- if(GLOB.security_level < SEC_LEVEL_RED)
- minor_announce(CONFIG_GET(string/alert_red_upto), "Attention! Code red!",1)
- if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL)
- if(GLOB.security_level == SEC_LEVEL_GREEN)
- SSshuttle.emergency.modTimer(0.25)
- else
- SSshuttle.emergency.modTimer(0.5)
- else
- minor_announce(CONFIG_GET(string/alert_red_downto), "Attention! Code red!")
-
- if(SEC_LEVEL_DELTA)
- minor_announce(CONFIG_GET(string/alert_delta), "Attention! Delta security level reached!",1)
- if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL)
- if(GLOB.security_level == SEC_LEVEL_GREEN)
- SSshuttle.emergency.modTimer(0.25)
- else if(GLOB.security_level == SEC_LEVEL_BLUE)
- SSshuttle.emergency.modTimer(0.5)
-
- GLOB.security_level = level
- SEND_GLOBAL_SIGNAL(COMSIG_GLOB_SECURITY_ALERT_CHANGE, level)
- SSblackbox.record_feedback("tally", "security_level_changes", 1, get_security_level())
- SSnightshift.check_nightshift()
-
-/proc/get_security_level()
- switch(GLOB.security_level)
- if(SEC_LEVEL_GREEN)
- return "green"
- if(SEC_LEVEL_BLUE)
- return "blue"
- if(SEC_LEVEL_RED)
- return "red"
- if(SEC_LEVEL_DELTA)
- return "delta"
-
-/proc/num2seclevel(num)
- switch(num)
- if(SEC_LEVEL_GREEN)
- return "green"
- if(SEC_LEVEL_BLUE)
- return "blue"
- if(SEC_LEVEL_RED)
- return "red"
- if(SEC_LEVEL_DELTA)
- return "delta"
-
-/proc/seclevel2num(seclevel)
- switch( lowertext(seclevel) )
- if("green")
- return SEC_LEVEL_GREEN
- if("blue")
- return SEC_LEVEL_BLUE
- if("red")
- return SEC_LEVEL_RED
- if("delta")
- return SEC_LEVEL_DELTA
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index 495a6bd7bc033..780b3787047fc 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -320,16 +320,10 @@
. = ..()
/obj/docking_port/mobile/emergency/request(obj/docking_port/stationary/S, area/signalOrigin, reason, redAlert, set_coefficient=null)
- if(!isnum_safe(set_coefficient))
- var/security_num = seclevel2num(get_security_level())
- switch(security_num)
- if(SEC_LEVEL_GREEN)
- set_coefficient = 2
- if(SEC_LEVEL_BLUE)
- set_coefficient = 1
- else
- set_coefficient = 0.5
- var/call_time = SSshuttle.emergencyCallTime * set_coefficient * engine_coeff
+ if(!isnum(set_coefficient))
+ set_coefficient = SSsecurity_level.current_security_level.shuttle_call_time_mod
+ alert_coeff = set_coefficient
+ var/call_time = SSshuttle.emergencyCallTime * alert_coeff * engine_coeff
switch(mode)
// The shuttle can not normally be called while "recalling", so
// if this proc is called, it's via admin fiat
@@ -587,7 +581,7 @@
var/obj/machinery/computer/shuttle_flight/C = getControlConsole()
if(!istype(C, /obj/machinery/computer/shuttle_flight/pod))
return ..()
- if(GLOB.security_level >= SEC_LEVEL_RED || (C && (C.obj_flags & EMAGGED)))
+ if(SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED || (C && (C.obj_flags & EMAGGED)))
if(launch_status == UNLAUNCHED)
launch_status = EARLY_LAUNCHED
return ..()
@@ -619,11 +613,7 @@
/obj/machinery/computer/shuttle_flight/pod/Initialize()
. = ..()
- RegisterSignal(SSdcs, COMSIG_GLOB_SECURITY_ALERT_CHANGE, PROC_REF(handle_alert))
-
-/obj/machinery/computer/shuttle_flight/pod/proc/handle_alert(datum/source, new_alert)
- SIGNAL_HANDLER
- admin_controlled = (new_alert < SEC_LEVEL_RED) // admin_controlled is FALSE if its red or delta
+ RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, PROC_REF(check_lock))
/obj/machinery/computer/shuttle_flight/pod/update_icon()
return
@@ -637,6 +627,20 @@
if(recall_docking_port_id == initial(recall_docking_port_id) || override)
recall_docking_port_id = "pod_lavaland[idnum]"
+/**
+ * Signal handler for checking if we should lock or unlock escape pods accordingly to a newly set security level
+ *
+ * Arguments:
+ * * source The datum source of the signal
+ * * new_level The new security level that is in effect
+ */
+/obj/machinery/computer/shuttle_flight/pod/proc/check_lock(datum/source, new_level)
+ SIGNAL_HANDLER
+
+ if(obj_flags & EMAGGED)
+ return
+ admin_controlled = (new_level < SEC_LEVEL_RED)
+
/obj/docking_port/stationary/random
name = "escape pod"
id = "pod"
@@ -728,7 +732,7 @@
/obj/item/storage/pod/can_interact(mob/user)
if(!..())
return FALSE
- if(GLOB.security_level >= SEC_LEVEL_RED || unlocked)
+ if(SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED || unlocked)
return TRUE
to_chat(user, "The storage unit will only unlock during a Red or Delta security alert.")
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index 1bbfc0f1b3025..a8461d69d042d 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -309,6 +309,8 @@ GLOBAL_LIST_INIT(shuttle_turf_blacklist, typecacheof(list(
var/list/shuttle_areas
+ ///Speed multiplier based on station alert level
+ var/alert_coeff = ALERT_COEFF_BLUE
///used as a timer (if you want time left to complete move, use timeLeft proc)
var/timer
var/last_timer_length
@@ -939,6 +941,20 @@ GLOBAL_LIST_INIT(shuttle_turf_blacklist, typecacheof(list(
last_timer_length *= multiple
setTimer(time_remaining)
+/obj/docking_port/mobile/proc/alert_coeff_change(new_coeff)
+ if(isnull(new_coeff))
+ return
+
+ var/time_multiplier = new_coeff / alert_coeff
+ var/time_remaining = timer - world.time
+ if(time_remaining < 0 || !last_timer_length)
+ return
+
+ time_remaining *= time_multiplier
+ last_timer_length *= time_multiplier
+ alert_coeff = new_coeff
+ setTimer(time_remaining)
+
/obj/docking_port/mobile/proc/invertTimer()
if(!last_timer_length)
return
diff --git a/code/modules/shuttle/shuttle_creation/shuttle_creator.dm b/code/modules/shuttle/shuttle_creation/shuttle_creator.dm
index a0f0ff5387a65..ba123aba0cd44 100644
--- a/code/modules/shuttle/shuttle_creation/shuttle_creator.dm
+++ b/code/modules/shuttle/shuttle_creation/shuttle_creator.dm
@@ -27,7 +27,7 @@ GLOBAL_LIST_EMPTY(custom_shuttle_machines) //Machines that require updating (He
throw_range = 5
w_class = WEIGHT_CLASS_TINY
req_access_txt = "11"
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
var/ready = TRUE
//pre-designation
diff --git a/code/modules/shuttle/super_cruise/orbital_poi_generator/objective_types/vip_extraction.dm b/code/modules/shuttle/super_cruise/orbital_poi_generator/objective_types/vip_extraction.dm
index 8b158429a80b4..b8c61af80464b 100644
--- a/code/modules/shuttle/super_cruise/orbital_poi_generator/objective_types/vip_extraction.dm
+++ b/code/modules/shuttle/super_cruise/orbital_poi_generator/objective_types/vip_extraction.dm
@@ -105,7 +105,8 @@
/datum/outfit/vip_target/centcom_official_vip
name = "Centcom (VIP Target)"
- uniform = /obj/item/clothing/under/rank/centcom/officer
+ uniform = /obj/item/clothing/under/rank/centcom/official
+ suit = /obj/item/clothing/suit/armor/bulletproof
gloves = /obj/item/clothing/gloves/color/black
ears = /obj/item/radio/headset/headset_cent/empty
glasses = /obj/item/clothing/glasses/sunglasses/advanced
diff --git a/code/modules/shuttle/white_ship.dm b/code/modules/shuttle/white_ship.dm
index 4e235731e2f19..76447f89ecfd3 100644
--- a/code/modules/shuttle/white_ship.dm
+++ b/code/modules/shuttle/white_ship.dm
@@ -21,5 +21,5 @@
/obj/effect/spawner/lootdrop/whiteship_cere_ripley
name = "25% mech 75% wreckage ripley spawner"
loot = list(/obj/vehicle/sealed/mecha/working/ripley/mining = 1,
- /obj/structure/mecha_wreckage/ripley = 5)
+ /obj/structure/mecha_wreckage/ripley = 3)
lootdoubles = FALSE
diff --git a/code/modules/spells/spell_types/devil.dm b/code/modules/spells/spell_types/devil.dm
index ef876286c30c8..d1ccd72301b75 100644
--- a/code/modules/spells/spell_types/devil.dm
+++ b/code/modules/spells/spell_types/devil.dm
@@ -158,7 +158,7 @@
return FALSE
fakefire()
forceMove(drop_location())
- client.eye = src
+ client.set_eye(src)
visible_message("[src] appears in a fiery blaze! ")
playsound(get_turf(src), 'sound/magic/exit_blood.ogg', 100, 1, -1)
addtimer(CALLBACK(src, PROC_REF(fakefireextinguish)), 15, TIMER_UNIQUE)
diff --git a/code/modules/spells/spell_types/ethereal_jaunt.dm b/code/modules/spells/spell_types/ethereal_jaunt.dm
index 7527ca9d9ac26..198cd51b0ee4c 100644
--- a/code/modules/spells/spell_types/ethereal_jaunt.dm
+++ b/code/modules/spells/spell_types/ethereal_jaunt.dm
@@ -52,7 +52,7 @@
return
mobloc = get_turf(target.loc)
jaunt_steam(mobloc)
- target.mobility_flags &= ~MOBILITY_MOVE
+ ADD_TRAIT(target, TRAIT_IMMOBILIZED, type)
holder.reappearing = 1
play_sound("exit",target)
sleep(25 - jaunt_in_time)
@@ -67,7 +67,7 @@
if(T)
if(target.Move(T))
break
- target.mobility_flags |= MOBILITY_MOVE
+ REMOVE_TRAIT(target, TRAIT_IMMOBILIZED, type)
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/jaunt_steam(mobloc)
var/datum/effect_system/steam_spread/steam = new /datum/effect_system/steam_spread()
@@ -99,7 +99,7 @@
AM.forceMove(get_turf(src))
return ..()
-/obj/effect/dummy/phased_mob/spell_jaunt/relaymove(var/mob/user, direction)
+/obj/effect/dummy/phased_mob/spell_jaunt/relaymove(mob/living/user, direction)
if ((movedelay > world.time) || reappearing || !direction)
return
var/turf/newLoc = get_step(src,direction)
diff --git a/code/modules/spells/spell_types/shadow_walk.dm b/code/modules/spells/spell_types/shadow_walk.dm
index 67d2fe2e0d989..992c303edecda 100644
--- a/code/modules/spells/spell_types/shadow_walk.dm
+++ b/code/modules/spells/spell_types/shadow_walk.dm
@@ -45,7 +45,7 @@
invisibility = 60
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
-/obj/effect/dummy/phased_mob/shadow/relaymove(mob/user, direction)
+/obj/effect/dummy/phased_mob/shadow/relaymove(mob/living/user, direction)
var/turf/newLoc = get_step(src,direction)
if(isspaceturf(newLoc))
to_chat(user, "It really would not be wise to go into space. ")
diff --git a/code/modules/spells/spell_types/touch_attacks.dm b/code/modules/spells/spell_types/touch_attacks.dm
index d17ebc1eecbf5..d91067853d646 100644
--- a/code/modules/spells/spell_types/touch_attacks.dm
+++ b/code/modules/spells/spell_types/touch_attacks.dm
@@ -50,7 +50,7 @@
attached_hand = create_hand()
if(!user.put_in_hands(attached_hand))
remove_hand()
- if (user.get_num_arms() <= 0)
+ if (user.usable_hands == 0)
to_chat(user, "You dont have any usable hands! ")
else
to_chat(user, "Your hands are full! ")
diff --git a/code/modules/surgery/amputation.dm b/code/modules/surgery/amputation.dm
index b58ef2be476a4..9ffc93497f8ee 100644
--- a/code/modules/surgery/amputation.dm
+++ b/code/modules/surgery/amputation.dm
@@ -28,5 +28,5 @@
if(surgery.operated_bodypart)
var/obj/item/bodypart/target_limb = surgery.operated_bodypart
target_limb.drop_limb()
-
+ target.cauterise_wounds()
return 1
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index a1d130ab522a6..dc6cc9f7b30bd 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -35,7 +35,13 @@
var/held_index = 0 //are we a hand? if so, which one!
var/is_pseudopart = FALSE //For limbs that don't really exist, eg chainsaws
- var/disabled = BODYPART_NOT_DISABLED //If disabled, limb is as good as missing
+ ///If disabled, limb is as good as missing.
+ var/bodypart_disabled = FALSE
+ ///Multiplied by max_damage it returns the threshold which defines a limb being disabled or not. From 0 to 1.
+ var/disable_threshold = 1
+ ///Controls whether bodypart_disabled makes sense or not for this limb.
+ var/can_be_disabled = FALSE
+
var/body_damage_coeff = 1 //Multiplier of the limb's damage that gets applied to the mob
var/stam_damage_coeff = 0.7 //Why is this the default???
var/brutestate = 0
@@ -76,13 +82,32 @@
var/medium_burn_msg = "blistered"
var/heavy_burn_msg = "peeling away"
+ /// So we know if we need to scream if this limb hits max damage
+ var/last_maxed
+
/obj/item/bodypart/Initialize(mapload)
. = ..()
+ if(can_be_disabled)
+ RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS), PROC_REF(on_paralysis_trait_gain))
+ RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS), PROC_REF(on_paralysis_trait_loss))
name = "[limb_id] [parse_zone(body_zone)]"
if(is_dimorphic)
limb_gender = pick("m", "f")
update_icon_dropped()
+/obj/item/bodypart/Destroy()
+ if(owner)
+ owner.remove_bodypart(src)
+ set_owner(null)
+ /*
+ for(var/wound in wounds)
+ qdel(wound) // wounds is a lazylist, and each wound removes itself from it on deletion.
+ if(length(wounds))
+ stack_trace("[type] qdeleted with [length(wounds)] uncleared wounds")
+ wounds.Cut()
+ */
+ return ..()
+
/obj/item/bodypart/forceMove(atom/destination) //Please. Never forcemove a limb if its's actually in use. This is only for borgs.
. = ..()
if(isturf(destination))
@@ -100,12 +125,6 @@
/obj/item/bodypart/blob_act()
take_damage(max_damage)
-/obj/item/bodypart/Destroy()
- if(owner)
- owner.bodyparts -= src
- owner = null
- return ..()
-
/obj/item/bodypart/attack(mob/living/carbon/C, mob/user)
if(ishuman(C))
var/mob/living/carbon/human/H = C
@@ -139,7 +158,7 @@
/obj/item/bodypart/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
..()
if(IS_ORGANIC_LIMB(src))
- playsound(get_turf(src), 'sound/misc/splort.ogg', 50, 1, -1)
+ playsound(get_turf(src), 'sound/misc/splort.ogg', 50, TRUE, -1)
pixel_x = rand(-3, 3)
pixel_y = rand(-3, 3)
@@ -151,17 +170,11 @@
for(var/obj/item/I in src)
I.forceMove(T)
-/obj/item/bodypart/proc/consider_processing()
- if(stamina_dam >= DAMAGE_PRECISION)
- . = TRUE
- //else if.. else if.. so on.
- else
- . = FALSE
- needs_processing = .
-
//Return TRUE to get whatever mob this is in to update health.
/obj/item/bodypart/proc/on_life(stam_regen)
- if(stamina_dam >= DAMAGE_PRECISION && stam_regen) //DO NOT update health here, it'll be done in the carbon's life.
+ SHOULD_CALL_PARENT(TRUE)
+ //DO NOT update health here, it'll be done in the carbon's life.
+ if(stamina_dam >= DAMAGE_PRECISION && stam_regen)
heal_damage(0, 0, stam_regen, null, FALSE)
. |= BODYPART_LIFE_UPDATE_HEALTH
@@ -169,6 +182,8 @@
//Damage will not exceed max_damage using this proc
//Cannot apply negative damage
/obj/item/bodypart/proc/receive_damage(brute = 0, burn = 0, stamina = 0, blocked = 0, updating_health = TRUE, required_status = null)
+ SHOULD_CALL_PARENT(TRUE)
+
var/hit_percent = (100-blocked)/100
if((!brute && !burn && !stamina) || hit_percent <= 0)
return FALSE
@@ -195,53 +210,91 @@
var/can_inflict = (max_damage * 2) - get_damage()
if(can_inflict <= 0)
return FALSE
-
var/total_damage = brute + burn
-
if(total_damage > can_inflict)
brute = round(brute * (can_inflict / total_damage),DAMAGE_PRECISION)
burn = round(burn * (can_inflict / total_damage),DAMAGE_PRECISION)
- brute_dam += brute
- burn_dam += burn
+ if(brute)
+ set_brute_dam(brute_dam + brute)
+ if(burn)
+ set_burn_dam(burn_dam + burn)
//We've dealt the physical damages, if there's room lets apply the stamina damage.
- var/current_damage = get_damage(TRUE) //This time around, count stamina loss too.
- var/available_damage = max_damage - current_damage
- var/applied_damage = min(max_stamina_damage - stamina_dam, available_damage)
- stamina_dam += round(clamp(stamina, 0, applied_damage), DAMAGE_PRECISION)
-
+ if(stamina)
+ set_stamina_dam(stamina_dam + round(clamp(stamina, 0, max_stamina_damage - stamina_dam), DAMAGE_PRECISION))
- if(owner && updating_health)
- owner.updatehealth()
- if(stamina >= DAMAGE_PRECISION)
- owner.update_stamina(TRUE)
- owner.stam_regen_start_time = max(owner.stam_regen_start_time, world.time + STAMINA_REGEN_BLOCK_TIME)
- consider_processing()
- update_disabled()
- return update_bodypart_damage_state()
+ if(owner)
+ if(can_be_disabled)
+ update_disabled()
+ if(updating_health)
+ owner.updatehealth()
+ if(stamina >= DAMAGE_PRECISION)
+ owner.update_stamina(TRUE)
+ owner.stam_regen_start_time = max(owner.stam_regen_start_time, world.time + STAMINA_REGEN_BLOCK_TIME)
+ . = TRUE
+ return update_bodypart_damage_state() || .
//Heals brute and burn damage for the organ. Returns 1 if the damage-icon states changed at all.
//Damage cannot go below zero.
//Cannot remove negative damage (i.e. apply damage)
/obj/item/bodypart/proc/heal_damage(brute, burn, stamina, required_status, updating_health = TRUE)
+ SHOULD_CALL_PARENT(TRUE)
if(required_status && !(bodytype & required_status)) //So we can only heal certain kinds of limbs, ie robotic vs organic.
return
- brute_dam = round(max(brute_dam - brute, 0), DAMAGE_PRECISION)
- burn_dam = round(max(burn_dam - burn, 0), DAMAGE_PRECISION)
- stamina_dam = round(max(stamina_dam - stamina, 0), DAMAGE_PRECISION)
- if(owner && updating_health)
- owner.updatehealth()
- if(owner.dna && owner.dna.species && (REVIVESBYHEALING in owner.dna.species.species_traits))
- if(owner.health > 0 && !owner.ishellbound())
- owner.revive(0)
- owner.cure_husk(0) // If it has REVIVESBYHEALING, it probably can't be cloned. No husk cure.
- consider_processing()
- update_disabled()
+ if(brute)
+ set_brute_dam(round(max(brute_dam - brute, 0), DAMAGE_PRECISION))
+ if(burn)
+ set_burn_dam(round(max(burn_dam - burn, 0), DAMAGE_PRECISION))
+ if(stamina)
+ set_stamina_dam(round(max(stamina_dam - stamina, 0), DAMAGE_PRECISION))
+
+ if(owner)
+ if(can_be_disabled)
+ update_disabled()
+ if(updating_health)
+ owner.updatehealth()
+ if(owner.dna?.species && (REVIVESBYHEALING in owner.dna.species.species_traits))
+ if(owner.health > 0 && !owner.ishellbound())
+ owner.revive(0)
+ owner.cure_husk(0) // If it has REVIVESBYHEALING, it probably can't be cloned. No husk cure.
return update_bodypart_damage_state()
+///Proc to hook behavior associated to the change of the brute_dam variable's value.
+/obj/item/bodypart/proc/set_brute_dam(new_value)
+ PROTECTED_PROC(TRUE)
+
+ if(brute_dam == new_value)
+ return
+ . = brute_dam
+ brute_dam = new_value
+
+
+///Proc to hook behavior associated to the change of the burn_dam variable's value.
+/obj/item/bodypart/proc/set_burn_dam(new_value)
+ PROTECTED_PROC(TRUE)
+
+ if(burn_dam == new_value)
+ return
+ . = burn_dam
+ burn_dam = new_value
+
+
+///Proc to hook behavior associated to the change of the stamina_dam variable's value.
+/obj/item/bodypart/proc/set_stamina_dam(new_value)
+ PROTECTED_PROC(TRUE)
+
+ if(stamina_dam == new_value)
+ return
+ . = stamina_dam
+ stamina_dam = new_value
+ if(stamina_dam > DAMAGE_PRECISION)
+ needs_processing = TRUE
+ else
+ needs_processing = FALSE
+
//Returns total damage.
/obj/item/bodypart/proc/get_damage(include_stamina = FALSE)
var/total = brute_dam + burn_dam
@@ -255,28 +308,144 @@
//Checks disabled status thresholds
/obj/item/bodypart/proc/update_disabled()
- set_disabled(is_disabled())
+ SHOULD_CALL_PARENT(TRUE)
+
+ if(!owner)
+ return
+
+ if(!can_be_disabled)
+ set_disabled(FALSE)
+ CRASH("update_disabled called with can_be_disabled false")
-/obj/item/bodypart/proc/is_disabled()
if(HAS_TRAIT(src, TRAIT_PARALYSIS))
- return BODYPART_DISABLED_PARALYSIS
- if(can_dismember() && !HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE))
- . = disabled //inertia, to avoid limbs healing 0.1 damage and being re-enabled
- if((get_damage(TRUE) >= max_damage) || (HAS_TRAIT(owner, TRAIT_EASYLIMBDISABLE) && (get_damage(TRUE) >= (max_damage * 0.6)))) //Easy limb disable disables the limb at 40% health instead of 0%
- return BODYPART_DISABLED_DAMAGE
- if(disabled && (get_damage(TRUE) <= (max_damage * 0.5)))
- return BODYPART_NOT_DISABLED
- else
- return BODYPART_NOT_DISABLED
+ set_disabled(TRUE)
+ return
+ var/total_damage = max(brute_dam + burn_dam, stamina_dam)
+
+ if(total_damage >= max_damage * disable_threshold) //Easy limb disable disables the limb at 40% health instead of 0%
+ if(!last_maxed)
+ if(owner.stat < UNCONSCIOUS)
+ INVOKE_ASYNC(owner, TYPE_PROC_REF(/mob, emote), "scream")
+ last_maxed = TRUE
+ set_disabled(TRUE)
+ return
+
+ if(bodypart_disabled && total_damage <= max_damage * 0.5)
+ last_maxed = FALSE
+ set_disabled(FALSE)
+
+
+///Proc to change the value of the `disabled` variable and react to the event of its change.
/obj/item/bodypart/proc/set_disabled(new_disabled)
- if(disabled == new_disabled)
+ SHOULD_CALL_PARENT(TRUE)
+ PROTECTED_PROC(TRUE)
+
+ if(bodypart_disabled == new_disabled)
+ return
+ . = bodypart_disabled
+ bodypart_disabled = new_disabled
+
+ if(!owner)
return
- disabled = new_disabled
owner.update_health_hud() //update the healthdoll
owner.update_body()
- owner.update_mobility()
- return TRUE //if there was a change.
+
+///Proc to change the value of the `owner` variable and react to the event of its change.
+/obj/item/bodypart/proc/set_owner(mob/living/carbon/new_owner)
+ SHOULD_CALL_PARENT(TRUE)
+
+ if(owner == new_owner)
+ return FALSE //`null` is a valid option, so we need to use a num var to make it clear no change was made.
+ var/mob/living/carbon/old_owner = owner
+ owner = new_owner
+ var/needs_update_disabled = FALSE //Only really relevant if there's an owner
+ if(old_owner)
+ if(initial(can_be_disabled))
+ if(HAS_TRAIT(old_owner, TRAIT_NOLIMBDISABLE))
+ if(!owner || !HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE))
+ set_can_be_disabled(initial(can_be_disabled))
+ needs_update_disabled = TRUE
+ UnregisterSignal(old_owner, list(
+ SIGNAL_REMOVETRAIT(TRAIT_NOLIMBDISABLE),
+ SIGNAL_ADDTRAIT(TRAIT_NOLIMBDISABLE),
+ ))
+ if(owner)
+ if(initial(can_be_disabled))
+ if(HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE))
+ set_can_be_disabled(FALSE)
+ needs_update_disabled = FALSE
+ RegisterSignal(new_owner, SIGNAL_REMOVETRAIT(TRAIT_NOLIMBDISABLE), PROC_REF(on_owner_nolimbdisable_trait_loss))
+ RegisterSignal(new_owner, SIGNAL_ADDTRAIT(TRAIT_NOLIMBDISABLE), PROC_REF(on_owner_nolimbdisable_trait_gain))
+
+ if(needs_update_disabled)
+ update_disabled()
+
+ return old_owner
+
+
+///Proc to change the value of the `can_be_disabled` variable and react to the event of its change.
+/obj/item/bodypart/proc/set_can_be_disabled(new_can_be_disabled)
+ if(can_be_disabled == new_can_be_disabled)
+ return
+ . = can_be_disabled
+ can_be_disabled = new_can_be_disabled
+ if(can_be_disabled)
+ if(owner)
+ if(HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE))
+ CRASH("set_can_be_disabled to TRUE with for limb whose owner has TRAIT_NOLIMBDISABLE")
+ RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS), PROC_REF(on_paralysis_trait_gain))
+ RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS), PROC_REF(on_paralysis_trait_loss))
+ update_disabled()
+ else if(.)
+ if(owner)
+ UnregisterSignal(owner, list(
+ SIGNAL_ADDTRAIT(TRAIT_PARALYSIS),
+ SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS),
+ ))
+ set_disabled(FALSE)
+
+
+///Called when TRAIT_PARALYSIS is added to the limb.
+/obj/item/bodypart/proc/on_paralysis_trait_gain(obj/item/bodypart/source)
+ SIGNAL_HANDLER
+ if(can_be_disabled)
+ set_disabled(TRUE)
+
+
+///Called when TRAIT_PARALYSIS is removed from the limb.
+/obj/item/bodypart/proc/on_paralysis_trait_loss(obj/item/bodypart/source)
+ SIGNAL_HANDLER
+ if(can_be_disabled)
+ update_disabled()
+
+
+///Called when TRAIT_NOLIMBDISABLE is added to the owner.
+/obj/item/bodypart/proc/on_owner_nolimbdisable_trait_gain(mob/living/carbon/source)
+ SIGNAL_HANDLER
+ set_can_be_disabled(FALSE)
+
+
+///Called when TRAIT_NOLIMBDISABLE is removed from the owner.
+/obj/item/bodypart/proc/on_owner_nolimbdisable_trait_loss(mob/living/carbon/source)
+ SIGNAL_HANDLER
+ set_can_be_disabled(initial(can_be_disabled))
+
+
+///Called when TRAIT_EASYLIMBWOUND is added to the owner.
+/obj/item/bodypart/proc/on_owner_easylimbwound_trait_gain(mob/living/carbon/source)
+ SIGNAL_HANDLER
+ disable_threshold = 0.6
+ if(can_be_disabled)
+ update_disabled()
+
+
+///Called when TRAIT_EASYLIMBWOUND is removed from the owner.
+/obj/item/bodypart/proc/on_owner_easylimbwound_trait_loss(mob/living/carbon/source)
+ SIGNAL_HANDLER
+ disable_threshold = initial(disable_threshold)
+ if(can_be_disabled)
+ update_disabled()
//Updates an organ's brute/burn states for use by update_damage_overlays()
//Returns 1 if we need to update overlays. 0 otherwise.
@@ -551,32 +720,64 @@
held_index = 1
px_x = -6
px_y = 0
+ can_be_disabled = TRUE
+
+
+/obj/item/bodypart/l_arm/set_owner(new_owner)
+ . = ..()
+ if(. == FALSE)
+ return
+ if(owner)
+ if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM))
+ ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM)
+ RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_loss))
+ else
+ REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM)
+ RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_gain))
+ if(.)
+ var/mob/living/carbon/old_owner = .
+ if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_L_ARM))
+ UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM))
+ if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM))
+ REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM)
+ else
+ UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM))
+
+
+///Proc to react to the owner gaining the TRAIT_PARALYSIS_L_ARM trait.
+/obj/item/bodypart/l_arm/proc/on_owner_paralysis_gain(mob/living/carbon/source)
+ SIGNAL_HANDLER
+ ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM)
+ UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM))
+ RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_loss))
+
+
+///Proc to react to the owner losing the TRAIT_PARALYSIS_L_ARM trait.
+/obj/item/bodypart/l_arm/proc/on_owner_paralysis_loss(mob/living/carbon/source)
+ SIGNAL_HANDLER
+ REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM)
+ UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM))
+ RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_gain))
-/obj/item/bodypart/l_arm/is_disabled()
- if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM))
- return BODYPART_DISABLED_PARALYSIS
- return ..()
/obj/item/bodypart/l_arm/set_disabled(new_disabled)
. = ..()
- if(!.)
+ if(isnull(.) || !owner)
return
- if(disabled == BODYPART_DISABLED_DAMAGE)
- if(owner.stat < UNCONSCIOUS)
- owner.emote("scream")
- if(owner.stat < DEAD)
- to_chat(owner, "Your [name] is too damaged to function! ")
- if(held_index)
- owner.dropItemToGround(owner.get_item_for_held_index(held_index))
- else if(disabled == BODYPART_DISABLED_PARALYSIS)
- if(owner.stat < DEAD)
- to_chat(owner, "You can't feel your [name]! ")
+
+ if(!.)
+ if(bodypart_disabled)
+ owner.set_usable_hands(owner.usable_hands - 1)
+ if(owner.stat < UNCONSCIOUS)
+ to_chat(owner, "Your lose control of your [name]! ")
if(held_index)
owner.dropItemToGround(owner.get_item_for_held_index(held_index))
+ else if(!bodypart_disabled)
+ owner.set_usable_hands(owner.usable_hands + 1)
+
if(owner.hud_used)
- var/atom/movable/screen/inventory/hand/L = owner.hud_used.hand_slots["[held_index]"]
- if(L)
- L.update_icon()
+ var/atom/movable/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots["[held_index]"]
+ hand_screen_object?.update_icon()
/obj/item/bodypart/l_arm/monkey
icon = 'icons/mob/animal_parts.dmi'
@@ -595,12 +796,14 @@
icon_state = "alien_l_arm"
px_x = 0
px_y = 0
- dismemberable = 0
+ dismemberable = FALSE
+ can_be_disabled = FALSE
max_damage = 100
animal_origin = ALIEN_BODYPART
/obj/item/bodypart/l_arm/devil
- dismemberable = 0
+ dismemberable = FALSE
+ can_be_disabled = FALSE
max_damage = 5000
animal_origin = DEVIL_BODYPART
@@ -621,32 +824,64 @@
held_index = 2
px_x = 6
px_y = 0
+ can_be_disabled = TRUE
+
+
+/obj/item/bodypart/r_arm/set_owner(new_owner)
+ . = ..()
+ if(. == FALSE)
+ return
+ if(owner)
+ if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM))
+ ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM)
+ RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_loss))
+ else
+ REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM)
+ RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_gain))
+ if(.)
+ var/mob/living/carbon/old_owner = .
+ if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_R_ARM))
+ UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM))
+ if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM))
+ REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM)
+ else
+ UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM))
+
+
+///Proc to react to the owner gaining the TRAIT_PARALYSIS_R_ARM trait.
+/obj/item/bodypart/r_arm/proc/on_owner_paralysis_gain(mob/living/carbon/source)
+ SIGNAL_HANDLER
+ ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM)
+ UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM))
+ RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_loss))
+
+
+///Proc to react to the owner losing the TRAIT_PARALYSIS_R_ARM trait.
+/obj/item/bodypart/r_arm/proc/on_owner_paralysis_loss(mob/living/carbon/source)
+ SIGNAL_HANDLER
+ REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM)
+ UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM))
+ RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_gain))
-/obj/item/bodypart/r_arm/is_disabled()
- if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM))
- return BODYPART_DISABLED_PARALYSIS
- return ..()
/obj/item/bodypart/r_arm/set_disabled(new_disabled)
. = ..()
- if(!.)
+ if(isnull(.) || !owner)
return
- if(disabled == BODYPART_DISABLED_DAMAGE)
- if(owner.stat < UNCONSCIOUS)
- owner.emote("scream")
- if(owner.stat < DEAD)
- to_chat(owner, "Your [name] is too damaged to function! ")
- if(held_index)
- owner.dropItemToGround(owner.get_item_for_held_index(held_index))
- else if(disabled == BODYPART_DISABLED_PARALYSIS)
- if(owner.stat < DEAD)
- to_chat(owner, "You can't feel your [name]! ")
+
+ if(!.)
+ if(bodypart_disabled)
+ owner.set_usable_hands(owner.usable_hands - 1)
+ if(owner.stat < UNCONSCIOUS)
+ to_chat(owner, "Your lose control of your [name]! ")
if(held_index)
owner.dropItemToGround(owner.get_item_for_held_index(held_index))
+ else if(!bodypart_disabled)
+ owner.set_usable_hands(owner.usable_hands + 1)
+
if(owner.hud_used)
- var/atom/movable/screen/inventory/hand/R = owner.hud_used.hand_slots["[held_index]"]
- if(R)
- R.update_icon()
+ var/atom/movable/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots["[held_index]"]
+ hand_screen_object?.update_icon()
/obj/item/bodypart/r_arm/monkey
icon = 'icons/mob/animal_parts.dmi'
@@ -666,12 +901,14 @@
icon_state = "alien_r_arm"
px_x = 0
px_y = 0
- dismemberable = 0
+ dismemberable = FALSE
+ can_be_disabled = FALSE
max_damage = 100
animal_origin = ALIEN_BODYPART
/obj/item/bodypart/r_arm/devil
- dismemberable = 0
+ dismemberable = FALSE
+ can_be_disabled = FALSE
max_damage = 5000
animal_origin = DEVIL_BODYPART
@@ -689,24 +926,58 @@
px_x = -2
px_y = 12
max_stamina_damage = 50
+ can_be_disabled = TRUE
+
+
+/obj/item/bodypart/l_leg/set_owner(new_owner)
+ . = ..()
+ if(. == FALSE)
+ return
+ if(owner)
+ if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_LEG))
+ ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG)
+ RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG), PROC_REF(on_owner_paralysis_loss))
+ else
+ REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG)
+ RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG), PROC_REF(on_owner_paralysis_gain))
+ if(.)
+ var/mob/living/carbon/old_owner = .
+ if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_L_LEG))
+ UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG))
+ if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_L_LEG))
+ REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG)
+ else
+ UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG))
+
+
+///Proc to react to the owner gaining the TRAIT_PARALYSIS_L_LEG trait.
+/obj/item/bodypart/l_leg/proc/on_owner_paralysis_gain(mob/living/carbon/source)
+ SIGNAL_HANDLER
+ ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG)
+ UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG))
+ RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG), PROC_REF(on_owner_paralysis_loss))
+
+
+///Proc to react to the owner losing the TRAIT_PARALYSIS_L_LEG trait.
+/obj/item/bodypart/l_leg/proc/on_owner_paralysis_loss(mob/living/carbon/source)
+ SIGNAL_HANDLER
+ REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG)
+ UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG))
+ RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG), PROC_REF(on_owner_paralysis_gain))
-/obj/item/bodypart/l_leg/is_disabled()
- if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_LEG))
- return BODYPART_DISABLED_PARALYSIS
- return ..()
/obj/item/bodypart/l_leg/set_disabled(new_disabled)
. = ..()
- if(!.)
+ if(isnull(.) || !owner)
return
- if(disabled == BODYPART_DISABLED_DAMAGE)
- if(owner.stat < UNCONSCIOUS)
- owner.emote("scream")
- if(owner.stat < DEAD)
- to_chat(owner, "Your [name] is too damaged to function! ")
- else if(disabled == BODYPART_DISABLED_PARALYSIS)
- if(owner.stat < DEAD)
- to_chat(owner, "You can't feel your [name]! ")
+
+ if(!.)
+ if(bodypart_disabled)
+ owner.set_usable_legs(owner.usable_legs - 1)
+ if(owner.stat < UNCONSCIOUS)
+ to_chat(owner, "Your lose control of your [name]! ")
+ else if(!bodypart_disabled)
+ owner.set_usable_legs(owner.usable_legs + 1)
/obj/item/bodypart/l_leg/monkey
@@ -726,12 +997,14 @@
icon_state = "alien_l_leg"
px_x = 0
px_y = 0
- dismemberable = 0
+ dismemberable = FALSE
+ can_be_disabled = FALSE
max_damage = 100
animal_origin = ALIEN_BODYPART
/obj/item/bodypart/l_leg/devil
- dismemberable = 0
+ dismemberable = FALSE
+ can_be_disabled = FALSE
max_damage = 5000
animal_origin = DEVIL_BODYPART
@@ -751,24 +1024,58 @@
px_x = 2
px_y = 12
max_stamina_damage = 50
+ can_be_disabled = TRUE
+
+
+/obj/item/bodypart/r_leg/set_owner(new_owner)
+ . = ..()
+ if(. == FALSE)
+ return
+ if(owner)
+ if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_LEG))
+ ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG)
+ RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_LEG), PROC_REF(on_owner_paralysis_loss))
+ else
+ REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG)
+ RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG), PROC_REF(on_owner_paralysis_gain))
+ if(.)
+ var/mob/living/carbon/old_owner = .
+ if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_R_LEG))
+ UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_LEG))
+ if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_R_LEG))
+ REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG)
+ else
+ UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG))
+
+
+///Proc to react to the owner gaining the TRAIT_PARALYSIS_R_LEG trait.
+/obj/item/bodypart/r_leg/proc/on_owner_paralysis_gain(mob/living/carbon/source)
+ SIGNAL_HANDLER
+ ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG)
+ UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG))
+ RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_LEG), PROC_REF(on_owner_paralysis_loss))
+
+
+///Proc to react to the owner losing the TRAIT_PARALYSIS_R_LEG trait.
+/obj/item/bodypart/r_leg/proc/on_owner_paralysis_loss(mob/living/carbon/source)
+ SIGNAL_HANDLER
+ REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG)
+ UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_LEG))
+ RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG), PROC_REF(on_owner_paralysis_gain))
-/obj/item/bodypart/r_leg/is_disabled()
- if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_LEG))
- return BODYPART_DISABLED_PARALYSIS
- return ..()
/obj/item/bodypart/r_leg/set_disabled(new_disabled)
. = ..()
- if(!.)
+ if(isnull(.) || !owner)
return
- if(disabled == BODYPART_DISABLED_DAMAGE)
- if(owner.stat < UNCONSCIOUS)
- owner.emote("scream")
- if(owner.stat < DEAD)
- to_chat(owner, "Your [name] is too damaged to function! ")
- else if(disabled == BODYPART_DISABLED_PARALYSIS)
- if(owner.stat < DEAD)
- to_chat(owner, "You can't feel your [name]! ")
+
+ if(!.)
+ if(bodypart_disabled)
+ owner.set_usable_legs(owner.usable_legs - 1)
+ if(owner.stat < UNCONSCIOUS)
+ to_chat(owner, "Your lose control of your [name]! ")
+ else if(!bodypart_disabled)
+ owner.set_usable_legs(owner.usable_legs + 1)
/obj/item/bodypart/r_leg/monkey
@@ -788,12 +1095,14 @@
icon_state = "alien_r_leg"
px_x = 0
px_y = 0
- dismemberable = 0
+ dismemberable = FALSE
+ can_be_disabled = FALSE
max_damage = 100
animal_origin = ALIEN_BODYPART
/obj/item/bodypart/r_leg/devil
- dismemberable = 0
+ dismemberable = FALSE
+ can_be_disabled = FALSE
max_damage = 5000
animal_origin = DEVIL_BODYPART
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index 27dbe0c7285d9..61848a6d847e0 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -27,9 +27,7 @@
drop_limb()
C.update_equipment_speed_mods() // Update in case speed affecting item unequipped by dismemberment
- var/turf/location = C.loc
- if(istype(location))
- C.add_splatter_floor(location)
+ C.add_bleeding(BLEED_CRITICAL)
if(QDELETED(src)) //Could have dropped into lava/explosion/chasm/whatever
return TRUE
@@ -61,7 +59,7 @@
return FALSE
. = list()
var/turf/T = get_turf(C)
- C.add_splatter_floor(T)
+ C.add_bleeding(BLEED_CRITICAL)
playsound(get_turf(C), 'sound/misc/splort.ogg', 80, 1)
for(var/X in C.internal_organs)
var/obj/item/organ/O = X
@@ -85,7 +83,7 @@
SEND_SIGNAL(owner, COMSIG_CARBON_REMOVE_LIMB, src, dismembered)
SEND_SIGNAL(src, COMSIG_BODYPART_REMOVED, owner, dismembered)
update_limb(TRUE)
- C.bodyparts -= src
+ C.remove_bodypart(src)
if(held_index)
C.dropItemToGround(owner.get_item_for_held_index(held_index), 1)
@@ -127,7 +125,6 @@
C.update_health_hud() //update the healthdoll
C.update_body()
C.update_hair()
- C.update_mobility()
if(!Tsec) // Tsec = null happens when a "dummy human" used for rendering icons on prefs screen gets its limbs replaced.
qdel(src)
@@ -275,8 +272,8 @@
SEND_SIGNAL(C, COMSIG_CARBON_ATTACH_LIMB, src, special)
SEND_SIGNAL(src, COMSIG_BODYPART_ATTACHED, C, special)
moveToNullspace()
- owner = C
- C.bodyparts += src
+ set_owner(C)
+ C.add_bodypart(src)
if(held_index)
if(held_index > C.hand_bodyparts.len)
C.hand_bodyparts.len = held_index
@@ -309,7 +306,6 @@
C.updatehealth()
C.update_body()
C.update_hair()
- C.update_mobility()
SEND_SIGNAL(C, COMSIG_CARBON_POST_ATTACH_LIMB, src, special)
diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm
index a4f6003f5ae64..ac6032ee14201 100644
--- a/code/modules/surgery/bodyparts/helpers.dm
+++ b/code/modules/surgery/bodyparts/helpers.dm
@@ -5,28 +5,39 @@
RETURN_TYPE(/obj/item/bodypart)
if(!zone)
zone = BODY_ZONE_CHEST
- for(var/obj/item/bodypart/L as() in bodyparts)
+ for(var/obj/item/bodypart/L as anything in bodyparts)
if(L.body_zone == zone)
return L
/mob/living/carbon/has_hand_for_held_index(i)
- if(i)
- var/obj/item/bodypart/L = hand_bodyparts[i]
- if(L && !L.disabled)
- return L
+ if(!i)
+ return FALSE
+ var/obj/item/bodypart/hand_instance = hand_bodyparts[i]
+ if(hand_instance && !hand_instance.bodypart_disabled)
+ return hand_instance
return FALSE
+///Get the bodypart for whatever hand we have active, Only relevant for carbons
+/mob/proc/get_active_hand()
+ return FALSE
+
+/mob/living/carbon/get_active_hand()
+ var/which_hand = BODY_ZONE_PRECISE_L_HAND
+ if(!(active_hand_index % 2))
+ which_hand = BODY_ZONE_PRECISE_R_HAND
+ return get_bodypart(check_zone(which_hand))
/mob/proc/has_left_hand(check_disabled = TRUE)
return TRUE
+
/mob/living/carbon/has_left_hand(check_disabled = TRUE)
- for(var/obj/item/bodypart/L in hand_bodyparts)
- if(L.held_index % 2)
- if(!check_disabled || !L.disabled)
- return TRUE
+ for(var/obj/item/bodypart/hand_instance in hand_bodyparts)
+ if(!(hand_instance.held_index % 2) || (check_disabled && hand_instance.bodypart_disabled))
+ continue
+ return TRUE
return FALSE
/mob/living/carbon/alien/larva/has_left_hand()
@@ -36,70 +47,24 @@
/mob/proc/has_right_hand(check_disabled = TRUE)
return TRUE
+
/mob/living/carbon/has_right_hand(check_disabled = TRUE)
- for(var/obj/item/bodypart/L in hand_bodyparts)
- if(!(L.held_index % 2))
- if(!check_disabled || !L.disabled)
- return TRUE
+ for(var/obj/item/bodypart/hand_instance in hand_bodyparts)
+ if(hand_instance.held_index % 2 || (check_disabled && hand_instance.bodypart_disabled))
+ continue
+ return TRUE
return FALSE
+
/mob/living/carbon/alien/larva/has_right_hand()
return 1
-
-//Limb numbers
-/mob/proc/get_num_arms(check_disabled = TRUE)
- return 2
-
-/mob/living/carbon/get_num_arms(check_disabled = TRUE)
- . = 0
- for(var/obj/item/bodypart/affecting as() in bodyparts)
- if(affecting.body_part == ARM_RIGHT)
- if(!check_disabled || !affecting.disabled)
- .++
- if(affecting.body_part == ARM_LEFT)
- if(!check_disabled || !affecting.disabled)
- .++
-
-
-//sometimes we want to ignore that we don't have the required amount of arms.
-/mob/proc/get_arm_ignore()
- return 0
-
-/mob/living/carbon/alien/larva/get_arm_ignore()
- return 1 //so we can still handcuff larvas.
-
-
-/mob/proc/get_num_legs(check_disabled = TRUE)
- return 2
-
-/mob/living/carbon/get_num_legs(check_disabled = TRUE)
- . = 0
- for(var/obj/item/bodypart/affecting as() in bodyparts)
- if(affecting.body_part == LEG_RIGHT)
- if(!check_disabled || !affecting.disabled)
- .++
- if(affecting.body_part == LEG_LEFT)
- if(!check_disabled || !affecting.disabled)
- .++
-
-//sometimes we want to ignore that we don't have the required amount of legs.
-/mob/proc/get_leg_ignore()
- return FALSE
-
-/mob/living/carbon/alien/larva/get_leg_ignore()
- return TRUE
-
-/mob/living/carbon/human/get_leg_ignore()
- if(movement_type & (FLYING | FLOATING))
- return TRUE
- return FALSE
-
/mob/living/proc/get_missing_limbs()
return list()
/mob/living/carbon/get_missing_limbs()
+ RETURN_TYPE(/list)
var/list/full = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
for(var/zone in full)
if(get_bodypart(zone))
@@ -121,7 +86,7 @@
var/list/disabled = list()
for(var/zone in full)
var/obj/item/bodypart/affecting = get_bodypart(zone)
- if(affecting && affecting.disabled)
+ if(affecting?.bodypart_disabled)
disabled += zone
return disabled
@@ -130,7 +95,7 @@
var/list/disabled = list()
for(var/zone in full)
var/obj/item/bodypart/affecting = get_bodypart(zone)
- if(affecting?.disabled)
+ if(affecting?.bodypart_disabled)
disabled += zone
return disabled
@@ -151,16 +116,6 @@
continue
return TRUE
-///Get the bodypart for whatever hand we have active, Only relevant for carbons
-/mob/proc/get_active_hand()
- return FALSE
-
-/mob/living/carbon/get_active_hand()
- var/which_hand = BODY_ZONE_PRECISE_L_HAND
- if(!(active_hand_index % 2))
- which_hand = BODY_ZONE_PRECISE_R_HAND
- return get_bodypart(check_zone(which_hand))
-
//Helper for quickly creating a new limb - used by augment code in species.dm spec_attacked_by
//
// FUCK YOU AUGMENT CODE - With love, Kapu
diff --git a/code/modules/surgery/cauterize.dm b/code/modules/surgery/cauterize.dm
new file mode 100644
index 0000000000000..b5ff8d7d3a854
--- /dev/null
+++ b/code/modules/surgery/cauterize.dm
@@ -0,0 +1,15 @@
+/datum/surgery/cauterize
+ steps = list(/datum/surgery_step/incise,
+ /datum/surgery_step/retract_skin,
+ /datum/surgery_step/close)
+
+ target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
+ possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD)
+ requires_bodypart_type = FALSE
+ replaced_by = /datum/surgery
+ ignore_clothes = TRUE
+
+/datum/surgery/cauterize/can_start(mob/user, mob/living/carbon/target, target_zone)
+ if (..())
+ return TRUE
+ return target.is_bleeding()
diff --git a/code/modules/surgery/coronary_bypass.dm b/code/modules/surgery/coronary_bypass.dm
index 2e49b36ade5c5..67b55e9399594 100644
--- a/code/modules/surgery/coronary_bypass.dm
+++ b/code/modules/surgery/coronary_bypass.dm
@@ -30,11 +30,11 @@
/datum/surgery_step/incise_heart/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery)
if(ishuman(target))
var/mob/living/carbon/human/H = target
- if (!(NOBLOOD in H.dna.species.species_traits))
+ if (!((NOBLOOD in H.dna.species.species_traits) || HAS_TRAIT(H, TRAIT_NO_BLOOD)))
display_results(user, target, "Blood pools around the incision in [H]'s heart. ",
"Blood pools around the incision in [H]'s heart.",
"")
- H.bleed_rate += 10
+ H.add_bleeding(BLEED_DEEP_WOUND)
H.adjustBruteLoss(10)
return TRUE
@@ -44,7 +44,7 @@
display_results(user, target, "You screw up, cutting too deeply into the heart! ",
"[user] screws up, causing blood to spurt out of [H]'s chest! ",
"[user] screws up, causing blood to spurt out of [H]'s chest! ")
- H.bleed_rate += 20
+ H.add_bleeding(BLEED_CRITICAL)
H.adjustOrganLoss(ORGAN_SLOT_HEART, 10)
H.adjustBruteLoss(10)
@@ -76,5 +76,5 @@
"[user] screws up, causing blood to spurt out of [H]'s chest profusely! ",
"[user] screws up, causing blood to spurt out of [H]'s chest profusely! ")
H.adjustOrganLoss(ORGAN_SLOT_HEART, 20)
- H.bleed_rate += 30
+ H.add_bleeding(BLEED_CRITICAL)
return FALSE
diff --git a/code/modules/surgery/dental_implant.dm b/code/modules/surgery/dental_implant.dm
index 7d6dfe54e1165..0b448fa3906cc 100644
--- a/code/modules/surgery/dental_implant.dm
+++ b/code/modules/surgery/dental_implant.dm
@@ -18,6 +18,7 @@
if(!istype(tool))
return 0
+ target.cauterise_wounds()
user.transferItemToLoc(tool, target, TRUE)
var/datum/action/item_action/hands_free/activate_pill/P = new(tool)
diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm
index 2e79428cf6731..0babec03994a9 100644
--- a/code/modules/surgery/helpers.dm
+++ b/code/modules/surgery/helpers.dm
@@ -38,7 +38,7 @@
continue
else if(C && S.requires_bodypart) //mob with no limb in surgery zone when we need a limb
continue
- if(S.lying_required && (M.mobility_flags & MOBILITY_STAND))
+ if(S.lying_required && M.body_position != LYING_DOWN)
continue
if(!S.can_start(user, M, target_zone))
continue
@@ -68,7 +68,7 @@
return
else if(C && S.requires_bodypart)
return
- if(S.lying_required && (M.mobility_flags & MOBILITY_STAND))
+ if(S.lying_required && M.body_position != LYING_DOWN)
return
if(!S.can_start(user, M, target_zone))
return
diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm
index f65f70c47a702..df406f8d8d8fb 100644
--- a/code/modules/surgery/limb_augmentation.dm
+++ b/code/modules/surgery/limb_augmentation.dm
@@ -25,17 +25,18 @@
to_chat(user, "[tool] isn't the right type for [parse_zone(surgery.location)]. ")
return -1
L = surgery.operated_bodypart
- if(L)
- if(L.is_disabled() == BODYPART_DISABLED_PARALYSIS)
- to_chat(user, "You can't augment a limb with paralysis! ")
- return -1
- else
- display_results(user, target, "You begin to augment [target]'s [parse_zone(surgery.location)]... ",
- "[user] begins to augment [target]'s [parse_zone(surgery.location)] with [aug].",
- "[user] begins to augment [target]'s [parse_zone(surgery.location)].")
- else
+
+ if(!L)
user.visible_message("[user] looks for [target]'s [parse_zone(surgery.location)].", "You look for [target]'s [parse_zone(surgery.location)]... ")
+ return
+ if(L?.bodypart_disabled)
+ to_chat(user, "You can't augment a limb with paralysis! ")
+ return -1
+ else
+ display_results(user, target, "You begin to augment [target]'s [parse_zone(surgery.location)]... ",
+ "[user] begins to augment [target]'s [parse_zone(surgery.location)] with [aug].",
+ "[user] begins to augment [target]'s [parse_zone(surgery.location)].")
//ACTUAL SURGERIES
diff --git a/code/modules/surgery/mechanic_steps.dm b/code/modules/surgery/mechanic_steps.dm
index 4d180a7014100..230353d9f3ca5 100644
--- a/code/modules/surgery/mechanic_steps.dm
+++ b/code/modules/surgery/mechanic_steps.dm
@@ -48,6 +48,10 @@
return TRUE
+/datum/surgery_step/mechanic_close/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery, default_display_results)
+ target.cauterise_wounds()
+ return ..()
+
//prepare electronics
/datum/surgery_step/prepare_electronics
name = "prepare electronics"
diff --git a/code/modules/surgery/organic_steps.dm b/code/modules/surgery/organic_steps.dm
index 9243218101665..900f9b7d19605 100644
--- a/code/modules/surgery/organic_steps.dm
+++ b/code/modules/surgery/organic_steps.dm
@@ -22,11 +22,11 @@
/datum/surgery_step/incise/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery)
if ishuman(target)
var/mob/living/carbon/human/H = target
- if (!(NOBLOOD in H.dna.species.species_traits))
+ if (!((NOBLOOD in H.dna.species.species_traits) || HAS_TRAIT(H, TRAIT_NO_BLOOD)))
display_results(user, target, "Blood pools around the incision in [H]'s [parse_zone(surgery.location)]. ",
"Blood pools around the incision in [H]'s [parse_zone(surgery.location)].",
"")
- H.bleed_rate += 3
+ H.add_bleeding(BLEED_CUT)
return TRUE
/datum/surgery_step/incise/nobleed //silly friendly!
@@ -95,6 +95,7 @@
/datum/surgery_step/close/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery)
if(locate(/datum/surgery_step/saw) in surgery.steps)
target.heal_bodypart_damage(45,0)
+ target.cauterise_wounds()
return ..()
diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm
index 97afce1b052a4..f359de46a4c65 100644
--- a/code/modules/surgery/organs/heart.dm
+++ b/code/modules/surgery/organs/heart.dm
@@ -17,9 +17,16 @@
var/beating = 1
var/icon_base = "heart"
attack_verb = list("beat", "thumped")
- var/beat = BEAT_NONE//is this mob having a heatbeat sound played? if so, which?
- var/failed = FALSE //to prevent constantly running failing code
- var/operated = FALSE //whether the heart's been operated on to fix some of its damages
+ //is this mob having a heatbeat sound played? if so, which?
+ var/beat = BEAT_NONE
+ //to prevent constantly running failing code
+ var/failed = FALSE
+ //whether the heart's been operated on to fix some of its damages
+ var/operated = FALSE
+ ///Color of the heart, is set by the species on gain
+ //var/ethereal_color = "#9c3030"
+
+
/obj/item/organ/heart/update_icon()
if(beating)
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index d2d9f5d45aa8e..eeb4bf3bbfc6e 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -349,6 +349,9 @@
if(prob(20))
to_chat(H, "You feel [hot_message] in your [name]! ")
+ // The air you breathe out should match your body temperature
+ breath.set_temperature(H.bodytemperature)
+
/obj/item/organ/lungs/on_life()
..()
if((!failed) && ((organ_flags & ORGAN_FAILING)))
diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm
index 516c027a3476a..53aa18210b69f 100644
--- a/code/modules/surgery/organs/vocal_cords.dm
+++ b/code/modules/surgery/organs/vocal_cords.dm
@@ -321,7 +321,7 @@
else if((findtext(message, bleed_words)))
cooldown = COOLDOWN_DAMAGE
for(var/mob/living/carbon/human/H in listeners)
- H.bleed_rate += (5 * power_multiplier)
+ H.add_bleeding(BLEED_SURFACE)
//FIRE
else if((findtext(message, burn_words)))
diff --git a/code/modules/surgery/organs/wings.dm b/code/modules/surgery/organs/wings.dm
index a7019ce1f0e23..6ce219b437b40 100644
--- a/code/modules/surgery/organs/wings.dm
+++ b/code/modules/surgery/organs/wings.dm
@@ -186,7 +186,7 @@
var/obj/item/organ/wings/bee/wings = locate(/obj/item/organ/wings/bee) in L.internal_organs
var/jumpdistance = wings.jumpdist
- if(L.stat != CONSCIOUS || L.buckling) // Has to be conscious and unbuckled
+ if(L.stat != CONSCIOUS || L.buckled) // Has to be conscious and unbuckled
return
if(recharging_time > world.time)
to_chat(L, "The wings aren't ready to dash yet! ")
diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/prosthetic_replacement.dm
index d3eb2dcc0a7d5..b9e9a9212a3c5 100644
--- a/code/modules/surgery/prosthetic_replacement.dm
+++ b/code/modules/surgery/prosthetic_replacement.dm
@@ -77,6 +77,7 @@
display_results(user, target, "You succeed in replacing [target]'s [parse_zone(surgery.location)]. ",
"[user] successfully replaces [target]'s [parse_zone(surgery.location)] with [tool]!",
"[user] successfully replaces [target]'s [parse_zone(surgery.location)]!")
+ target.cauterise_wounds()
return 1
else
var/obj/item/bodypart/L = target.newBodyPart(surgery.location, FALSE, FALSE)
@@ -90,16 +91,20 @@
if(istype(tool, /obj/item/chainsaw/energy/doom))
var/obj/item/mounted_chainsaw/super/new_arm = new(target)
surgery.location == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm)
+ target.cauterise_wounds()
return 1
else if(istype(tool, /obj/item/chainsaw/energy))
var/obj/item/mounted_chainsaw/energy/new_arm = new(target)
surgery.location == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm)
+ target.cauterise_wounds()
return 1
else if(istype(tool, /obj/item/chainsaw))
var/obj/item/mounted_chainsaw/normal/new_arm = new(target)
surgery.location == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm)
+ target.cauterise_wounds()
return 1
else if(istype(tool, /obj/item/melee/synthetic_arm_blade))
var/obj/item/melee/arm_blade/new_arm = new(target,TRUE,TRUE)
surgery.location == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm)
+ target.cauterise_wounds()
return 1
diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm
index 858946b3e9d92..34ce7cd96dfa0 100644
--- a/code/modules/surgery/remove_embedded_object.dm
+++ b/code/modules/surgery/remove_embedded_object.dm
@@ -27,6 +27,7 @@
if(L)
if(ishuman(target))
var/mob/living/carbon/human/H = target
+ H.cauterise_wounds()
var/objects = 0
for(var/obj/item/I in L.embedded_objects)
objects++
diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm
index 3f0095d2d3970..aa65fb0d06b71 100644
--- a/code/modules/surgery/tools.dm
+++ b/code/modules/surgery/tools.dm
@@ -150,6 +150,7 @@
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "tore", "ripped", "diced", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP_ACCURATE
+ bleed_force = BLEED_CUT
tool_behaviour = TOOL_SCALPEL
toolspeed = 1
@@ -173,6 +174,7 @@
toolspeed = 0.5
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP_ACCURATE
+ bleed_force = BLEED_CUT
/obj/item/scalpel/suicide_act(mob/living/user)
user.visible_message("[user] is slitting [user.p_their()] [pick("wrists", "throat", "stomach")] with [src]! It looks like [user.p_theyre()] trying to commit suicide! ")
@@ -196,6 +198,7 @@
custom_materials = list(/datum/material/iron=10000, /datum/material/glass=6000)
attack_verb = list("attacked", "slashed", "sawed", "cut")
sharpness = IS_SHARP
+ bleed_force = BLEED_DEEP_WOUND
tool_behaviour = TOOL_SAW
toolspeed = 1
@@ -220,6 +223,7 @@
toolspeed = 0.5
attack_verb = list("attacked", "slashed", "sawed", "cut")
sharpness = IS_SHARP
+ bleed_force = BLEED_DEEP_WOUND
/obj/item/hacksaw
name = "hacksaw"
@@ -342,7 +346,8 @@
light_range = 1
light_color = LIGHT_COLOR_GREEN
sharpness = IS_SHARP_ACCURATE
-
+ // It cauterises the wound it causes
+ bleed_force = 0
/obj/item/scalpel/advanced/attack_self(mob/user)
playsound(get_turf(user), 'sound/machines/click.ogg', 50, TRUE)
diff --git a/code/modules/tgchat/to_chat.dm b/code/modules/tgchat/to_chat.dm
index 73066c6e42943..cdce3a04b146d 100644
--- a/code/modules/tgchat/to_chat.dm
+++ b/code/modules/tgchat/to_chat.dm
@@ -59,7 +59,7 @@
handle_whitespace = TRUE,
trailing_newline = TRUE
)
- if(isnull(Master) || !Master.current_runlevel)
+ if(isnull(Master) || !SSchat?.initialized || !MC_RUNNING(SSchat.init_stage))
to_chat_immediate(target, html, type, text, avoid_highlighting, allow_linkify)
return
diff --git a/code/modules/tgs/README.md b/code/modules/tgs/README.md
index 6319028d8106d..35ca73d7e9a8e 100644
--- a/code/modules/tgs/README.md
+++ b/code/modules/tgs/README.md
@@ -1,6 +1,6 @@
# DMAPI Internals
-This folder should be placed on it's own inside a codebase that wishes to use the TGS DMAPI. Warranty void if modified.
+This folder should be placed on its own inside a codebase that wishes to use the TGS DMAPI. Warranty void if modified.
- [includes.dm](./includes.dm) is the file that should be included by DM code, it handles including the rest.
- The [core](./core) folder includes all code not directly part of any API version.
diff --git a/code/modules/tgs/v5/api.dm b/code/modules/tgs/v5/api.dm
index 95b8edd3ee5c2..05d0dee25b3c2 100644
--- a/code/modules/tgs/v5/api.dm
+++ b/code/modules/tgs/v5/api.dm
@@ -50,7 +50,9 @@
version = null // we want this to be the TGS version, not the interop version
// sleep once to prevent an issue where world.Export on the first tick can hang indefinitely
+ TGS_DEBUG_LOG("Starting Export bug prevention sleep tick. time:[world.time] sleep_offline:[world.sleep_offline]")
sleep(world.tick_lag)
+ TGS_DEBUG_LOG("Export bug prevention sleep complete")
var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands(), DMAPI5_PARAMETER_TOPIC_PORT = GetTopicPort()))
if(!istype(bridge_response))
diff --git a/code/modules/tgui/states/not_incapacitated.dm b/code/modules/tgui/states/not_incapacitated.dm
index 16dcb7881ed03..4d38c62392f0f 100644
--- a/code/modules/tgui/states/not_incapacitated.dm
+++ b/code/modules/tgui/states/not_incapacitated.dm
@@ -25,12 +25,8 @@ GLOBAL_DATUM_INIT(not_incapacitated_turf_state, /datum/ui_state/not_incapacitate
turf_check = no_turfs
/datum/ui_state/not_incapacitated_state/can_use_topic(src_object, mob/user)
- if(user.stat)
+ if(user.stat != CONSCIOUS)
return UI_CLOSE
- if(user.incapacitated() || (turf_check && !isturf(user.loc)))
+ if(HAS_TRAIT(src, TRAIT_UI_BLOCKED) || user.incapacitated() || (turf_check && !isturf(user.loc)))
return UI_DISABLED
- if(isliving(user))
- var/mob/living/L = user
- if(!(L.mobility_flags & MOBILITY_STAND))
- return UI_DISABLED
return UI_INTERACTIVE
diff --git a/code/modules/tgui/status_composers.dm b/code/modules/tgui/status_composers.dm
index 9a2200eda3b65..51f28367ecdab 100644
--- a/code/modules/tgui/status_composers.dm
+++ b/code/modules/tgui/status_composers.dm
@@ -101,6 +101,6 @@
return UI_UPDATE
var/mob/living/living_user = user
- return (!(living_user.mobility_flags & MOBILITY_STAND) && living_user.stat == CONSCIOUS) \
+ return (living_user.body_position == LYING_DOWN && living_user.stat == CONSCIOUS) \
? UI_INTERACTIVE \
: UI_UPDATE
diff --git a/code/modules/unit_tests/security_levels.dm b/code/modules/unit_tests/security_levels.dm
new file mode 100644
index 0000000000000..eecef51ff99c9
--- /dev/null
+++ b/code/modules/unit_tests/security_levels.dm
@@ -0,0 +1,16 @@
+/**
+ * Security Level Unit Test
+ *
+ * This test is here to ensure there are no security levels with the same name or number level. Having the same name or number level will cause problems.
+ */
+/datum/unit_test/security_levels
+
+/datum/unit_test/security_levels/Run()
+ var/list/comparison = subtypesof(/datum/security_level)
+
+ for(var/datum/security_level/iterating_level in comparison)
+ for(var/datum/security_level/iterating_level_check in comparison)
+ if(iterating_level == iterating_level_check) // If they are the same type, don't check
+ continue
+ TEST_ASSERT_NOTEQUAL(iterating_level.name, iterating_level_check.name, "Security level [iterating_level] has the same name as [iterating_level_check]!")
+ TEST_ASSERT_NOTEQUAL(iterating_level.number_level, iterating_level_check.number_level, "Security level [iterating_level] has the same level number as [iterating_level_check]!")
diff --git a/code/modules/vehicles/_vehicle.dm b/code/modules/vehicles/_vehicle.dm
index bf3584f74e24d..29dc5b3dfaf7c 100644
--- a/code/modules/vehicles/_vehicle.dm
+++ b/code/modules/vehicles/_vehicle.dm
@@ -4,7 +4,7 @@
icon = 'icons/obj/vehicles.dmi'
icon_state = "error"
max_integrity = 300
- armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 0)
+ armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 0, BLEED = 0)
density = TRUE
anchored = FALSE
COOLDOWN_DECLARE(cooldown_vehicle_move)
@@ -115,12 +115,12 @@
/obj/vehicle/proc/after_remove_occupant(mob/M)
-/obj/vehicle/relaymove(mob/user, direction)
+/obj/vehicle/relaymove(mob/living/user, direction)
if(is_driver(user))
return driver_move(user, direction)
return FALSE
-/obj/vehicle/proc/driver_move(mob/user, direction)
+/obj/vehicle/proc/driver_move(mob/living/user, direction)
if(key_type && !is_key(inserted_key))
to_chat(user, "[src] has no key inserted! ")
return FALSE
diff --git a/code/modules/vehicles/atv.dm b/code/modules/vehicles/atv.dm
index 7f756ba6cc3f8..a81633cf9a561 100644
--- a/code/modules/vehicles/atv.dm
+++ b/code/modules/vehicles/atv.dm
@@ -4,7 +4,7 @@
desc = "An all-terrain vehicle built for traversing rough terrain with ease. One of the few old-Earth technologies that are still relevant on most planet-bound outposts."
icon_state = "atv"
max_integrity = 150
- armor = list(MELEE = 50, BULLET = 25, LASER = 20, ENERGY = 0, BOMB = 50, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 25, LASER = 20, ENERGY = 0, BOMB = 50, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 0, BLEED = 0)
key_type = /obj/item/key
integrity_failure = 0.5
var/static/mutable_appearance/atvcover
@@ -13,6 +13,7 @@
. = ..()
var/datum/component/riding/D = LoadComponent(/datum/component/riding)
D.vehicle_move_delay = 1.5
+ D.empable = TRUE
D.set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(0, 4), TEXT_WEST = list( 0, 4)))
D.set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER)
D.set_vehicle_dir_layer(NORTH, OBJ_LAYER)
diff --git a/code/modules/vehicles/cars/car.dm b/code/modules/vehicles/cars/car.dm
index 75b59507e9510..68a332beee868 100644
--- a/code/modules/vehicles/cars/car.dm
+++ b/code/modules/vehicles/cars/car.dm
@@ -20,7 +20,7 @@
if(car_traits & CAN_KIDNAP)
initialize_controller_action_type(/datum/action/vehicle/sealed/DumpKidnappedMobs, VEHICLE_CONTROL_DRIVE)
-/obj/vehicle/sealed/car/driver_move(mob/user, direction)
+/obj/vehicle/sealed/car/driver_move(mob/living/user, direction)
if(key_type && !is_key(inserted_key))
to_chat(user, "[src] has no key inserted! ")
return FALSE
diff --git a/code/modules/vehicles/cars/clowncar.dm b/code/modules/vehicles/cars/clowncar.dm
index 2f48b6e31bc8a..b90c3e781043b 100644
--- a/code/modules/vehicles/cars/clowncar.dm
+++ b/code/modules/vehicles/cars/clowncar.dm
@@ -3,7 +3,7 @@
desc = "How someone could even fit in there is beyond me."
icon_state = "clowncar"
max_integrity = 150
- armor = list(MELEE = 70, BULLET = 40, LASER = 40, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 0)
+ armor = list(MELEE = 70, BULLET = 40, LASER = 40, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 80, ACID = 80, STAMINA = 0, BLEED = 0)
enter_delay = 20
max_occupants = 50
movedelay = 0.6
@@ -96,11 +96,13 @@
/obj/vehicle/sealed/car/clowncar/proc/restraintarget(mob/living/carbon/C)
if(istype(C))
- if(!C.handcuffed)
- if(C.get_num_arms(FALSE) >= 2 || C.get_arm_ignore())
- C.set_handcuffed(new /obj/item/restraints/handcuffs/energy/used(C))
- C.update_handcuffed()
- to_chat(C, " Your hands are restrained by the sheer volume of occupants in the car! ")
+ // Dont try and apply more handcuffs if already handcuffed, obviously
+ if(C.handcuffed)
+ return
+ if(C.canBeHandcuffed())
+ C.set_handcuffed(new /obj/item/restraints/handcuffs/energy/used(C))
+ C.update_handcuffed()
+ to_chat(C, " Your hands are restrained by the sheer volume of occupants in the car! ")
/obj/item/restraints/handcuffs/energy/used/clown
name = "tangle of limbs"
diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm
index ecf6168e53570..5565a41802307 100644
--- a/code/modules/vehicles/mecha/_mecha.dm
+++ b/code/modules/vehicles/mecha/_mecha.dm
@@ -890,7 +890,6 @@
AI.cancel_camera()
AI.controlled_mech = src
AI.remote_control = src
- AI.mobility_flags = ALL //Much easier than adding AI checks! Be sure to set this back to 0 if you decide to allow an AI to leave a mech somehow.
to_chat(AI, AI.can_dominate_mechs ? "Takeover of [name] complete! You are now loaded onto the onboard computer. Do not attempt to leave the station sector! " :\
"You have been uploaded to a mech's onboard computer. ")
to_chat(AI, "Use Middle-Mouse to activate mech functions and equipment. Click normally for AI interactions. ")
@@ -1039,12 +1038,11 @@
return FALSE
- brain_obj.mecha = src
+ brain_obj.set_mecha(src)
add_occupant(brain_mob)//Note this forcemoves the brain into the mech to allow relaymove
mecha_flags |= SILICON_PILOT
brain_mob.reset_perspective(src)
brain_mob.remote_control = src
- brain_mob.update_mobility()
brain_mob.update_mouse_pointer()
setDir(dir_in)
log_message("[brain_obj] moved in as pilot.", LOG_MECHA)
@@ -1112,9 +1110,8 @@
L.forceMove(mmi)
L.reset_perspective()
remove_occupant(L)
- mmi.mecha = null
+ mmi.set_mecha(null)
mmi.update_appearance()
- L.mobility_flags = NONE
setDir(dir_in)
return ..()
diff --git a/code/modules/vehicles/mecha/combat/combat.dm b/code/modules/vehicles/mecha/combat/combat.dm
index 6a6636b4b45a6..af78cadb9b7df 100644
--- a/code/modules/vehicles/mecha/combat/combat.dm
+++ b/code/modules/vehicles/mecha/combat/combat.dm
@@ -2,7 +2,7 @@
force = 30
internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_MECH_SECURITY)
internal_damage_threshold = 50
- armor = list(MELEE = 30, BULLET = 30, LASER = 15, ENERGY = 20, BOMB = 20, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 30, BULLET = 30, LASER = 15, ENERGY = 20, BOMB = 20, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
mouse_pointer = 'icons/mecha/mecha_mouse.dmi'
destruction_sleep_duration = 40
exit_delay = 40
diff --git a/code/modules/vehicles/mecha/combat/durand.dm b/code/modules/vehicles/mecha/combat/durand.dm
index fa04c84a77df6..e436afcaab9ee 100644
--- a/code/modules/vehicles/mecha/combat/durand.dm
+++ b/code/modules/vehicles/mecha/combat/durand.dm
@@ -7,7 +7,7 @@
dir_in = 1 //Facing North.
max_integrity = 400
deflect_chance = 20
- armor = list(MELEE = 40, BULLET = 35, LASER = 15, ENERGY = 10, BOMB = 20, BIO = 0, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 40, BULLET = 35, LASER = 15, ENERGY = 10, BOMB = 20, BIO = 0, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
max_temperature = 30000
force = 40
wreckage = /obj/structure/mecha_wreckage/durand
@@ -140,7 +140,6 @@ own integrity back to max. Shield is automatically dropped if we run out of powe
invisibility = INVISIBILITY_MAXIMUM //no showing on right-click
pixel_y = 4
max_integrity = 10000
- obj_integrity = 10000
anchored = TRUE
light_system = MOVABLE_LIGHT
light_range = MINIMUM_USEFUL_LIGHT_RANGE
diff --git a/code/modules/vehicles/mecha/combat/gygax.dm b/code/modules/vehicles/mecha/combat/gygax.dm
index 1ab526e29d6c7..9adf74ddd5470 100644
--- a/code/modules/vehicles/mecha/combat/gygax.dm
+++ b/code/modules/vehicles/mecha/combat/gygax.dm
@@ -7,7 +7,7 @@
dir_in = 1 //Facing North.
max_integrity = 250
deflect_chance = 5
- armor = list(MELEE = 25, BULLET = 20, LASER = 30, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 25, BULLET = 20, LASER = 30, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
max_temperature = 25000
leg_overload_coeff = 80
force = 25
@@ -23,7 +23,7 @@
base_icon_state = "darkgygax"
max_integrity = 300
deflect_chance = 15
- armor = list(MELEE = 40, BULLET = 40, LASER = 50, ENERGY = 35, BOMB = 20, BIO = 0, RAD = 20, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 40, BULLET = 40, LASER = 50, ENERGY = 35, BOMB = 20, BIO = 0, RAD = 20, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
max_temperature = 35000
leg_overload_coeff = 70
operation_req_access = list(ACCESS_SYNDICATE)
diff --git a/code/modules/vehicles/mecha/combat/honker.dm b/code/modules/vehicles/mecha/combat/honker.dm
index 7666b68d688b9..d9a8d0fe40fc5 100644
--- a/code/modules/vehicles/mecha/combat/honker.dm
+++ b/code/modules/vehicles/mecha/combat/honker.dm
@@ -7,7 +7,7 @@
max_integrity = 140
deflect_chance = 60
internal_damage_threshold = 60
- armor = list(MELEE = -20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = -20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
max_temperature = 25000
operation_req_access = list(ACCESS_THEATRE)
internals_req_access = list(ACCESS_MECH_SCIENCE, ACCESS_THEATRE)
diff --git a/code/modules/vehicles/mecha/combat/marauder.dm b/code/modules/vehicles/mecha/combat/marauder.dm
index 42d5cf7bb92ee..7a22dfdb54c44 100644
--- a/code/modules/vehicles/mecha/combat/marauder.dm
+++ b/code/modules/vehicles/mecha/combat/marauder.dm
@@ -6,7 +6,7 @@
movedelay = 5
max_integrity = 500
deflect_chance = 25
- armor = list(MELEE = 50, BULLET = 55, LASER = 40, ENERGY = 30, BOMB = 30, BIO = 0, RAD = 60, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 50, BULLET = 55, LASER = 40, ENERGY = 30, BOMB = 30, BIO = 0, RAD = 60, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
max_temperature = 60000
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
operation_req_access = list(ACCESS_CENT_SPECOPS)
diff --git a/code/modules/vehicles/mecha/combat/phazon.dm b/code/modules/vehicles/mecha/combat/phazon.dm
index d7d3f805ef7f0..af921d340fa0e 100644
--- a/code/modules/vehicles/mecha/combat/phazon.dm
+++ b/code/modules/vehicles/mecha/combat/phazon.dm
@@ -8,7 +8,7 @@
step_energy_drain = 3
max_integrity = 200
deflect_chance = 30
- armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 30, BIO = 0, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 30, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 30, BIO = 0, RAD = 50, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
max_temperature = 25000
wreckage = /obj/structure/mecha_wreckage/phazon
internal_damage_threshold = 25
diff --git a/code/modules/vehicles/mecha/combat/reticence.dm b/code/modules/vehicles/mecha/combat/reticence.dm
index c177124e7943d..420133de3861a 100644
--- a/code/modules/vehicles/mecha/combat/reticence.dm
+++ b/code/modules/vehicles/mecha/combat/reticence.dm
@@ -7,7 +7,7 @@
dir_in = 1 //Facing North.
max_integrity = 100
deflect_chance = 3
- armor = list(MELEE = 25, BULLET = 20, LASER = 30, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 25, BULLET = 20, LASER = 30, ENERGY = 15, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
max_temperature = 15000
wreckage = /obj/structure/mecha_wreckage/reticence
operation_req_access = list(ACCESS_THEATRE)
diff --git a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
index 52faec6cd5390..89c3f16316c46 100644
--- a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
+++ b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
@@ -248,8 +248,8 @@
chassis.clearInternalDamage(int_dam_flag)
repaired = 1
break
- if(h_boost<0 || chassis.obj_integrity < chassis.max_integrity)
- chassis.obj_integrity += min(h_boost, chassis.max_integrity-chassis.obj_integrity)
+ if(h_boost<0 || chassis.get_integrity() < chassis.max_integrity)
+ chassis.repair_damage(h_boost)
repaired = 1
if(repaired)
if(!chassis.use_power(energy_drain))
diff --git a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm
index 2768426699830..9c8a8c6dd774f 100644
--- a/code/modules/vehicles/mecha/equipment/tools/work_tools.dm
+++ b/code/modules/vehicles/mecha/equipment/tools/work_tools.dm
@@ -487,10 +487,10 @@
equipment.attach(marktwo)
marktwo.mecha_flags = markone.mecha_flags
marktwo.strafe = markone.strafe
- marktwo.obj_integrity = round((markone.obj_integrity / markone.max_integrity) * marktwo.obj_integrity) //Integ set to the same percentage integ as the old mecha, rounded to be whole number
+ //Integ set to the same percentage integ as the old mecha, rounded to be whole number
+ marktwo.update_integrity(round((markone.get_integrity() / markone.max_integrity) * marktwo.get_integrity()))
if(markone.name != initial(markone.name))
marktwo.name = markone.name
markone.wreckage = FALSE
qdel(markone)
playsound(get_turf(marktwo),'sound/items/ratchet.ogg',50,TRUE)
- return
diff --git a/code/modules/vehicles/mecha/mech_bay.dm b/code/modules/vehicles/mecha/mech_bay.dm
index 6fa463e15709f..cf2a0d9b2aa00 100644
--- a/code/modules/vehicles/mecha/mech_bay.dm
+++ b/code/modules/vehicles/mecha/mech_bay.dm
@@ -127,7 +127,7 @@
if(recharge_port && !QDELETED(recharge_port))
data["recharge_port"] = list("mech" = null)
if(recharge_port.recharging_mech && !QDELETED(recharge_port.recharging_mech))
- data["recharge_port"]["mech"] = list("health" = recharge_port.recharging_mech.obj_integrity, "maxhealth" = recharge_port.recharging_mech.max_integrity, "cell" = null, "name" = recharge_port.recharging_mech.name,)
+ data["recharge_port"]["mech"] = list("health" = recharge_port.recharging_mech.get_integrity(), "maxhealth" = recharge_port.recharging_mech.max_integrity, "cell" = null, "name" = recharge_port.recharging_mech.name,)
if(recharge_port.recharging_mech.cell && !QDELETED(recharge_port.recharging_mech.cell))
data["recharge_port"]["mech"]["cell"] = list(
"charge" = recharge_port.recharging_mech.cell.charge,
diff --git a/code/modules/vehicles/mecha/mech_melee_attack.dm b/code/modules/vehicles/mecha/mech_melee_attack.dm
index fbbe472a9c259..e9c60f9dd2ef8 100644
--- a/code/modules/vehicles/mecha/mech_melee_attack.dm
+++ b/code/modules/vehicles/mecha/mech_melee_attack.dm
@@ -93,9 +93,7 @@
switch(mecha_attacker.damtype)
if(BRUTE)
if(mecha_attacker.force > 35) // durand and other heavy mechas
- Unconscious(20)
- else if(mecha_attacker.force > 20 && !IsKnockdown()) // lightweight mechas like gygax
- Knockdown(40)
+ Knockdown(20)
update |= temp.receive_damage(dmg, 0)
playsound(src, 'sound/weapons/punch4.ogg', 50, TRUE)
if(FIRE)
diff --git a/code/modules/vehicles/mecha/mecha_control_console.dm b/code/modules/vehicles/mecha/mecha_control_console.dm
index cf91e1672318d..b2194d82b028e 100644
--- a/code/modules/vehicles/mecha/mecha_control_console.dm
+++ b/code/modules/vehicles/mecha/mecha_control_console.dm
@@ -33,7 +33,7 @@
var/obj/vehicle/sealed/mecha/M = MT.chassis
var/list/mech_data = list(
name = M.name,
- integrity = round((M.obj_integrity / M.max_integrity) * 100),
+ integrity = round((M.get_integrity() / M.max_integrity) * 100),
charge = M.cell ? round(M.cell.percent()) : null,
airtank = M.internal_tank ? M.return_pressure() : null,
pilot = M.return_drivers(),
@@ -100,7 +100,7 @@
var/cell_charge = chassis.get_charge()
var/answer = {"Name: [chassis.name]
- Integrity: [round((chassis.obj_integrity/chassis.max_integrity * 100), 0.01)]%
+ Integrity: [round((chassis.get_integrity()/chassis.max_integrity * 100), 0.01)]%
Cell Charge: [isnull(cell_charge) ? "Not Found":"[chassis.cell.percent()]%"]
Airtank: [chassis.internal_tank ? "[round(chassis.return_pressure(), 0.01)]" : "Not Equipped"] kPa
Pilot: [chassis.return_drivers() || "None"]
diff --git a/code/modules/vehicles/mecha/medical/odysseus.dm b/code/modules/vehicles/mecha/medical/odysseus.dm
index c20faa339563c..040f196037897 100644
--- a/code/modules/vehicles/mecha/medical/odysseus.dm
+++ b/code/modules/vehicles/mecha/medical/odysseus.dm
@@ -18,12 +18,13 @@
if(. && !HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
hud.add_hud_to(H)
+ ADD_TRAIT(H, TRAIT_MEDICAL_HUD, VEHICLE_TRAIT)
-/obj/vehicle/sealed/mecha/medical/odysseus/remove_occupant(mob/M)
- if(isliving(M) && HAS_TRAIT_FROM(M, TRAIT_MEDICAL_HUD, src))
- var/mob/living/L = M
+/obj/vehicle/sealed/mecha/medical/odysseus/remove_occupant(mob/living/carbon/human/H)
+ if(isliving(H) && HAS_TRAIT_FROM(H, TRAIT_MEDICAL_HUD, VEHICLE_TRAIT))
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
- hud.remove_hud_from(L)
+ hud.remove_hud_from(H)
+ REMOVE_TRAIT(H, TRAIT_MEDICAL_HUD, VEHICLE_TRAIT)
return ..()
/obj/vehicle/sealed/mecha/medical/odysseus/mmi_moved_inside(obj/item/mmi/M, mob/user)
diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm
index ebfbd769cff01..b0ff43ef1f7a3 100644
--- a/code/modules/vehicles/mecha/working/ripley.dm
+++ b/code/modules/vehicles/mecha/working/ripley.dm
@@ -13,7 +13,7 @@
max_integrity = 200
lights_power = 7
deflect_chance = 15
- armor = list(MELEE = 40, BULLET = 20, LASER = 10, ENERGY = 20, BOMB = 40, BIO = 0, RAD = 20, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 40, BULLET = 20, LASER = 10, ENERGY = 20, BOMB = 40, BIO = 0, RAD = 20, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
max_equip = 6
wreckage = /obj/structure/mecha_wreckage/ripley
internals_req_access = list(ACCESS_MECH_ENGINE, ACCESS_MECH_SCIENCE, ACCESS_MECH_MINING)
@@ -66,7 +66,7 @@
fast_pressure_step_in = 1.75 //step_in while in low pressure conditions
slow_pressure_step_in = 3 //step_in while in normal pressure conditions
movedelay = 4
- armor = list(MELEE = 40, BULLET = 20, LASER = 10, ENERGY = 20, BOMB = 40, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 40, BULLET = 20, LASER = 10, ENERGY = 20, BOMB = 40, BIO = 0, RAD = 0, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
wreckage = /obj/structure/mecha_wreckage/ripley/mk2
enclosed = TRUE
enter_delay = 40
@@ -93,7 +93,7 @@
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
rad_flags = RAD_PROTECT_CONTENTS
lights_power = 7
- armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 60, BIO = 0, RAD = 70, FIRE = 100, ACID = 100, STAMINA = 0)
+ armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 60, BIO = 0, RAD = 70, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
max_equip = 5 // More armor, less tools
wreckage = /obj/structure/mecha_wreckage/ripley/firefighter
enclosed = TRUE
@@ -137,10 +137,6 @@
desc = "An old, dusty mining Ripley."
name = "\improper APLU \"Miner\""
-/obj/vehicle/sealed/mecha/working/ripley/mining/Initialize(mapload)
- . = ..()
- take_damage(125) // Low starting health
-
/obj/vehicle/sealed/mecha/working/ripley/mining/Initialize(mapload)
. = ..()
if(cell)
@@ -160,6 +156,9 @@
//Attach hydraulic clamp
var/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/HC = new
HC.attach(src)
+
+ take_damage(max_integrity * 0.5, sound_effect=FALSE) //Low starting health
+
var/obj/item/mecha_parts/mecha_equipment/mining_scanner/scanner = new
scanner.attach(src)
diff --git a/code/modules/vehicles/motorized_wheelchair.dm b/code/modules/vehicles/motorized_wheelchair.dm
index 7cc5ceae0c855..b68c58a21a819 100644
--- a/code/modules/vehicles/motorized_wheelchair.dm
+++ b/code/modules/vehicles/motorized_wheelchair.dm
@@ -25,6 +25,7 @@
power_efficiency = C.rating
var/datum/component/riding/D = GetComponent(/datum/component/riding)
D.vehicle_move_delay = round(1.5 * delay_multiplier) / speed
+ D.empable = TRUE
/obj/vehicle/ridden/wheelchair/motorized/get_cell()
@@ -32,12 +33,10 @@
/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()
- ..()
+ for(var/c in contents)
+ var/atom/movable/thing = c
+ thing.forceMove(T)
+ return ..()
/obj/vehicle/ridden/wheelchair/motorized/driver_move(mob/living/user, direction)
if(istype(user))
@@ -53,7 +52,7 @@
canmove = FALSE
addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20)
return FALSE
- if(user.get_num_arms() < arms_required)
+ if(user.usable_hands < 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)
@@ -130,11 +129,9 @@
new /obj/item/stack/rods(drop_location(), 8)
new /obj/item/stack/sheet/iron(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()
+ for(var/c in contents)
+ var/atom/movable/thing = c
+ thing.forceMove(T)
qdel(src)
return TRUE
diff --git a/code/modules/vehicles/pimpin_ride.dm b/code/modules/vehicles/pimpin_ride.dm
index 621dc2c51f772..476e1fa2dcafa 100644
--- a/code/modules/vehicles/pimpin_ride.dm
+++ b/code/modules/vehicles/pimpin_ride.dm
@@ -13,6 +13,7 @@
update_icon()
var/datum/component/riding/D = LoadComponent(/datum/component/riding)
D.set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 7), TEXT_EAST = list(-12, 7), TEXT_WEST = list( 12, 7)))
+ D.empable = TRUE
GLOB.janitor_devices += src
if(floorbuffer)
AddElement(/datum/element/cleaning)
diff --git a/code/modules/vehicles/ridden.dm b/code/modules/vehicles/ridden.dm
index 1d01fb781dfad..ce22644b19de0 100644
--- a/code/modules/vehicles/ridden.dm
+++ b/code/modules/vehicles/ridden.dm
@@ -59,20 +59,18 @@
inserted_key = null
return
-/obj/vehicle/ridden/driver_move(mob/user, direction)
+/obj/vehicle/ridden/driver_move(mob/living/user, direction)
if(key_type && !is_key(inserted_key))
if(message_cooldown < world.time)
to_chat(user, "[src] has no key inserted! ")
message_cooldown = world.time + 5 SECONDS
return FALSE
if(legs_required)
- var/how_many_legs = user.get_num_legs()
- if(how_many_legs < legs_required)
- to_chat(user, "You can't seem to manage that with[how_many_legs ? " your leg[how_many_legs > 1 ? "s" : null]" : "out legs"]... ")
+ if(user.usable_legs < legs_required)
+ to_chat(user, "You can't seem to manage that with[user.usable_legs ? " your leg[user.usable_legs > 1 ? "s" : null]" : "out legs"]... ")
return FALSE
if(arms_required)
- var/how_many_arms = user.get_num_arms()
- if(how_many_arms < arms_required)
+ if(user.usable_hands < arms_required)
if(fall_off_if_missing_arms)
unbuckle_mob(user, TRUE)
user.visible_message("[user] falls off of \the [src].",\
@@ -82,7 +80,7 @@
L.Stun(30)
return FALSE
- to_chat(user, "You can't seem to manage that with[how_many_arms ? " your arm[how_many_arms > 1 ? "s" : null]" : "out arms"]... ")
+ to_chat(user, "You can't seem to manage that with[user.usable_hands ? " your arm[user.usable_hands > 1 ? "s" : null]" : "out arms"]... ")
return FALSE
var/datum/component/riding/R = GetComponent(/datum/component/riding)
R.handle_ride(user, direction)
diff --git a/code/modules/vehicles/scooter.dm b/code/modules/vehicles/scooter.dm
index 665400bcdefeb..6a7b97c5b40f3 100644
--- a/code/modules/vehicles/scooter.dm
+++ b/code/modules/vehicles/scooter.dm
@@ -28,7 +28,7 @@
. = ..()
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
- if(buckled_mob.get_num_legs(FALSE) > 0)
+ if(buckled_mob.num_legs > 0)
buckled_mob.pixel_y = 5
else
buckled_mob.pixel_y = -4
@@ -36,7 +36,7 @@
/obj/vehicle/ridden/scooter/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
if(!istype(M))
return FALSE
- if(M.get_num_legs() < legs_required && M.get_num_arms() < arms_required)
+ if(M.usable_legs < legs_required && M.usable_hands < arms_required)
to_chat(M, "You don't think it'd be a good idea trying to ride \the [src]... ")
return FALSE
return ..()
@@ -77,7 +77,7 @@
QDEL_NULL(sparks)
. = ..()
-/obj/vehicle/ridden/scooter/skateboard/relaymove()
+/obj/vehicle/ridden/scooter/skateboard/relaymove(mob/living/user, direction)
if (grinding || world.time < next_crash)
return FALSE
return ..()
diff --git a/code/modules/vehicles/secway.dm b/code/modules/vehicles/secway.dm
index ba22f4666d8b9..0dc23070ea4b6 100644
--- a/code/modules/vehicles/secway.dm
+++ b/code/modules/vehicles/secway.dm
@@ -4,7 +4,7 @@
desc = "A brave security cyborg gave its life to help you look like a complete tool."
icon_state = "secway"
max_integrity = 100
- armor = list(MELEE = 20, BULLET = 15, LASER = 10, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 0)
+ armor = list(MELEE = 20, BULLET = 15, LASER = 10, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 60, ACID = 60, STAMINA = 0, BLEED = 0)
key_type = /obj/item/key/security
integrity_failure = 0.5
@@ -12,6 +12,7 @@
. = ..()
var/datum/component/riding/D = LoadComponent(/datum/component/riding)
D.vehicle_move_delay = 1.5
+ D.empable = TRUE
D.set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(0, 4), TEXT_WEST = list( 0, 4)))
/obj/vehicle/ridden/secway/obj_break()
diff --git a/code/modules/vehicles/wheelchair.dm b/code/modules/vehicles/wheelchair.dm
index 76c70302ec73f..abd6ec9dc7787 100644
--- a/code/modules/vehicles/wheelchair.dm
+++ b/code/modules/vehicles/wheelchair.dm
@@ -5,7 +5,7 @@
icon_state = "wheelchair"
layer = OBJ_LAYER
max_integrity = 100
- armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 20, ACID = 30, STAMINA = 0) //Wheelchairs aren't super tough yo
+ armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 20, ACID = 30, STAMINA = 0, BLEED = 0) //Wheelchairs aren't super tough yo
legs_required = 0 //You'll probably be using this if you don't have legs
canmove = TRUE
density = FALSE //Thought I couldn't fix this one easily, phew
@@ -40,7 +40,7 @@
/obj/vehicle/ridden/wheelchair/driver_move(mob/living/user, direction)
if(istype(user))
- if(canmove && (user.get_num_arms() < arms_required))
+ if(canmove && (user.usable_hands < arms_required))
to_chat(user, "You don't have enough arms to operate the wheels! ")
canmove = FALSE
addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20)
@@ -52,7 +52,7 @@
var/datum/component/riding/D = GetComponent(/datum/component/riding)
//1.5 (movespeed as of this change) multiplied by 6.7 gets ABOUT 10 (rounded), the old constant for the wheelchair that gets divided by how many arms they have
//if that made no sense this simply makes the wheelchair speed change along with movement speed delay
- D.vehicle_move_delay = round(1.5 * delay_multiplier) / clamp(user.get_num_arms(), arms_required, 2)
+ D.vehicle_move_delay = round(1.5 * delay_multiplier) / clamp(user.usable_hands, 1, 2)
/obj/vehicle/ridden/wheelchair/Moved()
. = ..()
@@ -112,5 +112,5 @@
/obj/vehicle/ridden/wheelchair/the_whip/driver_move(mob/living/user, direction)
if(istype(user))
var/datum/component/riding/D = GetComponent(/datum/component/riding)
- D.vehicle_move_delay = round(1.5 * 6.7) / user.get_num_arms()
+ D.vehicle_move_delay = round(1.5 * 6.7) / max(user.usable_hands, 1)
return ..()
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index df4b672a68252..ceaae3686798e 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -59,7 +59,7 @@
verb_exclaim = "beeps"
max_integrity = 300
integrity_failure = 0.33
- armor = list(MELEE = 20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 70, STAMINA = 0)
+ armor = list(MELEE = 20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 70, STAMINA = 0, BLEED = 0)
circuit = /obj/item/circuitboard/machine/vendor
clicksound = 'sound/machines/pda_button1.ogg'
dept_req_for_free = ACCOUNT_SRV_BITFLAG
diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm
index bce076e64fc84..ac09f4ba2563c 100644
--- a/code/modules/vending/clothesmate.dm
+++ b/code/modules/vending/clothesmate.dm
@@ -184,7 +184,9 @@
/obj/item/clothing/suit/jacket/letterman_syndie = 1,
/obj/item/clothing/under/costume/jabroni = 1,
/obj/item/clothing/suit/costume/vapeshirt = 1,
- /obj/item/clothing/under/costume/geisha = 1
+ /obj/item/clothing/under/costume/geisha = 1,
+ /obj/item/clothing/under/rank/centcom/officer/replica = 1,
+ /obj/item/clothing/under/rank/centcom/officer_skirt/replica = 1
)
premium = list(
/obj/item/clothing/under/suit/checkered = 1,
diff --git a/code/modules/vending/liberation.dm b/code/modules/vending/liberation.dm
index 3023e2f45ab52..f217a7ead39c1 100644
--- a/code/modules/vending/liberation.dm
+++ b/code/modules/vending/liberation.dm
@@ -26,7 +26,7 @@
contraband = list(/obj/item/clothing/under/misc/patriotsuit = 3,
/obj/item/bedsheet/patriot = 5,
/obj/item/food/burger/superbite = 3) //U S A
- armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
default_price = 300
extra_price = 500
diff --git a/code/modules/vending/liberation_toy.dm b/code/modules/vending/liberation_toy.dm
index 86117c87a1c0a..09ffd5acef36b 100644
--- a/code/modules/vending/liberation_toy.dm
+++ b/code/modules/vending/liberation_toy.dm
@@ -22,7 +22,7 @@
/obj/item/toy/katana = 10,
/obj/item/dualsaber/toy = 5,
/obj/item/toy/cards/deck/syndicate = 10) //Gambling and it hurts, making it a +18 item
- armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
refill_canister = /obj/item/vending_refill/donksoft
default_price = 75
diff --git a/code/modules/vending/magivend.dm b/code/modules/vending/magivend.dm
index 6c0f75da728d2..a01f7615886a6 100644
--- a/code/modules/vending/magivend.dm
+++ b/code/modules/vending/magivend.dm
@@ -14,7 +14,7 @@
/obj/item/clothing/shoes/sandal/magic = 1,
/obj/item/staff = 2)
contraband = list(/obj/item/reagent_containers/glass/bottle/wizarditis = 1) //No one can get to the machine to hack it anyways; for the lulz - Microwave
- armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
default_price = 25
extra_price = 50
diff --git a/code/modules/vending/medical.dm b/code/modules/vending/medical.dm
index f0f745c5ff94f..09a84878e17c5 100644
--- a/code/modules/vending/medical.dm
+++ b/code/modules/vending/medical.dm
@@ -31,7 +31,7 @@
/obj/item/pinpointer/crew = 2,
/obj/item/healthanalyzer = 2,
/obj/item/wrench/medical = 1)
- armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
refill_canister = /obj/item/vending_refill/medical
default_price = 25
diff --git a/code/modules/vending/medical_wall.dm b/code/modules/vending/medical_wall.dm
index ef4518a8eca4b..df7b1935f9110 100644
--- a/code/modules/vending/medical_wall.dm
+++ b/code/modules/vending/medical_wall.dm
@@ -13,7 +13,7 @@
/obj/item/reagent_containers/medspray/sterilizine = 3)
contraband = list(/obj/item/reagent_containers/glass/bottle/toxin = 1,
/obj/item/reagent_containers/glass/bottle/morphine = 1)
- armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
refill_canister = /obj/item/vending_refill/wallmed
default_price = 25
@@ -22,6 +22,8 @@
tiltable = FALSE
light_mask = "wallmed-light-mask"
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/vending/wallmed, 32)
+
/obj/item/vending_refill/wallmed
machine_name = "NanoMed"
icon_state = "refill_medical"
diff --git a/code/modules/vending/toys.dm b/code/modules/vending/toys.dm
index 050e2f22cc8b9..e43d014bf1ea4 100644
--- a/code/modules/vending/toys.dm
+++ b/code/modules/vending/toys.dm
@@ -24,7 +24,7 @@
/obj/item/toy/katana = 10,
/obj/item/dualsaber/toy = 5)
- armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0)
+ armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 50, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
refill_canister = /obj/item/vending_refill/donksoft
default_price = 75
diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm
index 12e39365d3639..eb39dbefb83d5 100644
--- a/code/modules/vending/wardrobes.dm
+++ b/code/modules/vending/wardrobes.dm
@@ -571,3 +571,33 @@
/obj/item/vending_refill/wardrobe/det_wardrobe
machine_name = "DetDrobe"
+
+/obj/machinery/vending/wardrobe/cent_wardrobe
+ name = "\improper CentDrobe"
+ desc = "A one-of-a-kind vending machine for all your centcom aesthetic needs!"
+ icon_state = "centdrobe"
+ product_ads = "Show those ERTs who's the most stylish in the briefing room!"
+ vend_reply = "Thank you for using the CentDrobe!"
+ products = list(
+ /obj/item/clothing/shoes/laceup = 3,
+ /obj/item/clothing/shoes/jackboots = 3,
+ /obj/item/clothing/gloves/combat = 3,
+ /obj/item/clothing/glasses/sunglasses = 3,
+ /obj/item/clothing/under/rank/centcom/commander = 3,
+ /obj/item/clothing/under/rank/centcom/centcom_skirt = 3,
+ /obj/item/clothing/under/rank/centcom/intern = 3,
+ /obj/item/clothing/under/rank/centcom/official = 3,
+ /obj/item/clothing/under/rank/centcom/officer = 3,
+ /obj/item/clothing/under/rank/centcom/officer_skirt = 3,
+ /obj/item/clothing/suit/armor/centcom_formal = 3,
+ /obj/item/clothing/suit/space/officer = 3,
+ /obj/item/clothing/suit/hooded/wintercoat/centcom = 3,
+ /obj/item/clothing/head/hats/centcom_cap = 3,
+ /obj/item/clothing/head/hats/centhat = 3,
+ /obj/item/clothing/head/hats/intern = 3,
+ )
+ refill_canister = /obj/item/vending_refill/wardrobe/cent_wardrobe
+
+/obj/item/vending_refill/wardrobe/cent_wardrobe
+ machine_name = "CentDrobe"
+ light_color = LIGHT_COLOR_ELECTRIC_GREEN
diff --git a/code/modules/vending/youtool.dm b/code/modules/vending/youtool.dm
index bf62164dd3a5c..93df6958ea3fc 100644
--- a/code/modules/vending/youtool.dm
+++ b/code/modules/vending/youtool.dm
@@ -23,7 +23,7 @@
/obj/item/clothing/head/utility/welding = 2,
/obj/item/clothing/gloves/color/yellow = 1)
refill_canister = /obj/item/vending_refill/tool
- armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 70, STAMINA = 0)
+ armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 70, STAMINA = 0, BLEED = 0)
resistance_flags = FIRE_PROOF
default_price = 10
extra_price = 80
diff --git a/code/modules/wiremod/core/component_printer.dm b/code/modules/wiremod/core/component_printer.dm
index 3fbe7153ad526..3495bb2a7b839 100644
--- a/code/modules/wiremod/core/component_printer.dm
+++ b/code/modules/wiremod/core/component_printer.dm
@@ -6,7 +6,7 @@
circuit = /obj/item/circuitboard/machine/component_printer
remote_materials = TRUE
- auto_link = TRUE
+ auto_link = FALSE
can_sync = TRUE
//Quick.
@@ -16,8 +16,7 @@
categories = WIREMODE_CATEGORIES
-/obj/machinery/component_printer/crowbar_act(mob/living/user, obj/item/tool)
-
+/obj/machinery/modular_fabricator/component_printer/crowbar_act(mob/living/user, obj/item/tool)
if(..())
return TRUE
return default_deconstruction_crowbar(tool)
@@ -27,6 +26,18 @@
return TRUE
return default_deconstruction_screwdriver(user, "fab-o", "fab-idle", tool)
+/obj/machinery/modular_fabricator/component_printer/AfterMaterialInsert(type_inserted, id_inserted, amount_inserted)
+ . = ..()
+ var/datum/material/M = id_inserted
+ add_overlay("fab-load-[M.name]")
+ addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, cut_overlay), "fab-load-[M.name]"), 10)
+
+/obj/machinery/modular_fabricator/component_printer/set_default_sprite()
+ cut_overlay("fab-active")
+
+/obj/machinery/modular_fabricator/component_printer/set_working_sprite()
+ add_overlay("fab-active")
+
/obj/item/circuitboard/machine/component_printer
name = "\improper Component Printer (Machine Board)"
icon_state = "science"
@@ -34,7 +45,7 @@
req_components = list(
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/manipulator = 2,
- /obj/item/reagent_containers/glass/beaker = 2,
+ /obj/item/reagent_containers/glass/beaker = 2, //this doesn't make any sense, yet i wasn't allowed to fix it.
)
/// Module duplicator, allows you to save and recreate module components.
diff --git a/code/modules/wiremod/shell/compact_remote.dm b/code/modules/wiremod/shell/compact_remote.dm
index 83deaa989204c..b1565ee2b45d8 100644
--- a/code/modules/wiremod/shell/compact_remote.dm
+++ b/code/modules/wiremod/shell/compact_remote.dm
@@ -5,15 +5,16 @@
*/
/obj/item/compact_remote
name = "compact remote"
+ desc = "A smaller handheld device with one big button."
icon = 'icons/obj/wiremod.dmi'
icon_state = "setup_small_simple"
item_state = "electronic"
- w_class = WEIGHT_CLASS_SMALL
+ w_class = WEIGHT_CLASS_TINY
//worn_icon_state = "electronic" //remember to change it later lol
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
-
- light_system = MOVABLE_LIGHT
+ light_system = MOVABLE_LIGHT_DIRECTIONAL
+ light_on = FALSE
/obj/item/compact_remote/Initialize(mapload)
. = ..()
diff --git a/code/modules/wiremod/shell/controller.dm b/code/modules/wiremod/shell/controller.dm
index 024039e0795fd..c0a2ea48d794c 100644
--- a/code/modules/wiremod/shell/controller.dm
+++ b/code/modules/wiremod/shell/controller.dm
@@ -6,14 +6,16 @@
*/
/obj/item/controller
name = "controller"
+ desc = "A handheld device with three buttons."
icon = 'icons/obj/wiremod.dmi'
icon_state = "setup_small_calc"
item_state = "electronic"
+ w_class = WEIGHT_CLASS_SMALL
//worn_icon_state = "electronic" //remember to change it
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
-
- light_system = MOVABLE_LIGHT
+ light_system = MOVABLE_LIGHT_DIRECTIONAL
+ light_on = FALSE
/obj/item/controller/Initialize(mapload)
. = ..()
@@ -23,30 +25,32 @@
/obj/item/circuit_component/controller
display_name = "Controller"
- desc = "Used to receive inputs from the controller shell. Use the shell in hand to trigger the output signal. Alt-click for the alternate signal. Right click for the extra signal."
+ desc = "Used to receive inputs from the controller shell. Use the shell in hand to trigger the first signal. Alt-click for the second signal. CTRL-click for the thrid signal."
/// The three separate buttons that are called in attack_hand on the shell.
var/datum/port/output/signal
var/datum/port/output/alt
- var/datum/port/output/right
+ var/datum/port/output/ctrl
/// The entity output
var/datum/port/output/entity
/obj/item/circuit_component/controller/populate_ports()
entity = add_output_port("User", PORT_TYPE_ATOM)
- signal = add_output_port("Signal", PORT_TYPE_SIGNAL)
- alt = add_output_port("Alternate Signal", PORT_TYPE_SIGNAL)
- right = add_output_port("Extra Signal", PORT_TYPE_SIGNAL)
+ signal = add_output_port("First Signal", PORT_TYPE_SIGNAL)
+ alt = add_output_port("Second Signal", PORT_TYPE_SIGNAL)
+ ctrl = add_output_port("Third Signal", PORT_TYPE_SIGNAL)
/obj/item/circuit_component/controller/register_shell(atom/movable/shell)
RegisterSignal(shell, COMSIG_ITEM_ATTACK_SELF, PROC_REF(send_trigger))
RegisterSignal(shell, COMSIG_CLICK_ALT, PROC_REF(send_alternate_signal))
+ RegisterSignal(shell, COMSIG_CLICK_CTRL, PROC_REF(send_ctrl_signal))
/obj/item/circuit_component/controller/unregister_shell(atom/movable/shell)
UnregisterSignal(shell, list(
COMSIG_ITEM_ATTACK_SELF,
COMSIG_CLICK_ALT,
+ COMSIG_CLICK_CTRL,
))
/**
@@ -56,7 +60,7 @@
SIGNAL_HANDLER
if(!user.Adjacent(source))
return
- source.balloon_alert(user, "Clicked the primary button.")
+ source.balloon_alert(user, "Clicked the first button.")
playsound(source, get_sfx("terminal_type"), 25, FALSE)
entity.set_output(user)
signal.set_output(COMPONENT_SIGNAL)
@@ -68,20 +72,20 @@
SIGNAL_HANDLER
if(!user.Adjacent(source))
return
- source.balloon_alert(user, "Clicked the alternate button.")
+ source.balloon_alert(user, "Clicked the second button.")
playsound(source, get_sfx("terminal_type"), 25, FALSE)
entity.set_output(user)
alt.set_output(COMPONENT_SIGNAL)
return COMPONENT_INTERCEPT_ALT
/**
- * Called when the shell item is right-clicked in active hand
+ * Called when the shell item is ctrl-clicked in active hand
*/
-/obj/item/circuit_component/controller/proc/send_right_signal(atom/source, mob/user)
+/obj/item/circuit_component/controller/proc/send_ctrl_signal(atom/source, mob/user)
SIGNAL_HANDLER
if(!user.Adjacent(source))
return
- source.balloon_alert(user, "Clicked the extra button.")
+ source.balloon_alert(user, "Clicked the third button.")
playsound(source, get_sfx("terminal_type"), 25, FALSE)
entity.set_output(user)
- right.set_output(COMPONENT_SIGNAL)
+ ctrl.set_output(COMPONENT_SIGNAL)
diff --git a/code/modules/wiremod/shell/drone.dm b/code/modules/wiremod/shell/drone.dm
index 4e0b3bfb24bb1..b4c4b6df10751 100644
--- a/code/modules/wiremod/shell/drone.dm
+++ b/code/modules/wiremod/shell/drone.dm
@@ -6,9 +6,9 @@
/mob/living/circuit_drone
name = "drone"
icon = 'icons/obj/wiremod.dmi'
- icon_state = "setup_medium_med"
-
- light_system = MOVABLE_LIGHT
+ icon_state = "setup_drone_arms" //RIP setup_medium_med, you were too cute for this world. Maybe some other day they'll find a use for you
+ light_system = MOVABLE_LIGHT_DIRECTIONAL
+ light_on = FALSE
/mob/living/circuit_drone/Initialize(mapload)
. = ..()
diff --git a/code/modules/wiremod/shell/scanner.dm b/code/modules/wiremod/shell/scanner.dm
index 3017c9aef471a..48cb19e4f56e5 100644
--- a/code/modules/wiremod/shell/scanner.dm
+++ b/code/modules/wiremod/shell/scanner.dm
@@ -5,22 +5,22 @@
*/
/obj/item/wiremod_scanner
name = "scanner"
+ desc = "A handheld device that lets you scan people"
icon = 'icons/obj/wiremod.dmi'
icon_state = "setup_small"
item_state = "electronic"
+ w_class = WEIGHT_CLASS_SMALL
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
- light_system = MOVABLE_LIGHT
- light_range = 6
- light_power = 1
+ light_system = MOVABLE_LIGHT_DIRECTIONAL
light_on = FALSE
/obj/item/wiremod_scanner/Initialize(mapload)
. = ..()
AddComponent(/datum/component/shell, list(
new /obj/item/circuit_component/wiremod_scanner()
- ), SHELL_CAPACITY_SMALL)
+ ), SHELL_CAPACITY_MEDIUM)
/obj/item/circuit_component/wiremod_scanner
display_name = "Scanner"
diff --git a/code/modules/wiremod/shell/shell_items.dm b/code/modules/wiremod/shell/shell_items.dm
index a2d6ffa578579..7fdb48d5c75ad 100644
--- a/code/modules/wiremod/shell/shell_items.dm
+++ b/code/modules/wiremod/shell/shell_items.dm
@@ -29,22 +29,30 @@
name = "bot assembly"
icon_state = "setup_medium_box-open"
shell_to_spawn = /obj/structure/bot
+ w_class = WEIGHT_CLASS_NORMAL
/obj/item/shell/money_bot
name = "money bot assembly"
icon_state = "setup_large-open"
shell_to_spawn = /obj/structure/money_bot
+ w_class = WEIGHT_CLASS_NORMAL
/obj/item/shell/drone
name = "drone assembly"
- icon_state = "setup_medium_med-open"
+ icon_state = "setup_drone_arms-open"
shell_to_spawn = /mob/living/circuit_drone
+ w_class = WEIGHT_CLASS_NORMAL // you should be able to fit these in your back pack
/obj/item/shell/server
name = "server assembly"
icon_state = "setup_stationary-open"
shell_to_spawn = /obj/structure/server
- screw_delay = 10 SECONDS
+ screw_delay = 6 SECONDS
+ w_class = WEIGHT_CLASS_BULKY
+
+/obj/item/shell/server/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/two_handed, require_twohands=TRUE)
/obj/item/shell/airlock
name = "circuit airlock assembly"
@@ -52,14 +60,39 @@
icon_state = "construction"
shell_to_spawn = /obj/machinery/door/airlock/shell
screw_delay = 10 SECONDS
+ w_class = WEIGHT_CLASS_GIGANTIC
+
+/obj/item/shell/airlock/ComponentInitialize()
+ . = ..()
+ AddComponent(/datum/component/two_handed, require_twohands=TRUE) // that you even are allowed to carry around an airlock frame is weird.
/obj/item/shell/bci
name = "brain-computer interface assembly"
icon_state = "bci-open"
shell_to_spawn = /obj/item/organ/cyberimp/bci
+ w_class = WEIGHT_CLASS_TINY
/obj/item/shell/scanner_gate
name = "scanner gate assembly"
icon = 'icons/obj/machines/scangate.dmi'
icon_state = "scangate"
shell_to_spawn = /obj/structure/scanner_gate_shell
+ w_class = WEIGHT_CLASS_LARGE
+
+/obj/item/shell/controller
+ name = "controller assembly"
+ icon_state = "setup_small_calc-open"
+ shell_to_spawn = /obj/item/controller
+ w_class = WEIGHT_CLASS_SMALL
+
+/obj/item/shell/compact_remote
+ name = "compact remote assembly"
+ icon_state = "setup_small_simple-open"
+ shell_to_spawn = /obj/item/compact_remote
+ w_class = WEIGHT_CLASS_TINY
+
+/obj/item/shell/wiremod_scanner
+ name = "scanner assembly"
+ icon_state = "setup_small-open"
+ shell_to_spawn = /obj/item/wiremod_scanner
+ w_class = WEIGHT_CLASS_SMALL
diff --git a/code/modules/xenoarchaeology/traits/xenoartifact_minors.dm b/code/modules/xenoarchaeology/traits/xenoartifact_minors.dm
index cfc0474e6deec..eefe2027c1ed3 100644
--- a/code/modules/xenoarchaeology/traits/xenoartifact_minors.dm
+++ b/code/modules/xenoarchaeology/traits/xenoartifact_minors.dm
@@ -81,6 +81,7 @@
/datum/xenoartifact_trait/minor/sharp/on_init(obj/item/xenoartifact/X)
X.sharpness = IS_SHARP_ACCURATE
+ X.bleed_force = BLEED_CUT
X.force = X.charge_req*0.12
X.attack_verb = list("cleaved", "slashed", "stabbed", "sliced", "tore", "ripped", "diced", "cut")
X.attack_weight = 2
@@ -222,12 +223,12 @@
/datum/xenoartifact_trait/minor/delicate/on_init(obj/item/xenoartifact/X)
X.max_integrity = pick(200, 300, 500, 800, 1000)
- X.obj_integrity = X.max_integrity
+ X.update_integrity(X.max_integrity)
X.alpha = X.alpha * 0.55
/datum/xenoartifact_trait/minor/delicate/activate(obj/item/xenoartifact/X, atom/user)
- if(X.obj_integrity > 0)
- X.obj_integrity -= 100
+ if(X.get_integrity() > 0)
+ X.update_integrity(-100)
X.visible_message("The [X.name] cracks! ", "The [X.name] cracks! ")
else
X.visible_message("The [X.name] shatters! ", "The [X.name] shatters! ")
diff --git a/config/config.txt b/config/config.txt
index 738db8a75b258..4be517b113dc4 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -337,10 +337,6 @@ ALLOW_HOLIDAYS
## Uncomment to show the names of the admin sending a pm from IRC instead of showing as a stealthmin.
#SHOW_IRC_NAME
-## Defines the ticklimit for subsystem initialization (In percents of a byond tick). Lower makes world start smoother. Higher makes it faster.
-##This is currently a testing optimized setting. A good value for production would be 98.
-TICK_LIMIT_MC_INIT 500
-
## Uncomment to enable MC diagnostics, the MC will record all information about prior ticks and then report them
## to SSmetrics.
# MC_DIAGNOSTICS
diff --git a/html/changelog.html b/html/changelog.html
index 1ed3509b9ab1f..317a50d51b7b5 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -56,6 +56,512 @@
-->
+
08 August 2024
+
mystery3525 updated:
+
+ AIs can now change their internal camera capture size with "AI Commands" > "Adjust Camera Zoom"
+ Cyborgs can change their internal camera capture size in the Actions Menu on their internal PDA app
+
+
+
07 August 2024
+
DarnTheMarn updated:
+
+ Moved the security techfab to the warden office
+ Security techfab is now inaccessible to security officers and detectives
+
+
MarkusLarsson421 updated:
+
+ Fixes cheap lights not burning you
+
+
mystery3525 updated:
+
+ A pipe that was on top of another pipe in Fland Xenobio
+ A runtime with helmet of justice
+ Micro optimizes airlock access code with boolean short-circuiting
+
+
rkz, azarak, TemporalOroboros, Rohesie, Couls, ShizCalev, TastyFish updated:
+
+ Adds directional lighting system in 2024!
+ adds directional lighting to cyborg lights, flashlights, and gunlights
+ refactors glow effects to be less terrible. Includes ethereal glow, and also the glowy/antiglowy mutation.
+
+
+
06 August 2024
+
EdgeLordExe ported and fixed by mystery3525 with help from BriggsIDP updated:
+
+ Added new smart pipes mapping helper
+ Added new smart pipes air supply/scrubbers pipe helper
+ Added sanity checks for the pipes mapping helper
+ Updated Runtimestation to use the supply_scrubbers helper
+ Fixed found issues relating to smart pipes
+
+
EvilDragonfiend updated:
+
+ Added a tip to sillytips.txt: There is no supermatter SILVER. There is only supermatter SLIVER.
+
+
Tsar-Salat updated:
+
+ Reverts grayscaled blood and species specific colors for them. They will return at a later date
+
+
+
05 August 2024
+
Aramix updated:
+
+ Monkies no longer teleport at will when trying to kill you
+
+
Markus Larsson updated:
+
+ Fixed insuls not properly spawning in Engineering lockers.
+
+
MarkusLarsson421 updated:
+
+ Added aft security and aft science area.
+
+
XeonMations updated:
+
+ Humans are now Indomitable.
+
+
+
04 August 2024
+
EvilDragonfiend updated:
+
+ debug orb of the debug outfit now allows you to spacewalk
+ Pseudo-world diver debugging item - that makes a new z level then loads a desired map template onto the z.
+ smooth live debugging objects (wall, table, turf)
+ a new mapping helper - Spaceproof directional windows, Group directional windows
+ a new 10x10 maint room. You can stare at space as much as you want... for some reason there are items stuck in space??
+ a new turf proc /turf/proc/get_nearby_turf_by_dir(direction). It returns a turf from the turf that is next to from the given direction.
+ minor change to map template list code
+
+
Geatish updated:
+
+ Removed the deepthroat eatverb from the raw sausage
+
+
PowerfulBacon updated:
+
+ Chemical factories now use power instead of matter.
+ Removes pill presses and patch dispensors.
+ Bottle dispensors no longer produce glass bottles out of nowhere, they now require a bottle to fill.
+ The plumbing RCD can now print bottle fillers.
+ Security winter coat is now stronger than the armour vest for energy, laser, heat, and stamina but weaker against melee and projectiles.
+ Security corporate jacket slowdown reduced.
+ Security heavy armour vest is now stronger than the armour vest across the board, but has more slowdown.
+ Exercising now provides temporary stun resistance.
+ Reverts medical scanners showing missing organs
+
+
XeonMations updated:
+
+ Medical scanners now show missing organs.
+
+
rkz, Gandalf2k15, LemonInTheDark, LT3, MrMelbert updated:
+
+ Converts security levels into a subystem. Much more easily debugged and cleaner.
+ Datumizes individual levels to easily be added or removed
+
+
rkz, Yenwodyah updated:
+
+ cleaned up buckling checks, reducing edge cases. Documents buckling code.
+ removes snowflake code for cyborg buckling. Cyborgs can instantly buckle people on the same tile as them(like obj buckling), but now have the same time to buckle people to things as any other buckling object if buckled from an adjacent tile
+
+
rkz, mothblocks, ZephyrTFA, kubisopplay updated:
+
+ Dead/Catatonic mobs cannot have a split personality anymore.
+ Resolves issues related to split personality shitcode sending clients to lobby.
+ updates verbs on login to prevent weird inheritance of verbs
+
+
rkz, thgvr, Fikou updated:
+
+ Greyscales all blood decals.
+ Species now all have different blood colors, which will show in the footprints, blood trails, and damage overlays when they get hurt
+ Gave some species their own bloodtype
+ new footstep sprites
+
+
+
03 August 2024
+
mystery3525 updated:
+
+ Oversight which made infrequent runtimes with mining mechs
+ Mining mechs should actually spawn 25% of the time instead of 16% of the time.
+
+
rkz, CakeQ, MistakeNot4892 updated:
+
+ adds several new decal designs from Baystation
+
+
+
02 August 2024
+
PowerfulBacon updated:
+
+ Fixes issues with time freezing
+
+
+
01 August 2024
+
Aramix updated:
+
+ Cerulean Pylons will now make a best effort attempt at spawning 3 polycrystals instead of desperately trying to fulfill that as a guarantee
+
+
DrDuckedGoose updated:
+
+ Switch checker tiles back to their 'intended' sprite
+
+
XeonMations updated:
+
+ Electric vehicles such as the janicart, secway, electric wheelchair and ATV now are affected by EMPs
+
+
+
31 July 2024
+
Tsar-Salat updated:
+
+ fix surgery initiation failure
+ fixes martial arts lying state issues
+ fixes plastic flaps being completely dense, you can now move under them again
+
+
+
30 July 2024
+
EvilDragonfiend updated:
+
+ lighting object sprites now have 4 dir states.
+
+
Geatish updated:
+
+ Gave each shell a size, handheld shells are small (expect for the compact remote which is tiny) the rest are normal size or larger.
+ You can now press the third button on the controller shell by CTRL-clicking.
+ The component printer can now be deconstructed and its printing animation now works, it also no longer auto links to the silo.
+ Printing the compact remote, controller and scanner now gives you the unscrewed variant.
+ The drone shell now uses the correct sprite
+ The server shell now takes only 6 seconds to screw together, rather than 10
+
+
MarkusLarsson421 updated:
+
+ Removed the skeleton ghost spawn in dorm maintenance.
+
+
PowerfulBacon updated:
+
+ Made hacking easier across the board by lowering the security areas of some areas and revealing more wires.
+ Cutting wires on airlocks is no longer guaranteed to shock you.
+
+
Tsar-Salat updated:
+
+ fix boxstation autoname camera directionals
+
+
Varo updated:
+
+ Clown and mimes now appear in the correct department (service) in the job preferences menu
+
+
XeonMations updated:
+
+ Fixed metastation's brig shuttle area not having an exit for prisoners.
+
+
rkz, Thunder12345 updated:
+
+ adds CTF vests, replacing CTF Hardsuits. Same damage reduction & stats.
+ Any item of clothing can now be given an energy shield, not only hardsuits
+
+
rkz, nightred, Couls. RaveRadbury, Timberpoes, WarlockD, ArcaneMusic, MrMelbert updated:
+
+ adds temperature regulators to space suits. These are heaters attached to the suit dependent on a battery life. Not significant for humans, but helpful for species that do not do well against the cold.
+ hardsuit headlights are repairable after being hit by a nightmare's blade. Simply use a lightbulb on a hardsuit helmet
+ breath air exhaled from carbons lungs matches the mobs bodytemperature
+ Carbon hugging is now functional. It previously had the giver of the hug GAIN heat when hugging a colder person, instead of the other way around. Hugs were harmful!
+
+
rkz, ninjanomnom updated:
+
+ limits calls or changes to obj_integrity var, all must be made through getters or setters
+
+
rkz, rohesie, tralezab, dwasint updated:
+
+ You can now see if a limb is disabled through checkhealth (HUD, healthanalyzer, ghostscan)
+ being limbless while flying will never apply the limbless slowdown (because you are movin just fine, right?)
+ minor stamina fixes in the way it is applied & healed
+ kills a lot of unecessary limb updating
+ makes Limb removal & disabling event-based. Extricate it from update_mobility
+
+
+
29 July 2024
+
spockye updated:
+
+ adds missing wall to metastation
+
+
+
28 July 2024
+
Spockye updated:
+
+ removed glass floor from corgstation medical
+
+
+
27 July 2024
+
Spockye updated:
+
+ Replaces current warning cone sprite, with a newer one
+
+
Spockye, TheVekter, INFRARED_BARON, PigeonVerde updated:
+
+ Ports the shark plushie
+
+
+
26 July 2024
+
Markus Larsson updated:
+
+ fixed AI having Syndicate and CentCom comms.
+
+
XeonMations updated:
+
+ Made the space dragon's gust ability no longer hit people through walls.
+ Also fixed a runtime happening with the space dragon's gust ability.
+ Added the ability for people to make different types of lockers
+
+
+
25 July 2024
+
XeonMations updated:
+
+ Fixed space heaters making power cells from the void.
+
+
+
24 July 2024
+
Rukofamicom updated:
+
+ Reverted most recent pirate changes so that a proper discussion can take place before rushing a major balance change to pirates.
+
+
+
23 July 2024
+
Geatish updated:
+
+ Removed glass floor from the designated atmos work area and rerouted undertile distro piping around it.
+ Rad station atmos storage shutters now work. Tiles in space next to gas miners have been removed. Plasma windows in gas chambers no longer spawn with N2. Also removed extra APC in xenobio
+
+
rkz, spockye updated:
+
+ Adds some tile variety to MetaStation Security
+
+
spockye updated:
+
+ fixed floating cameras on the exploration shuttle
+
+
+
22 July 2024
+
ClownMoff updated:
+
+ Fixes the bananium sword causing bleed.
+
+
Spockye updated:
+
+ rebalanced the pirate shuttle
+ some misc decal changes for the pirate shuttle
+
+
+
19 July 2024
+
Aramix updated:
+
+ added a new 'divable' var in closets controlling interaction with skittish trait
+ supply pods are now not divable
+
+
+
18 July 2024
+
Hardly3D updated:
+
+ Added new hairstyle: Short Bangs 2
+
+
ToasterBan updated:
+
+ stunbatons only shove on disarm intent
+
+
Tsar-Salat updated:
+
+ placing lightswitch frame uses the correct pixelshift
+ weird camera thing
+
+
ro5490 updated:
+
+ If all Mimites are dead, an announcement plays.
+ If the Mimite event hits 60 minutes and mimites still alive, they stop replicating entirely
+ tweaked replication rate of the Mimites, and added a replication limit
+ Nerfed Mimite health and ambush venom. Remember that they can be scanned with Discovery Scanners and examine can reveal them.
+ fixed a few runtimes regarding Mimites
+ Threshold Define, and add destroy for Mimites
+
+
+
17 July 2024
+
rkz, esainane, fippefi, TastyFish updated:
+
+ emissives for air alarms & request consoles
+ Wall mounted and directional objects have undergone major internal simplification. Please report anything unusual!
+ You can no longer stack an indefinite amount of Intercoms on the same wall.
+ Wall mounted items on top of the wall now consistently check against other items on top of the wall, and items coming out of the wall now consistently check against other items coming out of the wall.
+ The various directional pixel offsets within an APC, Fire Extinguisher Cabinet, Intercom, or Newscaster have been made consistent with each other.
+ The pixel offsets of Intercoms, Fire Alarms, Fire Extinguisher Cabinets, Flashers, and Newscasters have been made consistent between roundstart and constructed instances.
+
+
+
16 July 2024
+
PowerfulBacon updated:
+
+ Rebalances bleeding making it significantly more dangerous, it now has a status effect.
+ You can now hold your bleeding wounds to slow the rate of blood-loss.
+ Burn weapons can cauterise bleeding wounds.
+ Medical items that heal multiple types of damage will now function if only 1 of those types of damages need healing, rather than all of them.
+ Blood type and volume percentage will now show up on medhuds.
+ Surgery tables and stasis beds will now temporarilly stop your bleeding while you are lying on them.
+
+
rkz, MLGTASTICa updated:
+
+
+
15 July 2024
+
HowToLoLu updated:
+
+ Modular Fabricators no longer dump the contents of a connected ore silo onto the ground
+
+
Programs-The-Station updated:
+
+ Printed Positronic Brains will now show the correct locations to ghosts on creation, instead of null.
+ Random Hardcoded pAI jobcode value.
+
+
+
14 July 2024
+
Gilgaxx updated:
+
+ The HoS and captain's guns now show distinctly if they've been blown up to the point of not working anymore.
+
+
LemonInTheDark, Timberpoes (Port by EvilDragonfiend) updated:
+
+ ported 'Fit Viewport' related PRs from TG to fix a runtime
+ added 'VERB_REF' macro
+ repathed '/datum/viewData' into '/datum/view_data' (to match TG code)
+
+
PowerfulBacon updated:
+
+ Revs no longer block the shuttle
+ Revs no longer have a deconversion message
+ Lawyers and HOPs can now deconvert people by using a space law book on them. If the lawyer is a revolutionary, then they will use this to convert people instead.
+ Revs no longer have objectives to kill all the heads of staff, instead its a soft objective to establish a new command structure which works the same way but doesn't really matter if someone fucks off to space since it won't affect if you win or lose
+ Revs no longer ends when all the heads of either side are killed
+ Completely removes the midround rev ruleset cause its just stupid
+
+
ToasterBan updated:
+
+ Aiming head with a tonfa will paralyze rather than put the target to sleep
+ Advanced Mutation Toxin is now cured via below freezing temperatures
+
+
Tsar-Salat updated:
+
+ Swapped VIP centcom official's coat for a vest
+ Switched Centcom Admiral's red beret for a centcom caphat, per admin request
+
+
Varo updated:
+
+ change a big no-no word in a poster
+
+
rkz updated:
+
+ fix tile sprites for white & textured tiles
+
+
rkz, Ghom, TemporalOroboros updated:
+
+ Basematerials alloy support (plasteel, plasmaglass, plastitanium, etc.)
+ plasteel basestructures apply slowdown based on material unit
+ alien alloy basestructures now have self-healing properties
+
+
rkz, Mothblocks updated:
+
+ genericized disarm code for humanoids/monkeys
+
+
rkz, PositiveEntropy, tf-4 updated:
+
+ Adds new centcom uniforms, suits, hats & armor. Adds to outfit selector. Now CC can dunk on crew with their superior pajamas.
+
+
rkz, mothblocks, Tastyfish, MrStonedOne, LemonInTheDark updated:
+
+ ss init stages
+ ss init logging
+ ss init time measurement messages now precise to 2 decimals
+
+
ro5490, kit-katz updated:
+
+ New creatures that enjoy fooling people into thinking they're just generic objects, Mimites, Ranged Mimites, and Crate Mimites now exist! Be careful what items you interact with!
+ Added Mimites Midround event
+ added an icon for Mimites, Courtesy of Kit-Katz
+
+
spockye updated:
+
+ Remakes Pirate_default.
+
+
+
12 July 2024
+
JixS4v updated:
+
+ fixes deadminning (again)
+
+
PestoVerde322 updated:
+
+ Decomissioned for good the E.X.P.E.R.I-MENTOR in favour of the anomaly system.
+ All of the Anomaly research room has been refurbished properly.
+
+
h42 updated:
+
+ adds a worn sprite to the doctor's bag
+
+
+
11 July 2024
+
Geatish updated:
+
+ you can now butt cigarettes on other people if you're on harm intent
+ cigarettes will have their smoke time reduced and have a chance to get extinguished if attacking on non harm intent
+
+
MarkusLarsson421 updated:
+
+ Added or moved insuls to Engineering lockers.
+ Gave the RD a departmental console so they can do ID stuff.
+ Fixed Engineering disposals chute.
+
+
tonty updated:
+
+ crewmembers no longer get cold feet when attempting to piggyback eachother
+
+
+
10 July 2024
+
EvilDragonfiend updated:
+
+ minor port of set_eye() and reset_perspective() proc from TG, #PR 69115 (LemonInTheDark)
+ improved basic game system to track client's currently used eye
+ advanced camera is now visible by anyone even if it's currently used by someone. (This doesn't support the shuttle docking system, because it uses different one.)
+ minor fix that advanced camera was still usable even if you're locker'ed
+
+
MarkusLarsson421 updated:
+
+ Changed PopulateItems() to check if it should be empty or not.
+ Changed Medkits to not use their empty variable.
+
+
PowerfulBacon updated:
+
+ Removes unconciousness from mech brute attacks
+
+
XeonMations updated:
+
+ NT's mapping department has repaired radstation's security disposals loop. It now works properly.
+
+
spockye updated:
+
+ fixed Rad decals
+ fixed half tiles
+ removes Captain spawner from rdm_captain_quarters.dmm
+ replaces item spawner in rdm_captain_quarters.dmm
+ Added glass floors and catwalk floors to corg station
+ small decal additions and changes to corg station
+ fixes to fland station
+ glass tiles to fland station
+
+
+
09 July 2024
+
Howluinb updated:
+
+ Digitigrade Lizards will no longer get their toe stubbed on tables.
+
+
TsunamiAnt updated:
+
+ paper frames now take 10 paper and 2 wood to craft
+ paper bundle is now also called that
+ add description text to paper bundle to show people you can just cut it open
+
+
08 July 2024
EvilDragonfiend updated:
@@ -291,274 +797,6 @@ ro5490 updated:
Added Final Darkness rite to the Shadow-Sect
Faithsworn mob
-
-
04 June 2024
-
EvilDragonfiend updated:
-
- _basemap.dm has FORCE_MAP define options for debug
-
-
PowerfulBacon updated:
-
- Increases weapon slowdown for heavy weapons.
- Fixes incorrect message on brains and heads.
- Fixes z-clear not announcing brains that have someone inside their brain instead of ghosted.
-
-
ro5490 updated:
-
- fixed openspace tiles being replaced by a nature orb
-
-
-
03 June 2024
-
Geatish updated:
-
- You can now choose cigars and DromedaryCo cigs in the smoker trait option
-
-
HowToLoLu updated:
-
- The autolathe shock wire reacts to cutting the wire once more
-
-
-
01 June 2024
-
Gilgaxx updated:
-
- fixed even MORE broken arcade machines
-
-
-
30 May 2024
-
PowerfulBacon updated:
-
- Fix cult construct creation spawning copies of the construct.
-
-
-
28 May 2024
-
PowerfulBacon updated:
-
- Fixes shards being deleted if you cancel their conversion into a construct.
-
-
XeonMations updated:
-
- Changed telecommunications on all maps to have HT piping.
-
-
-
27 May 2024
-
HowToLoLu updated:
-
- Object spawners properly return a QDEL_HINT now.
-
-
-
26 May 2024
-
PowerfulBacon updated:
-
- Fixes loading a gun from an ammo box multiple times resulting in the gun being unable to fire.
-
-
-
25 May 2024
-
Bokkiewokkie updated:
-
- Made it possible to disassemble pool ladders with wrenches and possible to build them with rods.
- Fixed pool ladders being unanchored.
-
-
-
24 May 2024
-
EvilDragonfiend updated:
-
- random maint spawner will spawn items correctly
-
-
PowerfulBacon updated:
-
- Immovable rods will no longer space the station.
-
-
rkz updated:
-
- fix clockwork armor error worn_states. No more pink drip
- bows arent invisible anymore. The code is still ugly, sorry
- Ion rifles have their emissivity back
- added a bunch of error icons to clothing icon files. Less invisible stuff, more people wearing ugly stuff for them to report so it can be fixed <3
-
-
rkz, Rohesie updated:
-
- Made actions restraining/handcuffing a carbon into traits. Split into two.
-
-
-
22 May 2024
-
Geatish updated:
-
- Added the alarm app on the atmos, engineer and CE job disks
-
-
HowToLoLu updated:
-
- Plasmamen helmets count as an internals mask once again
-
-
-
21 May 2024
-
celotajstg updated:
-
- added a check to confirm adminheals
- tguified a few admin topic procs
-
-
rkz, TiviPlus, Fikou, Timberpoes, necromanceranne, InvalidArgument3, zxaber, KathrinBailey updated:
-
- Cleaned up mech door bumping
- mechs no longer explode during destruction (inherited from cars lmao)
- AIs in mechs can use mech tools again
- cleaned up mining mech tools
- AI intellicard checks work on mechs again by checking occupants correctly
- Critical fix with mining mech drills
- drills now calculate gib damage by checking the mobs health, rather than assuming every mob's health is 200
- Xenos now do claw damage on mechs based on their actual arm damage, rather than a base hardcoded 15
-
-
-
19 May 2024
-
EvilDragonfiend updated:
-
- Jobs will be told when a job is not available to play in a shift.
- CentCom console can manage all jobs now. You can prioritize Captain role.
- fixed some job code glitches
-
-
MatiAvanti updated:
-
- changed LOBBY_COUNTDOWN from 180 to 300 seconds
-
-
-
18 May 2024
-
Gilgaxx updated:
-
- Fixed the speed and fireproof slimepotions
-
-
anturK, rkz updated:
-
- inverted CanReach to default to blocking
-
-
rkz, Tiviplus, msgerbs, Ghommie, Fikou, necromanceranne updated:
-
- mechs are now a vehicle subtype, instead of Winter Wonderland snowflake code
- mechs no longer need to use middle click as a janky override to utilize their equipment.
- fixed bugs with inconsistent mech equipment balloons/to_chat
- fixed mechs with ballistics shooting themselves while moving
-
-
-
17 May 2024
-
BeeLover updated:
-
- fixes a typo when trying to go on land with a lava boat
-
-
-
16 May 2024
-
XeonMations updated:
-
- Fixed the lavaland base's atmosphere alarm going off every shift
-
-
-
15 May 2024
-
PowerfulBacon updated:
-
- Fixes the hub entry not using the correct character to divide the station name.
-
-
-
11 May 2024
-
Geatish updated:
-
- Made the godeye, monocle, hipster, jamjar and round glasses correct vision for short sightedness
- The hipster glasses are now actually called hipster glasses instead of prescription glasses
-
-
Gilgaxx updated:
-
- Added 5 new slime plushies
- Added a rainbow flush plush
- Removed dehydrated carps from the plushes crate
- Added a new contraband crate: "Plushie Crate Without Moth Plushies". Dehydrated carps included, moth plushes excluded.
- Alien phobia now includes slime plushes (it already included slime mobs).
- There's no such thing as plushys, they're plushies now.
-
-
MatiAvanti updated:
-
- Harvester can now process corpsess with abiotic items like clothes and handcuffs if upgraded. Emagging it unlocks processing live people.
- added new sound for harvester.
- new sprites for harvester.
-
-
PowerfulBacon updated:
-
- Updates some uses of luminosity internall for lockers and turfs.
-
-
Tsar-Salat updated:
-
- pka seclite attachment
- legion cores are not eaten like demonic potatoes, you may apply them normally again and expect the usual healing
- fixes the flashlight on mini e_guns like the PTSD
- griddle to corg
-
-
rkz(organized & repathed every clothing sprite), MrMelbert, ShizCalev, ArcaneMusic(code contribution), maxymax13, TaG2e, LordVollkorn, Twaticus(sprite contribution) updated:
-
- A hell of a lot of new belt/back sprites for items
- Lawyer's aristocratic coats are now under premium in vendor
- All missing sprite icon_states in the game are now accounted for.
- All missing sprite worn_states in the game are now accounted for.
- all offending coders have been taken out back and cried at
- Implements full missing icon unit test
- Organizes obj/clothing & mob/clothing by category & typepath
- hooded cult robes now use hooded typepath instead of being hardsuit subtypes (all stats preserved)
- hooded carp suit now use hooded typepath instead of being hardsuit subtypes (all stats preserved)
- adjusts several body_parts_covered flags on different clothes articles to fix worn_icon issues
-
-
rkz, TastyFish, Mothblocks updated:
-
- adds colored text support for status displays
- Circuit support for status displays
- makes newscasters & status displays emissive!
- fixes hardels with Status Display vis_contents
- Status display marquee text flows nicer
-
-
-
10 May 2024
-
ClownMoff updated:
-
- CorgStation: Added 3 oxytans to the security E.V.A room.
- CorgStation: Split the HoS shutter controllers into 2 buttons instead of one, for both the private room and the office.
- CorgStation: Cargo windoor from maints could be opened by everyone. Not anymore.
- CorgStation: Solved a camera and a fire alarm being in a window
- CorgStation: Deleted an unnecesary shutter from the HoS room
-
-
rkz, Qustinnus, AnturK, TiviPlus, ShizCalev, MrMelbert, LemonInTheDark, ghommie updated:
-
- gunlight component
- refactored energy guns to have valid inhands
- adds automated handling for inhand and worn energy guns
- addresses possible runtime when qdeleting self-recharging guns with attached bayonets
- new minigunlight sprite for mini e_guns like the PTSD
- splits toggleable sec helmets into their own subtype to reduce snowflake code
-
-
-
08 May 2024
-
DrDuckedGoose updated:
-
- Fix emissives on players
- Add filter compatibility to emissives
-
-
EvilDragonfiend updated:
-
- Improved textification of the language icon rendering in TGUI.
- cleaned up religion code into multiple dm files
- Refactored weather code and fixed weather bad rendering issue.
- Void Heretic no longer shows void weather where they don't stand on.
-
-
PowerfulBacon updated:
-
- Fixes 515 compilation issue regarding species cold temperature
-
-
XeonMations updated:
-
- Fixed blood cultists being able to place structures on survival pods
-
-
rkz, coiax updated:
-
- Refactors step_action to save us from a few thousand useless proccalls per shift
-
-
rkz, nightred, lemoninthedark updated:
-
- refactored temperature stabilization in humans. Split human temperature into core temperature, which is affected by fevers & shivering symptoms and represents the overall temperature range, and Body Temperature which is what is directly affected by environmental factors and projectiles.
- All species will now receive temperature HUD alerts before receiving damage.
- recalculates burn damage based on overall temperature
-
GoonStation 13 Development Team
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index 741df904147e5..416879b326b0b 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -43485,3 +43485,379 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
tonty:
- bugfix: starting an emote with " 's " or "," won't leave a space anymore. roleplay
has been saved
+2024-07-09:
+ Howluinb:
+ - balance: Digitigrade Lizards will no longer get their toe stubbed on tables.
+ TsunamiAnt:
+ - tweak: paper frames now take 10 paper and 2 wood to craft
+ - tweak: paper bundle is now also called that
+ - rscadd: add description text to paper bundle to show people you can just cut it
+ open
+2024-07-10:
+ EvilDragonfiend:
+ - code_imp: 'minor port of set_eye() and reset_perspective() proc from TG, #PR 69115
+ (LemonInTheDark)'
+ - code_imp: improved basic game system to track client's currently used eye
+ - tweak: advanced camera is now visible by anyone even if it's currently used by
+ someone. (This doesn't support the shuttle docking system, because it uses different
+ one.)
+ - bugfix: minor fix that advanced camera was still usable even if you're locker'ed
+ MarkusLarsson421:
+ - code_imp: Changed PopulateItems() to check if it should be empty or not.
+ - tweak: Changed Medkits to not use their empty variable.
+ PowerfulBacon:
+ - rscdel: Removes unconciousness from mech brute attacks
+ XeonMations:
+ - bugfix: NT's mapping department has repaired radstation's security disposals loop.
+ It now works properly.
+ spockye:
+ - bugfix: fixed Rad decals
+ - bugfix: fixed half tiles
+ - rscdel: removes Captain spawner from rdm_captain_quarters.dmm
+ - tweak: replaces item spawner in rdm_captain_quarters.dmm
+ - rscadd: Added glass floors and catwalk floors to corg station
+ - rscadd: small decal additions and changes to corg station
+ - rscadd: fixes to fland station
+ - rscadd: glass tiles to fland station
+2024-07-11:
+ Geatish:
+ - tweak: you can now butt cigarettes on other people if you're on harm intent
+ - tweak: cigarettes will have their smoke time reduced and have a chance to get
+ extinguished if attacking on non harm intent
+ MarkusLarsson421:
+ - balance: Added or moved insuls to Engineering lockers.
+ - rscadd: Gave the RD a departmental console so they can do ID stuff.
+ - bugfix: Fixed Engineering disposals chute.
+ tonty:
+ - bugfix: crewmembers no longer get cold feet when attempting to piggyback eachother
+2024-07-12:
+ JixS4v:
+ - admin: fixes deadminning (again)
+ PestoVerde322:
+ - rscdel: Decomissioned for good the E.X.P.E.R.I-MENTOR in favour of the anomaly
+ system.
+ - rscadd: All of the Anomaly research room has been refurbished properly.
+ h42:
+ - imageadd: adds a worn sprite to the doctor's bag
+2024-07-14:
+ Gilgaxx:
+ - tweak: The HoS and captain's guns now show distinctly if they've been blown up
+ to the point of not working anymore.
+ LemonInTheDark, Timberpoes (Port by EvilDragonfiend):
+ - code_imp: ported 'Fit Viewport' related PRs from TG to fix a runtime
+ - code_imp: added 'VERB_REF' macro
+ - code_imp: repathed '/datum/viewData' into '/datum/view_data' (to match TG code)
+ PowerfulBacon:
+ - balance: Revs no longer block the shuttle
+ - balance: Revs no longer have a deconversion message
+ - balance: Lawyers and HOPs can now deconvert people by using a space law book on
+ them. If the lawyer is a revolutionary, then they will use this to convert people
+ instead.
+ - balance: Revs no longer have objectives to kill all the heads of staff, instead
+ its a soft objective to establish a new command structure which works the same
+ way but doesn't really matter if someone fucks off to space since it won't affect
+ if you win or lose
+ - balance: Revs no longer ends when all the heads of either side are killed
+ - balance: Completely removes the midround rev ruleset cause its just stupid
+ ToasterBan:
+ - tweak: Aiming head with a tonfa will paralyze rather than put the target to sleep
+ - balance: Advanced Mutation Toxin is now cured via below freezing temperatures
+ Tsar-Salat:
+ - tweak: Swapped VIP centcom official's coat for a vest
+ - tweak: Switched Centcom Admiral's red beret for a centcom caphat, per admin request
+ Varo:
+ - tweak: change a big no-no word in a poster
+ rkz:
+ - bugfix: fix tile sprites for white & textured tiles
+ rkz, Ghom, TemporalOroboros:
+ - rscadd: Basematerials alloy support (plasteel, plasmaglass, plastitanium, etc.)
+ - rscadd: plasteel basestructures apply slowdown based on material unit
+ - rscadd: alien alloy basestructures now have self-healing properties
+ rkz, Mothblocks:
+ - code_imp: genericized disarm code for humanoids/monkeys
+ rkz, PositiveEntropy, tf-4:
+ - rscadd: Adds new centcom uniforms, suits, hats & armor. Adds to outfit selector.
+ Now CC can dunk on crew with their superior pajamas.
+ rkz, mothblocks, Tastyfish, MrStonedOne, LemonInTheDark:
+ - server: ss init stages
+ - server: ss init logging
+ - server: ss init time measurement messages now precise to 2 decimals
+ ro5490, kit-katz:
+ - rscadd: New creatures that enjoy fooling people into thinking they're just generic
+ objects, Mimites, Ranged Mimites, and Crate Mimites now exist! Be careful what
+ items you interact with!
+ - rscadd: Added Mimites Midround event
+ - imageadd: added an icon for Mimites, Courtesy of Kit-Katz
+ spockye:
+ - tweak: Remakes Pirate_default.
+2024-07-15:
+ HowToLoLu:
+ - bugfix: Modular Fabricators no longer dump the contents of a connected ore silo
+ onto the ground
+ Programs-The-Station:
+ - bugfix: Printed Positronic Brains will now show the correct locations to ghosts
+ on creation, instead of null.
+ - bugfix: Random Hardcoded pAI jobcode value.
+2024-07-16:
+ PowerfulBacon:
+ - balance: Rebalances bleeding making it significantly more dangerous, it now has
+ a status effect.
+ - balance: You can now hold your bleeding wounds to slow the rate of blood-loss.
+ - balance: Burn weapons can cauterise bleeding wounds.
+ - bugfix: Medical items that heal multiple types of damage will now function if
+ only 1 of those types of damages need healing, rather than all of them.
+ - rscadd: Blood type and volume percentage will now show up on medhuds.
+ - balance: Surgery tables and stasis beds will now temporarilly stop your bleeding
+ while you are lying on them.
+ rkz, MLGTASTICa:
+ - bugfix: fixes ody mechhuds
+2024-07-17:
+ rkz, esainane, fippefi, TastyFish:
+ - rscadd: emissives for air alarms & request consoles
+ - refactor: Wall mounted and directional objects have undergone major internal simplification.
+ Please report anything unusual!
+ - bugfix: You can no longer stack an indefinite amount of Intercoms on the same
+ wall.
+ - bugfix: Wall mounted items on top of the wall now consistently check against other
+ items on top of the wall, and items coming out of the wall now consistently
+ check against other items coming out of the wall.
+ - bugfix: The various directional pixel offsets within an APC, Fire Extinguisher
+ Cabinet, Intercom, or Newscaster have been made consistent with each other.
+ - bugfix: The pixel offsets of Intercoms, Fire Alarms, Fire Extinguisher Cabinets,
+ Flashers, and Newscasters have been made consistent between roundstart and constructed
+ instances.
+2024-07-18:
+ Hardly3D:
+ - rscadd: 'Added new hairstyle: Short Bangs 2'
+ ToasterBan:
+ - tweak: stunbatons only shove on disarm intent
+ Tsar-Salat:
+ - bugfix: placing lightswitch frame uses the correct pixelshift
+ - bugfix: weird camera thing
+ ro5490:
+ - rscadd: If all Mimites are dead, an announcement plays.
+ - rscadd: If the Mimite event hits 60 minutes and mimites still alive, they stop
+ replicating entirely
+ - tweak: tweaked replication rate of the Mimites, and added a replication limit
+ - balance: Nerfed Mimite health and ambush venom. Remember that they can be scanned
+ with Discovery Scanners and examine can reveal them.
+ - bugfix: fixed a few runtimes regarding Mimites
+ - code_imp: Threshold Define, and add destroy for Mimites
+2024-07-19:
+ Aramix:
+ - code_imp: added a new 'divable' var in closets controlling interaction with skittish
+ trait
+ - tweak: supply pods are now not divable
+2024-07-22:
+ ClownMoff:
+ - bugfix: Fixes the bananium sword causing bleed.
+ Spockye:
+ - balance: rebalanced the pirate shuttle
+ - bugfix: some misc decal changes for the pirate shuttle
+2024-07-23:
+ Geatish:
+ - tweak: Removed glass floor from the designated atmos work area and rerouted undertile
+ distro piping around it.
+ - bugfix: Rad station atmos storage shutters now work. Tiles in space next to gas
+ miners have been removed. Plasma windows in gas chambers no longer spawn with
+ N2. Also removed extra APC in xenobio
+ rkz, spockye:
+ - rscadd: Adds some tile variety to MetaStation Security
+ spockye:
+ - bugfix: fixed floating cameras on the exploration shuttle
+2024-07-24:
+ Rukofamicom:
+ - rscdel: Reverted most recent pirate changes so that a proper discussion can take
+ place before rushing a major balance change to pirates.
+2024-07-25:
+ XeonMations:
+ - bugfix: Fixed space heaters making power cells from the void.
+2024-07-26:
+ Markus Larsson:
+ - bugfix: fixed AI having Syndicate and CentCom comms.
+ XeonMations:
+ - balance: Made the space dragon's gust ability no longer hit people through walls.
+ - bugfix: Also fixed a runtime happening with the space dragon's gust ability.
+ - rscadd: Added the ability for people to make different types of lockers
+2024-07-27:
+ 'Spockye ':
+ - rscadd: Replaces current warning cone sprite, with a newer one
+ Spockye, TheVekter, INFRARED_BARON, PigeonVerde:
+ - rscadd: Ports the shark plushie
+2024-07-28:
+ Spockye:
+ - bugfix: removed glass floor from corgstation medical
+2024-07-29:
+ spockye:
+ - bugfix: adds missing wall to metastation
+2024-07-30:
+ EvilDragonfiend:
+ - imageadd: lighting object sprites now have 4 dir states.
+ Geatish:
+ - balance: Gave each shell a size, handheld shells are small (expect for the compact
+ remote which is tiny) the rest are normal size or larger.
+ - bugfix: You can now press the third button on the controller shell by CTRL-clicking.
+ - bugfix: The component printer can now be deconstructed and its printing animation
+ now works, it also no longer auto links to the silo.
+ - bugfix: Printing the compact remote, controller and scanner now gives you the
+ unscrewed variant.
+ - bugfix: The drone shell now uses the correct sprite
+ - balance: The server shell now takes only 6 seconds to screw together, rather than
+ 10
+ MarkusLarsson421:
+ - bugfix: Removed the skeleton ghost spawn in dorm maintenance.
+ PowerfulBacon:
+ - balance: Made hacking easier across the board by lowering the security areas of
+ some areas and revealing more wires.
+ - balance: Cutting wires on airlocks is no longer guaranteed to shock you.
+ Tsar-Salat:
+ - bugfix: fix boxstation autoname camera directionals
+ Varo:
+ - bugfix: Clown and mimes now appear in the correct department (service) in the
+ job preferences menu
+ XeonMations:
+ - bugfix: Fixed metastation's brig shuttle area not having an exit for prisoners.
+ rkz, Thunder12345:
+ - rscadd: adds CTF vests, replacing CTF Hardsuits. Same damage reduction & stats.
+ - code_imp: Any item of clothing can now be given an energy shield, not only hardsuits
+ rkz, nightred, Couls. RaveRadbury, Timberpoes, WarlockD, ArcaneMusic, MrMelbert:
+ - rscadd: adds temperature regulators to space suits. These are heaters attached
+ to the suit dependent on a battery life. Not significant for humans, but helpful
+ for species that do not do well against the cold.
+ - rscadd: hardsuit headlights are repairable after being hit by a nightmare's blade.
+ Simply use a lightbulb on a hardsuit helmet
+ - bugfix: breath air exhaled from carbons lungs matches the mobs bodytemperature
+ - bugfix: Carbon hugging is now functional. It previously had the giver of the hug
+ GAIN heat when hugging a colder person, instead of the other way around. Hugs
+ were harmful!
+ rkz, ninjanomnom:
+ - code_imp: limits calls or changes to obj_integrity var, all must be made through
+ getters or setters
+ rkz, rohesie, tralezab, dwasint:
+ - rscadd: You can now see if a limb is disabled through checkhealth (HUD, healthanalyzer,
+ ghostscan)
+ - tweak: being limbless while flying will never apply the limbless slowdown (because
+ you are movin just fine, right?)
+ - bugfix: minor stamina fixes in the way it is applied & healed
+ - code_imp: kills a lot of unecessary limb updating
+ - code_imp: makes Limb removal & disabling event-based. Extricate it from update_mobility
+2024-07-31:
+ Tsar-Salat:
+ - bugfix: fix surgery initiation failure
+ - bugfix: fixes martial arts lying state issues
+ - bugfix: fixes plastic flaps being completely dense, you can now move under them
+ again
+2024-08-01:
+ Aramix:
+ - tweak: Cerulean Pylons will now make a best effort attempt at spawning 3 polycrystals
+ instead of desperately trying to fulfill that as a guarantee
+ DrDuckedGoose:
+ - bugfix: Switch checker tiles back to their 'intended' sprite
+ XeonMations:
+ - balance: Electric vehicles such as the janicart, secway, electric wheelchair and
+ ATV now are affected by EMPs
+2024-08-02:
+ PowerfulBacon:
+ - bugfix: Fixes issues with time freezing
+2024-08-03:
+ mystery3525:
+ - bugfix: Oversight which made infrequent runtimes with mining mechs
+ - bugfix: Mining mechs should actually spawn 25% of the time instead of 16% of the
+ time.
+ rkz, CakeQ, MistakeNot4892:
+ - rscadd: adds several new decal designs from Baystation
+2024-08-04:
+ EvilDragonfiend:
+ - rscadd: debug orb of the debug outfit now allows you to spacewalk
+ - rscadd: Pseudo-world diver debugging item - that makes a new z level then loads
+ a desired map template onto the z.
+ - rscadd: smooth live debugging objects (wall, table, turf)
+ - rscadd: a new mapping helper - Spaceproof directional windows, Group directional
+ windows
+ - rscadd: a new 10x10 maint room. You can stare at space as much as you want...
+ for some reason there are items stuck in space??
+ - rscadd: a new turf proc /turf/proc/get_nearby_turf_by_dir(direction). It returns
+ a turf from the turf that is next to from the given direction.
+ - code_imp: minor change to map template list code
+ Geatish:
+ - rscdel: Removed the deepthroat eatverb from the raw sausage
+ PowerfulBacon:
+ - balance: Chemical factories now use power instead of matter.
+ - rscdel: Removes pill presses and patch dispensors.
+ - tweak: Bottle dispensors no longer produce glass bottles out of nowhere, they
+ now require a bottle to fill.
+ - bugfix: The plumbing RCD can now print bottle fillers.
+ - balance: Security winter coat is now stronger than the armour vest for energy,
+ laser, heat, and stamina but weaker against melee and projectiles.
+ - balance: Security corporate jacket slowdown reduced.
+ - balance: Security heavy armour vest is now stronger than the armour vest across
+ the board, but has more slowdown.
+ - balance: Exercising now provides temporary stun resistance.
+ - rscdel: Reverts medical scanners showing missing organs
+ XeonMations:
+ - tweak: Medical scanners now show missing organs.
+ rkz, Gandalf2k15, LemonInTheDark, LT3, MrMelbert:
+ - rscadd: Converts security levels into a subystem. Much more easily debugged and
+ cleaner.
+ - code_imp: Datumizes individual levels to easily be added or removed
+ rkz, Yenwodyah:
+ - code_imp: cleaned up buckling checks, reducing edge cases. Documents buckling
+ code.
+ - balance: removes snowflake code for cyborg buckling. Cyborgs can instantly buckle
+ people on the same tile as them(like obj buckling), but now have the same time
+ to buckle people to things as any other buckling object if buckled from an adjacent
+ tile
+ rkz, mothblocks, ZephyrTFA, kubisopplay:
+ - tweak: Dead/Catatonic mobs cannot have a split personality anymore.
+ - bugfix: Resolves issues related to split personality shitcode sending clients
+ to lobby.
+ - bugfix: updates verbs on login to prevent weird inheritance of verbs
+ rkz, thgvr, Fikou:
+ - rscadd: Greyscales all blood decals.
+ - rscadd: Species now all have different blood colors, which will show in the footprints,
+ blood trails, and damage overlays when they get hurt
+ - rscadd: Gave some species their own bloodtype
+ - rscadd: new footstep sprites
+2024-08-05:
+ Aramix:
+ - bugfix: Monkies no longer teleport at will when trying to kill you
+ Markus Larsson:
+ - bugfix: Fixed insuls not properly spawning in Engineering lockers.
+ MarkusLarsson421:
+ - rscadd: Added aft security and aft science area.
+ XeonMations:
+ - rscadd: Humans are now Indomitable.
+2024-08-06:
+ EdgeLordExe ported and fixed by mystery3525 with help from BriggsIDP:
+ - rscadd: Added new smart pipes mapping helper
+ - rscadd: Added new smart pipes air supply/scrubbers pipe helper
+ - rscadd: Added sanity checks for the pipes mapping helper
+ - rscadd: Updated Runtimestation to use the supply_scrubbers helper
+ - bugfix: Fixed found issues relating to smart pipes
+ EvilDragonfiend:
+ - rscadd: 'Added a tip to sillytips.txt: There is no supermatter SILVER. There is
+ only supermatter SLIVER.'
+ Tsar-Salat:
+ - rscdel: Reverts grayscaled blood and species specific colors for them. They will
+ return at a later date
+2024-08-07:
+ DarnTheMarn:
+ - tweak: Moved the security techfab to the warden office
+ - balance: Security techfab is now inaccessible to security officers and detectives
+ MarkusLarsson421:
+ - bugfix: Fixes cheap lights not burning you
+ mystery3525:
+ - bugfix: A pipe that was on top of another pipe in Fland Xenobio
+ - bugfix: A runtime with helmet of justice
+ - code_imp: Micro optimizes airlock access code with boolean short-circuiting
+ rkz, azarak, TemporalOroboros, Rohesie, Couls, ShizCalev, TastyFish:
+ - rscadd: Adds directional lighting system in 2024!
+ - rscadd: adds directional lighting to cyborg lights, flashlights, and gunlights
+ - refactor: refactors glow effects to be less terrible. Includes ethereal glow,
+ and also the glowy/antiglowy mutation.
+2024-08-08:
+ mystery3525:
+ - rscadd: AIs can now change their internal camera capture size with "AI Commands"
+ > "Adjust Camera Zoom"
+ - rscadd: Cyborgs can change their internal camera capture size in the Actions Menu
+ on their internal PDA app
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 34a22bf26e4c2..c6772756c8720 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/effects/light_overlays/light_cone.dmi b/icons/effects/light_overlays/light_cone.dmi
new file mode 100644
index 0000000000000..75f322a937174
Binary files /dev/null and b/icons/effects/light_overlays/light_cone.dmi differ
diff --git a/icons/effects/lighting_object.dmi b/icons/effects/lighting_object.dmi
index b7dd2ce32e764..a8156e003b8ff 100644
Binary files a/icons/effects/lighting_object.dmi and b/icons/effects/lighting_object.dmi differ
diff --git a/icons/effects/mapping_helpers.dmi b/icons/effects/mapping_helpers.dmi
index 08d666a0a614e..ca696ef8b0a46 100644
Binary files a/icons/effects/mapping_helpers.dmi and b/icons/effects/mapping_helpers.dmi differ
diff --git a/icons/mob/actions/actions_spacesuit.dmi b/icons/mob/actions/actions_spacesuit.dmi
new file mode 100644
index 0000000000000..2b4f8a887bd72
Binary files /dev/null and b/icons/mob/actions/actions_spacesuit.dmi differ
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index a4b8ff6241606..c69321f2c7bd6 100644
Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ
diff --git a/icons/mob/clothing/belt.dmi b/icons/mob/clothing/belt.dmi
index e8c911bf84552..c13c65bb55cdf 100644
Binary files a/icons/mob/clothing/belt.dmi and b/icons/mob/clothing/belt.dmi differ
diff --git a/icons/mob/clothing/head/hats.dmi b/icons/mob/clothing/head/hats.dmi
index 6060bbc572166..c8c85e6205d74 100644
Binary files a/icons/mob/clothing/head/hats.dmi and b/icons/mob/clothing/head/hats.dmi differ
diff --git a/icons/mob/clothing/head/utility.dmi b/icons/mob/clothing/head/utility.dmi
index 281255830913c..e9990abfa1435 100644
Binary files a/icons/mob/clothing/head/utility.dmi and b/icons/mob/clothing/head/utility.dmi differ
diff --git a/icons/mob/clothing/head/winterhood.dmi b/icons/mob/clothing/head/winterhood.dmi
index e7a6750551b50..ce0d725f80e9b 100644
Binary files a/icons/mob/clothing/head/winterhood.dmi and b/icons/mob/clothing/head/winterhood.dmi differ
diff --git a/icons/mob/clothing/mask.dmi b/icons/mob/clothing/mask.dmi
index 1f1667b6c83be..b5514e6cadfdc 100644
Binary files a/icons/mob/clothing/mask.dmi and b/icons/mob/clothing/mask.dmi differ
diff --git a/icons/mob/clothing/suits/armor.dmi b/icons/mob/clothing/suits/armor.dmi
index b66c19d294ff6..e4519adcd6e36 100644
Binary files a/icons/mob/clothing/suits/armor.dmi and b/icons/mob/clothing/suits/armor.dmi differ
diff --git a/icons/mob/clothing/suits/ctf.dmi b/icons/mob/clothing/suits/ctf.dmi
new file mode 100644
index 0000000000000..5960b5179aa41
Binary files /dev/null and b/icons/mob/clothing/suits/ctf.dmi differ
diff --git a/icons/mob/clothing/suits/jacket.dmi b/icons/mob/clothing/suits/jacket.dmi
index 2fba49f09493b..bcf9b96e33bc9 100644
Binary files a/icons/mob/clothing/suits/jacket.dmi and b/icons/mob/clothing/suits/jacket.dmi differ
diff --git a/icons/mob/clothing/suits/wintercoat.dmi b/icons/mob/clothing/suits/wintercoat.dmi
index f0dfdc2c10fc0..bbcc9844ae8f5 100644
Binary files a/icons/mob/clothing/suits/wintercoat.dmi and b/icons/mob/clothing/suits/wintercoat.dmi differ
diff --git a/icons/mob/clothing/under/centcom.dmi b/icons/mob/clothing/under/centcom.dmi
index 3694374aff799..2390bedbaad18 100644
Binary files a/icons/mob/clothing/under/centcom.dmi and b/icons/mob/clothing/under/centcom.dmi differ
diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi
index eed8562545c00..214043d7ca891 100644
Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ
diff --git a/icons/mob/inhands/plushes_lefthand.dmi b/icons/mob/inhands/plushes_lefthand.dmi
index 084f2e015e50b..a4169514dd0fc 100644
Binary files a/icons/mob/inhands/plushes_lefthand.dmi and b/icons/mob/inhands/plushes_lefthand.dmi differ
diff --git a/icons/mob/inhands/plushes_righthand.dmi b/icons/mob/inhands/plushes_righthand.dmi
index e768ac7ade15e..899c63e3f81a0 100644
Binary files a/icons/mob/inhands/plushes_righthand.dmi and b/icons/mob/inhands/plushes_righthand.dmi differ
diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi
index 4c71ed24455b1..b99c973312bd8 100644
Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ
diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi
index 1ead9f6d2309d..35a90fcfd2f99 100644
Binary files a/icons/mob/screen_gen.dmi and b/icons/mob/screen_gen.dmi differ
diff --git a/icons/obj/assemblies.dmi b/icons/obj/assemblies.dmi
index b9f33f255e468..ffc35e90e511f 100644
Binary files a/icons/obj/assemblies.dmi and b/icons/obj/assemblies.dmi differ
diff --git a/icons/obj/beds_chairs/chairs.dmi b/icons/obj/beds_chairs/chairs.dmi
index 2a3752636d463..2e5d0129a13c5 100644
Binary files a/icons/obj/beds_chairs/chairs.dmi and b/icons/obj/beds_chairs/chairs.dmi differ
diff --git a/icons/obj/clothing/head/hats.dmi b/icons/obj/clothing/head/hats.dmi
index bd6950f4f9749..76b89a24ed0d5 100644
Binary files a/icons/obj/clothing/head/hats.dmi and b/icons/obj/clothing/head/hats.dmi differ
diff --git a/icons/obj/clothing/head/winterhood.dmi b/icons/obj/clothing/head/winterhood.dmi
index 10ab0576352dc..37a76b7a3e85a 100644
Binary files a/icons/obj/clothing/head/winterhood.dmi and b/icons/obj/clothing/head/winterhood.dmi differ
diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi
index c2be2e65111c6..13f977d2e0a16 100644
Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ
diff --git a/icons/obj/clothing/suits/armor.dmi b/icons/obj/clothing/suits/armor.dmi
index 279dc33bba026..55aef8f4624d4 100644
Binary files a/icons/obj/clothing/suits/armor.dmi and b/icons/obj/clothing/suits/armor.dmi differ
diff --git a/icons/obj/clothing/suits/ctf.dmi b/icons/obj/clothing/suits/ctf.dmi
new file mode 100644
index 0000000000000..d254504d945ce
Binary files /dev/null and b/icons/obj/clothing/suits/ctf.dmi differ
diff --git a/icons/obj/clothing/suits/jacket.dmi b/icons/obj/clothing/suits/jacket.dmi
index 6251dbed278d3..5c29196f54839 100644
Binary files a/icons/obj/clothing/suits/jacket.dmi and b/icons/obj/clothing/suits/jacket.dmi differ
diff --git a/icons/obj/clothing/suits/wintercoat.dmi b/icons/obj/clothing/suits/wintercoat.dmi
index 2cc456a528807..69a0670a7adb6 100644
Binary files a/icons/obj/clothing/suits/wintercoat.dmi and b/icons/obj/clothing/suits/wintercoat.dmi differ
diff --git a/icons/obj/clothing/under/centcom.dmi b/icons/obj/clothing/under/centcom.dmi
index a9d8c29720bff..3fd5a370973ed 100644
Binary files a/icons/obj/clothing/under/centcom.dmi and b/icons/obj/clothing/under/centcom.dmi differ
diff --git a/icons/obj/decals.dmi b/icons/obj/decals.dmi
index 98cfd251c76ff..c53226d8fdaf4 100644
Binary files a/icons/obj/decals.dmi and b/icons/obj/decals.dmi differ
diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi
index 3d3a7520e3428..0adb326799e2a 100644
Binary files a/icons/obj/guns/energy.dmi and b/icons/obj/guns/energy.dmi differ
diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi
index 8610b3cf001c4..eb591381cd35a 100644
Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ
diff --git a/icons/obj/janitor.dmi b/icons/obj/janitor.dmi
index ef41ac5b484ff..401b26af227f9 100644
Binary files a/icons/obj/janitor.dmi and b/icons/obj/janitor.dmi differ
diff --git a/icons/obj/machines/camera.dmi b/icons/obj/machines/camera.dmi
index 105cb33c84012..0b0ba30483ca1 100644
Binary files a/icons/obj/machines/camera.dmi and b/icons/obj/machines/camera.dmi differ
diff --git a/icons/obj/monitors.dmi b/icons/obj/monitors.dmi
index 06e2f8782ab04..ca919d0b9672c 100644
Binary files a/icons/obj/monitors.dmi and b/icons/obj/monitors.dmi differ
diff --git a/icons/obj/plushes.dmi b/icons/obj/plushes.dmi
index 8195aa5e0d4d2..2362941d592a1 100644
Binary files a/icons/obj/plushes.dmi and b/icons/obj/plushes.dmi differ
diff --git a/icons/obj/vending.dmi b/icons/obj/vending.dmi
index 923b8f730d898..565c8d5ef24b0 100644
Binary files a/icons/obj/vending.dmi and b/icons/obj/vending.dmi differ
diff --git a/icons/turf/decals.dmi b/icons/turf/decals.dmi
index eab84f230694b..cad83e5c4dc2d 100644
Binary files a/icons/turf/decals.dmi and b/icons/turf/decals.dmi differ
diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi
index 8d491fe2b4a41..63c62a8b1dd2f 100644
Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ
diff --git a/sound/surgery/blood_wound.ogg b/sound/surgery/blood_wound.ogg
new file mode 100644
index 0000000000000..e8f03caf63f8f
Binary files /dev/null and b/sound/surgery/blood_wound.ogg differ
diff --git a/sound/weapons/shrapnel.ogg b/sound/weapons/shrapnel.ogg
new file mode 100644
index 0000000000000..8582538411359
Binary files /dev/null and b/sound/weapons/shrapnel.ogg differ
diff --git a/strings/cas_white.txt b/strings/cas_white.txt
index 47e2f4a7596e6..fffb0344afef5 100644
--- a/strings/cas_white.txt
+++ b/strings/cas_white.txt
@@ -208,7 +208,6 @@ Krokodil addiction.
A H.O.N.K. mech.
A dominatrix HoS.
Sexcurity.
-The Experimentor.
That goddamn fucking mime.
Actually taking a hostage instead of just murdering them.
Spacing the clown at shift start.
diff --git a/strings/sillytips.txt b/strings/sillytips.txt
index d55dab251d4db..193f2b733e341 100644
--- a/strings/sillytips.txt
+++ b/strings/sillytips.txt
@@ -46,3 +46,4 @@ If in doubt, blame the clown.
Always remember that the mentors are there to help you. If you don't understand something, there's no shame in asking for help.
Nobody suspects the mime.
Purple is the sneakiest colour.
+There is no supermatter SILVER. There is only supermatter SLIVER.
diff --git a/tgui/packages/tgui/interfaces/AntagInfoBrainwashed.tsx b/tgui/packages/tgui/interfaces/AntagInfoBrainwashed.tsx
index b8c018dd76933..124d5f8bdb9fe 100644
--- a/tgui/packages/tgui/interfaces/AntagInfoBrainwashed.tsx
+++ b/tgui/packages/tgui/interfaces/AntagInfoBrainwashed.tsx
@@ -62,7 +62,7 @@ const ObjectivePrintout = (_props, context) => {
diff --git a/tgui/packages/tgui/interfaces/AntagInfoHoloparasite.tsx b/tgui/packages/tgui/interfaces/AntagInfoHoloparasite.tsx
index 8c8ef88c8850a..640a71d0ebff7 100644
--- a/tgui/packages/tgui/interfaces/AntagInfoHoloparasite.tsx
+++ b/tgui/packages/tgui/interfaces/AntagInfoHoloparasite.tsx
@@ -184,7 +184,7 @@ const ObjectiveInfo = (_props, context) => {
diff --git a/tgui/packages/tgui/interfaces/BottleDispenser.js b/tgui/packages/tgui/interfaces/BottleDispenser.js
deleted file mode 100644
index a41fc80fa0491..0000000000000
--- a/tgui/packages/tgui/interfaces/BottleDispenser.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { useBackend } from '../backend';
-import { Button, LabeledList, NumberInput, Section } from '../components';
-import { Window } from '../layouts';
-
-export const BottleDispenser = (props, context) => {
- const { act, data } = useBackend(context);
- const { bottle_size, bottle_name } = data;
- return (
-
-
-
-
-
-
- act('change_bottle_size', {
- volume: value,
- })
- }
- />
-
-
- act('change_bottle_name')} />
-
-
-
-
-
- );
-};
diff --git a/tgui/packages/tgui/interfaces/ChemPress.js b/tgui/packages/tgui/interfaces/ChemPress.js
deleted file mode 100644
index 919af860664c9..0000000000000
--- a/tgui/packages/tgui/interfaces/ChemPress.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import { classes } from 'common/react';
-import { useBackend } from '../backend';
-import { Box, Button, Input, LabeledList, NumberInput, Section } from '../components';
-import { Window } from '../layouts';
-
-export const ChemPress = (props, context) => {
- const { act, data } = useBackend(context);
- const { pill_size, pill_name, chosen_pill_style, pill_styles = [] } = data;
- return (
-
-
-
-
-
-
- act('change_pill_size', {
- volume: value,
- })
- }
- />
-
-
- act('change_pill_name')} />
-
-
- {pill_styles.map((each_style) => (
- act('change_pill_style', { id: each_style.id })}>
-
-
- ))}
-
-
-
-
-
- );
-};
diff --git a/tgui/packages/tgui/interfaces/NtosCyborgSelfMonitor.js b/tgui/packages/tgui/interfaces/NtosCyborgSelfMonitor.js
index f0325524aaf59..1d1d9f5833d6a 100644
--- a/tgui/packages/tgui/interfaces/NtosCyborgSelfMonitor.js
+++ b/tgui/packages/tgui/interfaces/NtosCyborgSelfMonitor.js
@@ -34,6 +34,7 @@ export const NtosCyborgSelfMonitorContent = (_, context) => {
printerPictures,
printerToner,
printerTonerMax,
+ cameraRadius,
thrustersInstalled,
thrustersStatus,
selfDestructAble,
@@ -139,6 +140,20 @@ export const NtosCyborgSelfMonitorContent = (_, context) => {
+
+
+ act('cameraRadius', {
+ ref: value,
+ })
+ }
+ />
+
{!!thrustersInstalled && (
act('toggleThrusters')} />
diff --git a/tgui/packages/tgui/interfaces/NtosMessenger.js b/tgui/packages/tgui/interfaces/NtosMessenger.js
index 057b48524d0d1..3817c242d679d 100644
--- a/tgui/packages/tgui/interfaces/NtosMessenger.js
+++ b/tgui/packages/tgui/interfaces/NtosMessenger.js
@@ -128,7 +128,6 @@ const ContactsScreen = (props, context) => {
act('PDA_ringSet')} />
act('PDA_viewMessages')} />
act('PDA_changeSortStyle')} />
- {!!isSilicon && act('PDA_selectPhoto')} />}
{!!virus_attach && (
{
/>
)}
+ {!!isSilicon && (
+
+ act('PDA_viewPhotos')} />
+ act('PDA_selectPhoto')} />
+
+ )}
{!!photo && (
diff --git a/tgui/packages/tgui/interfaces/PaperSheet.tsx b/tgui/packages/tgui/interfaces/PaperSheet.tsx
index 40078d71fc24e..6c7c3e085cb7b 100644
--- a/tgui/packages/tgui/interfaces/PaperSheet.tsx
+++ b/tgui/packages/tgui/interfaces/PaperSheet.tsx
@@ -29,6 +29,7 @@ type PaperContext = {
default_pen_font: string;
default_pen_color: string;
signature_font: string;
+ sanitize_test: boolean;
// ui_data
held_item_details?: WritingImplement;
@@ -39,6 +40,7 @@ type PaperInput = {
font?: string;
color?: string;
bold?: boolean;
+ advanced_html?: boolean;
};
type StampInput = {
@@ -554,6 +556,7 @@ export class PreviewView extends Component {
const fontColor = value.color || default_pen_color;
const fontFace = value.font || default_pen_font;
const fontBold = value.bold || false;
+ const advancedHtml = value.advanced_html || false;
let processingOutput = this.formatAndProcessRawText(
rawText,
@@ -562,7 +565,8 @@ export class PreviewView extends Component {
paper_color,
fontBold,
fieldCount,
- readOnly
+ readOnly,
+ advancedHtml
);
output += processingOutput.text;
@@ -679,16 +683,18 @@ export class PreviewView extends Component {
paperColor: string,
bold: boolean,
fieldCounter: number = 0,
- forceReadonlyFields: boolean = false
+ forceReadonlyFields: boolean = false,
+ advanced_html: boolean = false
): FieldCreationReturn => {
// First lets make sure it ends in a new line
+ const { data } = useBackend(this.context);
rawText += rawText[rawText.length] === '\n' ? '\n' : '\n\n';
// Second, parse the text using markup
const parsedText = this.runMarkedDefault(rawText);
// Third, we sanitize the text of html
- const sanitizedText = sanitizeText(parsedText);
+ const sanitizedText = sanitizeText(parsedText, advanced_html);
// Fourth we replace the [__] with fields
const fieldedText = this.createFields(sanitizedText, font, 12, color, paperColor, forceReadonlyFields, fieldCounter);
diff --git a/tgui/packages/tgui/interfaces/PatchDispenser.js b/tgui/packages/tgui/interfaces/PatchDispenser.js
deleted file mode 100644
index 56e8dbfdc5110..0000000000000
--- a/tgui/packages/tgui/interfaces/PatchDispenser.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { useBackend } from '../backend';
-import { Button, LabeledList, NumberInput, Section } from '../components';
-import { Window } from '../layouts';
-
-export const PatchDispenser = (props, context) => {
- const { act, data } = useBackend(context);
- const { patch_size, patch_name } = data;
- return (
-
-
-
-
-
-
- act('change_patch_size', {
- volume: value,
- })
- }
- />
-
-
- act('change_patch_name')} />
-
-
-
-
-
- );
-};
diff --git a/tgui/packages/tgui/interfaces/common/ObjectiveSection.tsx b/tgui/packages/tgui/interfaces/common/ObjectiveSection.tsx
index 36c40ccc5d0a8..27593d1b078c4 100644
--- a/tgui/packages/tgui/interfaces/common/ObjectiveSection.tsx
+++ b/tgui/packages/tgui/interfaces/common/ObjectiveSection.tsx
@@ -27,7 +27,7 @@ export const ObjectivesSection = (props: Props, _context) => {
diff --git a/tgui/packages/tgui/sanitize.js b/tgui/packages/tgui/sanitize.js
index 7ad47d731d26f..8077efa9b5037 100644
--- a/tgui/packages/tgui/sanitize.js
+++ b/tgui/packages/tgui/sanitize.js
@@ -45,21 +45,30 @@ const defTag = [
'ul',
];
+// Advanced HTML tags we can trust admins (but no players) with
+
+const advTag = ['img'];
+
let defAttr = ['class', 'style'];
/**
* Feed it a string and it should spit out a sanitized version.
*
* @param {string} input
+ * @param {boolean} advHtml
* @param {array} tags
* @param {array} forbidAttr
+ * @param {array} advTags
*/
-export const sanitizeText = (input, tags = defTag, forbidAttr = defAttr) => {
+export const sanitizeText = (input, advHtml, tags = defTag, forbidAttr = defAttr, advTags = advTag) => {
// This is VERY important to think first if you NEED
// the tag you put in here. We are pushing all this
// though dangerouslySetInnerHTML and even though
// the default DOMPurify kills javascript, it dosn't
// kill href links or such
+ if (advHtml) {
+ tags = tags.concat(advTags);
+ }
return DOMPurify.sanitize(input, {
ALLOWED_TAGS: tags,
FORBID_ATTR: forbidAttr,
diff --git a/tools/UpdatePaths/Scripts/1707_clothingunderrepath.txt b/tools/UpdatePaths/Scripts/1707_clothingunderrepath.txt
index fe0f19e454e25..dab21a7a9ce83 100644
--- a/tools/UpdatePaths/Scripts/1707_clothingunderrepath.txt
+++ b/tools/UpdatePaths/Scripts/1707_clothingunderrepath.txt
@@ -166,7 +166,7 @@
/obj/item/clothing/under/rank/engineer/hazard : /obj/item/clothing/under/rank/engineering/engineer/hazard
/obj/item/clothing/under/rank/engineer/skirt : /obj/item/clothing/under/rank/engineering/engineer/skirt
-/obj/item/clothing/under/rank/centcom_officer : /obj/item/clothing/under/rank/centcom/officer
+/obj/item/clothing/under/rank/centcom_officer : /obj/item/clothing/under/rank/centcom/official
/obj/item/clothing/under/rank/centcom_commander : /obj/item/clothing/under/rank/centcom/commander
/obj/item/clothing/under/gimmick/rank/captain/suit : /obj/item/clothing/under/rank/captain/suit
diff --git a/tools/UpdatePaths/Scripts/8748_NEWFOOD_cakebreadnoodle.txt b/tools/UpdatePaths/Scripts/8748_NEWFOOD_cakebreadnoodle.txt
index 14b038229770f..68cf1cf8e6d2d 100644
--- a/tools/UpdatePaths/Scripts/8748_NEWFOOD_cakebreadnoodle.txt
+++ b/tools/UpdatePaths/Scripts/8748_NEWFOOD_cakebreadnoodle.txt
@@ -4,7 +4,7 @@
/obj/item/reagent_containers/food/snacks/breadslice/@SUBTYPES : /obj/item/food/breadslice/@SUBTYPES{@OLD}
/obj/item/reagent_containers/food/snacks/store/cake : /obj/item/food/cake/plain{@OLD}
/obj/item/reagent_containers/food/snacks/store/cake/@SUBTYPES : /obj/item/food/cake/@SUBTYPES{@OLD}
-/obj/item/reagent_containers/food/snacks/cakeslice : /obj/item/reagent_containers/food/snacks/cakeslice/plain{@OLD
+/obj/item/reagent_containers/food/snacks/cakeslice : /obj/item/reagent_containers/food/snacks/cakeslice/plain{@OLD}
/obj/item/reagent_containers/food/snacks/cakeslice/@SUBTYPES : /obj/item/reagent_containers/food/snacks/cakeslice/@SUBTYPES{@OLD}
/obj/item/reagent_containers/food/snacks/bluecherrycupcake : /obj/item/reagent_containers/food/snacks/cherrycupcake/blue{@OLD}
diff --git a/tools/UpdatePaths/Scripts/camera_diag_f2w.txt b/tools/UpdatePaths/Scripts/camera_diag_f2w.txt
new file mode 100644
index 0000000000000..f8a9a51e92b76
--- /dev/null
+++ b/tools/UpdatePaths/Scripts/camera_diag_f2w.txt
@@ -0,0 +1,5 @@
+/obj/machinery/camera/@SUBTYPES {dir=5;conversion_done=@UNSET} : @OLD {@OLD;dir=10;conversion_done=1}
+/obj/machinery/camera/@SUBTYPES {dir=10;conversion_done=@UNSET} : @OLD {@OLD;dir=5;conversion_done=1}
+/obj/machinery/camera/@SUBTYPES {dir=6;conversion_done=@UNSET} : @OLD {@OLD;dir=9;conversion_done=1}
+/obj/machinery/camera/@SUBTYPES {dir=9;conversion_done=@UNSET} : @OLD {@OLD;dir=6;conversion_done=1}
+/obj/machinery/camera/@SUBTYPES {conversion_done=1} : @OLD {@OLD;conversion_done=@SKIP}
diff --git a/tools/UpdatePaths/Scripts/wallitems_f2w.txt b/tools/UpdatePaths/Scripts/wallitems_f2w.txt
new file mode 100644
index 0000000000000..4caa3432dc8b1
--- /dev/null
+++ b/tools/UpdatePaths/Scripts/wallitems_f2w.txt
@@ -0,0 +1,94 @@
+/obj/machinery/camera {dir=@UNSET} : /obj/machinery/camera/directional/north {@OLD}
+/obj/machinery/camera {dir=1} : /obj/machinery/camera/directional/south {@OLD;dir=@SKIP}
+/obj/machinery/camera {dir=2} : /obj/machinery/camera/directional/north {@OLD;dir=@SKIP}
+/obj/machinery/camera {dir=4} : /obj/machinery/camera/directional/west {@OLD;dir=@SKIP}
+/obj/machinery/camera {dir=8} : /obj/machinery/camera/directional/east {@OLD;dir=@SKIP}
+/obj/machinery/camera/autoname {dir=@UNSET} : /obj/machinery/camera/directional/north {@OLD}
+/obj/machinery/camera/autoname {dir=1} : /obj/machinery/camera/autoname/directional/south {@OLD;dir=@SKIP}
+/obj/machinery/camera/autoname {dir=2} : /obj/machinery/camera/autoname/directional/north {@OLD;dir=@SKIP}
+/obj/machinery/camera/autoname {dir=4} : /obj/machinery/camera/autoname/directional/west {@OLD;dir=@SKIP}
+/obj/machinery/camera/autoname {dir=8} : /obj/machinery/camera/autoname/directional/east {@OLD;dir=@SKIP}
+/obj/machinery/camera/emp_proof {dir=@UNSET} : /obj/machinery/camera/directional/north {@OLD}
+/obj/machinery/camera/emp_proof {dir=1} : /obj/machinery/camera/emp_proof/directional/south {@OLD;dir=@SKIP}
+/obj/machinery/camera/emp_proof {dir=2} : /obj/machinery/camera/directional/emp_proof/north {@OLD;dir=@SKIP}
+/obj/machinery/camera/emp_proof {dir=4} : /obj/machinery/camera/directional/emp_proof/west {@OLD;dir=@SKIP}
+/obj/machinery/camera/emp_proof {dir=8} : /obj/machinery/camera/directional/emp_proof/east {@OLD;dir=@SKIP}
+/obj/machinery/camera/motion {dir=@UNSET} : /obj/machinery/camera/directional/north {@OLD}
+/obj/machinery/camera/motion {dir=1} : /obj/machinery/camera/motion/directional/south {@OLD;dir=@SKIP}
+/obj/machinery/camera/motion {dir=2} : /obj/machinery/camera/motion/directional/north {@OLD;dir=@SKIP}
+/obj/machinery/camera/motion {dir=4} : /obj/machinery/camera/motion/directional/west {@OLD;dir=@SKIP}
+/obj/machinery/camera/motion {dir=8} : /obj/machinery/camera/motion/directional/east {@OLD;dir=@SKIP}
+/obj/machinery/camera/xray {dir=@UNSET} : /obj/machinery/camera/directional/north {@OLD}
+/obj/machinery/camera/xray {dir=1} : /obj/machinery/camera/xray/directional/south {@OLD;dir=@SKIP}
+/obj/machinery/camera/xray {dir=2} : /obj/machinery/camera/xray/directional/north {@OLD;dir=@SKIP}
+/obj/machinery/camera/xray {dir=4} : /obj/machinery/camera/xray/directional/west {@OLD;dir=@SKIP}
+/obj/machinery/camera/xray {dir=8} : /obj/machinery/camera/xray/directional/east {@OLD;dir=@SKIP}
+/obj/machinery/airalarm {dir=@UNSET} : /obj/machinery/airalarm/directional/north {@OLD;dir=@SKIP}
+/obj/machinery/airalarm {dir=1} : /obj/machinery/airalarm/directional/south {@OLD;dir=@SKIP}
+/obj/machinery/airalarm {dir=2} : /obj/machinery/airalarm/directional/north {@OLD;dir=@SKIP}
+/obj/machinery/airalarm {dir=4} : /obj/machinery/airalarm/directional/west {@OLD;dir=@SKIP}
+/obj/machinery/airalarm {dir=8} : /obj/machinery/airalarm/directional/east {@OLD;dir=@SKIP}
+/obj/machinery/airalarm/syndicate {dir=@UNSET} : /obj/machinery/airalarm/syndicate {@OLD;dir=1}
+/obj/machinery/airalarm/syndicate {dir=1} : /obj/machinery/airalarm/syndicate {@OLD;dir=2}
+/obj/machinery/airalarm/syndicate {dir=2} : /obj/machinery/airalarm/syndicate {@OLD;dir=1}
+/obj/machinery/airalarm/syndicate {dir=4} : /obj/machinery/airalarm/syndicate {@OLD;dir=8}
+/obj/machinery/airalarm/syndicate {dir=8} : /obj/machinery/airalarm/syndicate {@OLD;dir=4}
+/obj/machinery/airalarm/all_access {dir=@UNSET} : /obj/machinery/airalarm/all_access {@OLD;dir=1}
+/obj/machinery/airalarm/all_access {dir=1} : /obj/machinery/airalarm/all_access {@OLD;dir=2}
+/obj/machinery/airalarm/all_access {dir=2} : /obj/machinery/airalarm/all_access {@OLD;dir=1}
+/obj/machinery/airalarm/all_access {dir=4} : /obj/machinery/airalarm/all_access {@OLD;dir=8}
+/obj/machinery/airalarm/all_access {dir=8} : /obj/machinery/airalarm/all_access {@OLD;dir=4}
+/obj/machinery/airalarm/away {dir=@UNSET} : /obj/machinery/airalarm/away {@OLD;dir=1}
+/obj/machinery/airalarm/away {dir=1} : /obj/machinery/airalarm/away {@OLD;dir=2}
+/obj/machinery/airalarm/away {dir=2} : /obj/machinery/airalarm/away {@OLD;dir=1}
+/obj/machinery/airalarm/away {dir=4} : /obj/machinery/airalarm/away {@OLD;dir=8}
+/obj/machinery/airalarm/away {dir=8} : /obj/machinery/airalarm/away {@OLD;dir=4}
+/obj/machinery/airalarm/engine {dir=@UNSET} : /obj/machinery/airalarm/engine {@OLD;dir=1}
+/obj/machinery/airalarm/engine {dir=1} : /obj/machinery/airalarm/engine {@OLD;dir=2}
+/obj/machinery/airalarm/engine {dir=2} : /obj/machinery/airalarm/engine {@OLD;dir=1}
+/obj/machinery/airalarm/engine {dir=4} : /obj/machinery/airalarm/engine {@OLD;dir=8}
+/obj/machinery/airalarm/engine {dir=8} : /obj/machinery/airalarm/engine {@OLD;dir=4}
+/obj/machinery/airalarm/unlocked {dir=@UNSET} : /obj/machinery/airalarm/unlocked {@OLD;dir=1}
+/obj/machinery/airalarm/unlocked {dir=1} : /obj/machinery/airalarm/unlocked {@OLD;dir=2}
+/obj/machinery/airalarm/unlocked {dir=2} : /obj/machinery/airalarm/unlocked {@OLD;dir=1}
+/obj/machinery/airalarm/unlocked {dir=4} : /obj/machinery/airalarm/unlocked {@OLD;dir=8}
+/obj/machinery/airalarm/unlocked {dir=8} : /obj/machinery/airalarm/unlocked {@OLD;dir=4}
+/obj/machinery/airalarm/server {dir=@UNSET} : /obj/machinery/airalarm/server {@OLD;dir=1}
+/obj/machinery/airalarm/server {dir=1} : /obj/machinery/airalarm/server {@OLD;dir=2}
+/obj/machinery/airalarm/server {dir=2} : /obj/machinery/airalarm/server {@OLD;dir=1}
+/obj/machinery/airalarm/server {dir=4} : /obj/machinery/airalarm/server {@OLD;dir=8}
+/obj/machinery/airalarm/server {dir=8} : /obj/machinery/airalarm/server {@OLD;dir=4}
+/obj/machinery/airalarm/mixingchamber {dir=@UNSET} : /obj/machinery/airalarm/mixingchamber {@OLD;dir=1}
+/obj/machinery/airalarm/mixingchamber {dir=1} : /obj/machinery/airalarm/mixingchamber {@OLD;dir=2}
+/obj/machinery/airalarm/mixingchamber {dir=2} : /obj/machinery/airalarm/mixingchamber {@OLD;dir=1}
+/obj/machinery/airalarm/mixingchamber {dir=4} : /obj/machinery/airalarm/mixingchamber {@OLD;dir=8}
+/obj/machinery/airalarm/mixingchamber {dir=8} : /obj/machinery/airalarm/mixingchamber {@OLD;dir=4}
+/obj/machinery/airalarm/kitchen_cold_room {dir=@UNSET} : /obj/machinery/airalarm/kitchen_cold_room {@OLD;dir=1}
+/obj/machinery/airalarm/kitchen_cold_room {dir=1} : /obj/machinery/airalarm/kitchen_cold_room {@OLD;dir=2}
+/obj/machinery/airalarm/kitchen_cold_room {dir=2} : /obj/machinery/airalarm/kitchen_cold_room {@OLD;dir=1}
+/obj/machinery/airalarm/kitchen_cold_room {dir=4} : /obj/machinery/airalarm/kitchen_cold_room {@OLD;dir=8}
+/obj/machinery/airalarm/kitchen_cold_room {dir=8} : /obj/machinery/airalarm/kitchen_cold_room {@OLD;dir=4}
+/obj/structure/chair/stool {dir=1} : /obj/structure/chair/stool/directional/north {@OLD;dir=@SKIP}
+/obj/structure/chair/stool {dir=2} : /obj/structure/chair/stool/directional/south {@OLD;dir=@SKIP}
+/obj/structure/chair/stool {dir=4} : /obj/structure/chair/stool/directional/east {@OLD;dir=@SKIP}
+/obj/structure/chair/stool {dir=8} : /obj/structure/chair/stool/directional/west {@OLD;dir=@SKIP}
+/obj/structure/chair/stool/directional/south : /obj/structure/chair/stool/directional/north {@OLD;dir=@SKIP}
+/obj/structure/chair/stool/directional/north : /obj/structure/chair/stool/directional/south {@OLD;dir=@SKIP}
+/obj/structure/chair/stool/directional/west : /obj/structure/chair/stool/directional/east {@OLD;dir=@SKIP}
+/obj/structure/chair/stool/directional/east : /obj/structure/chair/stool/directional/west {@OLD;dir=@SKIP}
+/obj/structure/chair/stool/bar {dir=1} : /obj/structure/chair/stool/bar/directional/north {@OLD;dir=@SKIP}
+/obj/structure/chair/stool/bar {dir=2} : /obj/structure/chair/stool/bar/directional/south {@OLD;dir=@SKIP}
+/obj/structure/chair/stool/bar {dir=4} : /obj/structure/chair/stool/bar/directional/east {@OLD;dir=@SKIP}
+/obj/structure/chair/stool/bar {dir=8} : /obj/structure/chair/stool/bar/directional/west {@OLD;dir=@SKIP}
+/obj/structure/chair/stool/bar/directional/south : /obj/structure/chair/stool/bar/directional/north {@OLD;dir=@SKIP}
+/obj/structure/chair/stool/bar/directional/north : /obj/structure/chair/stool/bar/directional/south {@OLD;dir=@SKIP}
+/obj/structure/chair/stool/bar/directional/west : /obj/structure/chair/stool/bar/directional/east {@OLD;dir=@SKIP}
+/obj/structure/chair/stool/bar/directional/east : /obj/structure/chair/stool/bar/directional/west {@OLD;dir=@SKIP}
+/obj/machinery/power/apc/auto_name/north : /obj/machinery/power/apc/auto_name/directional/north {@OLD;dir=@SKIP;pixel_y=@SKIP}
+/obj/machinery/power/apc/auto_name/south : /obj/machinery/power/apc/auto_name/directional/south {@OLD;dir=@SKIP;pixel_y=@SKIP}
+/obj/machinery/power/apc/auto_name/east : /obj/machinery/power/apc/auto_name/directional/east {@OLD;dir=@SKIP;pixel_x=@SKIP}
+/obj/machinery/power/apc/auto_name/west : /obj/machinery/power/apc/auto_name/directional/west {@OLD;dir=@SKIP;pixel_y=@SKIP}
+/obj/machinery/bluespace_vendor/north : /obj/machinery/bluespace_vendor/directional/north {@OLD}
+/obj/machinery/bluespace_vendor/south : /obj/machinery/bluespace_vendor/directional/south {@OLD}
+/obj/machinery/bluespace_vendor/east : /obj/machinery/bluespace_vendor/directional/east {@OLD}
+/obj/machinery/bluespace_vendor/west : /obj/machinery/bluespace_vendor/directional/west {@OLD}
diff --git a/tools/ci/check_grep.sh b/tools/ci/check_grep.sh
index 58e1306a1137d..efc665bfb5f2a 100755
--- a/tools/ci/check_grep.sh
+++ b/tools/ci/check_grep.sh
@@ -10,6 +10,9 @@ GREEN="\033[0;32m"
BLUE="\033[0;34m"
NC="\033[0m" # No Color
+# Copy-pasted text
+HINT_REMOVE="please remove them. (Hint: Find out which area they are in!)${NC}"
+
st=0
echo -e "${BLUE}Checking for map issues...${NC}"
@@ -30,12 +33,12 @@ if grep -P '/obj/merge_conflict_marker' _maps/**/*.dmm; then
fi;
if grep -P '^\ttag = \"icon' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Tag vars from icon state generation detected in maps, please remove them.${NC}"
+ echo -e "${RED}ERROR: Tag vars from icon state generation detected in maps, ${HINT_REMOVE}"
st=1
fi;
if grep -P 'step_[xy]' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: step_x/step_y variables detected in maps, please remove them.${NC}"
+ echo -e "${RED}ERROR: step_x/step_y variables detected in maps, ${HINT_REMOVE}"
st=1
fi;
if grep -m 1 'pixel_[xy] = 0' _maps/**/*.dmm; then
@@ -45,60 +48,71 @@ if grep -m 1 'pixel_[xy] = 0' _maps/**/*.dmm; then
fi;
if grep -P '\td[1-2] =' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: d1/d2 cable variables detected in maps, please remove them.${NC}"
+ echo -e "${RED}ERROR: d1/d2 cable variables detected in maps, ${HINT_REMOVE}"
+ st=1
+fi;
+echo -e "${BLUE}Checking duplicate structures...${NC}"
+if grep -Pzo '"\w+" = \([^)]*?\n/obj/effect/mapping_helpers/simple_pipes(?[/\w]*),[^)]*?\n/obj/effect/mapping_helpers/simple_pipes\g{type},[^)]*?\n/area/.+\)' _maps/**/*.dmm; then
+ echo
+ echo -e "${RED}ERROR: Found multiple idendical simple_pipes mapping helpers on the same tile, ${HINT_REMOVE}"
+ st=1
+fi;
+if grep -Pzo '"\w+" = \([^)]*?\n/obj/machinery/atmospherics(?[/\w]*),[^)]*?\n/obj/machinery/atmospherics\g{type},[^)]*?\n/area/.+\)' _maps/**/*.dmm; then
+ echo
+ echo -e "${RED}ERROR: Found multiple idendical atmospherics machines or pipes on the same tile, ${HINT_REMOVE}"
st=1
fi;
-echo -e "${BLUE}Checking for stacked cables...${NC}"
if grep -Pzo '"\w+" = \([^)]*?\n/obj/structure/lattice[/\w,\n]*?[^)]*?\n/obj/structure/lattice[/\w,\n]*?[^)]*?\n/area/.+?\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found multiple lattices on the same tile, please remove them.${NC}"
+ echo -e "${RED}ERROR: Found multiple lattices on the same tile, ${HINT_REMOVE}"
st=1
fi;
if grep -Pzo '"\w+" = \([^)]*?\n/obj/structure/barricade(?[/\w]*),[^)]*?\n/obj/structure/barricade\g{type},[^)]*?\n/area/.+\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found multiple identical barricades on the same tile, please remove them.${NC}"
+ echo -e "${RED}ERROR: Found multiple identical barricades on the same tile, ${HINT_REMOVE}"
st=1
fi;
if grep -Pzo '"\w+" = \([^)]*?\n/obj/structure/table(?[/\w]*),[^)]*?\n/obj/structure/table\g{type},[^)]*?\n/area/.+\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found multiple identical tables on the same tile, please remove them.${NC}"
+ echo -e "${RED}ERROR: Found multiple identical tables on the same tile, ${HINT_REMOVE}"
st=1
fi;
if grep -Pzo '"\w+" = \([^)]*?\n/obj/structure/chair(?[/\w]*),[^)]*?\n/obj/structure/chair\g{type},[^)]*?\n/area/.+\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found multiple identical chairs on the same tile, please remove them.${NC}"
+ echo -e "${RED}ERROR: Found multiple identical chairs on the same tile, ${HINT_REMOVE}"
st=1
fi;
if grep -Pzo '"\w+" = \([^)]*?\n/obj/machinery/door/airlock[/\w,\n]*?[^)]*?\n/obj/machinery/door/airlock[/\w,\n]*?[^)]*?\n/area/.+\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found multiple airlocks on the same tile, please remove them.${NC}"
+ echo -e "${RED}ERROR: Found multiple airlocks on the same tile, ${HINT_REMOVE}"
st=1
fi;
if grep -Pzo '"\w+" = \([^)]*?\n/obj/machinery/door/firedoor[/\w,\n]*?[^)]*?\n/obj/machinery/door/firedoor[/\w,\n]*?[^)]*?\n/area/.+\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found multiple firelocks on the same tile, please remove them.${NC}"
+ echo -e "${RED}ERROR: Found multiple firelocks on the same tile, ${HINT_REMOVE}"
st=1
fi;
if grep -Pzo '"\w+" = \([^)]*?\n/obj/structure/closet(?[/\w]*),[^)]*?\n/obj/structure/closet\g{type},[^)]*?\n/area/.+\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found multiple identical closets on the same tile, please remove them.${NC}"
+ echo -e "${RED}ERROR: Found multiple identical closets on the same tile, ${HINT_REMOVE}"
st=1
fi;
if grep -Pzo '"\w+" = \([^)]*?\n/obj/structure/grille(?[/\w]*),[^)]*?\n/obj/structure/grille\g{type},[^)]*?\n/area/.+\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found multiple identical grilles on the same tile, please remove them.${NC}"
+ echo -e "${RED}ERROR: Found multiple identical grilles on the same tile, ${HINT_REMOVE}"
st=1
fi;
if grep -Pzo '"\w+" = \([^)]*?\n/obj/structure/girder(?[/\w]*),[^)]*?\n/obj/structure/girder\g{type},[^)]*?\n/area/.+\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found multiple identical girders on the same tile, please remove them.${NC}"
+ echo -e "${RED}ERROR: Found multiple identical girders on the same tile, ${HINT_REMOVE}"
st=1
fi;
if grep -Pzo '"\w+" = \([^)]*?\n/obj/structure/stairs(?[/\w]*),[^)]*?\n/obj/structure/stairs\g{type},[^)]*?\n/area/.+\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found multiple identical stairs on the same tile, please remove them.${NC}"
+ echo -e "${RED}ERROR: Found multiple identical stairs on the same tile, ${HINT_REMOVE}"
st=1
fi;
+echo -e "${BLUE}Checking for malformed files...${NC}"
if grep '^/area/.+[\{]' _maps/**/*.dmm; then
echo
echo -e "${RED}ERROR: Variable editted /area path use detected in a map, please replace with a proper area path.${NC}"
@@ -139,24 +153,25 @@ if grep -Pzo '"\w+" = \([^)]*?\n/area/.+?,[^)]*?\n/area/.+?\)' _maps/**/*.dmm; t
echo -e "${RED}ERROR: Multiple areas detected on the same tile! Please choose only one area!${NC}"
st=1
fi;
+echo -e "${BLUE}Checking for things inside of walls...${NC}"
if grep -Pzo '"\w+" = \([^)]*?\n/obj/structure/lattice[/\w,\n]*?[^)]*?\n/turf/closed/wall[/\w,\n]*?[^)]*?\n/area/.+?\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found a lattice stacked with a wall, please remove them.${NC}"
+ echo -e "${RED}ERROR: Found a lattice stacked with a wall, ${HINT_REMOVE}"
st=1
fi;
if grep -Pzo '"\w+" = \([^)]*?\n/obj/structure/lattice[/\w,\n]*?[^)]*?\n/turf/closed[/\w,\n]*?[^)]*?\n/area/.+?\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found a lattice stacked within a wall, please remove them.${NC}"
+ echo -e "${RED}ERROR: Found a lattice stacked within a wall, ${HINT_REMOVE}"
st=1
fi;
if grep -Pzo '"\w+" = \([^)]*?\n/obj/structure/window[/\w,\n]*?[^)]*?\n/turf/closed[/\w,\n]*?[^)]*?\n/area/.+?\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found a window stacked within a wall, please remove it.${NC}"
+ echo -e "${RED}ERROR: Found a window stacked within a wall, ${HINT_REMOVE}"
st=1
fi;
if grep -Pzo '"\w+" = \([^)]*?\n/obj/machinery/door/airlock[/\w,\n]*?[^)]*?\n/turf/closed[/\w,\n]*?[^)]*?\n/area/.+?\)' _maps/**/*.dmm; then
echo
- echo -e "${RED}ERROR: Found an airlock stacked within a wall, please remove it.${NC}"
+ echo -e "${RED}ERROR: Found an airlock stacked within a wall, ${HINT_REMOVE}"
st=1
fi;
if grep -Pzo '"\w+" = \([^)]*?\n/obj/structure/stairs[/\w,\n]*?[^)]*?\n/turf/open/genturf[/\w,\n]*?[^)]*?\n/area/.+?\)' _maps/**/*.dmm; then
@@ -169,6 +184,7 @@ if grep -Pzo '/obj/machinery/conveyor/inverted[/\w]*?\{\n[^}]*?dir = [1248];[^}]
echo -e "${RED}ERROR: Found an inverted conveyor belt with a cardinal dir. Please replace it with a normal conveyor belt.${NC}"
st=1
fi;
+echo -e "${BLUE}Checking mapping JSON...${NC}"
if ls _maps/*.json | grep -P "[A-Z]"; then
echo
echo -e "${RED}ERROR: Uppercase in a map .JSON file detected, these must be all lowercase.${NC}"