diff --git a/code/__DEFINES/dcs/signals/signals_reagent.dm b/code/__DEFINES/dcs/signals/signals_reagent.dm
index 00fdddc6c9e..a73d59a234c 100644
--- a/code/__DEFINES/dcs/signals/signals_reagent.dm
+++ b/code/__DEFINES/dcs/signals/signals_reagent.dm
@@ -6,6 +6,8 @@
#define COMSIG_ATOM_EXPOSE_REAGENTS "atom_expose_reagents"
/// Prevents the atom from being exposed to reagents if returned on [COMSIG_ATOM_EXPOSE_REAGENTS]
#define COMPONENT_NO_EXPOSE_REAGENTS (1<<0)
+///from base of atom/expose_reagents(): (/list, /datum/reagents, methods, volume_modifier, show_message)
+#define COMSIG_ATOM_AFTER_EXPOSE_REAGENTS "atom_after_expose_reagents"
///from base of [/datum/reagent/proc/expose_atom]: (/datum/reagent, reac_volume)
#define COMSIG_ATOM_EXPOSE_REAGENT "atom_expose_reagent"
///from base of [/datum/reagent/proc/expose_atom]: (/atom, reac_volume)
diff --git a/code/__DEFINES/wounds.dm b/code/__DEFINES/wounds.dm
index 0a020b2b5a8..5529ee1f0c6 100644
--- a/code/__DEFINES/wounds.dm
+++ b/code/__DEFINES/wounds.dm
@@ -32,11 +32,6 @@
#define WOUND_PIERCE 3
/// any concentrated burn attack (lasers really). rolls for burning wounds
#define WOUND_BURN 4
-//SKYRAT EDIT ADDITION BEGIN - MEDICAL
-/// any brute attacks, rolled on a chance
-#define WOUND_MUSCLE 5
-//SKYRAT EDIT ADDITION END
-
// ~determination second wind defines
// How much determination reagent to add each time someone gains a new wound in [/datum/wound/proc/second_wind]
@@ -50,36 +45,57 @@
/// While someone has determination in their system, their bleed rate is slightly reduced
#define WOUND_DETERMINATION_BLEED_MOD 0.85
-// ~wound global lists
-// list in order of highest severity to lowest
-GLOBAL_LIST_INIT(global_wound_types, list(
- WOUND_BLUNT = list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate),
- WOUND_SLASH = list(/datum/wound/slash/critical, /datum/wound/slash/severe, /datum/wound/slash/moderate),
- WOUND_PIERCE = list(/datum/wound/pierce/critical, /datum/wound/pierce/severe, /datum/wound/pierce/moderate),
- WOUND_BURN = list(/datum/wound/burn/critical, /datum/wound/burn/severe, /datum/wound/burn/moderate),
- WOUND_MUSCLE = list(/datum/wound/muscle/severe, /datum/wound/muscle/moderate), /* SKYRAT EDIT ADD */
-))
-
-// every single type of wound that can be rolled naturally, in case you need to pull a random one
-GLOBAL_LIST_INIT(global_all_wound_types, list(
- /datum/wound/blunt/critical,
- /datum/wound/blunt/severe,
- /datum/wound/blunt/moderate,
- /datum/wound/slash/critical,
- /datum/wound/slash/severe,
- /datum/wound/slash/moderate,
- /datum/wound/pierce/critical,
- /datum/wound/pierce/severe,
- /datum/wound/pierce/moderate,
- /datum/wound/burn/critical,
- /datum/wound/burn/severe,
- /datum/wound/burn/moderate,
- /* SKYRAT EDIT ADD START */
- /datum/wound/muscle/severe,
- /datum/wound/muscle/moderate,
- /* SKYRAT EDIT ADD END */
+// ~biology defines
+// What kind of biology a limb has, and what wounds it can suffer
+/// Has absolutely fucking nothing, no wounds
+#define BIO_INORGANIC NONE
+/// Has bone - allows the victim to suffer T2-T3 bone blunt wounds
+#define BIO_BONE (1<<0)
+/// Has flesh - allows the victim to suffer fleshy slash pierce and burn wounds
+#define BIO_FLESH (1<<1)
+/// Self explanatory
+#define BIO_FLESH_BONE (BIO_BONE | BIO_FLESH)
+/// Has metal - allows the victim to suffer robotic blunt and burn wounds
+#define BIO_METAL (1<<2)
+/// Is wired internally - allows the victim to suffer electrical wounds (robotic T1-T3 slash/pierce)
+#define BIO_WIRED (1<<3)
+/// Robotic: shit like cyborg limbs, mostly
+#define BIO_ROBOTIC (BIO_METAL|BIO_WIRED)
+/// Has bloodflow - can suffer bleeding wounds and can bleed
+#define BIO_BLOODED (1<<4)
+/// Is connected by a joint - can suffer T1 bone blunt wounds (dislocation)
+#define BIO_JOINTED (1<<5)
+/// Standard humanoid - can suffer all flesh wounds, such as: T1-3 slash/pierce/burn/blunt. Can also bleed
+#define BIO_STANDARD (BIO_FLESH_BONE|BIO_BLOODED)
+
+// "Where" a specific "bio" feature is within a given limb
+// Exterior is hard shit, the last line, shit lines bones
+// Interior is soft shit, targetted by slashes and pierces (usually), protects exterior
+// Yes, it makes no sense
+/// The given biostate is on the "exterior" of the limb - hard shit, protected by interior
+#define BIO_EXTERIOR (1<<0)
+/// The given biostate is on the "exterior" of the limb - soft shit, protects exterior
+#define BIO_INTERIOR (1<<1)
+#define BIO_EXTERIOR_AND_INTERIOR (BIO_EXTERIOR|BIO_INTERIOR)
+
+GLOBAL_LIST_INIT(bio_state_states, list(
+ "[BIO_WIRED]" = BIO_INTERIOR,
+ "[BIO_METAL]" = BIO_EXTERIOR,
+ "[BIO_FLESH]" = BIO_INTERIOR,
+ "[BIO_BONE]" = BIO_EXTERIOR,
))
+// Wound series
+// A "wound series" is just a family of wounds that logically follow eachother
+// Multiple wounds in a single series cannot be on a limb - the highest severity will always be prioritized, and lower ones will be skipped
+/// T1-T3 Bleeding slash wounds. Requires flesh. Can cause bleeding, but doesn't require it. From: slash.dm
+#define WOUND_SERIES_FLESH_SLASH_BLEED 1
+/// T1-T3 Basic blunt wounds. T1 requires jointed, but 2-3 require bone. From: bone.dm
+#define WOUND_SERIES_BONE_BLUNT_BASIC 2
+/// T1-T3 Basic burn wounds. Requires flesh. From: burns.dm
+#define WOUND_SERIES_FLESH_BURN_BASIC 3
+/// T1-3 Bleeding puncture wounds. Requires flesh. Can cause bleeding, but doesn't require it. From: pierce.dm
+#define WOUND_SERIES_FLESH_PUNCTURE_BLEED 4
// ~burn wound infection defines
// Thresholds for infection for burn wounds, once infestation hits each threshold, things get steadily worse
@@ -116,34 +132,13 @@ GLOBAL_LIST_INIT(global_all_wound_types, list(
#define BODYPART_MANGLED_FLESH (1<<1)
#define BODYPART_MANGLED_BOTH (BODYPART_MANGLED_BONE | BODYPART_MANGLED_FLESH)
-
-// ~biology defines
-// What kind of biology a limb has, and what wounds it can suffer
-/// golems and androids, cannot suffer any wounds
-#define BIO_INORGANIC NONE
-/// skeletons and plasmemes, can only suffer bone wounds, only needs mangled bone to be able to dismember
-#define BIO_BONE (1<<0)
-/// nothing right now, maybe slimepeople in the future, can only suffer slashing, piercing, and burn wounds
-#define BIO_FLESH (1<<1)
-/// standard humanoids, can suffer all wounds, needs mangled bone and flesh to dismember. conveniently, what you get when you combine BIO_BONE and BIO_FLESH
-#define BIO_FLESH_BONE (BIO_BONE | BIO_FLESH)
-
-
// ~wound flag defines
-/// If this wound requires having the BIO_FLESH biological_state on the limb
-#define FLESH_WOUND (1<<0)
-/// If this wound requires having the BIO_BONE biological_state on the limb
-#define BONE_WOUND (1<<1)
/// If having this wound counts as mangled flesh for dismemberment
-#define MANGLES_FLESH (1<<2)
+#define MANGLES_FLESH (1<<0)
/// If having this wound counts as mangled bone for dismemberment
-#define MANGLES_BONE (1<<3)
+#define MANGLES_BONE (1<<1)
/// If this wound marks the limb as being allowed to have gauze applied
-#define ACCEPTS_GAUZE (1<<4)
-//SKYRAT EDIT ADDITION BEGIN - MEDICAL
-/// If this wound marks the limb as being allowed to have gauze applied as a splint
-#define ACCEPTS_SPLINT (1<<5)
-//SKYRAT EDIT ADDITION END
+#define ACCEPTS_GAUZE (1<<2)
// ~scar persistence defines
// The following are the order placements for persistent scar save formats
@@ -161,11 +156,13 @@ GLOBAL_LIST_INIT(global_all_wound_types, list(
#define SCAR_SAVE_BIOLOGY 6
/// Which character slot this was saved to
#define SCAR_SAVE_CHAR_SLOT 7
+/// if the scar will check for any or all biostates on the limb (defaults to FALSE, so all)
+#define SCAR_SAVE_CHECK_ANY_BIO 8
///how many fields we save for each scar (so the number of above fields)
-#define SCAR_SAVE_LENGTH 7
+#define SCAR_SAVE_LENGTH 8
/// saved scars with a version lower than this will be discarded, increment when you update the persistent scarring format in a way that invalidates previous saved scars (new fields, reordering, etc)
-#define SCAR_CURRENT_VERSION 3
+#define SCAR_CURRENT_VERSION 4
/// how many scar slots, per character slot, we have to cycle through for persistent scarring, if enabled in character prefs
#define PERSISTENT_SCAR_SLOTS 3
diff --git a/code/__DEFINES/~skyrat_defines/combat.dm b/code/__DEFINES/~skyrat_defines/combat.dm
index 6ce9519992c..54659715cc3 100644
--- a/code/__DEFINES/~skyrat_defines/combat.dm
+++ b/code/__DEFINES/~skyrat_defines/combat.dm
@@ -173,6 +173,16 @@
/// Attempts to perform a limb dislocation, with the user violently twisting one of target's limbs (as passed in). Only useful for extremities, because only extremities can eat dislocations.
/datum/species/proc/try_dislocate(mob/living/carbon/human/user, mob/living/carbon/human/target, obj/item/bodypart/affecting)
+ var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[/datum/wound/blunt/bone/moderate]
+ if (!pregen_data)
+ stack_trace("/datum/wound/blunt/bone/moderate has no pregen data!")
+ return FALSE // shouldnt happen but sanity
+
+ if (!pregen_data.can_be_applied_to(affecting, random_roll = FALSE))
+ if (!(affecting.biological_state & BIO_JOINTED))
+ to_chat(user, span_warning("[target]'s [affecting.plaintext_zone] has no joint to dislocate!"))
+ return FALSE
+
user.changeNext_move(4 SECONDS)
target.visible_message(span_danger("[user.name] twists [target.name]'s [affecting.name] violently!"), \
span_userdanger("[user.name] twists your [affecting.name] violently!"), ignored_mobs=user)
@@ -182,7 +192,7 @@
target.visible_message(span_danger("[user.name] dislocates [target.name]'s [affecting.name]!"), \
span_userdanger("[user.name] dislocates your [affecting.name]!"), ignored_mobs=user)
to_chat(user, span_danger("You dislocate [target.name]'s [affecting.name]!"))
- affecting.force_wound_upwards(/datum/wound/blunt/moderate)
+ affecting.force_wound_upwards(/datum/wound/blunt/bone/moderate)
log_combat(user, target, "dislocates", "the [affecting.name]")
return TRUE
diff --git a/code/__DEFINES/~skyrat_defines/wounds.dm b/code/__DEFINES/~skyrat_defines/wounds.dm
new file mode 100644
index 00000000000..4c29cd6a642
--- /dev/null
+++ b/code/__DEFINES/~skyrat_defines/wounds.dm
@@ -0,0 +1,5 @@
+/// See muscle.dm
+#define WOUND_SERIES_MUSCLE_DAMAGE 10000 // We use a super high number as realistically speaking TG will never increment to this amount of wound series
+
+/// If this wound, when bandaged, will cause a splint overlay to generate rather than a bandage overlay.
+#define SPLINT_OVERLAY (1<<200) // we use a big number since tg realistically wouldnt go to it
diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm
index 6aa4555f3aa..3a360c012f6 100644
--- a/code/datums/components/butchering.dm
+++ b/code/datums/components/butchering.dm
@@ -92,8 +92,9 @@
H.apply_damage(source.force, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND) // easy tiger, we'll get to that in a sec
var/obj/item/bodypart/slit_throat = H.get_bodypart(BODY_ZONE_HEAD)
if(slit_throat)
- var/datum/wound/slash/critical/screaming_through_a_slit_throat = new
- screaming_through_a_slit_throat.apply_wound(slit_throat, wound_source = "throat slit")
+ var/datum/wound/slash/flesh/critical/screaming_through_a_slit_throat = new
+ if (!screaming_through_a_slit_throat.apply_wound(slit_throat, wound_source = "throat slit"))
+ qdel(screaming_through_a_slit_throat)
H.apply_status_effect(/datum/status_effect/neck_slice)
/**
diff --git a/code/datums/components/embedded.dm b/code/datums/components/embedded.dm
index 8abb32e0e53..433784e845e 100644
--- a/code/datums/components/embedded.dm
+++ b/code/datums/components/embedded.dm
@@ -303,7 +303,7 @@
return
var/damage = weapon.w_class * remove_pain_mult
limb.receive_damage(brute=(1-pain_stam_pct) * damage * 1.5, sharpness=SHARP_EDGED) // Performs exit wounds and flings the user to the caster if nearby
- limb.force_wound_upwards(/datum/wound/pierce/moderate)
+ limb.force_wound_upwards(/datum/wound/pierce/bleed/moderate)
victim.adjustStaminaLoss(pain_stam_pct * damage)
playsound(get_turf(victim), 'sound/effects/wounds/blood2.ogg', 50, TRUE)
diff --git a/code/datums/elements/kneecapping.dm b/code/datums/elements/kneecapping.dm
index f652a196323..217c11d4361 100644
--- a/code/datums/elements/kneecapping.dm
+++ b/code/datums/elements/kneecapping.dm
@@ -80,8 +80,8 @@
if(do_after(attacker, 3 SECONDS, target, interaction_key = weapon))
attacker.visible_message(span_warning("[attacker] swings [attacker.p_their()] [weapon] at [target]'s kneecaps!"), span_danger("You swing \the [weapon] at [target]'s kneecaps!"))
- var/datum/wound/blunt/severe/severe_wound_type = /datum/wound/blunt/severe
- var/datum/wound/blunt/critical/critical_wound_type = /datum/wound/blunt/critical
+ var/datum/wound/blunt/bone/severe/severe_wound_type = /datum/wound/blunt/bone/severe
+ var/datum/wound/blunt/bone/critical/critical_wound_type = /datum/wound/blunt/bone/critical
leg.receive_damage(brute = weapon.force, wound_bonus = rand(initial(severe_wound_type.threshold_minimum), initial(critical_wound_type.threshold_minimum) + 10), damage_source = "kneecapping")
target.emote("scream")
log_combat(attacker, target, "broke the kneecaps of", weapon)
diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm
index 0de7daa6589..28b88c246e3 100644
--- a/code/datums/mutations/hulk.dm
+++ b/code/datums/mutations/hulk.dm
@@ -65,11 +65,11 @@
/datum/mutation/human/hulk/proc/break_an_arm(obj/item/bodypart/arm)
switch(arm.brute_dam)
if(45 to 50)
- arm.force_wound_upwards(/datum/wound/blunt/critical, wound_source = "hulk smashing")
+ arm.force_wound_upwards(/datum/wound/blunt/bone/critical, wound_source = "hulk smashing")
if(41 to 45)
- arm.force_wound_upwards(/datum/wound/blunt/severe, wound_source = "hulk smashing")
+ arm.force_wound_upwards(/datum/wound/blunt/bone/severe, wound_source = "hulk smashing")
if(35 to 41)
- arm.force_wound_upwards(/datum/wound/blunt/moderate, wound_source = "hulk smashing")
+ arm.force_wound_upwards(/datum/wound/blunt/bone/moderate, wound_source = "hulk smashing")
/datum/mutation/human/hulk/on_life(seconds_per_tick, times_fired)
if(owner.health < owner.crit_threshold)
diff --git a/code/datums/status_effects/debuffs/choke.dm b/code/datums/status_effects/debuffs/choke.dm
index 4fb668b5fe0..f626cb52be5 100644
--- a/code/datums/status_effects/debuffs/choke.dm
+++ b/code/datums/status_effects/debuffs/choke.dm
@@ -216,7 +216,7 @@
var/mob/living/carbon/carbon_victim = victim
var/obj/item/bodypart/chest = carbon_victim.get_bodypart(BODY_ZONE_CHEST)
if(chest)
- chest.force_wound_upwards(/datum/wound/blunt/severe, wound_source = "human force to the chest")
+ chest.force_wound_upwards(/datum/wound/blunt/bone/severe, wound_source = "human force to the chest")
playsound(owner, 'sound/creatures/crack_vomit.ogg', 120, extrarange = 5, falloff_exponent = 4)
vomit_up()
diff --git a/code/datums/status_effects/debuffs/cursed.dm b/code/datums/status_effects/debuffs/cursed.dm
index 20afa8a7ea6..285fb86348e 100644
--- a/code/datums/status_effects/debuffs/cursed.dm
+++ b/code/datums/status_effects/debuffs/cursed.dm
@@ -66,7 +66,7 @@
playsound(human_owner, SFX_SEAR, 50, TRUE)
var/obj/item/bodypart/affecting = human_owner.get_active_hand()
branded_hand = affecting
- affecting.force_wound_upwards(/datum/wound/burn/severe/cursed_brand, wound_source = "curse of the slot machine")
+ affecting.force_wound_upwards(/datum/wound/burn/flesh/severe/cursed_brand, wound_source = "curse of the slot machine")
messages += span_boldwarning("Your hand burns, and you quickly let go of the lever! You feel a little sick as the nerves deaden in your hand...")
messages += span_boldwarning("Some smoke appears to be coming out of your hand now, but it's not too bad...")
@@ -116,7 +116,7 @@
SIGNAL_HANDLER
if(!isnull(branded_hand))
- var/datum/wound/brand = branded_hand.get_wound_type(/datum/wound/burn/severe/cursed_brand)
+ var/datum/wound/brand = branded_hand.get_wound_type(/datum/wound/burn/flesh/severe/cursed_brand)
brand?.remove_wound()
owner.visible_message(
diff --git a/code/datums/status_effects/wound_effects.dm b/code/datums/status_effects/wound_effects.dm
index dfee1c2ee2c..5da74ef7722 100644
--- a/code/datums/status_effects/wound_effects.dm
+++ b/code/datums/status_effects/wound_effects.dm
@@ -167,20 +167,20 @@
// bones
-/datum/status_effect/wound/blunt
+/datum/status_effect/wound/blunt/bone
-/datum/status_effect/wound/blunt/on_apply()
+/datum/status_effect/wound/blunt/bone/on_apply()
. = ..()
RegisterSignal(owner, COMSIG_MOB_SWAP_HANDS, PROC_REF(on_swap_hands))
on_swap_hands()
-/datum/status_effect/wound/blunt/on_remove()
+/datum/status_effect/wound/blunt/bone/on_remove()
. = ..()
UnregisterSignal(owner, COMSIG_MOB_SWAP_HANDS)
var/mob/living/carbon/wound_owner = owner
wound_owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/blunt_wound)
-/datum/status_effect/wound/blunt/proc/on_swap_hands()
+/datum/status_effect/wound/blunt/bone/proc/on_swap_hands()
SIGNAL_HANDLER
var/mob/living/carbon/wound_owner = owner
@@ -189,7 +189,7 @@
else
wound_owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/blunt_wound)
-/datum/status_effect/wound/blunt/nextmove_modifier()
+/datum/status_effect/wound/blunt/bone/nextmove_modifier()
var/mob/living/carbon/C = owner
if(C.get_active_hand() == linked_limb)
@@ -198,18 +198,20 @@
return 1
// blunt
-/datum/status_effect/wound/blunt/moderate
+/datum/status_effect/wound/blunt/bone/moderate
id = "disjoint"
-/datum/status_effect/wound/blunt/severe
+/datum/status_effect/wound/blunt/bone/severe
id = "hairline"
-/datum/status_effect/wound/blunt/critical
+/datum/status_effect/wound/blunt/bone/critical
id = "compound"
+
// slash
-/datum/status_effect/wound/slash/moderate
+
+/datum/status_effect/wound/slash/flesh/moderate
id = "abrasion"
-/datum/status_effect/wound/slash/severe
+/datum/status_effect/wound/slash/flesh/severe
id = "laceration"
-/datum/status_effect/wound/slash/critical
+/datum/status_effect/wound/slash/flesh/critical
id = "avulsion"
// pierce
/datum/status_effect/wound/pierce/moderate
@@ -219,9 +221,9 @@
/datum/status_effect/wound/pierce/critical
id = "rupture"
// burns
-/datum/status_effect/wound/burn/moderate
+/datum/status_effect/wound/burn/flesh/moderate
id = "seconddeg"
-/datum/status_effect/wound/burn/severe
+/datum/status_effect/wound/burn/flesh/severe
id = "thirddeg"
-/datum/status_effect/wound/burn/critical
+/datum/status_effect/wound/burn/flesh/critical
id = "fourthdeg"
diff --git a/code/datums/wounds/_wound_static_data.dm b/code/datums/wounds/_wound_static_data.dm
new file mode 100644
index 00000000000..4d28e80a910
--- /dev/null
+++ b/code/datums/wounds/_wound_static_data.dm
@@ -0,0 +1,136 @@
+// This datum is merely a singleton instance that allows for custom "can be applied" behaviors without instantiating a wound instance.
+// For example: You can make a pregen_data subtype for your wound that overrides can_be_applied_to to only apply to specifically slimeperson limbs.
+// Without this, youre stuck with very static initial variables.
+
+GLOBAL_LIST_INIT_TYPED(all_wound_pregen_data, /datum/wound_pregen_data, generate_wound_static_data())
+
+/proc/generate_wound_static_data()
+ RETURN_TYPE(/list/datum/wound_pregen_data)
+
+ var/list/datum/wound_pregen_data/data = list()
+
+ for (var/datum/wound_pregen_data/path as anything in typecacheof(path = /datum/wound_pregen_data, ignore_root_path = TRUE))
+ if (initial(path.abstract))
+ continue
+
+ if (!isnull(data[initial(path.wound_path_to_generate)]))
+ stack_trace("pre-existing pregen data for [initial(path.wound_path_to_generate)] when [path] was being considered: [data[initial(path.wound_path_to_generate)]]. \
+ this is definitely a bug, and is probably because one of the two pregen data have the wrong wound typepath defined. [path] will not be instantiated")
+
+ continue
+
+ var/datum/wound_pregen_data/pregen_data = new path
+ data[pregen_data.wound_path_to_generate] = pregen_data
+
+ return data
+
+/// A singleton datum that holds pre-gen and static data about a wound. Each wound datum should have a corresponding wound_pregen_data.
+/datum/wound_pregen_data
+ /// The typepath of the wound we will be handling and storing data of. NECESSARY IF THIS IS A NON-ABSTRACT TYPE!
+ var/datum/wound/wound_path_to_generate
+
+ /// Will this be instantiated?
+ var/abstract = FALSE
+
+ /// If true, our wound can be selected in ordinary wound rolling. If this is set to false, our wound can only be directly instantiated by use of specific typepath.
+ var/can_be_randomly_generated = TRUE
+
+ /// A list of biostates a limb must have to receive our wound, in wounds.dm.
+ var/required_limb_biostate
+ /// If false, we will check if the limb has all of our required biostates instead of just any.
+ var/check_for_any = FALSE
+
+ /// If false, we will iterate through wounds on a given limb, and if any match our type, we wont add our wound.
+ var/duplicates_allowed = FALSE
+
+ /// If we require BIO_BLOODED, we will not add our wound if this is true and the limb cannot bleed.
+ var/ignore_cannot_bleed = TRUE // a lot of bleed wounds should still be applied for purposes of mangling flesh
+
+ /// A list of bodyzones we are applicable to.
+ var/list/viable_zones = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
+
+/datum/wound_pregen_data/New()
+ . = ..()
+
+ if (!abstract)
+ if (required_limb_biostate == null)
+ stack_trace("required_limb_biostate null - please set it! occured on: [src.type]")
+ if (wound_path_to_generate == null)
+ stack_trace("wound_path_to_generate null - please set it! occured on: [src.type]")
+
+// this proc is the primary reason this datum exists - a singleton instance so we can always run this proc even without the wound existing
+/**
+ * Args:
+ * * obj/item/bodypart/limb: The limb we are considering.
+ * * wound_type: The type of the "wound acquisition attempt". Example: A slashing attack cannot proc a blunt wound, so wound_type = WOUND_SLASH would
+ * fail if we expect WOUND_BLUNT. Defaults to the wound type we expect.
+ * * datum/wound/old_wound: If we would replace a wound, this would be said wound. Nullable.
+ * * random_roll = FALSE: If this is in the context of a random wound generation, and this wound wasn't specifically checked.
+ *
+ * Returns:
+ * FALSE if the limb cannot be wounded, if wound_type is not ours, if we have a higher severity wound already in our series,
+ * if we have a biotype mismatch, if the limb isnt in a viable zone, or if theres any duplicate wound types.
+ * TRUE otherwise.
+ */
+/datum/wound_pregen_data/proc/can_be_applied_to(obj/item/bodypart/limb, wound_type = initial(wound_path_to_generate.wound_type), datum/wound/old_wound, random_roll = FALSE)
+ SHOULD_BE_PURE(TRUE)
+
+ if (!istype(limb) || !limb.owner)
+ return FALSE
+
+ if (random_roll && !can_be_randomly_generated)
+ return FALSE
+
+ if (HAS_TRAIT(limb.owner, TRAIT_NEVER_WOUNDED) || (limb.owner.status_flags & GODMODE))
+ return FALSE
+
+ if (wound_type != initial(wound_path_to_generate.wound_type))
+ return
+ else
+ for (var/datum/wound/preexisting_wound as anything in limb.wounds)
+ if (preexisting_wound.wound_series == initial(wound_path_to_generate.wound_series))
+ if (preexisting_wound.severity >= initial(wound_path_to_generate.severity))
+ return FALSE
+
+ if (!ignore_cannot_bleed && ((required_limb_biostate & BIO_BLOODED) && !limb.can_bleed()))
+ return FALSE
+
+ if (!biostate_valid(limb.biological_state))
+ return FALSE
+
+ if (!(limb.body_zone in viable_zones))
+ return FALSE
+
+ // we accept promotions and demotions, but no point in redundancy. This should have already been checked wherever the wound was rolled and applied for (see: bodypart damage code), but we do an extra check
+ // in case we ever directly add wounds
+ if (!duplicates_allowed)
+ for (var/datum/wound/preexisting_wound as anything in limb.wounds)
+ if (preexisting_wound.type == wound_path_to_generate && (preexisting_wound != old_wound))
+ return FALSE
+ return TRUE
+
+/// Returns true if we have the given biostates, or any biostate in it if check_for_any is true. False otherwise.
+/datum/wound_pregen_data/proc/biostate_valid(biostate)
+ if (check_for_any)
+ if (!(biostate & required_limb_biostate))
+ return FALSE
+ else if (!((biostate & required_limb_biostate) == required_limb_biostate)) // check for all
+ return FALSE
+
+ return TRUE
+
+/// Returns a new instance of our wound datum.
+/datum/wound_pregen_data/proc/generate_instance(obj/item/bodypart/limb, ...)
+ RETURN_TYPE(/datum/wound)
+
+ return new wound_path_to_generate
+
+/datum/wound_pregen_data/Destroy(force, ...)
+ stack_trace("[src], a singleton wound pregen data instance, was destroyed! This should not happen!")
+
+ if (!force)
+ return
+
+ . = ..()
+
+ GLOB.all_wound_pregen_data[wound_path_to_generate] = new src.type //recover
diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm
index 33686d6bc24..11f2dc6a63d 100644
--- a/code/datums/wounds/_wounds.dm
+++ b/code/datums/wounds/_wounds.dm
@@ -14,6 +14,8 @@
deciding what specific wound will be applied. I'd like to have a few different types of wounds for at least some of the choices, but I'm just doing rough generals for now. Expect polishing
*/
+#define WOUND_CRITICAL_BLUNT_DISMEMBER_BONUS 15
+
/datum/wound
/// What it's named
var/name = "Wound"
@@ -24,23 +26,31 @@
/// What the limb looks like on a cursory examine
var/examine_desc = "is badly hurt"
+ /// If this wound can generate a scar.
+ var/can_scar = TRUE
+
+ /// The file we take our scar descriptions from.
+ var/scar_file
+
/// needed for "your arm has a compound fracture" vs "your arm has some third degree burns"
var/a_or_from = "a"
/// The visible message when this happens
var/occur_text = ""
/// This sound will be played upon the wound being applied
var/sound_effect
+ /// The volume of [sound_effect]
+ var/sound_volume = 70
/// Either WOUND_SEVERITY_TRIVIAL (meme wounds like stubbed toe), WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_SEVERE, or WOUND_SEVERITY_CRITICAL (or maybe WOUND_SEVERITY_LOSS)
var/severity = WOUND_SEVERITY_MODERATE
- /// The list of wounds it belongs in, WOUND_LIST_BLUNT, WOUND_LIST_SLASH, or WOUND_LIST_BURN
+ /// The type of attack that can generate this wound. E.g. WOUND_SLASH = A sword can cause us, or WOUND_BLUNT = a hammer can cause us/a sword attacking mangled flesh.
var/wound_type
+ /// The series of wounds this is in. See wounds.dm (the defines file) for a more detailed explanation - but tldr is that no 2 wounds of the same series can be on a limb.
+ var/wound_series
- /// What body zones can we affect
- var/list/viable_zones = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
/// Who owns the body part that we're wounding
var/mob/living/carbon/victim = null
- /// The bodypart we're parented to
+ /// The bodypart we're parented to. Not guaranteed to be non-null, especially after/during removal or if we haven't been applied
var/obj/item/bodypart/limb = null
/// Specific items such as bandages or sutures that can try directly treating this wound
@@ -90,14 +100,13 @@
var/wound_source
/// What flags apply to this wound
- var/wound_flags = (FLESH_WOUND | BONE_WOUND | ACCEPTS_GAUZE)
+ var/wound_flags = (ACCEPTS_GAUZE)
/datum/wound/Destroy()
if(attached_surgery)
QDEL_NULL(attached_surgery)
- remove_wound()
- set_limb(null)
- victim = null
+ if (limb)
+ remove_wound()
return ..()
// Applied into wounds when they're scanned with the wound analyzer, halves time to treat them manually.
@@ -118,22 +127,10 @@
* * wound_source: The source of the wound, such as a weapon.
*/
/datum/wound/proc/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE, attack_direction = null, wound_source = "Unknown")
- if(!istype(L) || !L.owner || !(L.body_zone in viable_zones) || !IS_ORGANIC_LIMB(L) || HAS_TRAIT(L.owner, TRAIT_NEVER_WOUNDED) || (L.owner.status_flags & GODMODE))
- qdel(src)
- return
- // Checks for biological state, to ensure only valid wounds are applied on the limb
- if(((wound_flags & BONE_WOUND) && !(L.biological_state & BIO_BONE)) || ((wound_flags & FLESH_WOUND) && !(L.biological_state & BIO_FLESH)))
+ if (!can_be_applied_to(L, old_wound))
qdel(src)
- return
-
- // we accept promotions and demotions, but no point in redundancy. This should have already been checked wherever the wound was rolled and applied for (see: bodypart damage code), but we do an extra check
- // in case we ever directly add wounds
- for(var/i in L.wounds)
- var/datum/wound/preexisting_wound = i
- if((preexisting_wound.type == type) && (preexisting_wound != old_wound))
- qdel(src)
- return
+ return FALSE
if(isitem(wound_source))
var/obj/item/wound_item = wound_source
@@ -171,12 +168,35 @@
victim.visible_message(msg, span_userdanger("Your [limb.plaintext_zone] [occur_text]!"), vision_distance = vis_dist)
if(sound_effect)
- playsound(L.owner, sound_effect, 70 + 20 * severity, TRUE)
+ playsound(L.owner, sound_effect, sound_volume + (20 * severity), TRUE)
wound_injury(old_wound, attack_direction = attack_direction)
if(!demoted)
second_wind()
+ return TRUE
+
+/// Returns TRUE if we can be applied to the limb.
+/datum/wound/proc/can_be_applied_to(obj/item/bodypart/L, datum/wound/old_wound)
+ var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[type]
+
+ // We assume we aren't being randomly applied - we have no reason to believe we are
+ // And, besides, if we were, you could just as easily check our pregen data rather than run this proc
+ // Generally speaking this proc is called in apply_wound, which is called when the caller is already confidant in its ability to be applied
+ return pregen_data.can_be_applied_to(L, wound_type, old_wound)
+
+/// Returns the zones we can be applied to.
+/datum/wound/proc/get_viable_zones()
+ var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[type]
+
+ return pregen_data.viable_zones
+
+/// Returns the biostate we require to be applied.
+/datum/wound/proc/get_required_biostate()
+ var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[type]
+
+ return pregen_data.required_limb_biostate
+
// Updates descriptive texts for the wound, in case it can get altered for whatever reason
/datum/wound/proc/update_descriptions()
return
@@ -201,14 +221,16 @@
/datum/wound/proc/remove_wound(ignore_limb, replaced = FALSE)
//TODO: have better way to tell if we're getting removed without replacement (full heal) scar stuff
set_disabling(FALSE)
- if(limb && !already_scarred && !replaced)
+ if(limb && can_scar && !already_scarred && !replaced)
already_scarred = TRUE
var/datum/scar/new_scar = new
new_scar.generate(limb, src)
- remove_wound_from_victim()
+
+ null_victim() // we use the proc here because some behaviors may depend on changing victim to some new value
+
if(limb && !ignore_limb)
- LAZYREMOVE(limb.wounds, src)
- limb.update_wounds(replaced)
+ set_limb(null, replaced) // since we're removing limb's ref to us, we should do the same
+ // if you want to keep the ref, do it externally, theres no reason for us to remember it
/datum/wound/proc/remove_wound_from_victim()
if(!victim)
@@ -221,17 +243,15 @@
/**
* replace_wound() is used when you want to replace the current wound with a new wound, presumably of the same category, just of a different severity (either up or down counts)
*
- * This proc actually instantiates the new wound based off the specific type path passed, then returns the new instantiated wound datum.
- *
* Arguments:
- * * new_type- The TYPE PATH of the wound you want to replace this, like /datum/wound/slash/severe
+ * * new_wound- The wound instance you want to replace this
* * smited- If this is a smite, we don't care about this wound for stat tracking purposes (not yet implemented)
*/
-/datum/wound/proc/replace_wound(new_type, smited = FALSE, attack_direction = attack_direction)
- var/datum/wound/new_wound = new new_type
+/datum/wound/proc/replace_wound(datum/wound/new_wound, smited = FALSE, attack_direction = attack_direction)
already_scarred = TRUE
+ var/obj/item/bodypart/cached_limb = limb // remove_wound() nulls limb so we have to track it locally
remove_wound(replaced=TRUE)
- new_wound.apply_wound(limb, old_wound = src, smited = smited, attack_direction = attack_direction, wound_source = wound_source)
+ new_wound.apply_wound(cached_limb, old_wound = src, smited = smited, attack_direction = attack_direction, wound_source = wound_source)
. = new_wound
qdel(src)
@@ -239,24 +259,28 @@
/datum/wound/proc/wound_injury(datum/wound/old_wound = null, attack_direction = null)
return
-
/// Proc called to change the variable `limb` and react to the event.
-/datum/wound/proc/set_limb(new_value)
+/datum/wound/proc/set_limb(obj/item/bodypart/new_value, replaced = FALSE)
if(limb == new_value)
return FALSE //Limb can either be a reference to something or `null`. Returning the number variable makes it clear no change was made.
. = limb
- if(limb)
+ if(limb) // if we're nulling limb, we're basically detaching from it, so we should remove ourselves in that case
UnregisterSignal(limb, COMSIG_QDELETING)
+ LAZYREMOVE(limb.wounds, src)
+ limb.update_wounds(replaced)
+ if (disabling)
+ limb.remove_traits(list(TRAIT_PARALYSIS, TRAIT_DISABLED_BY_WOUND), REF(src))
+
limb = new_value
- RegisterSignal(new_value, COMSIG_QDELETING, PROC_REF(source_died))
- if(. && disabling)
- var/obj/item/bodypart/old_limb = .
- old_limb.remove_traits(list(TRAIT_PARALYSIS, TRAIT_DISABLED_BY_WOUND), REF(src))
+
+ // POST-CHANGE
+
+ if (limb)
+ RegisterSignal(limb, COMSIG_QDELETING, PROC_REF(source_died))
if(limb)
if(disabling)
limb.add_traits(list(TRAIT_PARALYSIS, TRAIT_DISABLED_BY_WOUND), REF(src))
-
/// Proc called to change the variable `disabling` and react to the event.
/datum/wound/proc/set_disabling(new_value)
if(disabling == new_value)
@@ -304,25 +328,7 @@
if(I.force && tendee.combat_mode)
return FALSE
- var/allowed = FALSE
-
- // check if we have a valid treatable tool
- if(I.tool_behaviour == treatable_tool)
- allowed = TRUE
- else if(treatable_tool == TOOL_CAUTERY && I.get_temperature() && user == victim) // allow improvised cauterization on yourself without an aggro grab
- allowed = TRUE
- // failing that, see if we're aggro grabbing them and if we have an item that works for aggro grabs only
- else if(user.pulling == victim && user.grab_state >= GRAB_AGGRESSIVE && check_grab_treatments(I, user))
- allowed = TRUE
- // failing THAT, we check if we have a generally allowed item
- else
- for(var/allowed_type in treatable_by)
- if(istype(I, allowed_type))
- allowed = TRUE
- break
-
- // if none of those apply, we return false to avoid interrupting
- if(!allowed)
+ if(!item_can_treat(I, user))
return FALSE
// now that we've determined we have a valid attempt at treating, we can stomp on their dreams if we're already interacting with the patient or if their part is obscured
@@ -338,8 +344,22 @@
return TRUE
// lastly, treat them
- treat(I, user)
- return TRUE
+ return treat(I, user) // we allow treat to return a value so it can control if the item does its normal interaction or not
+
+/// Returns TRUE if the item can be used to treat our wounds. Hooks into treat() - only things that return TRUE here may be used there.
+/datum/wound/proc/item_can_treat(obj/item/potential_treater, mob/user)
+ // check if we have a valid treatable tool
+ if(potential_treater.tool_behaviour == treatable_tool)
+ return TRUE
+ if(treatable_tool == TOOL_CAUTERY && potential_treater.get_temperature() && user == victim) // allow improvised cauterization on yourself without an aggro grab
+ return TRUE
+ // failing that, see if we're aggro grabbing them and if we have an item that works for aggro grabs only
+ if(user.pulling == victim && user.grab_state >= GRAB_AGGRESSIVE && check_grab_treatments(potential_treater, user))
+ return TRUE
+ // failing THAT, we check if we have a generally allowed item
+ for(var/allowed_type in treatable_by)
+ if(istype(potential_treater, allowed_type))
+ return TRUE
/// Return TRUE if we have an item that can only be used while aggro grabbed (unhanded aggro grab treatments go in [/datum/wound/proc/try_handling]). Treatment is still is handled in [/datum/wound/proc/treat]
/datum/wound/proc/check_grab_treatments(obj/item/I, mob/user)
@@ -361,8 +381,8 @@
/datum/wound/proc/still_exists()
return (!QDELETED(src) && limb)
-/// When our parent bodypart is hurt
-/datum/wound/proc/receive_damage(wounding_type, wounding_dmg, wound_bonus, attack_direction)
+/// When our parent bodypart is hurt.
+/datum/wound/proc/receive_damage(wounding_type, wounding_dmg, wound_bonus, attack_direction, damage_source)
return
/// Called from cryoxadone and pyroxadone when they're proc'ing. Wounds will slowly be fixed separately from other methods when these are in effect. crappy name but eh
@@ -427,9 +447,43 @@
return .
/datum/wound/proc/get_wound_description(mob/user)
- . = "[victim.p_Their()] [limb.plaintext_zone] [examine_desc]"
- . = severity <= WOUND_SEVERITY_MODERATE ? "[.]." : "[.]!"
- return .
+ var/desc
+
+ if ((wound_flags & ACCEPTS_GAUZE) && limb.current_gauze)
+ var/sling_condition = get_gauze_condition()
+ desc = "[victim.p_Their()] [limb.plaintext_zone] is [sling_condition] fastened in a sling of [limb.current_gauze.name]"
+ else
+ desc = "[victim.p_Their()] [limb.plaintext_zone] [examine_desc]"
+
+ desc = modify_desc_before_span(desc, user)
+
+ return get_desc_intensity(desc)
+
+/// A hook proc used to modify desc before it is spanned via [get_desc_intensity]. Useful for inserting spans yourself.
+/datum/wound/proc/modify_desc_before_span(desc, mob/user)
+ return desc
+
+/datum/wound/proc/get_gauze_condition()
+ SHOULD_BE_PURE(TRUE)
+ if (!limb.current_gauze)
+ return null
+
+ switch(limb.current_gauze.absorption_capacity)
+ if(0 to 1.25)
+ return "just barely"
+ if(1.25 to 2.75)
+ return "loosely"
+ if(2.75 to 4)
+ return "mostly"
+ if(4 to INFINITY)
+ return "tightly"
+
+/// Spans [desc] based on our severity.
+/datum/wound/proc/get_desc_intensity(desc)
+ SHOULD_BE_PURE(TRUE)
+ if (severity > WOUND_SEVERITY_MODERATE)
+ return span_bold("[desc]!")
+ return "[desc]."
/datum/wound/proc/get_scanner_description(mob/user)
return "Type: [name]\nSeverity: [severity_text()]\nDescription: [desc]\nRecommended Treatment: [treat_text]"
@@ -445,7 +499,30 @@
if(WOUND_SEVERITY_CRITICAL)
return "Critical"
+
+/// Returns TRUE if our limb is the head or chest, FALSE otherwise.
+/// Essential in the sense of "we cannot live without it".
+/datum/wound/proc/limb_essential()
+ return (limb.body_zone == BODY_ZONE_HEAD || limb.body_zone == BODY_ZONE_CHEST)
+
+/// Getter proc for our scar_keyword, in case we might have some custom scar gen logic.
+/datum/wound/proc/get_scar_keyword(obj/item/bodypart/scarred_limb, add_to_scars)
+ return scar_keyword
+
+/// Getter proc for our scar_file, in case we might have some custom scar gen logic.
+/datum/wound/proc/get_scar_file(obj/item/bodypart/scarred_limb, add_to_scars)
+ return scar_file
+
/// Returns what string is displayed when a limb that has sustained this wound is examined
/// (This is examining the LIMB ITSELF, when it's not attached to someone.)
/datum/wound/proc/get_limb_examine_description()
return
+
+/// Gets the flat percentage chance increment of a dismember occuring, if a dismember is attempted (requires mangled flesh and bone). returning 15 = +15%.
+/datum/wound/proc/get_dismember_chance_bonus(existing_chance)
+ SHOULD_BE_PURE(TRUE)
+
+ if (wound_type == WOUND_BLUNT && severity >= WOUND_SEVERITY_CRITICAL)
+ return WOUND_CRITICAL_BLUNT_DISMEMBER_BONUS // we only require mangled bone (T2 blunt), but if there's a critical blunt, we'll add 15% more
+
+#undef WOUND_CRITICAL_BLUNT_DISMEMBER_BONUS
diff --git a/code/datums/wounds/blunt.dm b/code/datums/wounds/blunt.dm
new file mode 100644
index 00000000000..8a9c34e163d
--- /dev/null
+++ b/code/datums/wounds/blunt.dm
@@ -0,0 +1,4 @@
+/datum/wound/blunt
+ name = "Blunt Wound"
+ sound_effect = 'sound/effects/wounds/crack1.ogg'
+ wound_type = WOUND_BLUNT
diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm
index aa6cad87ed8..eed0fb1d883 100644
--- a/code/datums/wounds/bones.dm
+++ b/code/datums/wounds/bones.dm
@@ -1,16 +1,17 @@
-//SKYRAT EDIT REMOVAL - MOVED - MEDICINE
-/*
-
/*
Blunt/Bone wounds
*/
// TODO: well, a lot really, but i'd kill to get overlays and a bonebreaking effect like Blitz: The League, similar to electric shock skeletons
-/datum/wound/blunt
+/datum/wound_pregen_data/bone
+ abstract = TRUE
+ required_limb_biostate = BIO_BONE
+
+/datum/wound/blunt/bone
name = "Blunt (Bone) Wound"
- sound_effect = 'sound/effects/wounds/crack1.ogg'
- wound_type = WOUND_BLUNT
- wound_flags = (BONE_WOUND | ACCEPTS_GAUZE)
+ wound_flags = (ACCEPTS_GAUZE | SPLINT_OVERLAY) // SKYRAT EDIT: MEDICAL -- Makes bone wounds have a splint overlay
+
+ scar_file = BONE_SCAR_FILE
/// Have we been bone gel'd?
var/gelled
@@ -31,19 +32,18 @@
/// If this is a chest wound and this is set, we have this chance to cough up blood when hit in the chest
var/internal_bleeding_chance = 0
+ wound_series = WOUND_SERIES_BONE_BLUNT_BASIC
+
/*
Overwriting of base procs
*/
-/datum/wound/blunt/wound_injury(datum/wound/old_wound = null, attack_direction = null)
+/datum/wound/blunt/bone/wound_injury(datum/wound/old_wound = null, attack_direction = null)
// hook into gaining/losing gauze so crit bone wounds can re-enable/disable depending if they're slung or not
- RegisterSignals(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED), PROC_REF(update_inefficiencies))
-
if(limb.body_zone == BODY_ZONE_HEAD && brain_trauma_group)
processes = TRUE
active_trauma = victim.gain_trauma_type(brain_trauma_group, TRAUMA_RESILIENCE_WOUND)
next_trauma_cycle = world.time + (rand(100-WOUND_BONE_HEAD_TIME_VARIANCE, 100+WOUND_BONE_HEAD_TIME_VARIANCE) * 0.01 * trauma_cycle_cooldown)
- RegisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(attack_with_hurt_hand))
if(limb.held_index && victim.get_item_for_held_index(limb.held_index) && (disabling || prob(30 * severity)))
var/obj/item/I = victim.get_item_for_held_index(limb.held_index)
if(istype(I, /obj/item/offhand))
@@ -53,19 +53,37 @@
victim.visible_message(span_danger("[victim] drops [I] in shock!"), span_warning("The force on your [limb.plaintext_zone] causes you to drop [I]!"), vision_distance=COMBAT_MESSAGE_RANGE)
update_inefficiencies()
+ return ..()
-/datum/wound/blunt/remove_wound(ignore_limb, replaced)
+/datum/wound/blunt/bone/set_victim(new_victim)
+
+ if (victim)
+ UnregisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK)
+ if (new_victim)
+ RegisterSignal(new_victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(attack_with_hurt_hand))
+
+ return ..()
+
+/datum/wound/blunt/bone/set_limb(obj/item/bodypart/new_value)
+ if (limb)
+ UnregisterSignal(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED))
+ if (new_value)
+ RegisterSignals(new_value, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED), PROC_REF(update_inefficiencies))
+
+ return ..()
+
+/datum/wound/blunt/bone/remove_wound(ignore_limb, replaced)
limp_slowdown = 0
limp_chance = 0
QDEL_NULL(active_trauma)
- if(limb)
- UnregisterSignal(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED))
- if(victim)
- UnregisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK)
return ..()
-/datum/wound/blunt/handle_process(seconds_per_tick, times_fired)
+/datum/wound/blunt/bone/handle_process(seconds_per_tick, times_fired)
. = ..()
+
+ if (!victim || IS_IN_STASIS(victim))
+ return
+
if(limb.body_zone == BODY_ZONE_HEAD && brain_trauma_group && world.time > next_trauma_cycle)
if(active_trauma)
QDEL_NULL(active_trauma)
@@ -98,7 +116,7 @@
remove_wound()
/// If we're a human who's punching something with a broken arm, we might hurt ourselves doing so
-/datum/wound/blunt/proc/attack_with_hurt_hand(mob/M, atom/target, proximity)
+/datum/wound/blunt/bone/proc/attack_with_hurt_hand(mob/M, atom/target, proximity)
SIGNAL_HANDLER
if(victim.get_active_hand() != limb || !victim.combat_mode || !ismob(target) || severity <= WOUND_SEVERITY_MODERATE)
@@ -119,7 +137,7 @@
return COMPONENT_CANCEL_ATTACK_CHAIN
-/datum/wound/blunt/receive_damage(wounding_type, wounding_dmg, wound_bonus)
+/datum/wound/blunt/bone/receive_damage(wounding_type, wounding_dmg, wound_bonus)
if(!victim || wounding_dmg < WOUND_MINIMUM_DAMAGE)
return
if(ishuman(victim))
@@ -145,45 +163,23 @@
new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
victim.add_splatter_floor(get_step(victim.loc, victim.dir))
+/datum/wound/blunt/bone/modify_desc_before_span(desc)
+ . = ..()
-/datum/wound/blunt/get_wound_description(mob/user)
- if(!limb.current_gauze && !gelled && !taped)
- return ..()
-
- var/list/msg = list()
- if(!limb.current_gauze)
- msg += "[victim.p_Their()] [limb.plaintext_zone] [examine_desc]"
- else
- var/sling_condition = ""
- // how much life we have left in these bandages
- switch(limb.current_gauze.absorption_capacity)
- if(0 to 1.25)
- sling_condition = "just barely"
- if(1.25 to 2.75)
- sling_condition = "loosely"
- if(2.75 to 4)
- sling_condition = "mostly"
- if(4 to INFINITY)
- sling_condition = "tightly"
-
- msg += "[victim.p_Their()] [limb.plaintext_zone] is [sling_condition] fastened in a sling of [limb.current_gauze.name]"
-
- if(taped)
- msg += ", [span_notice("and appears to be reforming itself under some surgical tape!")]"
- else if(gelled)
- msg += ", [span_notice("with fizzing flecks of blue bone gel sparking off the bone!")]"
- else
- msg += "!"
- return "[msg.Join()]"
+ if (!limb.current_gauze)
+ if(taped)
+ . += ", [span_notice("and appears to be reforming itself under some surgical tape!")]"
+ else if(gelled)
+ . += ", [span_notice("with fizzing flecks of blue bone gel sparking off the bone!")]"
/datum/wound/blunt/get_limb_examine_description()
return span_warning("The bones in this limb appear badly cracked.")
/*
- New common procs for /datum/wound/blunt/
+ New common procs for /datum/wound/blunt/bone/
*/
-/datum/wound/blunt/proc/update_inefficiencies()
+/datum/wound/blunt/bone/proc/update_inefficiencies()
SIGNAL_HANDLER
if(limb.body_zone in list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
@@ -205,42 +201,60 @@
limb.update_wounds()
+/datum/wound/blunt/bone/get_scar_file(obj/item/bodypart/scarred_limb, add_to_scars)
+ if (scarred_limb.biological_state & BIO_BONE && (!(scarred_limb.biological_state & BIO_FLESH))) // only bone
+ return BONE_SCAR_FILE
+ else if (scarred_limb.biological_state & BIO_FLESH && (!(scarred_limb.biological_state & BIO_BONE)))
+ return FLESH_SCAR_FILE
+
+ return ..()
+
/// Joint Dislocation (Moderate Blunt)
-/datum/wound/blunt/moderate
+/datum/wound/blunt/bone/moderate
name = "Joint Dislocation"
- desc = "Patient's bone has been unset from socket, causing pain and reduced motor function."
+ desc = "Patient's limb has been unset from socket, causing pain and reduced motor function."
treat_text = "Recommended application of bonesetter to affected limb, though manual relocation by applying an aggressive grab to the patient and helpfully interacting with afflicted limb may suffice."
examine_desc = "is awkwardly janked out of place"
occur_text = "janks violently and becomes unseated"
severity = WOUND_SEVERITY_MODERATE
- viable_zones = list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
interaction_efficiency_penalty = 1.3
limp_slowdown = 3
limp_chance = 50
threshold_minimum = 35
threshold_penalty = 15
treatable_tool = TOOL_BONESET
- wound_flags = (BONE_WOUND)
- status_effect_type = /datum/status_effect/wound/blunt/moderate
+ status_effect_type = /datum/status_effect/wound/blunt/bone/moderate
scar_keyword = "bluntmoderate"
-/datum/wound/blunt/moderate/Destroy()
+/datum/wound_pregen_data/bone/dislocate
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/blunt/bone/moderate
+
+ required_limb_biostate = BIO_JOINTED
+
+/datum/wound/blunt/bone/moderate/Destroy()
if(victim)
UnregisterSignal(victim, COMSIG_LIVING_DOORCRUSHED)
return ..()
-/datum/wound/blunt/moderate/wound_injury(datum/wound/old_wound, attack_direction = null)
- . = ..()
- RegisterSignal(victim, COMSIG_LIVING_DOORCRUSHED, PROC_REF(door_crush))
+/datum/wound/blunt/bone/moderate/set_victim(new_victim)
+
+ if (victim)
+ UnregisterSignal(victim, COMSIG_LIVING_DOORCRUSHED)
+ if (new_victim)
+ RegisterSignal(new_victim, COMSIG_LIVING_DOORCRUSHED, PROC_REF(door_crush))
+
+ return ..()
/// Getting smushed in an airlock/firelock is a last-ditch attempt to try relocating your limb
-/datum/wound/blunt/moderate/proc/door_crush()
+/datum/wound/blunt/bone/moderate/proc/door_crush()
SIGNAL_HANDLER
if(prob(40))
victim.visible_message(span_danger("[victim]'s dislocated [limb.plaintext_zone] pops back into place!"), span_userdanger("Your dislocated [limb.plaintext_zone] pops back into place! Ow!"))
remove_wound()
-/datum/wound/blunt/moderate/try_handling(mob/living/carbon/human/user)
+/datum/wound/blunt/bone/moderate/try_handling(mob/living/carbon/human/user)
if(user.pulling != victim || user.zone_selected != limb.body_zone)
return FALSE
@@ -258,7 +272,7 @@
return TRUE
/// If someone is snapping our dislocated joint back into place by hand with an aggro grab and help intent
-/datum/wound/blunt/moderate/proc/chiropractice(mob/living/carbon/human/user)
+/datum/wound/blunt/bone/moderate/proc/chiropractice(mob/living/carbon/human/user)
var/time = base_treat_time
if(!do_after(user, time, target=victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
@@ -277,7 +291,7 @@
chiropractice(user)
/// If someone is snapping our dislocated joint into a fracture by hand with an aggro grab and harm or disarm intent
-/datum/wound/blunt/moderate/proc/malpractice(mob/living/carbon/human/user)
+/datum/wound/blunt/bone/moderate/proc/malpractice(mob/living/carbon/human/user)
var/time = base_treat_time
if(!do_after(user, time, target=victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
@@ -295,7 +309,7 @@
malpractice(user)
-/datum/wound/blunt/moderate/treat(obj/item/I, mob/user)
+/datum/wound/blunt/bone/moderate/treat(obj/item/I, mob/user)
var/scanned = HAS_TRAIT(src, TRAIT_WOUND_SCANNED)
var/self_penalty_mult = user == victim ? 1.5 : 1
var/scanned_mult = scanned ? 0.5 : 1
@@ -324,7 +338,7 @@
Severe (Hairline Fracture)
*/
-/datum/wound/blunt/severe
+/datum/wound/blunt/bone/severe
name = "Hairline Fracture"
desc = "Patient's bone has suffered a crack in the foundation, causing serious pain and reduced limb functionality."
treat_text = "Recommended light surgical application of bone gel, though a sling of medical gauze will prevent worsening situation."
@@ -338,16 +352,21 @@
threshold_minimum = 60
threshold_penalty = 30
treatable_by = list(/obj/item/stack/sticky_tape/surgical, /obj/item/stack/medical/bone_gel)
- status_effect_type = /datum/status_effect/wound/blunt/severe
+ status_effect_type = /datum/status_effect/wound/blunt/bone/severe
scar_keyword = "bluntsevere"
brain_trauma_group = BRAIN_TRAUMA_MILD
trauma_cycle_cooldown = 1.5 MINUTES
internal_bleeding_chance = 40
- wound_flags = (BONE_WOUND | ACCEPTS_GAUZE | MANGLES_BONE)
+ wound_flags = (ACCEPTS_GAUZE | MANGLES_BONE | SPLINT_OVERLAY) // SKYRAT EDIT - MEDICAL (SPLINT_OVERLAY)
regen_ticks_needed = 120 // ticks every 2 seconds, 240 seconds, so roughly 4 minutes default
+/datum/wound_pregen_data/bone/hairline
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/blunt/bone/severe
+
/// Compound Fracture (Critical Blunt)
-/datum/wound/blunt/critical
+/datum/wound/blunt/bone/critical
name = "Compound Fracture"
desc = "Patient's bones have suffered multiple gruesome fractures, causing significant pain and near uselessness of limb."
treat_text = "Immediate binding of affected limb, followed by surgical intervention ASAP."
@@ -363,36 +382,40 @@
threshold_penalty = 50
disabling = TRUE
treatable_by = list(/obj/item/stack/sticky_tape/surgical, /obj/item/stack/medical/bone_gel)
- status_effect_type = /datum/status_effect/wound/blunt/critical
+ status_effect_type = /datum/status_effect/wound/blunt/bone/critical
scar_keyword = "bluntcritical"
brain_trauma_group = BRAIN_TRAUMA_SEVERE
trauma_cycle_cooldown = 2.5 MINUTES
internal_bleeding_chance = 60
- wound_flags = (BONE_WOUND | ACCEPTS_GAUZE | MANGLES_BONE)
+ wound_flags = (ACCEPTS_GAUZE | MANGLES_BONE | SPLINT_OVERLAY) // SKYRAT EDIT - MEDICAL (SPLINT_OVERLAY)
regen_ticks_needed = 240 // ticks every 2 seconds, 480 seconds, so roughly 8 minutes default
+/datum/wound_pregen_data/bone/compound
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/blunt/bone/critical
+
// doesn't make much sense for "a" bone to stick out of your head
-/datum/wound/blunt/critical/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE, attack_direction = null, wound_source = "Unknown")
+/datum/wound/blunt/bone/critical/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE, attack_direction = null, wound_source = "Unknown")
if(L.body_zone == BODY_ZONE_HEAD)
occur_text = "splits open, exposing a bare, cracked skull through the flesh and blood"
examine_desc = "has an unsettling indent, with bits of skull poking out"
. = ..()
/// if someone is using bone gel on our wound
-/datum/wound/blunt/proc/gel(obj/item/stack/medical/bone_gel/I, mob/user)
+/datum/wound/blunt/bone/proc/gel(obj/item/stack/medical/bone_gel/I, mob/user)
// skellies get treated nicer with bone gel since their "reattach dismembered limbs by hand" ability sucks when it's still critically wounded
if((limb.biological_state & BIO_BONE) && !(limb.biological_state & BIO_FLESH))
- skelly_gel(I, user)
- return
+ return skelly_gel(I, user)
if(gelled)
to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [limb.plaintext_zone] is already coated with bone gel!"))
- return
+ return TRUE
user.visible_message(span_danger("[user] begins hastily applying [I] to [victim]'s' [limb.plaintext_zone]..."), span_warning("You begin hastily applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone], disregarding the warning label..."))
if(!do_after(user, base_treat_time * 1.5 * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, PROC_REF(still_exists))))
- return
+ return TRUE
I.use(1)
victim.emote("scream")
@@ -415,15 +438,16 @@
if(prob(25 + (20 * (severity - 2)) - painkiller_bonus)) // 25%/45% chance to fail self-applying with severe and critical wounds, modded by painkillers
victim.visible_message(span_danger("[victim] fails to finish applying [I] to [victim.p_their()] [limb.plaintext_zone], passing out from the pain!"), span_notice("You pass out from the pain of applying [I] to your [limb.plaintext_zone] before you can finish!"))
victim.AdjustUnconscious(5 SECONDS)
- return
+ return TRUE
victim.visible_message(span_notice("[victim] finishes applying [I] to [victim.p_their()] [limb.plaintext_zone], grimacing from the pain!"), span_notice("You finish applying [I] to your [limb.plaintext_zone], and your bones explode in pain!"))
limb.receive_damage(25, wound_bonus=CANT_WOUND)
victim.adjustStaminaLoss(100)
gelled = TRUE
+ return TRUE
/// skellies are less averse to bone gel, since they're literally all bone
-/datum/wound/blunt/proc/skelly_gel(obj/item/stack/medical/bone_gel/I, mob/user)
+/datum/wound/blunt/bone/proc/skelly_gel(obj/item/stack/medical/bone_gel/I, mob/user)
if(gelled)
to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [limb.plaintext_zone] is already coated with bone gel!"))
return
@@ -442,20 +466,21 @@
gelled = TRUE
processes = TRUE
+ return TRUE
/// if someone is using surgical tape on our wound
-/datum/wound/blunt/proc/tape(obj/item/stack/sticky_tape/surgical/I, mob/user)
+/datum/wound/blunt/bone/proc/tape(obj/item/stack/sticky_tape/surgical/I, mob/user)
if(!gelled)
to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [limb.plaintext_zone] must be coated with bone gel to perform this emergency operation!"))
- return
+ return TRUE
if(taped)
to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [limb.plaintext_zone] is already wrapped in [I.name] and reforming!"))
- return
+ return TRUE
user.visible_message(span_danger("[user] begins applying [I] to [victim]'s' [limb.plaintext_zone]..."), span_warning("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone]..."))
if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, PROC_REF(still_exists))))
- return
+ return TRUE
if(victim == user)
regen_ticks_needed *= 1.5
@@ -469,14 +494,15 @@
taped = TRUE
processes = TRUE
+ return TRUE
-/datum/wound/blunt/treat(obj/item/I, mob/user)
+/datum/wound/blunt/bone/treat(obj/item/I, mob/user)
if(istype(I, /obj/item/stack/medical/bone_gel))
- gel(I, user)
+ return gel(I, user)
else if(istype(I, /obj/item/stack/sticky_tape/surgical))
- tape(I, user)
+ return tape(I, user)
-/datum/wound/blunt/get_scanner_description(mob/user)
+/datum/wound/blunt/bone/get_scanner_description(mob/user)
. = ..()
. += "
"
@@ -500,4 +526,3 @@
else if(limb.body_zone == BODY_ZONE_CHEST && victim.blood_volume)
. += "Ribcage Trauma Detected: Further trauma to chest is likely to worsen internal bleeding until bone is repaired."
. += "
"
-*/
diff --git a/code/datums/wounds/burns.dm b/code/datums/wounds/burns.dm
index d3e7221d8f3..7ef1cd68268 100644
--- a/code/datums/wounds/burns.dm
+++ b/code/datums/wounds/burns.dm
@@ -1,6 +1,3 @@
-//SKYRAT EDIT REMOVAL - MOVED - MEDICINE
-/*
-
/*
Burn wounds
*/
@@ -10,9 +7,17 @@
name = "Burn Wound"
a_or_from = "from"
wound_type = WOUND_BURN
- processes = TRUE
sound_effect = 'sound/effects/wounds/sizzle1.ogg'
- wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE)
+
+/datum/wound/burn/flesh
+ name = "Burn (Flesh) Wound"
+ a_or_from = "from"
+ wound_type = WOUND_BURN
+ processes = TRUE
+
+ scar_file = FLESH_SCAR_FILE
+
+ wound_series = WOUND_SERIES_FLESH_BURN_BASIC
treatable_by = list(/obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh) // sterilizer and alcohol will require reagent treatments, coming soon
@@ -33,8 +38,11 @@
/// Once we reach infestation beyond WOUND_INFESTATION_SEPSIS, we get this many warnings before the limb is completely paralyzed (you'd have to ignore a really bad burn for a really long time for this to happen)
var/strikes_to_lose_limb = 3
+/datum/wound/burn/flesh/handle_process(seconds_per_tick, times_fired)
+
+ if (!victim || IS_IN_STASIS(victim))
+ return
-/datum/wound/burn/handle_process(seconds_per_tick, times_fired)
. = ..()
if(strikes_to_lose_limb == 0) // we've already hit sepsis, nothing more to do
victim.adjustToxLoss(0.25 * seconds_per_tick)
@@ -130,7 +138,7 @@
var/datum/brain_trauma/severe/paralysis/sepsis = new (limb.body_zone)
victim.gain_trauma(sepsis)
-/datum/wound/burn/get_wound_description(mob/user)
+/datum/wound/burn/flesh/get_wound_description(mob/user)
if(strikes_to_lose_limb <= 0)
return span_deadsay("[victim.p_Their()] [limb.plaintext_zone] has locked up completely and is non-functional.")
@@ -163,7 +171,7 @@
return "[condition.Join()]"
-/datum/wound/burn/get_scanner_description(mob/user)
+/datum/wound/burn/flesh/get_scanner_description(mob/user)
if(strikes_to_lose_limb <= 0) // Unclear if it can go below 0, best to not take the chance
var/oopsie = "Type: [name]\nSeverity: [severity_text()]"
oopsie += "Infection Level: [span_deadsay("The body part has suffered complete sepsis and must be removed. Amputate or augment limb immediately, or place the patient in a cryotube.")]
"
@@ -196,12 +204,12 @@
*/
/// if someone is using ointment or mesh on our burns
-/datum/wound/burn/proc/ointmentmesh(obj/item/stack/medical/I, mob/user)
+/datum/wound/burn/flesh/proc/ointmentmesh(obj/item/stack/medical/I, mob/user)
user.visible_message(span_notice("[user] begins applying [I] to [victim]'s [limb.plaintext_zone]..."), span_notice("You begin applying [I] to [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone]..."))
if (I.amount <= 0)
- return
+ return TRUE
if(!do_after(user, (user == victim ? I.self_delay : I.other_delay), extra_checks = CALLBACK(src, PROC_REF(still_exists))))
- return
+ return TRUE
limb.heal_damage(I.heal_brute, I.heal_burn)
user.visible_message(span_green("[user] applies [I] to [victim]."), span_green("You apply [I] to [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone]."))
@@ -211,36 +219,38 @@
if((infestation <= 0 || sanitization >= infestation) && (flesh_damage <= 0 || flesh_healing > flesh_damage))
to_chat(user, span_notice("You've done all you can with [I], now you must wait for the flesh on [victim]'s [limb.plaintext_zone] to recover."))
+ return TRUE
else
- try_treating(I, user)
+ return try_treating(I, user)
/// Paramedic UV penlights
-/datum/wound/burn/proc/uv(obj/item/flashlight/pen/paramedic/I, mob/user)
+/datum/wound/burn/flesh/proc/uv(obj/item/flashlight/pen/paramedic/I, mob/user)
if(!COOLDOWN_FINISHED(I, uv_cooldown))
to_chat(user, span_notice("[I] is still recharging!"))
- return
+ return TRUE
if(infestation <= 0 || infestation < sanitization)
to_chat(user, span_notice("There's no infection to treat on [victim]'s [limb.plaintext_zone]!"))
- return
+ return TRUE
user.visible_message(span_notice("[user] flashes the burns on [victim]'s [limb] with [I]."), span_notice("You flash the burns on [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone] with [I]."), vision_distance=COMBAT_MESSAGE_RANGE)
sanitization += I.uv_power
COOLDOWN_START(I, uv_cooldown, I.uv_cooldown_length)
+ return TRUE
-/datum/wound/burn/treat(obj/item/I, mob/user)
+/datum/wound/burn/flesh/treat(obj/item/I, mob/user)
if(istype(I, /obj/item/stack/medical/ointment))
- ointmentmesh(I, user)
+ return ointmentmesh(I, user)
else if(istype(I, /obj/item/stack/medical/mesh))
var/obj/item/stack/medical/mesh/mesh_check = I
if(!mesh_check.is_open)
to_chat(user, span_warning("You need to open [mesh_check] first."))
return
- ointmentmesh(mesh_check, user)
+ return ointmentmesh(mesh_check, user)
else if(istype(I, /obj/item/flashlight/pen/paramedic))
- uv(I, user)
+ return uv(I, user)
// people complained about burns not healing on stasis beds, so in addition to checking if it's cured, they also get the special ability to very slowly heal on stasis beds if they have the healing effects stored
-/datum/wound/burn/on_stasis(seconds_per_tick, times_fired)
+/datum/wound/burn/flesh/on_stasis(seconds_per_tick, times_fired)
. = ..()
if(strikes_to_lose_limb == 0) // we've already hit sepsis, nothing more to do
if(SPT_PROB(0.5, seconds_per_tick))
@@ -255,14 +265,19 @@
if(sanitization > 0)
infestation = max(infestation - (0.1 * WOUND_BURN_SANITIZATION_RATE * seconds_per_tick), 0)
-/datum/wound/burn/on_synthflesh(amount)
+/datum/wound/burn/flesh/on_synthflesh(amount)
flesh_healing += amount * 0.5 // 20u patch will heal 10 flesh standard
+/datum/wound_pregen_data/flesh_burn
+ abstract = TRUE
+
+ required_limb_biostate = BIO_FLESH
+
/datum/wound/burn/get_limb_examine_description()
return span_warning("The flesh on this limb appears badly cooked.")
// we don't even care about first degree burns, straight to second
-/datum/wound/burn/moderate
+/datum/wound/burn/flesh/moderate
name = "Second Degree Burns"
desc = "Patient is suffering considerable burns with mild skin penetration, weakening limb integrity and increased burning sensations."
treat_text = "Recommended application of topical ointment or regenerative mesh to affected region."
@@ -272,11 +287,16 @@
damage_mulitplier_penalty = 1.1
threshold_minimum = 40
threshold_penalty = 30 // burns cause significant decrease in limb integrity compared to other wounds
- status_effect_type = /datum/status_effect/wound/burn/moderate
+ status_effect_type = /datum/status_effect/wound/burn/flesh/moderate
flesh_damage = 5
scar_keyword = "burnmoderate"
-/datum/wound/burn/severe
+/datum/wound_pregen_data/flesh_burn/second_degree
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/burn/flesh/moderate
+
+/datum/wound/burn/flesh/severe
name = "Third Degree Burns"
desc = "Patient is suffering extreme burns with full skin penetration, creating serious risk of infection and greatly reduced limb integrity."
treat_text = "Recommended immediate disinfection and excision of any infected skin, followed by bandaging and ointment. If the limb has locked up, it must be amputated, augmented or treated with cryogenics."
@@ -286,13 +306,18 @@
damage_mulitplier_penalty = 1.2
threshold_minimum = 80
threshold_penalty = 40
- status_effect_type = /datum/status_effect/wound/burn/severe
+ status_effect_type = /datum/status_effect/wound/burn/flesh/severe
treatable_by = list(/obj/item/flashlight/pen/paramedic, /obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh)
infestation_rate = 0.07 // appx 9 minutes to reach sepsis without any treatment
flesh_damage = 12.5
scar_keyword = "burnsevere"
-/datum/wound/burn/critical
+/datum/wound_pregen_data/flesh_burn/third_degree
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/burn/flesh/severe
+
+/datum/wound/burn/flesh/critical
name = "Catastrophic Burns"
desc = "Patient is suffering near complete loss of tissue and significantly charred muscle and bone, creating life-threatening risk of infection and negligible limb integrity."
treat_text = "Immediate surgical debriding of any infected skin, followed by potent tissue regeneration formula and bandaging. If the limb has locked up, it must be amputated, augmented or treated with cryogenics."
@@ -303,26 +328,42 @@
sound_effect = 'sound/effects/wounds/sizzle2.ogg'
threshold_minimum = 140
threshold_penalty = 80
- status_effect_type = /datum/status_effect/wound/burn/critical
+ status_effect_type = /datum/status_effect/wound/burn/flesh/critical
treatable_by = list(/obj/item/flashlight/pen/paramedic, /obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh)
infestation_rate = 0.075 // appx 4.33 minutes to reach sepsis without any treatment
flesh_damage = 20
scar_keyword = "burncritical"
+/datum/wound_pregen_data/flesh_burn/fourth_degree
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/burn/flesh/critical
+
///special severe wound caused by sparring interference or other god related punishments.
-/datum/wound/burn/severe/brand
+/datum/wound/burn/flesh/severe/brand
name = "Holy Brand"
desc = "Patient is suffering extreme burns from a strange brand marking, creating serious risk of infection and greatly reduced limb integrity."
examine_desc = "appears to have holy symbols painfully branded into their flesh, leaving severe burns."
occur_text = "chars rapidly into a strange pattern of holy symbols, burned into the flesh."
+/datum/wound_pregen_data/flesh_burn/holy
+ abstract = FALSE
+ can_be_randomly_generated = FALSE
+
+ wound_path_to_generate = /datum/wound/burn/flesh/severe/brand
/// special severe wound caused by the cursed slot machine.
-/datum/wound/burn/severe/cursed_brand
+
+/datum/wound/burn/flesh/severe/cursed_brand
name = "Ancient Brand"
- desc = "Patient is suffering extreme burns with oddly ornate brand markings, creating serious risk of infection and greatly reduced limb integrity."
+ desc = "Patient is suffering extreme burns with oddly ornate brand markings, creating serious risk of infection and greatly reduced limb integrity."
examine_desc = "appears to have ornate symbols painfully branded into their flesh, leaving severe burns"
occur_text = "chars rapidly into a pattern that can only be described as an agglomeration of several financial symbols, burned into the flesh"
-/datum/wound/burn/severe/cursed_brand/get_limb_examine_description()
+/datum/wound/burn/flesh/severe/cursed_brand/get_limb_examine_description()
return span_warning("The flesh on this limb has several ornate symbols burned into it, with pitting throughout.")
-*/
+
+/datum/wound_pregen_data/flesh_burn/cursed_brand
+ abstract = FALSE
+ can_be_randomly_generated = FALSE
+
+ wound_path_to_generate = /datum/wound/burn/flesh/severe/cursed_brand
diff --git a/code/datums/wounds/loss.dm b/code/datums/wounds/loss.dm
index 66dddc99e1d..d396b3a469f 100644
--- a/code/datums/wounds/loss.dm
+++ b/code/datums/wounds/loss.dm
@@ -1,3 +1,9 @@
+/datum/wound_pregen_data/loss
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/loss
+ required_limb_biostate = NONE
+ check_for_any = TRUE
/datum/wound/loss
name = "Dismemberment Wound"
@@ -11,9 +17,12 @@
wound_flags = null
already_scarred = TRUE // We manually assign scars for dismembers through endround missing limbs and aheals
+ /// The wound_type of the attack that caused us. Used to generate the description of our scar. Currently unused, but primarily exists in case non-biological wounds are added.
+ var/loss_wound_type
+
/// Our special proc for our special dismembering, the wounding type only matters for what text we have
-/datum/wound/loss/proc/apply_dismember(obj/item/bodypart/dismembered_part, wounding_type=WOUND_SLASH, outright = FALSE, attack_direction)
- if(!istype(dismembered_part) || !dismembered_part.owner || !(dismembered_part.body_zone in viable_zones) || isalien(dismembered_part.owner) || !dismembered_part.can_dismember())
+/datum/wound/loss/proc/apply_dismember(obj/item/bodypart/dismembered_part, wounding_type = WOUND_SLASH, outright = FALSE, attack_direction)
+ if(!istype(dismembered_part) || !dismembered_part.owner || !(dismembered_part.body_zone in get_viable_zones()) || isalien(dismembered_part.owner) || !dismembered_part.can_dismember())
qdel(src)
return
@@ -23,7 +32,28 @@
if(dismembered_part.body_zone == BODY_ZONE_CHEST)
occur_text = "is split open, causing [victim.p_their()] internal organs to spill out!"
self_msg = "is split open, causing your internal organs to spill out!"
- else if(outright)
+ else
+ occur_text = dismembered_part.get_dismember_message(wounding_type, outright)
+
+ var/msg = span_bolddanger("[victim]'s [dismembered_part.plaintext_zone] [occur_text]")
+
+ victim.visible_message(msg, span_userdanger("Your [dismembered_part.plaintext_zone] [self_msg ? self_msg : occur_text]"))
+
+ loss_wound_type = wounding_type
+
+ set_limb(dismembered_part)
+ second_wind()
+ log_wound(victim, src)
+ if(dismembered_part.can_bleed() && wounding_type != WOUND_BURN && victim.blood_volume)
+ victim.spray_blood(attack_direction, severity)
+ dismembered_part.dismember(wounding_type == WOUND_BURN ? BURN : BRUTE, wound_type = wounding_type)
+ qdel(src)
+ return TRUE
+
+/obj/item/bodypart/proc/get_dismember_message(wounding_type, outright)
+ var/occur_text
+
+ if(outright)
switch(wounding_type)
if(WOUND_BLUNT)
occur_text = "is outright smashed to a gross pulp, severing it completely!"
@@ -34,25 +64,34 @@
if(WOUND_BURN)
occur_text = "is outright incinerated, falling to dust!"
else
+ var/bone_text
+ if (biological_state & BIO_BONE)
+ bone_text = "bone"
+ else if (biological_state & BIO_METAL)
+ bone_text = "metal"
+
+ var/tissue_text
+ if (biological_state & BIO_FLESH)
+ tissue_text = "flesh"
+ else if (biological_state & BIO_WIRED)
+ tissue_text = "wire"
+
switch(wounding_type)
if(WOUND_BLUNT)
- occur_text = "is shattered through the last bone holding it together, severing it completely!"
+ occur_text = "is shattered through the last [bone_text] holding it together, severing it completely!"
if(WOUND_SLASH)
- occur_text = "is slashed through the last tissue holding it together, severing it completely!"
+ occur_text = "is slashed through the last [tissue_text] holding it together, severing it completely!"
if(WOUND_PIERCE)
- occur_text = "is pierced through the last tissue holding it together, severing it completely!"
+ occur_text = "is pierced through the last [tissue_text] holding it together, severing it completely!"
if(WOUND_BURN)
occur_text = "is completely incinerated, falling to dust!"
- var/msg = span_bolddanger("[victim]'s [dismembered_part.plaintext_zone] [occur_text]")
+ return occur_text
- victim.visible_message(msg, span_userdanger("Your [dismembered_part.plaintext_zone] [self_msg ? self_msg : occur_text]"))
+/datum/wound/loss/get_scar_file(obj/item/bodypart/scarred_limb, add_to_scars)
+ if (scarred_limb.biological_state & BIO_FLESH)
+ return FLESH_SCAR_FILE
+ if (scarred_limb.biological_state & BIO_BONE)
+ return BONE_SCAR_FILE
- set_limb(dismembered_part)
- second_wind()
- log_wound(victim, src)
- if(wounding_type != WOUND_BURN && victim.blood_volume)
- victim.spray_blood(attack_direction, severity)
- dismembered_part.dismember(wounding_type == WOUND_BURN ? BURN : BRUTE)
- qdel(src)
- return TRUE
+ return ..()
diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm
index 0f49496c91b..72dac45a877 100644
--- a/code/datums/wounds/pierce.dm
+++ b/code/datums/wounds/pierce.dm
@@ -1,19 +1,22 @@
-//SKYRAT EDIT REMOVAL - MOVED - MEDICINE
-/*
-
/*
Piercing wounds
*/
-
/datum/wound/pierce
+ wound_type = WOUND_PIERCE
+
+/datum/wound/pierce/bleed
name = "Piercing Wound"
sound_effect = 'sound/weapons/slice.ogg'
processes = TRUE
- wound_type = WOUND_PIERCE
treatable_by = list(/obj/item/stack/medical/suture)
treatable_tool = TOOL_CAUTERY
base_treat_time = 3 SECONDS
- wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE)
+ wound_flags = (ACCEPTS_GAUZE)
+
+ wound_series = WOUND_SERIES_FLESH_SLASH_BLEED
+
+ scar_file = FLESH_SCAR_FILE
+
/// How much blood we start losing when this wound is first applied
var/initial_flow
@@ -25,12 +28,14 @@
/// If we let off blood when hit, the max blood lost is this * the incoming damage
var/internal_bleeding_coefficient
-/datum/wound/pierce/wound_injury(datum/wound/old_wound = null, attack_direction = null)
+/datum/wound/pierce/bleed/wound_injury(datum/wound/old_wound = null, attack_direction = null)
set_blood_flow(initial_flow)
if(!no_bleeding && attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY)
victim.spray_blood(attack_direction, severity)
-/datum/wound/pierce/receive_damage(wounding_type, wounding_dmg, wound_bonus)
+ return ..()
+
+/datum/wound/pierce/bleed/receive_damage(wounding_type, wounding_dmg, wound_bonus)
if(victim.stat == DEAD || (wounding_dmg < 5) || no_bleeding || !victim.blood_volume || !prob(internal_bleeding_chance + wounding_dmg))
return
if(limb.current_gauze?.splint_factor)
@@ -52,7 +57,7 @@
new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
victim.add_splatter_floor(get_step(victim.loc, victim.dir))
-/datum/wound/pierce/get_bleed_rate_of_change()
+/datum/wound/pierce/bleed/get_bleed_rate_of_change()
//basically if a species doesn't bleed, the wound is stagnant and will not heal on it's own (nor get worse)
if(no_bleeding)
return BLOOD_FLOW_STEADY
@@ -62,7 +67,10 @@
return BLOOD_FLOW_DECREASING
return BLOOD_FLOW_STEADY
-/datum/wound/pierce/handle_process(seconds_per_tick, times_fired)
+/datum/wound/pierce/bleed/handle_process(seconds_per_tick, times_fired)
+ if (!victim || IS_IN_STASIS(victim))
+ return
+
set_blood_flow(min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW))
if(!no_bleeding)
@@ -81,31 +89,33 @@
if(blood_flow <= 0)
qdel(src)
-/datum/wound/pierce/on_stasis(seconds_per_tick, times_fired)
+/datum/wound/pierce/bleed/on_stasis(seconds_per_tick, times_fired)
. = ..()
if(blood_flow <= 0)
qdel(src)
-/datum/wound/pierce/check_grab_treatments(obj/item/I, mob/user)
+/datum/wound/pierce/bleed/check_grab_treatments(obj/item/I, mob/user)
if(I.get_temperature()) // if we're using something hot but not a cautery, we need to be aggro grabbing them first, so we don't try treating someone we're eswording
return TRUE
-/datum/wound/pierce/treat(obj/item/I, mob/user)
+/datum/wound/pierce/bleed/treat(obj/item/I, mob/user)
if(istype(I, /obj/item/stack/medical/suture))
- suture(I, user)
+ return suture(I, user)
else if(I.tool_behaviour == TOOL_CAUTERY || I.get_temperature())
- tool_cauterize(I, user)
+ return tool_cauterize(I, user)
-/datum/wound/pierce/on_xadone(power)
+/datum/wound/pierce/bleed/on_xadone(power)
. = ..()
- adjust_blood_flow(-0.03 * power) // i think it's like a minimum of 3 power, so .09 blood_flow reduction per tick is pretty good for 0 effort
-/datum/wound/pierce/on_synthflesh(power)
+ if (limb) // parent can cause us to be removed, so its reasonable to check if we're still applied
+ adjust_blood_flow(-0.03 * power) // i think it's like a minimum of 3 power, so .09 blood_flow reduction per tick is pretty good for 0 effort
+
+/datum/wound/pierce/bleed/on_synthflesh(power)
. = ..()
adjust_blood_flow(-0.025 * power) // 20u * 0.05 = -1 blood flow, less than with slashes but still good considering smaller bleed rates
/// If someone is using a suture to close this puncture
-/datum/wound/pierce/proc/suture(obj/item/stack/medical/suture/I, mob/user)
+/datum/wound/pierce/bleed/proc/suture(obj/item/stack/medical/suture/I, mob/user)
var/self_penalty_mult = (user == victim ? 1.4 : 1)
var/treatment_delay = base_treat_time * self_penalty_mult
@@ -116,7 +126,7 @@
user.visible_message(span_notice("[user] begins stitching [victim]'s [limb.plaintext_zone] with [I]..."), span_notice("You begin stitching [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone] with [I]..."))
if(!do_after(user, treatment_delay, target = victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
- return
+ return TRUE
var/bleeding_wording = (no_bleeding ? "holes" : "bleeding")
user.visible_message(span_green("[user] stitches up some of the [bleeding_wording] on [victim]."), span_green("You stitch up some of the [bleeding_wording] on [user == victim ? "yourself" : "[victim]"]."))
var/blood_sutured = I.stop_bleeding / self_penalty_mult
@@ -125,12 +135,13 @@
I.use(1)
if(blood_flow > 0)
- try_treating(I, user)
+ return try_treating(I, user)
else
to_chat(user, span_green("You successfully close the hole in [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone]."))
+ return TRUE
/// If someone is using either a cautery tool or something with heat to cauterize this pierce
-/datum/wound/pierce/proc/tool_cauterize(obj/item/I, mob/user)
+/datum/wound/pierce/bleed/proc/tool_cauterize(obj/item/I, mob/user)
var/improv_penalty_mult = (I.tool_behaviour == TOOL_CAUTERY ? 1 : 1.25) // 25% longer and less effective if you don't use a real cautery
var/self_penalty_mult = (user == victim ? 1.5 : 1) // 50% longer and less effective if you do it to yourself
@@ -144,7 +155,7 @@
user.visible_message(span_danger("[user] begins cauterizing [victim]'s [limb.plaintext_zone] with [I]..."), span_warning("You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone] with [I]..."))
if(!do_after(user, treatment_delay, target = victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
- return
+ return TRUE
var/bleeding_wording = (no_bleeding ? "holes" : "bleeding")
user.visible_message(span_green("[user] cauterizes some of the [bleeding_wording] on [victim]."), span_green("You cauterize some of the [bleeding_wording] on [victim]."))
@@ -155,13 +166,19 @@
adjust_blood_flow(-blood_cauterized)
if(blood_flow > 0)
- try_treating(I, user)
+ return try_treating(I, user)
+ return TRUE
+
+/datum/wound_pregen_data/flesh_pierce
+ abstract = TRUE
+
+ required_limb_biostate = (BIO_FLESH)
/datum/wound/pierce/get_limb_examine_description()
return span_warning("The flesh on this limb appears badly perforated.")
-/datum/wound/pierce/moderate
- name = "Minor Breakage"
+/datum/wound/pierce/bleed/moderate
+ name = "Minor Skin Breakage"
desc = "Patient's skin has been broken open, causing severe bruising and minor internal bleeding in affected area."
treat_text = "Treat affected site with bandaging or exposure to extreme cold. In dire cases, brief exposure to vacuum may suffice." // space is cold in ss13, so it's like an ice pack!
examine_desc = "has a small, circular hole, gently bleeding"
@@ -177,12 +194,17 @@
status_effect_type = /datum/status_effect/wound/pierce/moderate
scar_keyword = "piercemoderate"
-/datum/wound/pierce/moderate/update_descriptions()
+/datum/wound_pregen_data/flesh_pierce/breakage
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/pierce/bleed/moderate
+
+/datum/wound/pierce/bleed/moderate/update_descriptions()
if(no_bleeding)
examine_desc = "has a small, circular hole"
occur_text = "splits a small hole open"
-/datum/wound/pierce/severe
+/datum/wound/pierce/bleed/severe
name = "Open Puncture"
desc = "Patient's internal tissue is penetrated, causing sizeable internal bleeding and reduced limb stability."
treat_text = "Repair punctures in skin by suture or cautery, extreme cold may also work."
@@ -199,11 +221,16 @@
status_effect_type = /datum/status_effect/wound/pierce/severe
scar_keyword = "piercesevere"
-/datum/wound/pierce/severe/update_descriptions()
+/datum/wound_pregen_data/flesh_pierce/open_puncture
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/pierce/bleed/severe
+
+/datum/wound/pierce/bleed/severe/update_descriptions()
if(no_bleeding)
occur_text = "tears a hole open"
-/datum/wound/pierce/critical
+/datum/wound/pierce/bleed/critical
name = "Ruptured Cavity"
desc = "Patient's internal tissue and circulatory system is shredded, causing significant internal bleeding and damage to internal organs."
treat_text = "Surgical repair of puncture wound, followed by supervised resanguination."
@@ -219,5 +246,9 @@
threshold_penalty = 50
status_effect_type = /datum/status_effect/wound/pierce/critical
scar_keyword = "piercecritical"
- wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE | MANGLES_FLESH)
-*/
+ wound_flags = (ACCEPTS_GAUZE | MANGLES_FLESH)
+
+/datum/wound_pregen_data/flesh_pierce/cavity
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/pierce/bleed/critical
diff --git a/code/datums/wounds/scars/_scars.dm b/code/datums/wounds/scars/_scars.dm
index db6275ea62b..bf33af3fefc 100644
--- a/code/datums/wounds/scars/_scars.dm
+++ b/code/datums/wounds/scars/_scars.dm
@@ -22,11 +22,14 @@
var/visibility = 2
/// Whether this scar can actually be covered up by clothing
var/coverable = TRUE
- /// Obviously, scars that describe damaged flesh wouldn't apply to a skeleton (in some cases like bone wounds, there can be different descriptions for skeletons and fleshy humanoids)
- var/biology = BIO_FLESH_BONE
/// If we're a persistent scar or may become one, we go in this character slot
var/persistent_character_slot = 0
+ /// The biostates we require from a limb to give them our scar.
+ var/required_limb_biostate
+ /// If false, we will only check to see if a limb has ALL our biostates, instead of just any.
+ var/check_any_biostates
+
/datum/scar/Destroy(force, ...)
if(limb)
LAZYREMOVE(limb.scars, src)
@@ -47,6 +50,19 @@
* * add_to_scars- Should always be TRUE unless you're just storing a scar for later usage, like how cuts want to store a scar for the highest severity of cut, rather than the severity when the wound is fully healed (probably demoted to moderate)
*/
/datum/scar/proc/generate(obj/item/bodypart/BP, datum/wound/W, add_to_scars=TRUE)
+
+ if (!W.can_scar)
+ qdel(src)
+ return
+
+ var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[W.type]
+ if (!pregen_data)
+ qdel(src)
+ return
+
+ required_limb_biostate = pregen_data.required_limb_biostate
+ check_any_biostates = pregen_data.check_for_any
+
limb = BP
RegisterSignal(limb, COMSIG_QDELETING, PROC_REF(limb_gone))
@@ -59,12 +75,13 @@
if(victim)
LAZYADD(victim.all_scars, src)
- biology = limb?.biological_state || BIO_FLESH_BONE
+ var/scar_file = W.get_scar_file(BP, add_to_scars)
+ var/scar_keyword = W.get_scar_keyword(BP, add_to_scars)
+ if (!scar_file || !scar_keyword)
+ qdel(src)
+ return
- if((biology & BIO_BONE) && !(biology & BIO_FLESH))
- description = pick_list(BONE_SCAR_FILE, W.scar_keyword) || "general disfigurement"
- else // no specific support for flesh w/o bone scars since it's not really useful
- description = pick_list(FLESH_SCAR_FILE, W.scar_keyword) || "general disfigurement"
+ description = pick_list(W.get_scar_file(BP, add_to_scars), W.get_scar_keyword(BP, add_to_scars)) || "general disfigurement"
precise_location = pick_list_replacements(SCAR_LOC_FILE, limb.body_zone)
switch(W.severity)
@@ -86,22 +103,28 @@
LAZYADD(victim.all_scars, src)
/// Used to "load" a persistent scar
-/datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity=WOUND_SEVERITY_SEVERE, biology=BIO_FLESH_BONE, char_slot)
- if(!IS_ORGANIC_LIMB(BP))
+/datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity = WOUND_SEVERITY_SEVERE, required_limb_biostate = BIO_STANDARD, char_slot, check_any_biostates = FALSE)
+ if(!BP.scarrable)
qdel(src)
return
limb = BP
RegisterSignal(limb, COMSIG_QDELETING, PROC_REF(limb_gone))
- if(limb.owner)
- victim = limb.owner
- if(limb.biological_state != biology)
+ if (isnull(check_any_biostates)) // so we dont break old scars. NOTE: REMOVE AFTER VERSION NUMBER MOVES PAST 3
+ check_any_biostates = FALSE
+ if (check_any_biostates)
+ if (!(limb.biological_state & required_limb_biostate))
qdel(src)
return
+ else if (!((limb.biological_state & required_limb_biostate) == required_limb_biostate)) // check for all
+ qdel(src)
+ return
+ if(limb.owner)
+ victim = limb.owner
LAZYADD(victim.all_scars, src)
src.severity = severity
- src.biology = biology
+ src.required_limb_biostate = required_limb_biostate
persistent_character_slot = char_slot
LAZYADD(limb.scars, src)
@@ -163,9 +186,9 @@
/// Used to format a scar to save for either persistent scars, or for changeling disguises
/datum/scar/proc/format()
- return "[SCAR_CURRENT_VERSION]|[limb.body_zone]|[description]|[precise_location]|[severity]|[biology]|[persistent_character_slot]"
+ return "[SCAR_CURRENT_VERSION]|[limb.body_zone]|[description]|[precise_location]|[severity]|[required_limb_biostate]|[persistent_character_slot]|[check_any_biostates]"
/// Used to format a scar to save in preferences for persistent scars
-/datum/scar/proc/format_amputated(body_zone)
- description = pick_list(FLESH_SCAR_FILE, "dismember")
- return "[SCAR_CURRENT_VERSION]|[body_zone]|[description]|amputated|[WOUND_SEVERITY_LOSS]|[BIO_FLESH_BONE]|[persistent_character_slot]"
+/datum/scar/proc/format_amputated(body_zone, scar_file = FLESH_SCAR_FILE)
+ description = pick_list(scar_file, "dismember")
+ return "[SCAR_CURRENT_VERSION]|[body_zone]|[description]|amputated|[WOUND_SEVERITY_LOSS]|[required_limb_biostate]|[persistent_character_slot]|[check_any_biostates]"
diff --git a/code/datums/wounds/scars/_static_scar_data.dm b/code/datums/wounds/scars/_static_scar_data.dm
new file mode 100644
index 00000000000..942dcffff9c
--- /dev/null
+++ b/code/datums/wounds/scars/_static_scar_data.dm
@@ -0,0 +1,20 @@
+GLOBAL_LIST_INIT_TYPED(all_static_scar_data, /datum/static_scar_data, generate_static_scar_data())
+
+/proc/generate_static_scar_data()
+ RETURN_TYPE(/list/datum/static_scar_data)
+
+ var/list/datum/wound_pregen_data/data = list()
+
+ for (var/datum/wound_pregen_data/path as anything in typecacheof(path = /datum/static_scar_data, ignore_root_path = TRUE))
+ if (initial(path.abstract))
+ continue
+
+ var/datum/wound_pregen_data/pregen_data = new path
+ data[pregen_data.wound_path_to_generate] = pregen_data
+
+ return data
+
+/datum/static_scar_data
+ var/abstract = FALSE
+
+
diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm
index 97fb744d3b3..e8165368952 100644
--- a/code/datums/wounds/slash.dm
+++ b/code/datums/wounds/slash.dm
@@ -1,5 +1,3 @@
-//SKYRAT EDIT REMOVAL - MOVED - MEDICINE
-/*
/*
Slashing wounds
@@ -8,13 +6,26 @@
/datum/wound/slash
name = "Slashing (Cut) Wound"
sound_effect = 'sound/weapons/slice.ogg'
+ wound_type = WOUND_SLASH
+
+/datum/wound_pregen_data/flesh_slash
+ abstract = TRUE
+
+ required_limb_biostate = BIO_FLESH
+
+/datum/wound/slash/flesh
+ name = "Slashing (Cut) Flesh Wound"
processes = TRUE
wound_type = WOUND_SLASH
treatable_by = list(/obj/item/stack/medical/suture)
treatable_by_grabbed = list(/obj/item/gun/energy/laser)
treatable_tool = TOOL_CAUTERY
base_treat_time = 3 SECONDS
- wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE)
+ wound_flags = (ACCEPTS_GAUZE)
+
+ scar_file = FLESH_SCAR_FILE
+
+ wound_series = WOUND_SERIES_FLESH_SLASH_BLEED
/// How much blood we start losing when this wound is first applied
var/initial_flow
@@ -32,7 +43,7 @@
/// A bad system I'm using to track the worst scar we earned (since we can demote, we want the biggest our wound has been, not what it was when it was cured (probably moderate))
var/datum/scar/highest_scar
-/datum/wound/slash/wound_injury(datum/wound/slash/old_wound = null, attack_direction = null)
+/datum/wound/slash/flesh/wound_injury(datum/wound/slash/flesh/old_wound = null, attack_direction = null)
if(old_wound)
set_blood_flow(max(old_wound.blood_flow, initial_flow))
if(old_wound.severity > severity && old_wound.highest_scar)
@@ -48,24 +59,26 @@
set_highest_scar(new_scar)
new_scar.generate(limb, src, add_to_scars=FALSE)
-/datum/wound/slash/proc/set_highest_scar(datum/scar/new_scar)
+ return ..()
+
+/datum/wound/slash/flesh/proc/set_highest_scar(datum/scar/new_scar)
if(highest_scar)
UnregisterSignal(highest_scar, COMSIG_QDELETING)
if(new_scar)
RegisterSignal(new_scar, COMSIG_QDELETING, PROC_REF(clear_highest_scar))
highest_scar = new_scar
-/datum/wound/slash/proc/clear_highest_scar(datum/source)
+/datum/wound/slash/flesh/proc/clear_highest_scar(datum/source)
SIGNAL_HANDLER
set_highest_scar(null)
-/datum/wound/slash/remove_wound(ignore_limb, replaced)
+/datum/wound/slash/flesh/remove_wound(ignore_limb, replaced)
if(!replaced && highest_scar)
already_scarred = TRUE
highest_scar.lazy_attach(limb)
return ..()
-/datum/wound/slash/get_wound_description(mob/user)
+/datum/wound/slash/flesh/get_wound_description(mob/user)
if(!limb.current_gauze)
return ..()
@@ -84,11 +97,16 @@
return "[msg.Join()]"
-/datum/wound/slash/receive_damage(wounding_type, wounding_dmg, wound_bonus)
+/datum/wound/slash/flesh/receive_damage(wounding_type, wounding_dmg, wound_bonus)
+ if (!victim) // if we are dismembered, we can still take damage, its fine to check here
+ return
+
if(victim.stat != DEAD && wound_bonus != CANT_WOUND && wounding_type == WOUND_SLASH) // can't stab dead bodies to make it bleed faster this way
adjust_blood_flow(WOUND_SLASH_DAMAGE_FLOW_COEFF * wounding_dmg)
-/datum/wound/slash/drag_bleed_amount()
+ return ..()
+
+/datum/wound/slash/flesh/drag_bleed_amount()
// say we have 3 severe cuts with 3 blood flow each, pretty reasonable
// compare with being at 100 brute damage before, where you bled (brute/100 * 2), = 2 blood per tile
var/bleed_amt = min(blood_flow * 0.1, 1) // 3 * 3 * 0.1 = 0.9 blood total, less than before! the share here is .3 blood of course.
@@ -99,7 +117,7 @@
return bleed_amt
-/datum/wound/slash/get_bleed_rate_of_change()
+/datum/wound/slash/flesh/get_bleed_rate_of_change()
//basically if a species doesn't bleed, the wound is stagnant and will not heal on it's own (nor get worse)
if(no_bleeding)
return BLOOD_FLOW_STEADY
@@ -110,7 +128,11 @@
if(clot_rate < 0)
return BLOOD_FLOW_INCREASING
-/datum/wound/slash/handle_process(seconds_per_tick, times_fired)
+/datum/wound/slash/flesh/handle_process(seconds_per_tick, times_fired)
+
+ if (!victim || IS_IN_STASIS(victim))
+ return
+
// in case the victim has the NOBLOOD trait, the wound will simply not clot on it's own
if(!no_bleeding)
set_blood_flow(min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW))
@@ -133,36 +155,36 @@
if(blood_flow < minimum_flow)
if(demotes_to)
- replace_wound(demotes_to)
+ replace_wound(new demotes_to)
else
to_chat(victim, span_green("The cut on your [limb.plaintext_zone] has [no_bleeding ? "healed up" : "stopped bleeding"]!"))
qdel(src)
-/datum/wound/slash/on_stasis(seconds_per_tick, times_fired)
+/datum/wound/slash/flesh/on_stasis(seconds_per_tick, times_fired)
if(blood_flow >= minimum_flow)
return
if(demotes_to)
- replace_wound(demotes_to)
+ replace_wound(new demotes_to)
return
qdel(src)
/* BEWARE, THE BELOW NONSENSE IS MADNESS. bones.dm looks more like what I have in mind and is sufficiently clean, don't pay attention to this messiness */
-/datum/wound/slash/check_grab_treatments(obj/item/I, mob/user)
+/datum/wound/slash/flesh/check_grab_treatments(obj/item/I, mob/user)
if(istype(I, /obj/item/gun/energy/laser))
return TRUE
if(I.get_temperature()) // if we're using something hot but not a cautery, we need to be aggro grabbing them first, so we don't try treating someone we're eswording
return TRUE
-/datum/wound/slash/treat(obj/item/I, mob/user)
+/datum/wound/slash/flesh/treat(obj/item/I, mob/user)
if(istype(I, /obj/item/gun/energy/laser))
- las_cauterize(I, user)
+ return las_cauterize(I, user)
else if(I.tool_behaviour == TOOL_CAUTERY || I.get_temperature())
- tool_cauterize(I, user)
+ return tool_cauterize(I, user)
else if(istype(I, /obj/item/stack/medical/suture))
- suture(I, user)
+ return suture(I, user)
-/datum/wound/slash/try_handling(mob/living/carbon/human/user)
+/datum/wound/slash/flesh/try_handling(mob/living/carbon/human/user)
if(user.pulling != victim || user.zone_selected != limb.body_zone || !isfelinid(user) || !victim.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE))
return FALSE
if(DOING_INTERACTION_WITH_TARGET(user, victim))
@@ -179,7 +201,7 @@
return TRUE
/// if a felinid is licking this cut to reduce bleeding
-/datum/wound/slash/proc/lick_wounds(mob/living/carbon/human/user)
+/datum/wound/slash/flesh/proc/lick_wounds(mob/living/carbon/human/user)
// transmission is one way patient -> felinid since google said cat saliva is antiseptic or whatever, and also because felinids are already risking getting beaten for this even without people suspecting they're spreading a deathvirus
for(var/i in victim.diseases)
var/datum/disease/iter_disease = i
@@ -201,16 +223,18 @@
else if(demotes_to)
to_chat(user, span_green("You successfully lower the severity of [victim]'s cuts."))
-/datum/wound/slash/on_xadone(power)
+/datum/wound/slash/flesh/on_xadone(power)
. = ..()
- adjust_blood_flow(-0.03 * power) // i think it's like a minimum of 3 power, so .09 blood_flow reduction per tick is pretty good for 0 effort
-/datum/wound/slash/on_synthflesh(power)
+ if (limb) // parent can cause us to be removed, so its reasonable to check if we're still applied
+ adjust_blood_flow(-0.03 * power) // i think it's like a minimum of 3 power, so .09 blood_flow reduction per tick is pretty good for 0 effort
+
+/datum/wound/slash/flesh/on_synthflesh(power)
. = ..()
adjust_blood_flow(-0.075 * power) // 20u * 0.075 = -1.5 blood flow, pretty good for how little effort it is
/// If someone's putting a laser gun up to our cut to cauterize it
-/datum/wound/slash/proc/las_cauterize(obj/item/gun/energy/laser/lasgun, mob/user)
+/datum/wound/slash/flesh/proc/las_cauterize(obj/item/gun/energy/laser/lasgun, mob/user)
var/self_penalty_mult = (user == victim ? 1.25 : 1)
user.visible_message(span_warning("[user] begins aiming [lasgun] directly at [victim]'s [limb.plaintext_zone]..."), span_userdanger("You begin aiming [lasgun] directly at [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone]..."))
if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
@@ -223,9 +247,10 @@
victim.emote("scream")
adjust_blood_flow(-1 * (damage / (5 * self_penalty_mult))) // 20 / 5 = 4 bloodflow removed, p good
victim.visible_message(span_warning("The cuts on [victim]'s [limb.plaintext_zone] scar over!"))
+ return TRUE
/// If someone is using either a cautery tool or something with heat to cauterize this cut
-/datum/wound/slash/proc/tool_cauterize(obj/item/I, mob/user)
+/datum/wound/slash/flesh/proc/tool_cauterize(obj/item/I, mob/user)
var/improv_penalty_mult = (I.tool_behaviour == TOOL_CAUTERY ? 1 : 1.25) // 25% longer and less effective if you don't use a real cautery
var/self_penalty_mult = (user == victim ? 1.5 : 1) // 50% longer and less effective if you do it to yourself
@@ -248,12 +273,14 @@
adjust_blood_flow(-blood_cauterized)
if(blood_flow > minimum_flow)
- try_treating(I, user)
+ return try_treating(I, user)
else if(demotes_to)
to_chat(user, span_green("You successfully lower the severity of [user == victim ? "your" : "[victim]'s"] cuts."))
+ return TRUE
+ return FALSE
/// If someone is using a suture to close this cut
-/datum/wound/slash/proc/suture(obj/item/stack/medical/suture/I, mob/user)
+/datum/wound/slash/flesh/proc/suture(obj/item/stack/medical/suture/I, mob/user)
var/self_penalty_mult = (user == victim ? 1.4 : 1)
var/treatment_delay = base_treat_time * self_penalty_mult
@@ -264,7 +291,7 @@
user.visible_message(span_notice("[user] begins stitching [victim]'s [limb.plaintext_zone] with [I]..."), span_notice("You begin stitching [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone] with [I]..."))
if(!do_after(user, treatment_delay, target = victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
- return
+ return TRUE
var/bleeding_wording = (no_bleeding ? "cuts" : "bleeding")
user.visible_message(span_green("[user] stitches up some of the [bleeding_wording] on [victim]."), span_green("You stitch up some of the [bleeding_wording] on [user == victim ? "yourself" : "[victim]"]."))
var/blood_sutured = I.stop_bleeding / self_penalty_mult
@@ -273,14 +300,16 @@
I.use(1)
if(blood_flow > minimum_flow)
- try_treating(I, user)
+ return try_treating(I, user)
else if(demotes_to)
to_chat(user, span_green("You successfully lower the severity of [user == victim ? "your" : "[victim]'s"] cuts."))
+ return TRUE
+ return TRUE
/datum/wound/slash/get_limb_examine_description()
return span_warning("The flesh on this limb appears badly lacerated.")
-/datum/wound/slash/moderate
+/datum/wound/slash/flesh/moderate
name = "Rough Abrasion"
desc = "Patient's skin has been badly scraped, generating moderate blood loss."
treat_text = "Application of clean bandages or first-aid grade sutures, followed by food and rest."
@@ -293,14 +322,19 @@
clot_rate = 0.05
threshold_minimum = 20
threshold_penalty = 10
- status_effect_type = /datum/status_effect/wound/slash/moderate
+ status_effect_type = /datum/status_effect/wound/slash/flesh/moderate
scar_keyword = "slashmoderate"
-/datum/wound/slash/moderate/update_descriptions()
+/datum/wound/slash/flesh/moderate/update_descriptions()
if(no_bleeding)
occur_text = "is cut open"
-/datum/wound/slash/severe
+/datum/wound_pregen_data/flesh_slash/abrasion
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/slash/flesh/moderate
+
+/datum/wound/slash/flesh/severe
name = "Open Laceration"
desc = "Patient's skin is ripped clean open, allowing significant blood loss."
treat_text = "Speedy application of first-aid grade sutures and clean bandages, followed by vitals monitoring to ensure recovery."
@@ -313,22 +347,25 @@
clot_rate = 0.03
threshold_minimum = 50
threshold_penalty = 25
- demotes_to = /datum/wound/slash/moderate
- status_effect_type = /datum/status_effect/wound/slash/severe
+ demotes_to = /datum/wound/slash/flesh/moderate
+ status_effect_type = /datum/status_effect/wound/slash/flesh/severe
scar_keyword = "slashsevere"
-/datum/wound/slash/severe/update_descriptions()
+/datum/wound_pregen_data/flesh_slash/laceration
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/slash/flesh/severe
+
+/datum/wound/slash/flesh/severe/update_descriptions()
if(no_bleeding)
occur_text = "is ripped open"
-/datum/wound/slash/critical
+/datum/wound/slash/flesh/critical
name = "Weeping Avulsion"
desc = "Patient's skin is completely torn open, along with significant loss of tissue. Extreme blood loss will lead to quick death without intervention."
treat_text = "Immediate bandaging and either suturing or cauterization, followed by supervised resanguination."
examine_desc = "is carved down to the bone, spraying blood wildly"
- examine_desc = "is carved down to the bone"
occur_text = "is torn open, spraying blood wildly"
- occur_text = "is torn open"
sound_effect = 'sound/effects/wounds/blood3.ogg'
severity = WOUND_SEVERITY_CRITICAL
initial_flow = 4
@@ -336,25 +373,40 @@
clot_rate = -0.015 // critical cuts actively get worse instead of better
threshold_minimum = 80
threshold_penalty = 40
- demotes_to = /datum/wound/slash/severe
- status_effect_type = /datum/status_effect/wound/slash/critical
+ demotes_to = /datum/wound/slash/flesh/severe
+ status_effect_type = /datum/status_effect/wound/slash/flesh/critical
scar_keyword = "slashcritical"
- wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE | MANGLES_FLESH)
+ wound_flags = (ACCEPTS_GAUZE | MANGLES_FLESH)
-/datum/wound/slash/moderate/many_cuts
+/datum/wound_pregen_data/flesh_slash/avulsion
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/slash/flesh/critical
+
+/datum/wound/slash/flesh/moderate/many_cuts
name = "Numerous Small Slashes"
desc = "Patient's skin has numerous small slashes and cuts, generating moderate blood loss."
examine_desc = "has a ton of small cuts"
occur_text = "is cut numerous times, leaving many small slashes."
+/datum/wound_pregen_data/flesh_slash/cuts
+ abstract = FALSE
+ can_be_randomly_generated = FALSE
+
+ wound_path_to_generate = /datum/wound/slash/flesh/moderate/many_cuts
+
// Subtype for cleave (heretic spell)
-/datum/wound/slash/critical/cleave
+/datum/wound/slash/flesh/critical/cleave
name = "Burning Avulsion"
examine_desc = "is ruptured, spraying blood wildly"
clot_rate = 0.01
-/datum/wound/slash/critical/cleave/update_descriptions()
+/datum/wound/slash/flesh/critical/cleave/update_descriptions()
if(no_bleeding)
occur_text = "is ruptured"
-*/
+/datum/wound_pregen_data/flesh_slash/cleave
+ abstract = FALSE
+ can_be_randomly_generated = FALSE
+
+ wound_path_to_generate = /datum/wound/slash/flesh/critical/cleave
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 87250df486e..29c5ea6e4df 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -541,6 +541,7 @@
SEND_SIGNAL(source, COMSIG_REAGENTS_EXPOSE_ATOM, src, reagents, methods, volume_modifier, show_message)
for(var/datum/reagent/current_reagent as anything in reagents)
. |= current_reagent.expose_atom(src, reagents[current_reagent])
+ SEND_SIGNAL(src, COMSIG_ATOM_AFTER_EXPOSE_REAGENTS, reagents, source, methods, volume_modifier, show_message)
/// Are you allowed to drop this atom
/atom/proc/AllowDrop()
diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm
index 10c19336119..816814b1bcf 100644
--- a/code/game/machinery/iv_drip.dm
+++ b/code/game/machinery/iv_drip.dm
@@ -248,7 +248,7 @@
var/list/arm_zones = shuffle(list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM))
var/obj/item/bodypart/chosen_limb = attached_mob.get_bodypart(arm_zones[1]) || attached_mob.get_bodypart(arm_zones[2]) || attached_mob.get_bodypart(BODY_ZONE_CHEST)
chosen_limb.receive_damage(3)
- chosen_limb.force_wound_upwards(/datum/wound/pierce/moderate, wound_source = "IV needle")
+ chosen_limb.force_wound_upwards(/datum/wound/pierce/bleed/moderate, wound_source = "IV needle")
else
visible_message(span_warning("[attached] is detached from [src]."))
detach_iv()
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 447ebb87d03..14fc91ea7d0 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -286,7 +286,7 @@
holo_cooldown = world.time + 10 SECONDS
return
-// see: [/datum/wound/burn/proc/uv()]
+// see: [/datum/wound/burn/flesh/proc/uv()]
/obj/item/flashlight/pen/paramedic
name = "paramedic penlight"
desc = "A high-powered UV penlight intended to help stave off infection in the field on serious burned patients. Probably really bad to look into."
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 7bfb330d271..d071e3465af 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -434,9 +434,9 @@
patient.emote("scream")
for(var/i in patient.bodyparts)
var/obj/item/bodypart/bone = i
- var/datum/wound/blunt/severe/oof_ouch = new
+ var/datum/wound/blunt/bone/severe/oof_ouch = new
oof_ouch.apply_wound(bone, wound_source = "bone gel")
- var/datum/wound/blunt/critical/oof_OUCH = new
+ var/datum/wound/blunt/bone/critical/oof_OUCH = new
oof_OUCH.apply_wound(bone, wound_source = "bone gel")
for(var/i in patient.bodyparts)
diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm
index deede6ea83b..533fc755fa1 100644
--- a/code/game/objects/items/teleportation.dm
+++ b/code/game/objects/items/teleportation.dm
@@ -465,7 +465,8 @@
new /obj/effect/temp_visual/teleport_abductor/syndi_teleporter(mobloc)
new /obj/effect/temp_visual/teleport_abductor/syndi_teleporter(emergency_destination)
balloon_alert(user, "emergency teleport triggered!")
- make_bloods(mobloc, emergency_destination, user)
+ if (!HAS_TRAIT(user, TRAIT_NOBLOOD))
+ make_bloods(mobloc, emergency_destination, user)
playsound(mobloc, SFX_SPARKS, 50, 1, SHORT_RANGE_SOUND_EXTRARANGE)
playsound(emergency_destination, 'sound/effects/phasein.ogg', 25, 1, SHORT_RANGE_SOUND_EXTRARANGE)
playsound(emergency_destination, SFX_SPARKS, 50, 1, SHORT_RANGE_SOUND_EXTRARANGE)
diff --git a/code/modules/admin/smites/bloodless.dm b/code/modules/admin/smites/bloodless.dm
index f42711c0f74..db68a1cd3a2 100644
--- a/code/modules/admin/smites/bloodless.dm
+++ b/code/modules/admin/smites/bloodless.dm
@@ -10,9 +10,9 @@
var/mob/living/carbon/carbon_target = target
for(var/_limb in carbon_target.bodyparts)
var/obj/item/bodypart/limb = _limb
- var/type_wound = pick(list(/datum/wound/slash/severe, /datum/wound/slash/moderate))
+ var/type_wound = pick(list(/datum/wound/slash/flesh/severe, /datum/wound/slash/flesh/moderate))
limb.force_wound_upwards(type_wound, smited = TRUE)
- type_wound = pick(list(/datum/wound/slash/critical, /datum/wound/slash/severe, /datum/wound/slash/moderate))
+ type_wound = pick(list(/datum/wound/slash/flesh/critical, /datum/wound/slash/flesh/severe, /datum/wound/slash/flesh/moderate))
limb.force_wound_upwards(type_wound, smited = TRUE)
- type_wound = pick(list(/datum/wound/slash/critical, /datum/wound/slash/severe))
+ type_wound = pick(list(/datum/wound/slash/flesh/critical, /datum/wound/slash/flesh/severe))
limb.force_wound_upwards(type_wound, smited = TRUE)
diff --git a/code/modules/admin/smites/boneless.dm b/code/modules/admin/smites/boneless.dm
index 09361cf75cb..5d859669a68 100644
--- a/code/modules/admin/smites/boneless.dm
+++ b/code/modules/admin/smites/boneless.dm
@@ -12,10 +12,10 @@
var/mob/living/carbon/carbon_target = target
for(var/obj/item/bodypart/limb as anything in carbon_target.bodyparts)
var/type_wound = pick(list(
- /datum/wound/blunt/critical,
- /datum/wound/blunt/severe,
- /datum/wound/blunt/critical,
- /datum/wound/blunt/severe,
- /datum/wound/blunt/moderate,
+ /datum/wound/blunt/bone/critical,
+ /datum/wound/blunt/bone/severe,
+ /datum/wound/blunt/bone/critical,
+ /datum/wound/blunt/bone/severe,
+ /datum/wound/blunt/bone/moderate,
))
limb.force_wound_upwards(type_wound, smited = TRUE)
diff --git a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm
index a2e234f3ab8..26395396c06 100644
--- a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm
@@ -269,7 +269,7 @@
var/mob/living/carbon/carbon_target = target
var/obj/item/bodypart/bodypart = pick(carbon_target.bodyparts)
- var/datum/wound/slash/severe/crit_wound = new()
+ var/datum/wound/slash/flesh/severe/crit_wound = new()
crit_wound.apply_wound(bodypart, attack_direction = get_dir(source, target))
/datum/heretic_knowledge/summon/stalker
diff --git a/code/modules/antagonists/heretic/magic/blood_cleave.dm b/code/modules/antagonists/heretic/magic/blood_cleave.dm
index eca27e55566..d5317f23e34 100644
--- a/code/modules/antagonists/heretic/magic/blood_cleave.dm
+++ b/code/modules/antagonists/heretic/magic/blood_cleave.dm
@@ -19,7 +19,7 @@
/// The radius of the cleave effect
var/cleave_radius = 1
/// What type of wound we apply
- var/wound_type = /datum/wound/slash/critical/cleave
+ var/wound_type = /datum/wound/slash/flesh/critical/cleave
/datum/action/cooldown/spell/pointed/cleave/is_valid_target(atom/cast_on)
return ..() && ishuman(cast_on)
@@ -45,7 +45,7 @@
)
var/obj/item/bodypart/bodypart = pick(victim.bodyparts)
- var/datum/wound/slash/crit_wound = new wound_type()
+ var/datum/wound/slash/flesh/crit_wound = new wound_type()
crit_wound.apply_wound(bodypart)
victim.apply_damage(20, BURN, wound_bonus = CANT_WOUND)
@@ -56,7 +56,7 @@
/datum/action/cooldown/spell/pointed/cleave/long
name = "Lesser Cleave"
cooldown_time = 60 SECONDS
- wound_type = /datum/wound/slash/severe
+ wound_type = /datum/wound/slash/flesh/severe
/obj/effect/temp_visual/cleave
icon = 'icons/effects/eldritch.dmi'
diff --git a/code/modules/antagonists/heretic/status_effects/mark_effects.dm b/code/modules/antagonists/heretic/status_effects/mark_effects.dm
index 83a7e7accff..c454ebdc462 100644
--- a/code/modules/antagonists/heretic/status_effects/mark_effects.dm
+++ b/code/modules/antagonists/heretic/status_effects/mark_effects.dm
@@ -61,7 +61,7 @@
if(ishuman(owner))
var/mob/living/carbon/human/human_owner = owner
var/obj/item/bodypart/bodypart = pick(human_owner.bodyparts)
- var/datum/wound/slash/severe/crit_wound = new()
+ var/datum/wound/slash/flesh/severe/crit_wound = new()
crit_wound.apply_wound(bodypart)
return ..()
diff --git a/code/modules/antagonists/traitor/objectives/eyesnatching.dm b/code/modules/antagonists/traitor/objectives/eyesnatching.dm
index 49c53180b39..d912be2384a 100644
--- a/code/modules/antagonists/traitor/objectives/eyesnatching.dm
+++ b/code/modules/antagonists/traitor/objectives/eyesnatching.dm
@@ -179,8 +179,8 @@
if(!do_after(user, eye_snatch_enthusiasm, target = target, extra_checks = CALLBACK(src, PROC_REF(eyeballs_exist), eyeballies, head, target)))
return
- var/datum/wound/blunt/severe/severe_wound_type = /datum/wound/blunt/severe
- var/datum/wound/blunt/critical/critical_wound_type = /datum/wound/blunt/critical
+ var/datum/wound/blunt/bone/severe/severe_wound_type = /datum/wound/blunt/bone/severe
+ var/datum/wound/blunt/bone/critical/critical_wound_type = /datum/wound/blunt/bone/critical
target.apply_damage(20, BRUTE, BODY_ZONE_HEAD, wound_bonus = rand(initial(severe_wound_type.threshold_minimum), initial(critical_wound_type.threshold_minimum) + 10), attacking_item = src)
target.visible_message(
span_danger("[src] pierces through [target]'s skull, horribly mutilating their eyes!"),
diff --git a/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm b/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm
index 8af5d4e5a9d..ca2b6ec39c9 100644
--- a/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm
+++ b/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm
@@ -13,7 +13,7 @@
/obj/effect/mob_spawn/corpse/human/tigercultist/perforated/special(mob/living/carbon/human/spawned_human)
. = ..()
- var/datum/wound/pierce/critical/exit_hole = new()
+ var/datum/wound/pierce/bleed/critical/exit_hole = new()
exit_hole.apply_wound(spawned_human.get_bodypart(BODY_ZONE_CHEST))
/// A fun drink enjoyed by the tiger cooperative, might corrode your brain if you drink the whole bottle
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 2ddb20b8b4e..36399dbc71d 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -1268,12 +1268,17 @@
else
wound_type = forced_type
else
- wound_type = pick(GLOB.global_all_wound_types)
+ for (var/datum/wound/path as anything in shuffle(GLOB.all_wound_pregen_data))
+ var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[path]
+ if (pregen_data.can_be_applied_to(scar_part, random_roll = TRUE))
+ wound_type = path
+ break
- var/datum/wound/phantom_wound = new wound_type
- scaries.generate(scar_part, phantom_wound)
- scaries.fake = TRUE
- QDEL_NULL(phantom_wound)
+ if (wound_type) // can feasibly happen, if its an inorganic limb/cant be wounded/scarred
+ var/datum/wound/phantom_wound = new wound_type
+ scaries.generate(scar_part, phantom_wound)
+ scaries.fake = TRUE
+ QDEL_NULL(phantom_wound)
/mob/living/carbon/is_face_visible()
return !(wear_mask?.flags_inv & HIDEFACE) && !(head?.flags_inv & HIDEFACE)
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 4a4dbeeec70..3ab34e70230 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -775,7 +775,6 @@
return ..()
var/obj/item/bodypart/grasped_part = get_bodypart(zone_selected)
- //SKYRAT EDIT CHANGE BEGIN - MEDICAL
/*
if(!grasped_part?.get_modified_bleed_rate())
return
@@ -795,9 +794,8 @@
QDEL_NULL(grasp)
return
grasp.grasp_limb(grasped_part)
- */
+ */ // SKYRAT EDIT REMOVAL - MODULARIZED INTO grasp.dm's self_grasp_bleeding_limb !! IF THIS PROC IS UPDATED, PUT IT IN THERE !!
self_grasp_bleeding_limb(grasped_part, supress_message)
- //SKYRAT EDIT CHANGE END
/// an abstract item representing you holding your own limb to staunch the bleeding, see [/mob/living/carbon/proc/grabbedby] will probably need to find somewhere else to put this.
/obj/item/hand_item/self_grasp
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 16b5b478af0..ec44dcec13e 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -104,6 +104,9 @@
/// All of the scars a carbon has afflicted throughout their limbs
var/list/all_scars
+ /// Assoc list of BODY_ZONE -> WOUND_TYPE. Set when a limb is dismembered, unset when one is attached. Used for determining what scar to add when it comes time to generate them.
+ var/list/body_zone_dismembered_by
+
/// Simple modifier for whether this mob can handle greater or lesser skillchip complexity. See /datum/mutation/human/biotechcompat/ for example.
var/skillchip_complexity_modifier = 0
diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm
index 3d1e08f8151..75a31925c33 100644
--- a/code/modules/mob/living/carbon/examine.dm
+++ b/code/modules/mob/living/carbon/examine.dm
@@ -154,7 +154,7 @@
SEND_SIGNAL(src, COMSIG_ATOM_EXAMINE, user, .)
-//SKYRAT EDIT REMOVAL - MOVED - MEDICAL
+//SKYRAT EDIT REMOVAL - MOVED - MEDICAL - carbon_examine.dm
/*
/mob/living/carbon/examine_more(mob/user)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm
index a77156dddfa..eb4bb54ea80 100644
--- a/code/modules/mob/living/carbon/human/_species.dm
+++ b/code/modules/mob/living/carbon/human/_species.dm
@@ -1327,7 +1327,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
if(!(prob(25 + (weapon.force * 2))))
return TRUE
- if(IS_ORGANIC_LIMB(affecting))
+ if(affecting.can_bleed())
weapon.add_mob_blood(human) //Make the weapon bloody, not the person.
if(prob(weapon.force * 2)) //blood spatter!
bloody = TRUE
@@ -1706,19 +1706,19 @@ GLOBAL_LIST_EMPTY(features_by_species)
// Lets pick a random body part and check for an existing burn
var/obj/item/bodypart/bodypart = pick(humi.bodyparts)
- var/datum/wound/burn/existing_burn = locate(/datum/wound/burn) in bodypart.wounds
+ var/datum/wound/burn/flesh/existing_burn = locate(/datum/wound/burn) in bodypart.wounds
// If we have an existing burn try to upgrade it
if(existing_burn)
switch(existing_burn.severity)
if(WOUND_SEVERITY_MODERATE)
if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 400) // 800k
- bodypart.force_wound_upwards(/datum/wound/burn/severe, wound_source = "hot temperatures")
+ bodypart.force_wound_upwards(/datum/wound/burn/flesh/severe, wound_source = "hot temperatures")
if(WOUND_SEVERITY_SEVERE)
if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 2800) // 3200k
- bodypart.force_wound_upwards(/datum/wound/burn/critical, wound_source = "hot temperatures")
+ bodypart.force_wound_upwards(/datum/wound/burn/flesh/critical, wound_source = "hot temperatures")
else // If we have no burn apply the lowest level burn
- bodypart.force_wound_upwards(/datum/wound/burn/moderate, wound_source = "hot temperatures")
+ bodypart.force_wound_upwards(/datum/wound/burn/flesh/moderate, wound_source = "hot temperatures")
// always take some burn damage
var/burn_damage = HEAT_DAMAGE_LEVEL_1
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index b8d21e60daa..1475d61ed38 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -705,11 +705,7 @@
//SKYRAT EDIT ADDITION BEGIN - MEDICAL
if(body_part.current_gauze)
- var/datum/bodypart_aid/current_gauze = body_part.current_gauze
- combined_msg += "\t [span_notice("Your [body_part.name] is [current_gauze.desc_prefix] with [current_gauze.get_description()].")]"
- if(body_part.current_splint)
- var/datum/bodypart_aid/current_splint = body_part.current_splint
- combined_msg += "\t [span_notice("Your [body_part.name] is [current_splint.desc_prefix] with [current_splint.get_description()].")]"
+ combined_msg += "\t [span_notice("Your [body_part.name] is [body_part.current_gauze.get_gauze_usage_prefix()] with [body_part.current_gauze.get_gauze_description()].")]"
//SKYRAT EDIT END
for(var/t in missing)
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 41273946aa5..818ca1cf860 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -169,13 +169,15 @@
if(LAZYLEN(scar_data) != SCAR_SAVE_LENGTH)
return // invalid, should delete
var/version = text2num(scar_data[SCAR_SAVE_VERS])
- if(!version || version < SCAR_CURRENT_VERSION) // get rid of old scars
+ if(!version || version != SCAR_CURRENT_VERSION) // get rid of scars using a incompatable version
return
if(specified_char_index && (mind?.original_character_slot_index != specified_char_index))
return
+ if (isnull(text2num(scar_data[SCAR_SAVE_BIOLOGY])))
+ return
var/obj/item/bodypart/the_part = get_bodypart("[scar_data[SCAR_SAVE_ZONE]]")
var/datum/scar/scaries = new
- return scaries.load(the_part, scar_data[SCAR_SAVE_VERS], scar_data[SCAR_SAVE_DESC], scar_data[SCAR_SAVE_PRECISE_LOCATION], text2num(scar_data[SCAR_SAVE_SEVERITY]), text2num(scar_data[SCAR_SAVE_BIOLOGY]), text2num(scar_data[SCAR_SAVE_CHAR_SLOT]))
+ return scaries.load(the_part, scar_data[SCAR_SAVE_VERS], scar_data[SCAR_SAVE_DESC], scar_data[SCAR_SAVE_PRECISE_LOCATION], text2num(scar_data[SCAR_SAVE_SEVERITY]), text2num(scar_data[SCAR_SAVE_BIOLOGY]), text2num(scar_data[SCAR_SAVE_CHAR_SLOT]), text2num(scar_data[SCAR_SAVE_CHECK_ANY_BIO]))
/// Read all the scars we have for the designated character/scar slots, verify they're good/dump them if they're old/wrong format, create them on the user, and write the scars that passed muster back to the file
/mob/living/carbon/human/proc/load_persistent_scars()
diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm
index ed9eb3c1094..58a46da81a4 100644
--- a/code/modules/mob/living/carbon/human/species_types/abductors.dm
+++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm
@@ -9,6 +9,8 @@
TRAIT_VIRUSIMMUNE,
TRAIT_NOBLOOD,
TRAIT_CHUNKYFINGERS_IGNORE_BATON,
+ TRAIT_NODISMEMBER,
+ TRAIT_NEVER_WOUNDED
)
mutanttongue = /obj/item/organ/internal/tongue/abductor
mutantstomach = null
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 cf16c236605..3f5f46edf6c 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -7,7 +7,6 @@
TRAIT_GENELESS,
TRAIT_LAVA_IMMUNE,
TRAIT_NOBREATH,
- TRAIT_NODISMEMBER,
TRAIT_NOBLOOD,
TRAIT_NOFIRE,
TRAIT_PIERCEIMMUNE,
@@ -15,6 +14,8 @@
TRAIT_NO_DNA_COPY,
TRAIT_NO_TRANSFORMATION_STING,
TRAIT_NO_AUGMENTS,
+ TRAIT_NODISMEMBER,
+ TRAIT_NEVER_WOUNDED
)
mutantheart = null
mutantlungs = null
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 d7b8fdf34db..a8b1be203a3 100644
--- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
@@ -10,6 +10,8 @@
TRAIT_RADIMMUNE,
TRAIT_VIRUSIMMUNE,
TRAIT_NOBLOOD,
+ TRAIT_NODISMEMBER,
+ TRAIT_NEVER_WOUNDED
)
inherent_factions = list(FACTION_FAITHLESS)
changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index c2e46d697cd..cea0d00fc21 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -49,8 +49,6 @@
handle_diseases(seconds_per_tick, times_fired)// DEAD check is in the proc itself; we want it to spread even if the mob is dead, but to handle its disease-y properties only if you're not.
- handle_wounds(seconds_per_tick, times_fired)
-
if (QDELETED(src)) // diseases can qdel the mob via transformations
return
@@ -65,6 +63,8 @@
handle_gravity(seconds_per_tick, times_fired)
+ handle_wounds(seconds_per_tick, times_fired)
+
if(machine)
machine.check_eye(src)
diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm
index 0dddb90c1db..31cbe153f9e 100644
--- a/code/modules/paperwork/paper_cutter.dm
+++ b/code/modules/paperwork/paper_cutter.dm
@@ -171,7 +171,7 @@
to_chat(user, span_userdanger("You neatly cut [stored_paper][clumsy ? "... and your finger in the process!" : "."]"))
if(clumsy)
var/obj/item/bodypart/finger = user.get_active_hand()
- var/datum/wound/slash/moderate/papercut = new
+ var/datum/wound/slash/flesh/moderate/papercut = new
papercut.apply_wound(finger, wound_source = "paper cut")
stored_paper = null
qdel(stored_paper)
diff --git a/code/modules/religion/festival/instrument_rites.dm b/code/modules/religion/festival/instrument_rites.dm
index 83b064a6398..a1c94c92425 100644
--- a/code/modules/religion/festival/instrument_rites.dm
+++ b/code/modules/religion/festival/instrument_rites.dm
@@ -90,7 +90,7 @@
/datum/religion_rites/song_tuner/pain/finish_effect(mob/living/carbon/human/listener, atom/song_source)
var/obj/item/bodypart/sliced_limb = pick(listener.bodyparts)
- sliced_limb.force_wound_upwards(/datum/wound/slash/moderate/many_cuts)
+ sliced_limb.force_wound_upwards(/datum/wound/slash/flesh/moderate/many_cuts)
/datum/religion_rites/song_tuner/lullaby
name = "Spiritual Lullaby"
diff --git a/code/modules/religion/sparring/sparring_datum.dm b/code/modules/religion/sparring/sparring_datum.dm
index f292293f90c..bfaa94d65a8 100644
--- a/code/modules/religion/sparring/sparring_datum.dm
+++ b/code/modules/religion/sparring/sparring_datum.dm
@@ -216,7 +216,7 @@
var/mob/living/carbon/human/branded = interfering
to_chat(interfering, span_warning("[GLOB.deity] brands your flesh for interfering with [chaplain]'s sparring match!!"))
var/obj/item/bodypart/branded_limb = pick(branded.bodyparts)
- branded_limb.force_wound_upwards(/datum/wound/burn/severe/brand, wound_source = "divine intervention")
+ branded_limb.force_wound_upwards(/datum/wound/burn/flesh/severe/brand, wound_source = "divine intervention")
branded.emote("scream")
flubs--
diff --git a/code/modules/spells/spell_types/touch/scream_for_me.dm b/code/modules/spells/spell_types/touch/scream_for_me.dm
index 941885e7577..e10bdaebcc5 100644
--- a/code/modules/spells/spell_types/touch/scream_for_me.dm
+++ b/code/modules/spells/spell_types/touch/scream_for_me.dm
@@ -21,7 +21,7 @@
span_userdanger("The spell bounces from [victim]'s skin back into your arm!"),
)
var/obj/item/bodypart/to_wound = caster.get_holding_bodypart_of_item(hand)
- to_wound.force_wound_upwards(/datum/wound/slash/critical)
+ to_wound.force_wound_upwards(/datum/wound/slash/flesh/critical)
/datum/action/cooldown/spell/touch/scream_for_me/cast_on_hand_hit(obj/item/melee/touch_attack/hand, mob/living/victim, mob/living/carbon/caster)
if(!ishuman(victim))
@@ -29,7 +29,7 @@
var/mob/living/carbon/human/human_victim = victim
human_victim.emote("scream")
for(var/obj/item/bodypart/to_wound as anything in human_victim.bodyparts)
- to_wound.force_wound_upwards(/datum/wound/slash/critical)
+ to_wound.force_wound_upwards(/datum/wound/slash/flesh/critical)
return TRUE
/obj/item/melee/touch_attack/scream_for_me
diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm
index 2b85e7843ff..5967e3502dc 100644
--- a/code/modules/surgery/bodyparts/_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/_bodyparts.dm
@@ -1,3 +1,6 @@
+#define AUGGED_LIMB_EMP_BRUTE_DAMAGE 3
+#define AUGGED_LIMB_EMP_BURN_DAMAGE 2
+
/obj/item/bodypart
name = "limb"
desc = "Why is it detached..."
@@ -22,14 +25,15 @@
/// DO NOT MODIFY DIRECTLY. Use set_owner()
var/mob/living/carbon/owner
+ /// If this limb can be scarred.
+ var/scarrable = TRUE
+
/**
* A bitfield of biological states, exclusively used to determine which wounds this limb will get,
* as well as how easily it will happen.
- * Set to BIO_FLESH_BONE because most species have both flesh and bone in their limbs.
- *
- * This currently has absolutely no meaning for robotic limbs.
+ * Set to BIO_STANDARD because most species have both flesh bone and blood in their limbs.
*/
- var/biological_state = BIO_FLESH_BONE
+ var/biological_state = BIO_STANDARD
///A bitfield of bodytypes for clothing, surgery, and misc information
var/bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC
///Defines when a bodypart should not be changed. Example: BP_BLOCK_CHANGE_SPECIES prevents the limb from being overwritten on species gain
@@ -66,16 +70,14 @@
var/speed_modifier = 0
// Limb disabling variables
+ ///Whether it is possible for the limb to be disabled whatsoever. TRUE means that it is possible.
+ var/can_be_disabled = FALSE //Defaults to FALSE, as only human limbs can be disabled, and only the appendages.
///Controls if the limb is disabled. TRUE means it is disabled (similar to being removed, but still present for the sake of targeted interactions).
var/bodypart_disabled = FALSE
///Handles limb disabling by damage. If 0 (0%), a limb can't be disabled via damage. If 1 (100%), it is disabled at max limb damage. Anything between is the percentage of damage against maximum limb damage needed to disable the limb.
- //var/disabling_threshold_percentage = 0 //ORIGINAL
- var/disabling_threshold_percentage = 1 //SKYRAT EDIT CHANGE - COMBAT
- ///Whether it is possible for the limb to be disabled whatsoever. TRUE means that it is possible.
- var/can_be_disabled = FALSE //Defaults to FALSE, as only human limbs can be disabled, and only the appendages.
-
- // Damage state variables
+ var/disabling_threshold_percentage = 1 //SKYRAT EDIT CHANGE - COMBAT - ORIGINAL : var/disabling_threshold_percentage = 0
+ // Damage variables
///A mutiplication of the burn and brute damage that the limb's stored damage contributes to its attached mob's overall wellbeing.
var/body_damage_coeff = 1
///The current amount of brute damage the limb has
@@ -152,20 +154,8 @@
var/cached_bleed_rate = 0
/// How much generic bleedstacks we have on this bodypart
var/generic_bleedstacks
- //SKYRAT EDIT CHANGE BEGIN - MEDICAL
- /*
/// If we have a gauze wrapping currently applied (not including splints)
var/obj/item/stack/current_gauze
- */
- /// If we have a gauze wrapping currently applied
- var/datum/bodypart_aid/gauze/current_gauze
- /// If we have a splint currently applied
- var/datum/bodypart_aid/splint/current_splint
- /// What icon do we use to render this limb? Ususally used by robotic limb augments.
- var/rendered_bp_icon
- /// Do we use an organic render for this robotic limb?
- var/organic_render = TRUE
- //SKYRAT EDIT CHANGE END
/// If something is currently grasping this bodypart and trying to staunch bleeding (see [/obj/item/hand_item/self_grasp])
var/obj/item/hand_item/self_grasp/grasped_by
@@ -200,6 +190,16 @@
/// List of the above datums which have actually been instantiated, managed automatically
var/list/feature_offsets = list()
+ /// In the case we dont have dismemberable features, or literally cant get wounds, we will use this percent to determine when we can be dismembered.
+ /// Compared to our ABSOLUTE maximum. Stored in decimal; 0.8 = 80%.
+ var/hp_percent_to_dismemberable = 0.8
+ /// If true, we will use [hp_percent_to_dismemberable] even if we are dismemberable via wounds. Useful for things with extreme wound resistance.
+ var/use_alternate_dismemberment_calc_even_if_mangleable = FALSE
+ /// If false, no wound that can be applied to us can mangle our flesh. Used for determining if we should use [hp_percent_to_dismemberable] instead of normal dismemberment.
+ var/any_existing_wound_can_mangle_our_flesh
+ /// If false, no wound that can be applied to us can mangle our bone. Used for determining if we should use [hp_percent_to_dismemberable] instead of normal dismemberment.
+ var/any_existing_wound_can_mangle_our_bone
+
/obj/item/bodypart/apply_fantasy_bonuses(bonus)
. = ..()
unarmed_damage_low = modify_fantasy_variable("unarmed_damage_low", unarmed_damage_low, bonus, minimum = 1)
@@ -241,12 +241,6 @@
if(length(wounds))
stack_trace("[type] qdeleted with [length(wounds)] uncleared wounds")
wounds.Cut()
- //SKYRAT EDIT ADDITION BEGIN - MEDICAL
- if(current_gauze)
- qdel(current_gauze)
- if(current_splint)
- qdel(current_splint)
- //SKYRAT EDIT ADDITION END
if(length(external_organs))
for(var/obj/item/organ/external/external_organ as anything in external_organs)
@@ -415,11 +409,7 @@
var/atom/drop_loc = drop_location()
if(IS_ORGANIC_LIMB(src))
playsound(drop_loc, 'sound/misc/splort.ogg', 50, TRUE, -1)
- //seep_gauze(9999) // destroy any existing gauze if any exists
- if(current_gauze)
- qdel(current_gauze)
- if(current_splint)
- qdel(current_splint)
+ seep_gauze(9999) // destroy any existing gauze if any exists
for(var/obj/item/organ/bodypart_organ in get_organs())
bodypart_organ.transfer_to_limb(src, owner)
for(var/obj/item/organ/external/external in external_organs)
@@ -505,40 +495,75 @@
else if (sharpness & SHARP_POINTY)
wounding_type = WOUND_PIERCE
- if(owner)
+ if(owner) // i tried to modularize the below, but the modifications to wounding_dmg and wounding_type cant be extracted to a proc
var/mangled_state = get_mangled_state()
var/easy_dismember = HAS_TRAIT(owner, TRAIT_EASYDISMEMBER) // if we have easydismember, we don't reduce damage when redirecting damage to different types (slashing weapons on mangled/skinless limbs attack at 100% instead of 50%)
- //Handling for bone only/flesh only(none right now)/flesh and bone targets
- switch(biological_state)
- // if we're bone only, all cutting attacks go straight to the bone
- if(BIO_BONE)
- if(wounding_type == WOUND_SLASH)
- wounding_type = WOUND_BLUNT
- wounding_dmg *= (easy_dismember ? 1 : 0.6)
- else if(wounding_type == WOUND_PIERCE)
- wounding_type = WOUND_BLUNT
- wounding_dmg *= (easy_dismember ? 1 : 0.75)
- if((mangled_state & BODYPART_MANGLED_BONE) && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus))
- return
- // note that there's no handling for BIO_FLESH since we don't have any that are that right now (slimepeople maybe someday)
- // standard humanoids
- if(BIO_FLESH_BONE)
- //SKYRAT EDIT ADDITION BEGIN - MEDICAL
- //We do a body zone check here because muscles dont have any variants for head or chest, and rolling a muscle wound on them wound end up on a wasted wound roll
- if(body_zone != BODY_ZONE_CHEST && body_zone != BODY_ZONE_HEAD && prob(35))
- wounding_type = WOUND_MUSCLE
- //SKYRAT EDIT ADDITION END
- // if we've already mangled the skin (critical slash or piercing wound), then the bone is exposed, and we can damage it with sharp weapons at a reduced rate
- // So a big sharp weapon is still all you need to destroy a limb
- if((mangled_state & BODYPART_MANGLED_FLESH) && !(mangled_state & BODYPART_MANGLED_BONE) && sharpness)
- playsound(src, "sound/effects/wounds/crackandbleed.ogg", 100)
- if(wounding_type == WOUND_SLASH && !easy_dismember)
- wounding_dmg *= 0.6 // edged weapons pass along 60% of their wounding damage to the bone since the power is spread out over a larger area
- if(wounding_type == WOUND_PIERCE && !easy_dismember)
- wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated
- wounding_type = WOUND_BLUNT
- else if((mangled_state & BODYPART_MANGLED_FLESH) && (mangled_state & BODYPART_MANGLED_BONE) && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus))
+ var/has_exterior = FALSE
+ var/has_interior = FALSE
+
+ for (var/state as anything in GLOB.bio_state_states)
+ var/flag = text2num(state)
+ if (!(biological_state & flag))
+ continue
+
+ var/value = GLOB.bio_state_states[state]
+ if (value & BIO_EXTERIOR)
+ has_exterior = TRUE
+ if (value & BIO_INTERIOR)
+ has_interior = TRUE
+
+ if (has_exterior && has_interior)
+ break
+
+ // We put this here so we dont increase init time by doing this all at once on initialization
+ // Effectively, we "lazy load"
+ if (isnull(any_existing_wound_can_mangle_our_bone) || isnull(any_existing_wound_can_mangle_our_flesh))
+ any_existing_wound_can_mangle_our_bone = FALSE
+ any_existing_wound_can_mangle_our_flesh = FALSE
+ for (var/datum/wound/wound_type as anything in GLOB.all_wound_pregen_data)
+ var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound_type]
+ if (!pregen_data.can_be_applied_to(src, random_roll = TRUE)) // we only consider randoms because non-randoms are usually really specific
+ continue
+ if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_FLESH)
+ any_existing_wound_can_mangle_our_flesh = TRUE
+ if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_BONE)
+ any_existing_wound_can_mangle_our_bone = TRUE
+
+ if (any_existing_wound_can_mangle_our_bone && any_existing_wound_can_mangle_our_flesh)
+ break
+
+ var/can_theoretically_be_dismembered = (any_existing_wound_can_mangle_our_bone || (any_existing_wound_can_mangle_our_flesh && !has_exterior))
+
+ var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_BONE) == BODYPART_MANGLED_BONE))
+ var/interior_ready_to_dismember = (!has_interior || ((mangled_state & BODYPART_MANGLED_FLESH) == BODYPART_MANGLED_FLESH))
+
+ // if we're bone only, all cutting attacks go straight to the bone
+ if(has_exterior && interior_ready_to_dismember)
+ if(wounding_type == WOUND_SLASH)
+ wounding_type = WOUND_BLUNT
+ wounding_dmg *= (easy_dismember ? 1 : 0.6)
+ else if(wounding_type == WOUND_PIERCE)
+ wounding_type = WOUND_BLUNT
+ wounding_dmg *= (easy_dismember ? 1 : 0.75)
+ if(exterior_ready_to_dismember && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus))
+ return
+ else
+ // if we've already mangled the skin (critical slash or piercing wound), then the bone is exposed, and we can damage it with sharp weapons at a reduced rate
+ // So a big sharp weapon is still all you need to destroy a limb
+ if(has_exterior && interior_ready_to_dismember && !(mangled_state & BODYPART_MANGLED_BONE) && sharpness)
+ playsound(src, "sound/effects/wounds/crackandbleed.ogg", 100)
+ if(wounding_type == WOUND_SLASH && !easy_dismember)
+ wounding_dmg *= 0.6 // edged weapons pass along 60% of their wounding damage to the bone since the power is spread out over a larger area
+ if(wounding_type == WOUND_PIERCE && !easy_dismember)
+ wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated
+ wounding_type = WOUND_BLUNT
+ else if(interior_ready_to_dismember && exterior_ready_to_dismember && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus))
+ return
+ if (use_alternate_dismemberment_calc_even_if_mangleable || !can_theoretically_be_dismembered)
+ var/percent_to_total_max = (get_damage() / max_damage)
+ if (percent_to_total_max >= hp_percent_to_dismemberable)
+ if (try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus))
return
// now we have our wounding_type and are ready to carry on with wounds and dealing the actual damage
@@ -552,15 +577,14 @@
damaged_percent = DAMAGED_BODYPART_BONUS_WOUNDING_THRESHOLD
wounding_dmg = min(DAMAGED_BODYPART_BONUS_WOUNDING_BONUS, wounding_dmg + (damaged_percent * DAMAGED_BODYPART_BONUS_WOUNDING_COEFF))
- if(current_gauze)
- current_gauze.take_damage()
- if(current_splint)
- current_splint.take_damage()
+ if (istype(current_gauze, /obj/item/stack/medical/gauze))
+ var/obj/item/stack/medical/gauze/our_gauze = current_gauze
+ our_gauze.get_hit()
//SKYRAT EDIT ADDITION END - MEDICAL
check_wounding(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus, attack_direction, damage_source = damage_source)
for(var/datum/wound/iter_wound as anything in wounds)
- iter_wound.receive_damage(wounding_type, wounding_dmg, wound_bonus)
+ iter_wound.receive_damage(wounding_type, wounding_dmg, wound_bonus, damage_source)
/*
// END WOUND HANDLING
@@ -1162,7 +1186,7 @@
if(!owner)
return
- if(HAS_TRAIT(owner, TRAIT_NOBLOOD) || !IS_ORGANIC_LIMB(src))
+ if(!can_bleed())
if(cached_bleed_rate != old_bleed_rate)
update_part_wound_overlay()
return
@@ -1203,7 +1227,7 @@
/obj/item/bodypart/proc/update_part_wound_overlay()
if(!owner)
return FALSE
- if(HAS_TRAIT(owner, TRAIT_NOBLOOD) || !IS_ORGANIC_LIMB(src))
+ if(!can_bleed())
if(bleed_overlay_icon)
bleed_overlay_icon = null
owner.update_wound_overlays()
@@ -1236,6 +1260,11 @@
#undef BLEED_OVERLAY_MED
#undef BLEED_OVERLAY_GUSH
+/obj/item/bodypart/proc/can_bleed()
+ SHOULD_BE_PURE(TRUE)
+
+ return ((biological_state & BIO_BLOODED) && (!owner || !HAS_TRAIT(owner, TRAIT_NOBLOOD)))
+
/**
* apply_gauze() is used to- well, apply gauze to a bodypart
*
@@ -1247,7 +1276,6 @@
* Arguments:
* * gauze- Just the gauze stack we're taking a sheet from to apply here
*/
-/* SKYRAT EDIT REMOVAL
/obj/item/bodypart/proc/apply_gauze(obj/item/stack/gauze)
if(!istype(gauze) || !gauze.absorption_capacity)
return
@@ -1259,7 +1287,6 @@
gauze.use(1)
if(newly_gauzed)
SEND_SIGNAL(src, COMSIG_BODYPART_GAUZED, gauze)
-*/
/**
* seep_gauze() is for when a gauze wrapping absorbs blood or pus from wounds, lowering its absorption capacity.
@@ -1269,7 +1296,6 @@
* Arguments:
* * seep_amt - How much absorption capacity we're removing from our current bandages (think, how much blood or pus are we soaking up this tick?)
*/
-/* SKYRAT EDIT REMOVAL
/obj/item/bodypart/proc/seep_gauze(seep_amt = 0)
if(!current_gauze)
return
@@ -1278,7 +1304,6 @@
owner.visible_message(span_danger("\The [current_gauze.name] on [owner]'s [name] falls away in rags."), span_warning("\The [current_gauze.name] on your [name] falls away in rags."), vision_distance=COMBAT_MESSAGE_RANGE)
QDEL_NULL(current_gauze)
SEND_SIGNAL(src, COMSIG_BODYPART_GAUZE_DESTROYED)
-*/
///Loops through all of the bodypart's external organs and update's their color.
/obj/item/bodypart/proc/recolor_external_organs()
@@ -1328,14 +1353,17 @@
/obj/item/bodypart/emp_act(severity)
. = ..()
- if(. & EMP_PROTECT_WIRES || !(bodytype & BODYTYPE_ROBOTIC))
+ if(. & EMP_PROTECT_WIRES || !IS_ROBOTIC_LIMB(src))
return FALSE
owner.visible_message(span_danger("[owner]'s [src.name] seems to malfunction!"))
+ // with defines at the time of writing, this is 3 brute and 2 burn
+ // 3 + 2 = 5, with 6 limbs thats 30, on a heavy 60
+ // 60 * 0.8 = 48
var/time_needed = 10 SECONDS
- var/brute_damage = 2.5 // SKYRAT EDIT : Balances direct EMP damage for Brute - SR's synth values are multiplied 3x 2.5 * 1.3 * 1.3
- var/burn_damage = 2 // SKYRAT EDIT : Balances direct EMP damage for Burn - SR's synth values are multiplied 3x 2 * 1.3 * 1.3
+ var/brute_damage = AUGGED_LIMB_EMP_BRUTE_DAMAGE
+ var/burn_damage = AUGGED_LIMB_EMP_BURN_DAMAGE
if(severity == EMP_HEAVY)
time_needed *= 2
brute_damage *= 1.3 // SKYRAT EDIT : Balance - Lowers total damage from ~125 Brute to ~30
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index 850bfc7b9e7..22a325f1974 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -1,11 +1,11 @@
/obj/item/bodypart/proc/can_dismember(obj/item/item)
- if(bodypart_flags & BODYPART_UNREMOVABLE)
+ if(bodypart_flags & BODYPART_UNREMOVABLE || (owner && HAS_TRAIT(owner, TRAIT_NODISMEMBER)))
return FALSE
return TRUE
///Remove target limb from it's owner, with side effects.
-/obj/item/bodypart/proc/dismember(dam_type = BRUTE, silent=TRUE)
+/obj/item/bodypart/proc/dismember(dam_type = BRUTE, silent=TRUE, wound_type)
if(!owner || (bodypart_flags & BODYPART_UNREMOVABLE))
return FALSE
var/mob/living/carbon/limb_owner = owner
@@ -22,11 +22,15 @@
playsound(get_turf(limb_owner), 'sound/effects/dismember.ogg', 80, TRUE)
limb_owner.add_mood_event("dismembered_[body_zone]", /datum/mood_event/dismembered, src)
limb_owner.add_mob_memory(/datum/memory/was_dismembered, lost_limb = src)
+
+ if (wound_type)
+ LAZYSET(limb_owner.body_zone_dismembered_by, body_zone, wound_type)
+
drop_limb()
limb_owner.update_equipment_speed_mods() // Update in case speed affecting item unequipped by dismemberment
var/turf/owner_location = limb_owner.loc
- if(istype(owner_location))
+ if(wound_type != WOUND_BURN && istype(owner_location) && can_bleed())
limb_owner.add_splatter_floor(owner_location)
if(QDELETED(src)) //Could have dropped into lava/explosion/chasm/whatever
@@ -34,8 +38,9 @@
if(dam_type == BURN)
burn()
return TRUE
- add_mob_blood(limb_owner)
- limb_owner.bleed(rand(20, 40))
+ if (can_bleed())
+ add_mob_blood(limb_owner)
+ limb_owner.bleed(rand(20, 40))
var/direction = pick(GLOB.cardinals)
var/t_range = rand(2,max(throw_range/2, 2))
var/turf/target_turf = get_turf(src)
@@ -47,10 +52,10 @@
if(new_turf.density)
break
throw_at(target_turf, throw_range, throw_speed)
+
return TRUE
-
-/obj/item/bodypart/chest/dismember()
+/obj/item/bodypart/chest/dismember(dam_type = BRUTE, silent=TRUE, wound_type)
if(!owner)
return FALSE
var/mob/living/carbon/chest_owner = owner
@@ -59,7 +64,7 @@
if(HAS_TRAIT(chest_owner, TRAIT_NODISMEMBER))
return FALSE
. = list()
- if(isturf(chest_owner.loc))
+ if(wound_type != WOUND_BURN && isturf(chest_owner.loc) && can_bleed())
chest_owner.add_splatter_floor(chest_owner.loc)
playsound(get_turf(chest_owner), 'sound/misc/splort.ogg', 80, TRUE)
for(var/obj/item/organ/organ as anything in chest_owner.organs)
@@ -81,8 +86,6 @@
. += cavity_item
cavity_item = null
-
-
///limb removal. The "special" argument is used for swapping a limb with a new one without the effects of losing a limb kicking in.
/obj/item/bodypart/proc/drop_limb(special, dismembered)
if(!owner)
@@ -180,14 +183,17 @@
* * bare_wound_bonus: ditto above
*/
/obj/item/bodypart/proc/try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)
+ if (!can_dismember())
+ return
+
if(wounding_dmg < DISMEMBER_MINIMUM_DAMAGE)
return
var/base_chance = wounding_dmg
base_chance += (get_damage() / max_damage * 50) // how much damage we dealt with this blow, + 50% of the damage percentage we already had on this bodypart
- if(locate(/datum/wound/blunt/critical) in wounds) // we only require a severe bone break, but if there's a critical bone break, we'll add 15% more
- base_chance += 15
+ for (var/datum/wound/iterated_wound as anything in wounds)
+ base_chance += iterated_wound.get_dismember_chance_bonus(base_chance)
if(prob(base_chance))
var/datum/wound/loss/dismembering = new
@@ -328,6 +334,8 @@
set_owner(new_limb_owner)
new_limb_owner.add_bodypart(src)
+ LAZYREMOVE(new_limb_owner.body_zone_dismembered_by, body_zone)
+
if(special) //non conventional limb attachment
for(var/datum/surgery/attach_surgery as anything in new_limb_owner.surgeries) //if we had an ongoing surgery to attach a new limb, we stop it.
var/surgery_zone = check_zone(attach_surgery.location)
@@ -416,12 +424,15 @@
/mob/living/carbon/proc/regenerate_limbs(list/excluded_zones = list())
SEND_SIGNAL(src, COMSIG_CARBON_REGENERATE_LIMBS, excluded_zones)
var/list/zone_list = 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/dismembered_by_copy = body_zone_dismembered_by?.Copy()
+
if(length(excluded_zones))
zone_list -= excluded_zones
for(var/limb_zone in zone_list)
- regenerate_limb(limb_zone)
+ regenerate_limb(limb_zone, dismembered_by_copy)
-/mob/living/carbon/proc/regenerate_limb(limb_zone)
+/mob/living/carbon/proc/regenerate_limb(limb_zone, list/dismembered_by_copy = body_zone_dismembered_by?.Copy())
var/obj/item/bodypart/limb
if(get_bodypart(limb_zone))
return FALSE
@@ -431,9 +442,16 @@
qdel(limb)
return FALSE
limb.update_limb(is_creating = TRUE)
- var/datum/scar/scaries = new
- var/datum/wound/loss/phantom_loss = new // stolen valor, really
- scaries.generate(limb, phantom_loss)
+ if (LAZYLEN(dismembered_by_copy))
+ var/datum/scar/scaries = new
+ var/datum/wound/loss/phantom_loss = new // stolen valor, really
+ phantom_loss.loss_wound_type = dismembered_by_copy?[limb_zone]
+ if (phantom_loss.loss_wound_type)
+ scaries.generate(limb, phantom_loss)
+ LAZYREMOVE(dismembered_by_copy, limb_zone) // in case we're using a passed list
+ else
+ qdel(scaries)
+ qdel(phantom_loss)
//Copied from /datum/species/proc/on_species_gain()
for(var/obj/item/organ/external/organ_path as anything in dna.species.external_organs)
diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm
index 73e7d4207e5..30fb63a8034 100644
--- a/code/modules/surgery/bodyparts/head.dm
+++ b/code/modules/surgery/bodyparts/head.dm
@@ -191,9 +191,10 @@
/obj/item/bodypart/head/update_limb(dropping_limb, is_creating)
. = ..()
if(!isnull(owner))
- real_name = owner.real_name
- if(HAS_TRAIT(owner, TRAIT_HUSK))
- real_name = "Unknown"
+ if(HAS_TRAIT(owner, TRAIT_HUSK))
+ real_name = "Unknown"
+ else
+ real_name = owner.real_name
update_hair_and_lips(dropping_limb, is_creating)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm
index cbe533de54d..d022e003f2f 100644
--- a/code/modules/surgery/bodyparts/parts.dm
+++ b/code/modules/surgery/bodyparts/parts.dm
@@ -114,6 +114,8 @@
/// Datum describing how to offset things held in the hands of this arm, the x offset IS functional here
var/datum/worn_feature_offset/held_hand_offset
+ biological_state = (BIO_STANDARD|BIO_JOINTED)
+
/obj/item/bodypart/arm/Destroy()
QDEL_NULL(worn_glove_offset)
QDEL_NULL(held_hand_offset)
@@ -344,6 +346,8 @@
/// Datum describing how to offset things worn on the foot of this leg, note that an x offset won't do anything here
var/datum/worn_feature_offset/worn_foot_offset
+ biological_state = (BIO_STANDARD|BIO_JOINTED)
+
/obj/item/bodypart/leg/Destroy()
QDEL_NULL(worn_foot_offset)
return ..()
diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm
index cd0ac286559..0382f4b048f 100644
--- a/code/modules/surgery/bodyparts/robot_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm
@@ -37,6 +37,8 @@
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
+ biological_state = (BIO_ROBOTIC|BIO_JOINTED)
+
damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT)
disabling_threshold_percentage = 1
@@ -58,6 +60,7 @@
brute_modifier = 0.8
burn_modifier = 0.8
+
disabling_threshold_percentage = 1
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
@@ -68,6 +71,8 @@
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
+ biological_state = (BIO_ROBOTIC|BIO_JOINTED)
+
damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT)
/obj/item/bodypart/leg/left/robot
@@ -88,6 +93,7 @@
brute_modifier = 0.8
burn_modifier = 0.8
+
disabling_threshold_percentage = 1
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
@@ -98,6 +104,8 @@
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
+ biological_state = (BIO_ROBOTIC|BIO_JOINTED)
+
damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT)
/obj/item/bodypart/leg/left/robot/emp_act(severity)
@@ -127,6 +135,7 @@
brute_modifier = 0.8
burn_modifier = 0.8
+
disabling_threshold_percentage = 1
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
@@ -137,6 +146,8 @@
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
+ biological_state = (BIO_ROBOTIC|BIO_JOINTED)
+
damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT)
/obj/item/bodypart/leg/right/robot/emp_act(severity)
@@ -174,6 +185,8 @@
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
+ biological_state = (BIO_ROBOTIC)
+
damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT)
var/wired = FALSE
@@ -294,6 +307,8 @@
medium_burn_msg = ROBOTIC_MEDIUM_BURN_MSG
heavy_burn_msg = ROBOTIC_HEAVY_BURN_MSG
+ biological_state = (BIO_ROBOTIC)
+
damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT)
head_flags = HEAD_EYESPRITES
@@ -380,6 +395,11 @@
flash2?.forceMove(drop_loc)
return ..()
+// Prosthetics - Cheap, mediocre, and worse than organic limbs
+// The fact they dont have a internal biotype means theyre a lot weaker defensively,
+// since they skip slash and go right to blunt
+// They are VERY easy to delimb as a result
+// HP is also reduced just in case this isnt enough
/obj/item/bodypart/arm/left/robot/surplus
name = "surplus prosthetic left arm"
@@ -390,6 +410,8 @@
brute_modifier = 1
max_damage = 20
+ biological_state = (BIO_METAL|BIO_JOINTED)
+
/obj/item/bodypart/arm/right/robot/surplus
name = "surplus prosthetic right arm"
desc = "A skeletal, robotic limb. Outdated and fragile, but it's still better than nothing."
@@ -399,6 +421,8 @@
brute_modifier = 1
max_damage = 20
+ biological_state = (BIO_METAL|BIO_JOINTED)
+
/obj/item/bodypart/leg/left/robot/surplus
name = "surplus prosthetic left leg"
desc = "A skeletal, robotic limb. Outdated and fragile, but it's still better than nothing."
@@ -408,6 +432,8 @@
burn_modifier = 1
max_damage = 20
+ biological_state = (BIO_METAL|BIO_JOINTED)
+
/obj/item/bodypart/leg/right/robot/surplus
name = "surplus prosthetic right leg"
desc = "A skeletal, robotic limb. Outdated and fragile, but it's still better than nothing."
@@ -417,6 +443,8 @@
burn_modifier = 1
max_damage = 20
+ biological_state = (BIO_METAL|BIO_JOINTED)
+
#undef ROBOTIC_LIGHT_BRUTE_MSG
#undef ROBOTIC_MEDIUM_BRUTE_MSG
#undef ROBOTIC_HEAVY_BRUTE_MSG
diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm
index e57c014c02b..1126d1ee036 100644
--- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm
@@ -1,19 +1,19 @@
///SNAIL
/obj/item/bodypart/head/snail
- biological_state = BIO_FLESH //SKYRAT EDIT - Roundstart Snails - Now invertebrates!
+ biological_state = (BIO_BLOODED|BIO_FLESH) //SKYRAT EDIT - Roundstart Snails - Now invertebrates!
limb_id = SPECIES_SNAIL
is_dimorphic = FALSE
burn_modifier = 2
head_flags = HEAD_EYESPRITES|HEAD_DEBRAIN
/obj/item/bodypart/chest/snail
- biological_state = BIO_FLESH //SKYRAT EDIT - Roundstart Snails - Now invertebrates!
+ biological_state = (BIO_BLOODED|BIO_FLESH) //SKYRAT EDIT - Roundstart Snails - Now invertebrates!
limb_id = SPECIES_SNAIL
is_dimorphic = FALSE
burn_modifier = 2
/obj/item/bodypart/arm/left/snail
- biological_state = BIO_FLESH //SKYRAT EDIT - Roundstart Snails - Now invertebrates!
+ biological_state = (BIO_BLOODED|BIO_FLESH) //SKYRAT EDIT - Roundstart Snails - Now invertebrates!
limb_id = SPECIES_SNAIL
unarmed_attack_verb = "slap"
unarmed_attack_effect = ATTACK_EFFECT_DISARM
@@ -22,7 +22,7 @@
burn_modifier = 2
/obj/item/bodypart/arm/right/snail
- biological_state = BIO_FLESH //SKYRAT EDIT - Roundstart Snails - Now invertebrates!
+ biological_state = (BIO_BLOODED|BIO_FLESH) //SKYRAT EDIT - Roundstart Snails - Now invertebrates!
limb_id = SPECIES_SNAIL
unarmed_attack_verb = "slap"
unarmed_attack_effect = ATTACK_EFFECT_DISARM
@@ -31,7 +31,7 @@
burn_modifier = 2
/obj/item/bodypart/leg/left/snail
- biological_state = BIO_FLESH //SKYRAT EDIT - Roundstart Snails - Now invertebrates!
+ biological_state = (BIO_BLOODED|BIO_FLESH) //SKYRAT EDIT - Roundstart Snails - Now invertebrates!
limb_id = SPECIES_SNAIL
unarmed_damage_low = 1 //SKYRAT EDIT - Roundstart Snails - Lowest possible punch damage. if this is set to 0, punches will always miss.
unarmed_damage_high = 5 //snails are soft and squishy //SKYRAT EDIT - Roundstart Snails - A Bit More Damage. - ORIGINAL: unarmed_damage_high = 0.5 //snails are soft and squishy
@@ -39,7 +39,7 @@
// speed_modifier = 3 //disgustingly slow // SKYRAT EDIT - Moved the movespeed to the shell.
/obj/item/bodypart/leg/right/snail
- biological_state = BIO_FLESH //SKYRAT EDIT - Roundstart Snails - Now invertebrates!
+ biological_state = (BIO_BLOODED|BIO_FLESH) //SKYRAT EDIT - Roundstart Snails - Now invertebrates!
limb_id = SPECIES_SNAIL
unarmed_damage_low = 1 //SKYRAT EDIT - Roundstart Snails - Lowest possible punch damage. if this is set to 0, punches will always miss.
unarmed_damage_high = 5 //snails are soft and squishy //SKYRAT EDIT - Roundstart Snails - A Bit More Damage. - ORIGINAL: unarmed_damage_high = 0.5 //snails are soft and squishy
@@ -48,43 +48,37 @@
///ABDUCTOR
/obj/item/bodypart/head/abductor
- biological_state = BIO_INORGANIC //i have no fucking clue why these mfs get no wounds but SURE
limb_id = SPECIES_ABDUCTOR
is_dimorphic = FALSE
should_draw_greyscale = FALSE
head_flags = NONE
/obj/item/bodypart/chest/abductor
- biological_state = BIO_INORGANIC
limb_id = SPECIES_ABDUCTOR
is_dimorphic = FALSE
should_draw_greyscale = FALSE
/obj/item/bodypart/arm/left/abductor
- biological_state = BIO_INORGANIC
limb_id = SPECIES_ABDUCTOR
should_draw_greyscale = FALSE
bodypart_traits = list(TRAIT_CHUNKYFINGERS)
/obj/item/bodypart/arm/right/abductor
- biological_state = BIO_INORGANIC
limb_id = SPECIES_ABDUCTOR
should_draw_greyscale = FALSE
bodypart_traits = list(TRAIT_CHUNKYFINGERS)
/obj/item/bodypart/leg/left/abductor
- biological_state = BIO_INORGANIC
limb_id = SPECIES_ABDUCTOR
should_draw_greyscale = FALSE
/obj/item/bodypart/leg/right/abductor
- biological_state = BIO_INORGANIC
limb_id = SPECIES_ABDUCTOR
should_draw_greyscale = FALSE
///JELLY
/obj/item/bodypart/head/jelly
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED)
limb_id = SPECIES_JELLYPERSON
is_dimorphic = TRUE
dmg_overlay_type = null
@@ -92,90 +86,90 @@
head_flags = HEAD_ALL_FEATURES
/obj/item/bodypart/chest/jelly
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED)
limb_id = SPECIES_JELLYPERSON
is_dimorphic = TRUE
dmg_overlay_type = null
burn_modifier = 0.5 // = 1/2x generic burn damage
/obj/item/bodypart/arm/left/jelly
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED)
limb_id = SPECIES_JELLYPERSON
dmg_overlay_type = null
burn_modifier = 0.5 // = 1/2x generic burn damage
/obj/item/bodypart/arm/right/jelly
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED)
limb_id = SPECIES_JELLYPERSON
dmg_overlay_type = null
burn_modifier = 0.5 // = 1/2x generic burn damage
/obj/item/bodypart/leg/left/jelly
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED)
limb_id = SPECIES_JELLYPERSON
dmg_overlay_type = null
burn_modifier = 0.5 // = 1/2x generic burn damage
/obj/item/bodypart/leg/right/jelly
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED)
limb_id = SPECIES_JELLYPERSON
dmg_overlay_type = null
burn_modifier = 0.5 // = 1/2x generic burn damage
///SLIME
/obj/item/bodypart/head/slime
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED)
limb_id = SPECIES_SLIMEPERSON
is_dimorphic = FALSE
head_flags = HEAD_ALL_FEATURES
/obj/item/bodypart/chest/slime
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED)
limb_id = SPECIES_SLIMEPERSON
is_dimorphic = TRUE
/obj/item/bodypart/arm/left/slime
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED)
limb_id = SPECIES_SLIMEPERSON
/obj/item/bodypart/arm/right/slime
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED)
limb_id = SPECIES_SLIMEPERSON
/obj/item/bodypart/leg/left/slime
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED)
limb_id = SPECIES_SLIMEPERSON
/obj/item/bodypart/leg/right/slime
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED)
limb_id = SPECIES_SLIMEPERSON
///LUMINESCENT
/obj/item/bodypart/head/luminescent
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED)
limb_id = SPECIES_LUMINESCENT
is_dimorphic = TRUE
head_flags = HEAD_ALL_FEATURES
/obj/item/bodypart/chest/luminescent
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED)
limb_id = SPECIES_LUMINESCENT
is_dimorphic = TRUE
/obj/item/bodypart/arm/left/luminescent
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED)
limb_id = SPECIES_LUMINESCENT
/obj/item/bodypart/arm/right/luminescent
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED)
limb_id = SPECIES_LUMINESCENT
/obj/item/bodypart/leg/left/luminescent
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED)
limb_id = SPECIES_LUMINESCENT
/obj/item/bodypart/leg/right/luminescent
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED)
limb_id = SPECIES_LUMINESCENT
///ZOMBIE
@@ -282,7 +276,6 @@
///SHADOW
/obj/item/bodypart/head/shadow
- biological_state = BIO_INORGANIC
limb_id = SPECIES_SHADOW
is_dimorphic = FALSE
should_draw_greyscale = FALSE
@@ -290,32 +283,27 @@
head_flags = NONE
/obj/item/bodypart/chest/shadow
- biological_state = BIO_INORGANIC
limb_id = SPECIES_SHADOW
is_dimorphic = FALSE
should_draw_greyscale = FALSE
burn_modifier = 1.5
/obj/item/bodypart/arm/left/shadow
- biological_state = BIO_INORGANIC
limb_id = SPECIES_SHADOW
should_draw_greyscale = FALSE
burn_modifier = 1.5
/obj/item/bodypart/arm/right/shadow
- biological_state = BIO_INORGANIC
limb_id = SPECIES_SHADOW
should_draw_greyscale = FALSE
burn_modifier = 1.5
/obj/item/bodypart/leg/left/shadow
- biological_state = BIO_INORGANIC
limb_id = SPECIES_SHADOW
should_draw_greyscale = FALSE
burn_modifier = 1.5
/obj/item/bodypart/leg/right/shadow
- biological_state = BIO_INORGANIC
limb_id = SPECIES_SHADOW
should_draw_greyscale = FALSE
burn_modifier = 1.5
@@ -343,25 +331,25 @@
dmg_overlay_type = null
/obj/item/bodypart/arm/left/skeleton
- biological_state = BIO_BONE
+ biological_state = (BIO_BONE|BIO_JOINTED)
limb_id = SPECIES_SKELETON
should_draw_greyscale = FALSE
dmg_overlay_type = null
/obj/item/bodypart/arm/right/skeleton
- biological_state = BIO_BONE
+ biological_state = (BIO_BONE|BIO_JOINTED)
limb_id = SPECIES_SKELETON
should_draw_greyscale = FALSE
dmg_overlay_type = null
/obj/item/bodypart/leg/left/skeleton
- biological_state = BIO_BONE
+ biological_state = (BIO_BONE|BIO_JOINTED)
limb_id = SPECIES_SKELETON
should_draw_greyscale = FALSE
dmg_overlay_type = null
/obj/item/bodypart/leg/right/skeleton
- biological_state = BIO_BONE
+ biological_state = (BIO_BONE|BIO_JOINTED)
limb_id = SPECIES_SKELETON
should_draw_greyscale = FALSE
dmg_overlay_type = null
@@ -414,7 +402,7 @@
icon = 'icons/mob/human/species/golems.dmi'
icon_static = 'icons/mob/human/species/golems.dmi'
icon_state = "golem_head"
- biological_state = BIO_INORGANIC
+ biological_state = BIO_BONE
bodytype = BODYTYPE_GOLEM | BODYTYPE_ORGANIC
limb_id = SPECIES_GOLEM
is_dimorphic = FALSE
@@ -451,7 +439,7 @@
icon = 'icons/mob/human/species/golems.dmi'
icon_static = 'icons/mob/human/species/golems.dmi'
icon_state = "golem_chest"
- biological_state = BIO_INORGANIC
+ biological_state = BIO_BONE
acceptable_bodytype = BODYTYPE_GOLEM
bodytype = BODYTYPE_GOLEM | BODYTYPE_ORGANIC
limb_id = SPECIES_GOLEM
@@ -472,7 +460,7 @@
icon = 'icons/mob/human/species/golems.dmi'
icon_static = 'icons/mob/human/species/golems.dmi'
icon_state = "golem_l_arm"
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_BONE|BIO_JOINTED)
bodytype = BODYTYPE_GOLEM | BODYTYPE_ORGANIC
limb_id = SPECIES_GOLEM
should_draw_greyscale = FALSE
@@ -506,7 +494,7 @@
icon = 'icons/mob/human/species/golems.dmi'
icon_static = 'icons/mob/human/species/golems.dmi'
icon_state = "golem_r_arm"
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_BONE|BIO_JOINTED)
bodytype = BODYTYPE_GOLEM | BODYTYPE_ORGANIC
limb_id = SPECIES_GOLEM
should_draw_greyscale = FALSE
@@ -540,7 +528,7 @@
icon = 'icons/mob/human/species/golems.dmi'
icon_static = 'icons/mob/human/species/golems.dmi'
icon_state = "golem_l_leg"
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_BONE|BIO_JOINTED)
bodytype = BODYTYPE_GOLEM | BODYTYPE_ORGANIC
limb_id = SPECIES_GOLEM
should_draw_greyscale = FALSE
@@ -553,7 +541,7 @@
icon = 'icons/mob/human/species/golems.dmi'
icon_static = 'icons/mob/human/species/golems.dmi'
icon_state = "golem_r_leg"
- biological_state = BIO_INORGANIC
+ biological_state = (BIO_BONE|BIO_JOINTED)
bodytype = BODYTYPE_GOLEM | BODYTYPE_ORGANIC
limb_id = SPECIES_GOLEM
should_draw_greyscale = FALSE
diff --git a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm
index 85eea7edba0..f478d522d56 100644
--- a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm
@@ -27,7 +27,7 @@
icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi'
icon_state = "plasmaman_l_arm"
icon_static = 'icons/mob/human/species/plasmaman/bodyparts.dmi'
- biological_state = BIO_BONE
+ biological_state = (BIO_BONE|BIO_JOINTED)
limb_id = SPECIES_PLASMAMAN
should_draw_greyscale = FALSE
dmg_overlay_type = null
@@ -38,7 +38,7 @@
icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi'
icon_state = "plasmaman_r_arm"
icon_static = 'icons/mob/human/species/plasmaman/bodyparts.dmi'
- biological_state = BIO_BONE
+ biological_state = (BIO_BONE|BIO_JOINTED)
limb_id = SPECIES_PLASMAMAN
should_draw_greyscale = FALSE
dmg_overlay_type = null
@@ -49,7 +49,7 @@
icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi'
icon_state = "plasmaman_l_leg"
icon_static = 'icons/mob/human/species/plasmaman/bodyparts.dmi'
- biological_state = BIO_BONE
+ biological_state = (BIO_BONE|BIO_JOINTED)
limb_id = SPECIES_PLASMAMAN
should_draw_greyscale = FALSE
dmg_overlay_type = null
@@ -60,7 +60,7 @@
icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi'
icon_state = "plasmaman_r_leg"
icon_static = 'icons/mob/human/species/plasmaman/bodyparts.dmi'
- biological_state = BIO_BONE
+ biological_state = (BIO_BONE|BIO_JOINTED)
limb_id = SPECIES_PLASMAMAN
should_draw_greyscale = FALSE
dmg_overlay_type = null
diff --git a/code/modules/surgery/bodyparts/wounds.dm b/code/modules/surgery/bodyparts/wounds.dm
index 1961993ec64..db1407953b6 100644
--- a/code/modules/surgery/bodyparts/wounds.dm
+++ b/code/modules/surgery/bodyparts/wounds.dm
@@ -8,40 +8,74 @@
var/mangled_state = get_mangled_state()
var/easy_dismember = HAS_TRAIT(owner, TRAIT_EASYDISMEMBER) // if we have easydismember, we don't reduce damage when redirecting damage to different types (slashing weapons on mangled/skinless limbs attack at 100% instead of 50%)
- if(wounding_type == WOUND_BLUNT && sharpness)
- if(sharpness & SHARP_EDGED)
- wounding_type = WOUND_SLASH
- else if (sharpness & SHARP_POINTY)
- wounding_type = WOUND_PIERCE
+ var/has_exterior = FALSE
+ var/has_interior = FALSE
- //Handling for bone only/flesh only(none right now)/flesh and bone targets
- switch(biological_state)
- // if we're bone only, all cutting attacks go straight to the bone
- if(BIO_BONE)
- if(wounding_type == WOUND_SLASH)
- wounding_type = WOUND_BLUNT
- phantom_wounding_dmg *= (easy_dismember ? 1 : 0.6)
- else if(wounding_type == WOUND_PIERCE)
- wounding_type = WOUND_BLUNT
- phantom_wounding_dmg *= (easy_dismember ? 1 : 0.75)
- if((mangled_state & BODYPART_MANGLED_BONE) && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus))
- return
- // note that there's no handling for BIO_FLESH since we don't have any that are that right now (slimepeople maybe someday)
- // standard humanoids
- if(BIO_FLESH_BONE)
- // if we've already mangled the skin (critical slash or piercing wound), then the bone is exposed, and we can damage it with sharp weapons at a reduced rate
- // So a big sharp weapon is still all you need to destroy a limb
- if((mangled_state & BODYPART_MANGLED_FLESH) && !(mangled_state & BODYPART_MANGLED_BONE) && sharpness)
- playsound(src, "sound/effects/wounds/crackandbleed.ogg", 100)
- if(wounding_type == WOUND_SLASH && !easy_dismember)
- phantom_wounding_dmg *= 0.6 // edged weapons pass along 60% of their wounding damage to the bone since the power is spread out over a larger area
- if(wounding_type == WOUND_PIERCE && !easy_dismember)
- phantom_wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated
- wounding_type = WOUND_BLUNT
- else if((mangled_state & BODYPART_MANGLED_FLESH) && (mangled_state & BODYPART_MANGLED_BONE) && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus))
+ for (var/state as anything in GLOB.bio_state_states)
+ var/flag = text2num(state)
+ if (!(biological_state & flag))
+ continue
+
+ var/value = GLOB.bio_state_states[state]
+ if (value & BIO_EXTERIOR)
+ has_exterior = TRUE
+ if (value & BIO_INTERIOR)
+ has_interior = TRUE
+
+ if (has_exterior && has_interior)
+ break
+
+ // We put this here so we dont increase init time by doing this all at once on initialization
+ // Effectively, we "lazy load"
+ if (isnull(any_existing_wound_can_mangle_our_bone) || isnull(any_existing_wound_can_mangle_our_flesh))
+ any_existing_wound_can_mangle_our_bone = FALSE
+ any_existing_wound_can_mangle_our_flesh = FALSE
+ for (var/datum/wound/wound_type as anything in GLOB.all_wound_pregen_data)
+ var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[wound_type]
+ if (!pregen_data.can_be_applied_to(src, random_roll = TRUE)) // we only consider randoms because non-randoms are usually really specific
+ continue
+ if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_FLESH)
+ any_existing_wound_can_mangle_our_flesh = TRUE
+ if (initial(pregen_data.wound_path_to_generate.wound_flags) & MANGLES_BONE)
+ any_existing_wound_can_mangle_our_bone = TRUE
+
+ if (any_existing_wound_can_mangle_our_bone && any_existing_wound_can_mangle_our_flesh)
+ break
+
+ var/can_theoretically_be_dismembered = (any_existing_wound_can_mangle_our_bone || (any_existing_wound_can_mangle_our_flesh && !has_exterior))
+
+ var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_BONE) == BODYPART_MANGLED_BONE))
+ var/interior_ready_to_dismember = (!has_interior || ((mangled_state & BODYPART_MANGLED_FLESH) == BODYPART_MANGLED_FLESH))
+
+ // if we're bone only, all cutting attacks go straight to the bone
+ if(has_exterior && interior_ready_to_dismember)
+ if(wounding_type == WOUND_SLASH)
+ wounding_type = WOUND_BLUNT
+ phantom_wounding_dmg *= (easy_dismember ? 1 : 0.6)
+ else if(wounding_type == WOUND_PIERCE)
+ wounding_type = WOUND_BLUNT
+ phantom_wounding_dmg *= (easy_dismember ? 1 : 0.75)
+ if(exterior_ready_to_dismember && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus))
+ return
+ else
+ // if we've already mangled the skin (critical slash or piercing wound), then the bone is exposed, and we can damage it with sharp weapons at a reduced rate
+ // So a big sharp weapon is still all you need to destroy a limb
+ if(has_exterior && interior_ready_to_dismember && !(mangled_state & BODYPART_MANGLED_BONE) && sharpness)
+ playsound(src, "sound/effects/wounds/crackandbleed.ogg", 100)
+ if(wounding_type == WOUND_SLASH && !easy_dismember)
+ phantom_wounding_dmg *= 0.6 // edged weapons pass along 60% of their wounding damage to the bone since the power is spread out over a larger area
+ if(wounding_type == WOUND_PIERCE && !easy_dismember)
+ phantom_wounding_dmg *= 0.75 // piercing weapons pass along 75% of their wounding damage to the bone since it's more concentrated
+ wounding_type = WOUND_BLUNT
+ else if(interior_ready_to_dismember && exterior_ready_to_dismember && try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus))
+ return
+ if (use_alternate_dismemberment_calc_even_if_mangleable || !can_theoretically_be_dismembered)
+ var/percent_to_total_max = (get_damage() / max_damage)
+ if (percent_to_total_max >= hp_percent_to_dismemberable)
+ if (try_dismember(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus))
return
- check_wounding(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus)
+ return check_wounding(wounding_type, phantom_wounding_dmg, wound_bonus, bare_wound_bonus)
/**
* check_wounding() is where we handle rolling for, selecting, and applying a wound if we meet the criteria
@@ -82,7 +116,11 @@
dismembering.apply_dismember(src, woundtype, outright = TRUE, attack_direction = attack_direction)
return
- var/list/wounds_checking = GLOB.global_wound_types[woundtype]
+ var/list/datum/wound/possible_wounds = list()
+ for (var/datum/wound/type as anything in GLOB.all_wound_pregen_data)
+ var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[type]
+ if (pregen_data.can_be_applied_to(src, woundtype, random_roll = TRUE))
+ possible_wounds += type
// quick re-check to see if bare_wound_bonus applies, for the benefit of log_wound(), see about getting the check from check_woundings_mods() somehow
if(ishuman(owner))
var/mob/living/carbon/human/human_wearer = owner
@@ -94,19 +132,19 @@
break
//cycle through the wounds of the relevant category from the most severe down
- for(var/datum/wound/possible_wound as anything in wounds_checking)
+ for(var/datum/wound/possible_wound as anything in possible_wounds)
var/datum/wound/replaced_wound
for(var/datum/wound/existing_wound as anything in wounds)
- if(existing_wound.type in wounds_checking)
+ if(existing_wound.wound_series == initial(possible_wound.wound_series))
if(existing_wound.severity >= initial(possible_wound.severity))
return
else
- replaced_wound = existing_wound
+ replaced_wound = existing_wound // if we find something we keep iterating untilw e're done or we find we're outclassed by something in our series
if(initial(possible_wound.threshold_minimum) < injury_roll)
var/datum/wound/new_wound
if(replaced_wound)
- new_wound = replaced_wound.replace_wound(possible_wound, attack_direction = attack_direction)
+ new_wound = replaced_wound.replace_wound(new possible_wound, attack_direction = attack_direction)
else
new_wound = new possible_wound
new_wound.apply_wound(src, attack_direction = attack_direction, wound_source = damage_source)
@@ -119,9 +157,9 @@
var/datum/wound/potential_wound = specific_woundtype
for(var/datum/wound/existing_wound as anything in wounds)
- if(existing_wound.wound_type == initial(potential_wound.wound_type))
+ if (existing_wound.wound_series == initial(potential_wound.wound_series))
if(existing_wound.severity < initial(potential_wound.severity)) // we only try if the existing one is inferior to the one we're trying to force
- existing_wound.replace_wound(potential_wound, smited)
+ existing_wound.replace_wound(new potential_wound, smited)
return
var/datum/wound/new_wound = new potential_wound
diff --git a/code/modules/surgery/bone_mending.dm b/code/modules/surgery/bone_mending.dm
index 2396f49c322..48114fe6d04 100644
--- a/code/modules/surgery/bone_mending.dm
+++ b/code/modules/surgery/bone_mending.dm
@@ -5,7 +5,7 @@
/datum/surgery/repair_bone_hairline
name = "Repair bone fracture (hairline)"
surgery_flags = SURGERY_REQUIRE_RESTING | SURGERY_REQUIRE_LIMB | SURGERY_REQUIRES_REAL_LIMB
- targetable_wound = /datum/wound/blunt/severe
+ targetable_wound = /datum/wound/blunt/bone/severe
possible_locs = list(
BODY_ZONE_R_ARM,
BODY_ZONE_L_ARM,
@@ -31,7 +31,7 @@
/datum/surgery/repair_bone_compound
name = "Repair Compound Fracture"
surgery_flags = SURGERY_REQUIRE_RESTING | SURGERY_REQUIRE_LIMB | SURGERY_REQUIRES_REAL_LIMB
- targetable_wound = /datum/wound/blunt/critical
+ targetable_wound = /datum/wound/blunt/bone/critical
possible_locs = list(
BODY_ZONE_R_ARM,
BODY_ZONE_L_ARM,
diff --git a/code/modules/surgery/burn_dressing.dm b/code/modules/surgery/burn_dressing.dm
index f448195d3ef..c22a8f4be97 100644
--- a/code/modules/surgery/burn_dressing.dm
+++ b/code/modules/surgery/burn_dressing.dm
@@ -5,7 +5,7 @@
/datum/surgery/debride
name = "Debride burnt flesh"
surgery_flags = SURGERY_REQUIRE_RESTING | SURGERY_REQUIRE_LIMB | SURGERY_REQUIRES_REAL_LIMB
- targetable_wound = /datum/wound/burn
+ targetable_wound = /datum/wound/burn/flesh
possible_locs = list(
BODY_ZONE_R_ARM,
BODY_ZONE_L_ARM,
@@ -24,7 +24,7 @@
return FALSE
if(..())
var/obj/item/bodypart/targeted_bodypart = target.get_bodypart(user.zone_selected)
- var/datum/wound/burn/burn_wound = targeted_bodypart.get_wound_type(targetable_wound)
+ var/datum/wound/burn/flesh/burn_wound = targeted_bodypart.get_wound_type(targetable_wound)
return(burn_wound && burn_wound.infestation > 0)
//SURGERY STEPS
@@ -48,7 +48,7 @@
var/infestation_removed = 4
/// To give the surgeon a heads up how much work they have ahead of them
-/datum/surgery_step/debride/proc/get_progress(mob/user, mob/living/carbon/target, datum/wound/burn/burn_wound)
+/datum/surgery_step/debride/proc/get_progress(mob/user, mob/living/carbon/target, datum/wound/burn/flesh/burn_wound)
if(!burn_wound?.infestation || !infestation_removed)
return
var/estimated_remaining_steps = burn_wound.infestation / infestation_removed
@@ -68,7 +68,7 @@
/datum/surgery_step/debride/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(surgery.operated_wound)
- var/datum/wound/burn/burn_wound = surgery.operated_wound
+ var/datum/wound/burn/flesh/burn_wound = surgery.operated_wound
if(burn_wound.infestation <= 0)
to_chat(user, span_notice("[target]'s [parse_zone(user.zone_selected)] has no infected flesh to remove!"))
surgery.status++
@@ -86,7 +86,7 @@
user.visible_message(span_notice("[user] looks for [target]'s [parse_zone(user.zone_selected)]."), span_notice("You look for [target]'s [parse_zone(user.zone_selected)]..."))
/datum/surgery_step/debride/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
- var/datum/wound/burn/burn_wound = surgery.operated_wound
+ var/datum/wound/burn/flesh/burn_wound = surgery.operated_wound
if(burn_wound)
var/progress_text = get_progress(user, target, burn_wound)
display_results(
@@ -120,7 +120,7 @@
/datum/surgery_step/debride/initiate(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE)
if(!..())
return
- var/datum/wound/burn/burn_wound = surgery.operated_wound
+ var/datum/wound/burn/flesh/burn_wound = surgery.operated_wound
while(burn_wound && burn_wound.infestation > 0.25)
if(!..())
break
@@ -139,7 +139,7 @@
/datum/surgery_step/dress/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- var/datum/wound/burn/burn_wound = surgery.operated_wound
+ var/datum/wound/burn/flesh/burn_wound = surgery.operated_wound
if(burn_wound)
display_results(
user,
@@ -153,7 +153,7 @@
user.visible_message(span_notice("[user] looks for [target]'s [parse_zone(user.zone_selected)]."), span_notice("You look for [target]'s [parse_zone(user.zone_selected)]..."))
/datum/surgery_step/dress/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
- var/datum/wound/burn/burn_wound = surgery.operated_wound
+ var/datum/wound/burn/flesh/burn_wound = surgery.operated_wound
if(burn_wound)
display_results(
user,
diff --git a/code/modules/surgery/repair_puncture.dm b/code/modules/surgery/repair_puncture.dm
index 843336c258b..bb33c314689 100644
--- a/code/modules/surgery/repair_puncture.dm
+++ b/code/modules/surgery/repair_puncture.dm
@@ -9,7 +9,7 @@
/datum/surgery/repair_puncture
name = "Repair puncture"
surgery_flags = SURGERY_REQUIRE_RESTING | SURGERY_REQUIRE_LIMB | SURGERY_REQUIRES_REAL_LIMB
- targetable_wound = /datum/wound/pierce
+ targetable_wound = /datum/wound/pierce/bleed
target_mobtypes = list(/mob/living/carbon)
possible_locs = list(
BODY_ZONE_R_ARM,
@@ -32,7 +32,7 @@
. = ..()
if(.)
var/obj/item/bodypart/targeted_bodypart = target.get_bodypart(user.zone_selected)
- var/datum/wound/burn/pierce_wound = targeted_bodypart.get_wound_type(targetable_wound)
+ var/datum/wound/burn/flesh/pierce_wound = targeted_bodypart.get_wound_type(targetable_wound)
return(pierce_wound && pierce_wound.blood_flow > 0)
//SURGERY STEPS
@@ -47,7 +47,7 @@
time = 3 SECONDS
/datum/surgery_step/repair_innards/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- var/datum/wound/pierce/pierce_wound = surgery.operated_wound
+ var/datum/wound/pierce/bleed/pierce_wound = surgery.operated_wound
if(!pierce_wound)
user.visible_message(span_notice("[user] looks for [target]'s [parse_zone(user.zone_selected)]."), span_notice("You look for [target]'s [parse_zone(user.zone_selected)]..."))
return
@@ -67,7 +67,7 @@
display_pain(target, "You feel a horrible stabbing pain in your [parse_zone(user.zone_selected)]!")
/datum/surgery_step/repair_innards/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
- var/datum/wound/pierce/pierce_wound = surgery.operated_wound
+ var/datum/wound/pierce/bleed/pierce_wound = surgery.operated_wound
if(!pierce_wound)
to_chat(user, span_warning("[target] has no puncture wound there!"))
return ..()
@@ -112,7 +112,7 @@
return TRUE
/datum/surgery_step/seal_veins/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- var/datum/wound/pierce/pierce_wound = surgery.operated_wound
+ var/datum/wound/pierce/bleed/pierce_wound = surgery.operated_wound
if(!pierce_wound)
user.visible_message(span_notice("[user] looks for [target]'s [parse_zone(user.zone_selected)]."), span_notice("You look for [target]'s [parse_zone(user.zone_selected)]..."))
return
@@ -126,7 +126,7 @@
display_pain(target, "You're being burned inside your [parse_zone(user.zone_selected)]!")
/datum/surgery_step/seal_veins/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
- var/datum/wound/pierce/pierce_wound = surgery.operated_wound
+ var/datum/wound/pierce/bleed/pierce_wound = surgery.operated_wound
if(!pierce_wound)
to_chat(user, span_warning("[target] has no puncture there!"))
return ..()
diff --git a/code/modules/unit_tests/medical_wounds.dm b/code/modules/unit_tests/medical_wounds.dm
index 56c7a43104f..0838b2d18be 100644
--- a/code/modules/unit_tests/medical_wounds.dm
+++ b/code/modules/unit_tests/medical_wounds.dm
@@ -12,10 +12,10 @@
var/i = 1
var/list/iter_test_wound_list
- for(iter_test_wound_list in list(list(/datum/wound/blunt/moderate, /datum/wound/blunt/severe, /datum/wound/blunt/critical),\
- list(/datum/wound/slash/moderate, /datum/wound/slash/severe, /datum/wound/slash/critical),\
- list(/datum/wound/pierce/moderate, /datum/wound/pierce/severe, /datum/wound/pierce/critical),\
- list(/datum/wound/burn/moderate, /datum/wound/burn/severe, /datum/wound/burn/critical)))
+ for(iter_test_wound_list in list(list(/datum/wound/blunt/bone/moderate, /datum/wound/blunt/bone/severe, /datum/wound/blunt/bone/critical),\
+ list(/datum/wound/slash/flesh/moderate, /datum/wound/slash/flesh/severe, /datum/wound/slash/flesh/critical),\
+ list(/datum/wound/pierce/bleed/moderate, /datum/wound/pierce/bleed/severe, /datum/wound/pierce/bleed/critical),\
+ list(/datum/wound/burn/flesh/moderate, /datum/wound/burn/flesh/severe, /datum/wound/burn/flesh/critical)))
TEST_ASSERT_EQUAL(length(victim.all_wounds), 0, "Patient is somehow wounded before test")
var/datum/wound/iter_test_wound
@@ -52,10 +52,10 @@
var/list/iter_test_wound_list
tested_part.biological_state &= ~BIO_FLESH // take away the base limb's flesh (ouchie!) ((not actually ouchie, this just affects their wounds and dismemberment handling))
- for(iter_test_wound_list in list(list(/datum/wound/blunt/moderate, /datum/wound/blunt/severe, /datum/wound/blunt/critical),\
- list(/datum/wound/slash/moderate, /datum/wound/slash/severe, /datum/wound/slash/critical),\
- list(/datum/wound/pierce/moderate, /datum/wound/pierce/severe, /datum/wound/pierce/critical),\
- list(/datum/wound/burn/moderate, /datum/wound/burn/severe, /datum/wound/burn/critical)))
+ for(iter_test_wound_list in list(list(/datum/wound/blunt/bone/moderate, /datum/wound/blunt/bone/severe, /datum/wound/blunt/bone/critical),\
+ list(/datum/wound/slash/flesh/moderate, /datum/wound/slash/flesh/severe, /datum/wound/slash/flesh/critical),\
+ list(/datum/wound/pierce/bleed/moderate, /datum/wound/pierce/bleed/severe, /datum/wound/pierce/bleed/critical),\
+ list(/datum/wound/burn/flesh/moderate, /datum/wound/burn/flesh/severe, /datum/wound/burn/flesh/critical)))
TEST_ASSERT_EQUAL(length(victim.all_wounds), 0, "Patient is somehow wounded before test")
var/datum/wound/iter_test_wound
@@ -69,13 +69,15 @@
tested_part.receive_damage(0, WOUND_MINIMUM_DAMAGE, wound_bonus = threshold, sharpness=sharps[i])
// so if we just tried to deal a flesh wound, make sure we didn't actually suffer it. We may have suffered a bone wound instead, but we just want to make sure we don't have a flesh wound
- if(initial(iter_test_wound.wound_flags) & FLESH_WOUND)
+ var/datum/wound_pregen_data/pregen_data = GLOB.all_wound_pregen_data[iter_test_wound]
+ if (pregen_data.required_limb_biostate & BIO_FLESH)
if(!length(victim.all_wounds)) // not having a wound is good news
continue
else // we have to check that it's actually a bone wound and not the intended wound type
TEST_ASSERT_EQUAL(length(victim.all_wounds), 1, "Patient has more than one wound when only one is expected. Severity: [initial(iter_test_wound.severity)]")
var/datum/wound/actual_wound = victim.all_wounds[1]
- TEST_ASSERT((actual_wound.wound_flags & ~FLESH_WOUND), "Limb has flesh wound despite no BIO_FLESH biological_state, expected either no wound or bone wound. Offending wound: [actual_wound]")
+ var/datum/wound_pregen_data/actual_pregen_data = GLOB.all_wound_pregen_data[actual_wound.type]
+ TEST_ASSERT((actual_pregen_data.required_limb_biostate & ~BIO_FLESH), "Limb has flesh wound despite no BIO_FLESH biological_state, expected either no wound or bone wound. Offending wound: [actual_wound]")
threshold_penalty = actual_wound.threshold_penalty
else // otherwise if it's a bone wound, check that we have it per usual
TEST_ASSERT(length(victim.all_wounds), "Patient has no wounds when one wound is expected. Severity: [initial(iter_test_wound.severity)]")
diff --git a/code/modules/vehicles/cars/clowncar.dm b/code/modules/vehicles/cars/clowncar.dm
index 3fb6d37bd2c..f08e30a7554 100644
--- a/code/modules/vehicles/cars/clowncar.dm
+++ b/code/modules/vehicles/cars/clowncar.dm
@@ -122,8 +122,8 @@
continue
for(var/obj/item/bodypart/head/head_to_wound as anything in carbon_occupant.bodyparts)
var/type_wound = pick(list(
- /datum/wound/blunt/moderate,
- /datum/wound/blunt/severe,
+ /datum/wound/blunt/bone/moderate,
+ /datum/wound/blunt/bone/severe,
))
head_to_wound.force_wound_upwards(type_wound, wound_source = src)
carbon_occupant.playsound_local(src, 'sound/weapons/flash_ring.ogg', 50)
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index c68d70f5164..298af4a7cf9 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -954,11 +954,13 @@
return FALSE
var/mob/living/carbon/carbon_target = atom_target
for(var/obj/item/bodypart/squish_part in carbon_target.bodyparts)
- if(IS_ORGANIC_LIMB(squish_part))
- var/type_wound = pick(list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate))
- squish_part.force_wound_upwards(type_wound, wound_source = "crushed by [src]")
+ var/type_wound
+ if (squish_part.biological_state & BIO_BONE)
+ type_wound = pick(list(/datum/wound/blunt/bone/critical, /datum/wound/blunt/bone/severe, /datum/wound/blunt/bone/moderate))
else
squish_part.receive_damage(brute=30)
+ if (type_wound)
+ squish_part.force_wound_upwards(type_wound, wound_source = "crushed by [src]")
carbon_target.visible_message(span_danger("[carbon_target]'s body is maimed underneath the mass of [src]!"), span_userdanger("Your body is maimed underneath the mass of [src]!"))
return TRUE
if(CRUSH_CRIT_HEADGIB) // skull squish!
diff --git a/modular_skyrat/modules/bodyparts/code/roundstartslime_bodyparts.dm b/modular_skyrat/modules/bodyparts/code/roundstartslime_bodyparts.dm
index e5894249ac1..302d3488931 100644
--- a/modular_skyrat/modules/bodyparts/code/roundstartslime_bodyparts.dm
+++ b/modular_skyrat/modules/bodyparts/code/roundstartslime_bodyparts.dm
@@ -3,25 +3,25 @@
/obj/item/bodypart/head/slime/roundstart
is_dimorphic = TRUE
icon_greyscale = BODYPART_ICON_ROUNDSTARTSLIME
- biological_state = BIO_FLESH
+ biological_state = (BIO_FLESH|BIO_BLOODED)
/obj/item/bodypart/chest/slime/roundstart
is_dimorphic = TRUE
icon_greyscale = BODYPART_ICON_ROUNDSTARTSLIME
- biological_state = BIO_FLESH
+ biological_state = (BIO_FLESH|BIO_BLOODED)
/obj/item/bodypart/arm/left/slime/roundstart
icon_greyscale = BODYPART_ICON_ROUNDSTARTSLIME
- biological_state = BIO_FLESH
+ biological_state = (BIO_FLESH|BIO_BLOODED)
/obj/item/bodypart/arm/right/slime/roundstart
icon_greyscale = BODYPART_ICON_ROUNDSTARTSLIME
- biological_state = BIO_FLESH
+ biological_state = (BIO_FLESH|BIO_BLOODED)
/obj/item/bodypart/leg/left/slime/roundstart
icon_greyscale = BODYPART_ICON_ROUNDSTARTSLIME
- biological_state = BIO_FLESH
+ biological_state = (BIO_FLESH|BIO_BLOODED)
/obj/item/bodypart/leg/right/slime/roundstart
icon_greyscale = BODYPART_ICON_ROUNDSTARTSLIME
- biological_state = BIO_FLESH
+ biological_state = (BIO_FLESH|BIO_BLOODED)
diff --git a/modular_skyrat/modules/contractor/code/datums/contract.dm b/modular_skyrat/modules/contractor/code/datums/contract.dm
index 087cb438dac..47e7906254d 100644
--- a/modular_skyrat/modules/contractor/code/datums/contract.dm
+++ b/modular_skyrat/modules/contractor/code/datums/contract.dm
@@ -213,8 +213,8 @@
for(var/i in 1 to 2)
var/obj/item/bodypart/limb = target.get_bodypart(pick_n_take(parts_to_fuck_up))
- var/datum/wound/blunt/severe/severe_wound_type = /datum/wound/blunt/severe
- var/datum/wound/blunt/critical/critical_wound_type = /datum/wound/blunt/critical
+ var/datum/wound/blunt/bone/severe/severe_wound_type = /datum/wound/blunt/bone/severe
+ var/datum/wound/blunt/bone/critical/critical_wound_type = /datum/wound/blunt/bone/critical
limb.receive_damage(brute = WOUND_MINIMUM_DAMAGE, wound_bonus = rand(initial(severe_wound_type.threshold_minimum), initial(critical_wound_type.threshold_minimum) + 10))
target.update_damage_overlays()
diff --git a/modular_skyrat/modules/customization/readme.md b/modular_skyrat/modules/customization/readme.md
index af197a1baca..b488c032194 100644
--- a/modular_skyrat/modules/customization/readme.md
+++ b/modular_skyrat/modules/customization/readme.md
@@ -53,8 +53,6 @@ Re-writes how mutant bodyparts exist and how they're handled. Adds in a per limb
./code/_globalvars/lists/flavor_misc.dm > Removed accessory list defines
.\code\datums\keybindings\living.dm > /datum/keybinding/living/look_up > from L to P
-./code/modules/surgery/bodyparts/_bodyparts.dm > var/rendered_bp_icon
-
./code/__DEFINES/~skyrat_defines/DNA.dm > A TON of defines
./code/__DEFINES/~skyrat_defines/obj_flags.dm > Organ flags
./code/__DEFINES/~skyrat_defines/say.dm > MAX_FLAVOR_LEN
diff --git a/modular_skyrat/modules/hev_suit/code/hev_suit.dm b/modular_skyrat/modules/hev_suit/code/hev_suit.dm
index 87f7d7788ab..081b4a0853f 100644
--- a/modular_skyrat/modules/hev_suit/code/hev_suit.dm
+++ b/modular_skyrat/modules/hev_suit/code/hev_suit.dm
@@ -614,51 +614,30 @@
/obj/item/clothing/suit/space/hev_suit/proc/process_wound(carbon, wound, bodypart)
SIGNAL_HANDLER
- var/list/minor_fractures = list(
- /datum/wound/blunt,
- /datum/wound/blunt/moderate,
- /datum/wound/muscle,
- /datum/wound/muscle/moderate
- )
- var/list/major_fractures = list(
- /datum/wound/blunt/severe,
- /datum/wound/blunt/critical,
- /datum/wound/muscle/severe,
- /datum/wound/loss
- )
- var/list/minor_lacerations = list(
- /datum/wound/burn,
- /datum/wound/burn/moderate,
- /datum/wound/pierce,
- /datum/wound/pierce/moderate,
- /datum/wound/slash,
- /datum/wound/slash/moderate
- )
- var/list/major_lacerations = list(
- /datum/wound/burn/severe,
- /datum/wound/burn/critical,
- /datum/wound/pierce/severe,
- /datum/wound/pierce/critical,
- /datum/wound/slash/severe,
- /datum/wound/slash/critical
- )
+ if (!istype(wound, /datum/wound))
+ return
- if(wound in minor_fractures)
- send_hev_sound(minor_fracture_sound)
- else if(wound in major_fractures)
- send_hev_sound(major_fracture_sound)
- else if(wound in minor_lacerations)
- send_hev_sound(minor_lacerations_sound)
- else if(wound in major_lacerations)
- send_hev_sound(major_lacerations_sound)
- else
- var/sound2play = pick(list(
- minor_fracture_sound,
- major_fracture_sound,
- minor_lacerations_sound,
- major_lacerations_sound
- ))
- send_hev_sound(sound2play)
+ var/datum/wound/new_wound = wound
+
+ var/sound_to_play
+
+ var/wound_series = new_wound.wound_series
+ var/wound_type = new_wound.wound_type
+ var/wound_severity = new_wound.severity
+
+ if (wound_type == WOUND_SLASH || wound_type == WOUND_PIERCE)
+ if (wound_severity >= WOUND_SEVERITY_SEVERE)
+ sound_to_play = major_lacerations_sound
+ else
+ sound_to_play = minor_lacerations_sound
+ else if (wound_type == WOUND_BLUNT || wound_series == WOUND_SERIES_MUSCLE_DAMAGE)
+ if (wound_severity >= WOUND_SEVERITY_SEVERE)
+ sound_to_play = major_fracture_sound
+ else
+ sound_to_play = minor_fracture_sound
+
+ if (sound_to_play)
+ send_hev_sound(sound_to_play)
/obj/item/clothing/suit/space/hev_suit/proc/process_acid()
SIGNAL_HANDLER
diff --git a/modular_skyrat/modules/medical/code/bodypart.dm b/modular_skyrat/modules/medical/code/bodypart.dm
deleted file mode 100644
index 60a695f59ef..00000000000
--- a/modular_skyrat/modules/medical/code/bodypart.dm
+++ /dev/null
@@ -1,11 +0,0 @@
-/obj/item/bodypart/proc/apply_gauze(obj/item/stack/medical/gauze/new_gauze)
- if(!istype(new_gauze) || current_gauze)
- return
- current_gauze = new new_gauze.gauze_type(src)
- new_gauze.use(1)
-
-/obj/item/bodypart/proc/apply_splint(obj/item/stack/medical/gauze/new_splint)
- if(!istype(new_splint) || current_splint)
- return
- current_splint = new new_splint.splint_type(src)
- new_splint.use(1)
diff --git a/modular_skyrat/modules/medical/code/bodypart_aid.dm b/modular_skyrat/modules/medical/code/bodypart_aid.dm
deleted file mode 100644
index e5b3b13ceaa..00000000000
--- a/modular_skyrat/modules/medical/code/bodypart_aid.dm
+++ /dev/null
@@ -1,227 +0,0 @@
-#define SELF_AID_REMOVE_DELAY (5 SECONDS)
-#define OTHER_AID_REMOVE_DELAY (2 SECONDS)
-
-/datum/bodypart_aid
- var/name
- /// Keeping track of how damaged our aid is from external things, such as hits, it will break when it reaches 0
- var/integrity = 2
- /// To which bodypart we're attached to
- var/obj/item/bodypart/bodypart
- /// Which item do we get when we rip this off, while its in pristine condition
- var/stack_to_drop
- /// Suffix for our used overlay. The suffix is the bodypart zone, and "_digitigrade" for some legs. If this is null then it wont make an overlay. Gauzes are rendered before splints
- var/overlay_prefix
- /// Bodypart is [this_prefix] with get_description()
- var/desc_prefix
-
-/datum/bodypart_aid/Topic(href, href_list)
- . = ..()
- if(href_list["remove"])
- if(!bodypart.owner)
- return
- if(!iscarbon(usr))
- return
- if(!in_range(usr, bodypart.owner))
- return
- var/mob/living/carbon/C = usr
- var/self = (C == bodypart.owner)
- C.visible_message(span_notice("[C] begins removing [name] from [self ? "[bodypart.owner.p_Their()]" : "[bodypart.owner]'s" ] [bodypart.name]..."), span_notice("You begin to remove [name] from [self ? "your" : "[bodypart.owner]'s"] [bodypart.name]..."))
- if(!do_after(C, (self ? SELF_AID_REMOVE_DELAY : OTHER_AID_REMOVE_DELAY), target=bodypart.owner))
- return
- if(QDELETED(src))
- return
- C.visible_message(span_notice("[C] removes [name] from [self ? "[bodypart.owner.p_Their()]" : "[bodypart.owner]'s" ] [bodypart.name]."), span_notice("You remove [name] from [self ? "your" : "[bodypart.owner]'s" ] [bodypart.name]."))
- var/obj/item/gotten = rip_off()
- if(gotten && !C.put_in_hands(gotten))
- gotten.forceMove(get_turf(C))
-
-/datum/bodypart_aid/New(obj/item/bodypart/BP)
- //'bodypart == BP' is set in subtypes to ensure some proper signals and behaviours
- if(overlay_prefix && bodypart.owner)
- bodypart.owner.update_bandage_overlays()
-
-/datum/bodypart_aid/Destroy()
- if(overlay_prefix && bodypart.owner)
- bodypart.owner.update_bandage_overlays()
- bodypart = null
- ..()
-
-/**
- * take_damage() called when the bandage gets damaged
- *
- * This proc will subtract integrity and delete the bandage with a to_chat message to whoever was bandaged
- *
- */
-
-/datum/bodypart_aid/proc/take_damage()
- integrity--
- if(integrity <= 0)
- if(bodypart.owner)
- to_chat(bodypart.owner, span_warning("The [name] on your [bodypart.name] tears and falls off!"))
- qdel(src)
-
-/**
- * rip_off() called when someone rips it off
- *
- * It will return the bandage if it's considered pristine
- *
- */
-
-/datum/bodypart_aid/proc/rip_off()
- if(is_pristine())
- . = new stack_to_drop(null, 1)
- qdel(src)
-
-/**
- * get_description() called by examine procs
- *
- * It will returns a description of the bandage
- *
- */
-
-/datum/bodypart_aid/proc/get_description()
- return "[name]"
-
-/**
- * is_pristine() called by rip_off()
- *
- * Used to determine whether the bandage can be re-used and won't qdel itself
- *
- */
-
-/datum/bodypart_aid/proc/is_pristine()
- return (integrity == initial(integrity))
-
-/datum/bodypart_aid/splint
- name = "splint"
- overlay_prefix = "splint"
- desc_prefix = "fastened"
- stack_to_drop = /obj/item/stack/medical/gauze
- /// How effective are we in keeping the bodypart rigid
- var/splint_factor = 0.3
- /// Whether the splint prevents the limb from being disabled, with a ruptured tendon or a shattered bone
- var/helps_disabled = TRUE
- /// Total condition of our splint, the more we use it the more it gets looser
- var/sling_condition = 5
-
-/datum/bodypart_aid/splint/get_description()
- var/desc
- switch(sling_condition)
- if(0 to 1.25)
- desc = "barely holding"
- if(1.25 to 2.75)
- desc = "loose"
- if(2.75 to 4)
- desc = "rigid"
- if(4 to INFINITY)
- desc = "tight"
- desc += " [name]"
- return desc
-
-/datum/bodypart_aid/splint/Destroy()
- SEND_SIGNAL(bodypart, COMSIG_BODYPART_SPLINT_DESTROYED)
- bodypart.current_splint = null
- return ..()
-
-/datum/bodypart_aid/splint/New(obj/item/bodypart/BP)
- bodypart = BP
- BP.current_splint = src
- SEND_SIGNAL(BP, COMSIG_BODYPART_SPLINTED, src)
- ..()
-
-/datum/bodypart_aid/splint/improvised
- name = "improvised splint"
- splint_factor = 0.6
- helps_disabled= FALSE
- stack_to_drop = /obj/item/stack/medical/gauze/improvised
- overlay_prefix = "splint_improv"
-
-/datum/bodypart_aid/gauze
- name = "gauze"
- stack_to_drop = /obj/item/stack/medical/gauze
- overlay_prefix = "gauze"
- desc_prefix = "bandaged"
- /// How much more can we absorb
- var/absorption_capacity = 5
- /// How fast do we absorb
- var/absorption_rate = 0.12
- /// How much does the gauze help with keeping infections clean
- var/sanitisation_factor = 0.4
- /// How much sanitisation we've got after we become fairly stained and worn
- var/sanitisation_factor_stained = 0.8
- /// Is it blood stained? For description
- var/blood_stained = FALSE
- /// Is it pus stained? For description
- var/pus_stained = FALSE
-
-/datum/bodypart_aid/gauze/get_description()
- var/desc
- switch(absorption_capacity)
- if(-INFINITY to 0)
- desc = "unusable"
- if(0 to 1.25)
- desc = "nearly ruined"
- if(1.25 to 2.75)
- desc = "badly worn"
- if(2.75 to 4)
- desc = "slightly used"
- if(4 to INFINITY)
- desc = "clean"
- if(blood_stained)
- desc += ", bloodied"
- if(pus_stained)
- desc += ", pus stained"
- desc += " [name]"
- return desc
-
-/datum/bodypart_aid/gauze/New(obj/item/bodypart/BP)
- bodypart = BP
- BP.current_gauze = src
- SEND_SIGNAL(BP, COMSIG_BODYPART_GAUZED, src)
- ..()
-
-/datum/bodypart_aid/gauze/Destroy()
- SEND_SIGNAL(bodypart, COMSIG_BODYPART_GAUZE_DESTROYED)
- bodypart.current_gauze = null
- return ..()
-
-/datum/bodypart_aid/gauze/is_pristine()
- . = ..()
- if(.)
- return (absorption_capacity == initial(absorption_capacity))
-
-/**
- * seep_gauze() is for when a gauze wrapping absorbs blood or pus from wounds, lowering its absorption capacity.
- *
- * The passed amount of seepage is deducted from the bandage's absorption capacity, and if we reach a negative absorption capacity, the bandage won't help our wounds.
- * When the bandage is left with a low amount of absorption, it'll notify user and act worse as a sanitiser for infections
- * Returns TRUE if the bandage absorbed anything, FALSE if it's fully stained.
- *
- * Arguments:
- * * seep_amt - How much absorption capacity we're removing from our current bandages (think, how much blood or pus are we soaking up this tick?)
- * * type - Is it blood or pus we're being stained with? GAUZE_STAIN_BLOOD, GAUZE_STAIN_PUS defines from wounds.dm
- */
-
-/datum/bodypart_aid/gauze/proc/seep_gauze(amount, type)
- if(absorption_capacity > 0)
- . = TRUE
- absorption_capacity -= amount
- else
- return FALSE
- //If our remaining absorption capacity is low, make so blood and pus stains show
- if(absorption_capacity < 2)
- sanitisation_factor = sanitisation_factor_stained
- if(type == GAUZE_STAIN_BLOOD && !blood_stained)
- blood_stained = TRUE
- if(bodypart.owner)
- to_chat(bodypart.owner, span_warning("The [name] on your [bodypart.name] [pick(list("pools", "trickles", "seeps"))] with blood."))
- else if(type == GAUZE_STAIN_PUS && !pus_stained)
- pus_stained = TRUE
- if(bodypart.owner)
- to_chat(bodypart.owner, span_warning("The [name] on your [bodypart.name] [pick(list("pools", "trickles", "seeps"))] with pus."))
-
-/datum/bodypart_aid/gauze/improvised
- name = "improvised gauze"
- stack_to_drop = /obj/item/stack/medical/gauze/improvised
- absorption_rate = 0.09
- absorption_capacity = 3
diff --git a/modular_skyrat/modules/medical/code/carbon_examine.dm b/modular_skyrat/modules/medical/code/carbon_examine.dm
index aab30138184..e86ed9f9267 100644
--- a/modular_skyrat/modules/medical/code/carbon_examine.dm
+++ b/modular_skyrat/modules/medical/code/carbon_examine.dm
@@ -49,11 +49,7 @@
if(WOUND_SEVERITY_CRITICAL)
msg += "\t[t_His] [LB.name] is suffering [W.a_or_from] [W.get_topic_name(user)]!!"
if(LB.current_gauze)
- var/datum/bodypart_aid/current_gauze = LB.current_gauze
- msg += "\t[t_His] [LB.name] is [current_gauze.desc_prefix] with [current_gauze.get_description()]."
- if(LB.current_splint)
- var/datum/bodypart_aid/current_splint = LB.current_splint
- msg += "\t[t_His] [LB.name] is [current_splint.desc_prefix] with a [current_splint.get_description()]."
+ msg += "\t[t_His] [LB.name] is [LB.current_gauze.get_gauze_usage_prefix()] with [LB.current_gauze.get_gauze_description()]."
if(!any_bodypart_damage)
msg += "\t[t_He] [t_Has] no significantly damaged bodyparts."
diff --git a/modular_skyrat/modules/medical/code/carbon_update_icons.dm b/modular_skyrat/modules/medical/code/carbon_update_icons.dm
index 76167bbf6ea..0c3b4bb4f47 100644
--- a/modular_skyrat/modules/medical/code/carbon_update_icons.dm
+++ b/modular_skyrat/modules/medical/code/carbon_update_icons.dm
@@ -6,15 +6,9 @@
for(var/b in bodyparts)
var/obj/item/bodypart/BP = b
- if(BP.current_gauze && BP.current_gauze.overlay_prefix)
- var/bp_suffix = BP.body_zone
- if(BP.bodytype & BODYTYPE_DIGITIGRADE)
- bp_suffix += "_digitigrade"
- overlays.add_overlay("[BP.current_gauze.overlay_prefix]_[bp_suffix]")
- if(BP.current_splint && BP.current_splint.overlay_prefix)
- var/bp_suffix = BP.body_zone
- if(BP.bodytype & BODYTYPE_DIGITIGRADE)
- bp_suffix += "_digitigrade"
- overlays.add_overlay("[BP.current_splint.overlay_prefix]_[bp_suffix]")
+ var/obj/item/stack/medical/gauze/our_gauze = BP.current_gauze
+ if (!our_gauze)
+ continue
+ overlays.add_overlay(our_gauze.get_overlay_prefix())
apply_overlay(BANDAGE_LAYER)
diff --git a/modular_skyrat/modules/medical/code/carbon_defense.dm b/modular_skyrat/modules/medical/code/grasp.dm
similarity index 100%
rename from modular_skyrat/modules/medical/code/carbon_defense.dm
rename to modular_skyrat/modules/medical/code/grasp.dm
diff --git a/modular_skyrat/modules/medical/code/medical_stacks.dm b/modular_skyrat/modules/medical/code/medical_stacks.dm
deleted file mode 100644
index 35b2ff1b1f9..00000000000
--- a/modular_skyrat/modules/medical/code/medical_stacks.dm
+++ /dev/null
@@ -1,65 +0,0 @@
-/obj/item/stack/medical/gauze
- var/gauze_type = /datum/bodypart_aid/gauze
- var/splint_type = /datum/bodypart_aid/splint
-
-/obj/item/stack/medical/gauze/improvised
- gauze_type = /datum/bodypart_aid/gauze/improvised
- splint_type = /datum/bodypart_aid/splint/improvised
-
-// gauze is only relevant for wounds, which are handled in the wounds themselves
-/obj/item/stack/medical/gauze/try_heal(mob/living/patient, mob/user, silent)
-
- var/treatment_delay = (user == patient ? self_delay : other_delay)
-
- var/obj/item/bodypart/limb = patient.get_bodypart(check_zone(user.zone_selected))
- if(!limb)
- patient.balloon_alert(user, "missing limb!")
- return
- if(!LAZYLEN(limb.wounds))
- patient.balloon_alert(user, "no wounds!") // good problem to have imo
- return
-
- var/gauzeable_wound = FALSE
- var/splintable_wound = FALSE
- var/datum/wound/woundies
- for(var/i in limb.wounds)
- woundies = i
- if(woundies.wound_flags & (ACCEPTS_GAUZE | ACCEPTS_SPLINT))
- if(woundies.wound_flags & ACCEPTS_GAUZE)
- gauzeable_wound = TRUE
- continue
- if(woundies.wound_flags & ACCEPTS_SPLINT)
- splintable_wound = TRUE
- continue
- if(!gauzeable_wound && !splintable_wound)
- patient.balloon_alert(user, "can't heal those!")
- return
-
- if(limb.current_gauze && gauzeable_wound)
- gauzeable_wound = FALSE
- if(limb.current_splint && splintable_wound)
- splintable_wound = FALSE
- if(!gauzeable_wound && !splintable_wound)
- balloon_alert(user, "already bandaged!")
- return
-
- if(HAS_TRAIT(woundies, TRAIT_WOUND_SCANNED))
- treatment_delay *= 0.5
- if(user == patient)
- user.visible_message(span_warning("[user] begins expertly [gauzeable_wound ? "wrapping the wounds on their [limb.plaintext_zone]" : "splinting their [limb.plaintext_zone]"] with [src]..."), span_notice("You keep in mind the indications from the holo-image about your injury, and expertly begin [gauzeable_wound ? "wrapping your wounds" : "splinting your [limb.plaintext_zone]"] with [src]."))
- else
- user.visible_message(span_warning("[user] begins expertly [gauzeable_wound ? "wrapping the wounds on [patient]'s [limb.plaintext_zone]" : "splinting [patient]'s [limb.plaintext_zone]"] with [src]..."), span_warning("You begin quickly [gauzeable_wound ? "wrapping the wounds on [patient]'s [limb.plaintext_zone]" : "splinting [patient]'s [limb.plaintext_zone]"] with [src], keeping the holo-image indications in mind..."))
- else
- user.visible_message(span_warning("[user] begins [gauzeable_wound ? "wrapping the wounds on [patient]'s [limb.plaintext_zone]" : "splinting [patient]'s [limb.plaintext_zone]"] with [src]..."), span_warning("You begin [gauzeable_wound ? "wrapping the wounds on" : "splinting"] [user == patient ? "your" : "[patient]'s"] [limb.plaintext_zone] with [src]..."))
-
- if(!do_after(user, treatment_delay, target = patient))
- return
-
- user.visible_message("[user] [gauzeable_wound ? "wraps the wounds on" : "splints"] [user == patient ? "[user.p_their()]" : "[patient]'s"] [limb.plaintext_zone] with [src].", "You [gauzeable_wound ? "wrap the wounds on" : "splint"] [user == patient ? "your" : "[patient]'s"] [limb.plaintext_zone].")
- if(gauzeable_wound)
- limb.apply_gauze(src)
- return
- if(splintable_wound)
- limb.apply_splint(src)
- return
-
diff --git a/modular_skyrat/modules/medical/code/wounds/bleed.dm b/modular_skyrat/modules/medical/code/wounds/bleed.dm
new file mode 100644
index 00000000000..75d80d3b384
--- /dev/null
+++ b/modular_skyrat/modules/medical/code/wounds/bleed.dm
@@ -0,0 +1,19 @@
+/datum/wound/slash/flesh/show_wound_topic(mob/user)
+ return (user == victim && blood_flow)
+
+/datum/wound/slash/flesh/Topic(href, href_list)
+ . = ..()
+ if(href_list["wound_topic"])
+ if(!usr == victim)
+ return
+ victim.self_grasp_bleeding_limb(limb)
+
+/datum/wound/pierce/bleed/show_wound_topic(mob/user)
+ return (user == victim && blood_flow)
+
+/datum/wound/slash/bleed/Topic(href, href_list)
+ . = ..()
+ if(href_list["wound_topic"])
+ if(!usr == victim)
+ return
+ victim.self_grasp_bleeding_limb(limb)
diff --git a/modular_skyrat/modules/medical/code/wounds/bones.dm b/modular_skyrat/modules/medical/code/wounds/bones.dm
deleted file mode 100644
index 089e289e3d8..00000000000
--- a/modular_skyrat/modules/medical/code/wounds/bones.dm
+++ /dev/null
@@ -1,455 +0,0 @@
-
-/*
- Blunt/Bone wounds
-*/
-// TODO: well, a lot really, but i'd kill to get overlays and a bonebreaking effect like Blitz: The League, similar to electric shock skeletons
-
-/datum/wound/blunt
- name = "Blunt (Bone) Wound"
- sound_effect = 'sound/effects/wounds/crack1.ogg'
- wound_type = WOUND_BLUNT
- wound_flags = (BONE_WOUND | ACCEPTS_SPLINT)
-
- /// Have we been taped?
- var/taped
- /// Have we been bone gel'd?
- var/gelled
- /// If we did the gel + surgical tape healing method for fractures, how many ticks does it take to heal by default
- var/regen_ticks_needed
- /// Our current counter for gel + surgical tape regeneration
- var/regen_ticks_current
- /// If we suffer severe head booboos, we can get brain traumas tied to them
- var/datum/brain_trauma/active_trauma
- /// What brain trauma group, if any, we can draw from for head wounds
- var/brain_trauma_group
- /// If we deal brain traumas, when is the next one due?
- var/next_trauma_cycle
- /// How long do we wait +/- 20% for the next trauma?
- var/trauma_cycle_cooldown
- /// If this is a chest wound and this is set, we have this chance to cough up blood when hit in the chest
- var/internal_bleeding_chance = 0
-
-/*
- Overwriting of base procs
-*/
-/datum/wound/blunt/wound_injury(datum/wound/old_wound = null, attack_direction)
- // hook into gaining/losing gauze so crit bone wounds can re-enable/disable depending if they're slung or not
- RegisterSignals(limb, list(COMSIG_BODYPART_SPLINTED, COMSIG_BODYPART_SPLINT_DESTROYED), PROC_REF(update_inefficiencies))
-
- if(limb.body_zone == BODY_ZONE_HEAD && brain_trauma_group)
- processes = TRUE
- active_trauma = victim.gain_trauma_type(brain_trauma_group, TRAUMA_RESILIENCE_WOUND)
- next_trauma_cycle = world.time + (rand(100-WOUND_BONE_HEAD_TIME_VARIANCE, 100+WOUND_BONE_HEAD_TIME_VARIANCE) * 0.01 * trauma_cycle_cooldown)
-
- RegisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(attack_with_hurt_hand))
- if(limb.held_index && victim.get_item_for_held_index(limb.held_index) && (disabling || prob(30 * severity)))
- var/obj/item/held_item = victim.get_item_for_held_index(limb.held_index)
- if(istype(held_item, /obj/item/offhand))
- held_item = victim.get_inactive_held_item()
-
- if(held_item && victim.dropItemToGround(held_item))
- victim.visible_message(span_danger("[victim] drops [held_item] in shock!"), span_warning("The force on your [parse_zone(limb.body_zone)] causes you to drop [held_item]!"), vision_distance=COMBAT_MESSAGE_RANGE)
-
- update_inefficiencies()
-
-/datum/wound/blunt/remove_wound(ignore_limb, replaced)
- limp_slowdown = 0
- QDEL_NULL(active_trauma)
- if(limb)
- UnregisterSignal(limb, list(COMSIG_BODYPART_GAUZED, COMSIG_BODYPART_GAUZE_DESTROYED))
- if(victim)
- UnregisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK)
- return ..()
-
-/datum/wound/blunt/handle_process()
- . = ..()
- if(limb.body_zone == BODY_ZONE_HEAD && brain_trauma_group && world.time > next_trauma_cycle)
- if(active_trauma)
- QDEL_NULL(active_trauma)
- else
- active_trauma = victim.gain_trauma_type(brain_trauma_group, TRAUMA_RESILIENCE_WOUND)
- next_trauma_cycle = world.time + (rand(100-WOUND_BONE_HEAD_TIME_VARIANCE, 100+WOUND_BONE_HEAD_TIME_VARIANCE) * 0.01 * trauma_cycle_cooldown)
-
- if(!gelled || !taped)
- return
-
- regen_ticks_current++
- if(victim.body_position == LYING_DOWN)
- if(prob(50))
- regen_ticks_current += 0.5
- if(victim.IsSleeping() && prob(50))
- regen_ticks_current += 0.5
-
- if(prob(severity * 3))
- victim.take_bodypart_damage(rand(1, severity * 2), wound_bonus = CANT_WOUND)
- victim.adjustStaminaLoss(rand(2, severity * 2.5))
- if(prob(33))
- to_chat(victim, span_danger("You feel a sharp pain in your body as your bones are reforming!"))
-
- if(regen_ticks_current > regen_ticks_needed)
- if(!victim || !limb)
- qdel(src)
- return
- to_chat(victim, span_green("Your [parse_zone(limb.body_zone)] has recovered from your fracture!"))
- remove_wound()
-
-/// If we're a human who's punching something with a broken arm, we might hurt ourselves doing so
-/datum/wound/blunt/proc/attack_with_hurt_hand(mob/M, atom/target, proximity)
- SIGNAL_HANDLER
-
- if(victim.get_active_hand() != limb || !victim.combat_mode || !ismob(target) || severity <= WOUND_SEVERITY_MODERATE)
- return
-
- // With a severe or critical wound, you have a 15% or 30% chance to proc pain on hit
- if(prob((severity - 1) * 15))
- // And you have a 70% or 50% chance to actually land the blow, respectively
- if(prob(70 - 20 * (severity - 1)))
- to_chat(victim, span_userdanger("The fracture in your [parse_zone(limb.body_zone)] shoots with pain as you strike [target]!"))
- limb.receive_damage(brute=rand(1,5))
- else
- victim.visible_message(span_danger("[victim] weakly strikes [target] with [victim.p_their()] broken [parse_zone(limb.body_zone)], recoiling from pain!"), \
- span_userdanger("You fail to strike [target] as the fracture in your [parse_zone(limb.body_zone)] lights up in unbearable pain!"), vision_distance=COMBAT_MESSAGE_RANGE)
- INVOKE_ASYNC(victim, TYPE_PROC_REF(/mob, emote), "scream")
- victim.Stun(0.5 SECONDS)
- limb.receive_damage(brute=rand(3,7))
- return COMPONENT_CANCEL_ATTACK_CHAIN
-
-
-/datum/wound/blunt/receive_damage(wounding_type, wounding_dmg, wound_bonus)
- if(!victim || wounding_dmg < WOUND_MINIMUM_DAMAGE)
- return
- if(ishuman(victim))
- var/mob/living/carbon/human/human_victim = victim
- if(HAS_TRAIT(human_victim, TRAIT_NOBLOOD))
- return
-
- if(limb.body_zone == BODY_ZONE_CHEST && victim.blood_volume && prob(internal_bleeding_chance + wounding_dmg))
- var/blood_bled = rand(1, wounding_dmg * (severity == WOUND_SEVERITY_CRITICAL ? 2 : 1.5)) // 12 brute toolbox can cause up to 18/24 bleeding with a severe/critical chest wound
- switch(blood_bled)
- if(1 to 6)
- victim.bleed(blood_bled, TRUE)
- if(7 to 13)
- victim.visible_message(span_smalldanger("A thin stream of blood drips from [victim]'s mouth from the blow to [victim.p_their()] chest."), span_danger("You cough up a bit of blood from the blow to your chest."), vision_distance=COMBAT_MESSAGE_RANGE)
- victim.bleed(blood_bled, TRUE)
- if(14 to 19)
- victim.visible_message(span_smalldanger("Blood spews out of [victim]'s mouth from the blow to [victim.p_their()] chest!"), span_danger("You spit out a string of blood from the blow to your chest!"), vision_distance=COMBAT_MESSAGE_RANGE)
- new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
- victim.bleed(blood_bled)
- if(20 to INFINITY)
- victim.visible_message(span_danger("Blood spurts out of [victim]'s mouth from the blow to [victim.p_their()] chest!"), span_danger("You choke up on a spray of blood from the blow to your chest!"), vision_distance=COMBAT_MESSAGE_RANGE)
- victim.bleed(blood_bled)
- new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
- victim.add_splatter_floor(get_step(victim.loc, victim.dir))
-
-
-/datum/wound/blunt/get_examine_description(mob/user)
- if(!limb.current_splint && !gelled && !taped)
- return ..()
-
- var/list/msg = list()
- if(!limb.current_splint)
- msg += "[victim.p_their(TRUE)] [parse_zone(limb.body_zone)] [examine_desc]"
- else
- var/sling_condition = ""
- // how much life we have left in these bandages
- switch(limb.current_splint.sling_condition)
- if(0 to 1.25)
- sling_condition = "just barely"
- if(1.25 to 2.75)
- sling_condition = "loosely"
- if(2.75 to 4)
- sling_condition = "mostly"
- if(4 to INFINITY)
- sling_condition = "tightly"
-
- msg += "[victim.p_their(TRUE)] [parse_zone(limb.body_zone)] is [sling_condition] fastened with a [limb.current_splint.name]"
-
- if(taped)
- msg += ", and appears to be reforming itself under some surgical tape!"
- else if(gelled)
- msg += ", with fizzing flecks of blue bone gel sparking off the bone!"
- else
- msg += "!"
- return "[msg.Join()]"
-
-/*
- New common procs for /datum/wound/blunt/
-*/
-
-/datum/wound/blunt/proc/update_inefficiencies()
- SIGNAL_HANDLER
- if(limb.body_zone in list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
- if(limb.current_splint)
- limp_slowdown = initial(limp_slowdown) * limb.current_splint.splint_factor
- else
- limp_slowdown = initial(limp_slowdown)
- victim.apply_status_effect(/datum/status_effect/limp)
- else if(limb.body_zone in list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
- if(limb.current_splint)
- interaction_efficiency_penalty = 1 + ((interaction_efficiency_penalty - 1) * limb.current_splint.splint_factor)
- else
- interaction_efficiency_penalty = interaction_efficiency_penalty
-
- if(initial(disabling))
- set_disabling(!(limb.current_splint && limb.current_splint.helps_disabled))
-
- limb.update_wounds()
-
-/// Joint Dislocation (Moderate Blunt)
-/datum/wound/blunt/moderate
- name = "Joint Dislocation"
- desc = "Patient's bone has been unset from socket, causing pain and reduced motor function."
- treat_text = "Recommended application of bonesetter to affected limb, though manual relocation by applying an aggressive grab to the patient and helpfully interacting with afflicted limb may suffice."
- examine_desc = "is awkwardly jammed out of place"
- occur_text = "jerks violently and becomes unseated"
- severity = WOUND_SEVERITY_MODERATE
- viable_zones = list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
- interaction_efficiency_penalty = 1.5
- limp_slowdown = 3
- threshold_minimum = 35
- threshold_penalty = 15
- treatable_tool = TOOL_BONESET
- wound_flags = (BONE_WOUND)
- status_effect_type = /datum/status_effect/wound/blunt/moderate
- scar_keyword = "bluntmoderate"
-
-/datum/wound/blunt/moderate/Destroy()
- if(victim)
- UnregisterSignal(victim, COMSIG_LIVING_DOORCRUSHED)
- return ..()
-
-/datum/wound/blunt/moderate/wound_injury(datum/wound/old_wound, attack_direction)
- . = ..()
- RegisterSignal(victim, COMSIG_LIVING_DOORCRUSHED, PROC_REF(door_crush))
-
-/// Getting smushed in an airlock/firelock is a last-ditch attempt to try relocating your limb
-/datum/wound/blunt/moderate/proc/door_crush()
- SIGNAL_HANDLER
- if(prob(33))
- victim.visible_message(span_danger("[victim]'s dislocated [parse_zone(limb.body_zone)] pops back into place!"), span_userdanger("Your dislocated [parse_zone(limb.body_zone)] pops back into place! Ow!"))
- remove_wound()
-
-/datum/wound/blunt/moderate/try_handling(mob/living/carbon/human/user)
- if(user.pulling != victim || user.zone_selected != limb.body_zone)
- return FALSE
-
- if(user.grab_state == GRAB_PASSIVE)
- to_chat(user, span_warning("You must have [victim] in an aggressive grab to manipulate [victim.p_their()] [lowertext(name)]!"))
- return TRUE
-
- if(user.grab_state >= GRAB_AGGRESSIVE)
- user.visible_message(span_danger("[user] begins twisting and straining [victim]'s dislocated [parse_zone(limb.body_zone)]!"), span_notice("You begin twisting and straining [victim]'s dislocated [parse_zone(limb.body_zone)]..."), ignored_mobs=victim)
- to_chat(victim, span_userdanger("[user] begins twisting and straining your dislocated [parse_zone(limb.body_zone)]!"))
- if(!user.combat_mode)
- chiropractice(user)
- else
- malpractice(user)
- return TRUE
-
-/// If someone is snapping our dislocated joint back into place by hand with an aggro grab and help intent
-/datum/wound/blunt/moderate/proc/chiropractice(mob/living/carbon/human/user)
- var/time = base_treat_time
-
- if(!do_after(user, time, target=victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
- return
-
- if(prob(65))
- user.visible_message(span_danger("[user] snaps [victim]'s dislocated [parse_zone(limb.body_zone)] back into place!"), span_notice("You snap [victim]'s dislocated [parse_zone(limb.body_zone)] back into place!"), ignored_mobs=victim)
- to_chat(victim, span_userdanger("[user] snaps your dislocated [parse_zone(limb.body_zone)] back into place!"))
- victim.emote("scream")
- limb.receive_damage(brute=20, wound_bonus=CANT_WOUND)
- qdel(src)
- else
- user.visible_message(span_danger("[user] wrenches [victim]'s dislocated [parse_zone(limb.body_zone)] around painfully!"), span_danger("You wrench [victim]'s dislocated [parse_zone(limb.body_zone)] around painfully!"), ignored_mobs=victim)
- to_chat(victim, span_userdanger("[user] wrenches your dislocated [parse_zone(limb.body_zone)] around painfully!"))
- limb.receive_damage(brute=10, wound_bonus=CANT_WOUND)
- chiropractice(user)
-
-/// If someone is snapping our dislocated joint into a fracture by hand with an aggro grab and harm or disarm intent
-/datum/wound/blunt/moderate/proc/malpractice(mob/living/carbon/human/user)
- var/time = base_treat_time
-
- if(!do_after(user, time, target=victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
- return
-
- if(prob(65))
- user.visible_message(span_danger("[user] snaps [victim]'s dislocated [parse_zone(limb.body_zone)] with a sickening crack!"), span_danger("You snap [victim]'s dislocated [parse_zone(limb.body_zone)] with a sickening crack!"), ignored_mobs=victim)
- to_chat(victim, span_userdanger("[user] snaps your dislocated [parse_zone(limb.body_zone)] with a sickening crack!"))
- victim.emote("scream")
- limb.receive_damage(brute=25, wound_bonus=30)
- else
- user.visible_message(span_danger("[user] wrenches [victim]'s dislocated [parse_zone(limb.body_zone)] around painfully!"), span_danger("You wrench [victim]'s dislocated [parse_zone(limb.body_zone)] around painfully!"), ignored_mobs=victim)
- to_chat(victim, span_userdanger("[user] wrenches your dislocated [parse_zone(limb.body_zone)] around painfully!"))
- limb.receive_damage(brute=10, wound_bonus=CANT_WOUND)
- malpractice(user)
-
-
-/datum/wound/blunt/moderate/treat(obj/item/I, mob/user)
- if(victim == user)
- victim.visible_message(span_danger("[user] begins resetting [victim.p_their()] [parse_zone(limb.body_zone)] with [I]."), span_warning("You begin resetting your [parse_zone(limb.body_zone)] with [I]..."))
- else
- user.visible_message(span_danger("[user] begins resetting [victim]'s [parse_zone(limb.body_zone)] with [I]."), span_notice("You begin resetting [victim]'s [parse_zone(limb.body_zone)] with [I]..."))
-
- if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, PROC_REF(still_exists))))
- return
-
- if(victim == user)
- limb.receive_damage(brute=15, wound_bonus=CANT_WOUND)
- victim.visible_message(span_danger("[user] finishes resetting [victim.p_their()] [parse_zone(limb.body_zone)]!"), span_userdanger("You reset your [parse_zone(limb.body_zone)]!"))
- else
- limb.receive_damage(brute=10, wound_bonus=CANT_WOUND)
- user.visible_message(span_danger("[user] finishes resetting [victim]'s [parse_zone(limb.body_zone)]!"), span_nicegreen("You finish resetting [victim]'s [parse_zone(limb.body_zone)]!"), victim)
- to_chat(victim, span_userdanger("[user] resets your [parse_zone(limb.body_zone)]!"))
-
- victim.emote("scream")
- qdel(src)
-
-/*
- Severe (Hairline Fracture)
-*/
-
-/datum/wound/blunt/severe
- name = "Hairline Fracture"
- desc = "Patient's bone has suffered a crack in the foundation, causing serious pain and reduced limb functionality."
- treat_text = "Recommended light surgical application of bone gel, though a sling of medical gauze will prevent worsening situation."
- examine_desc = "appears grotesquely swollen, its attachment weakened"
- occur_text = "sprays chips of bone and develops a nasty looking bruise"
-
- severity = WOUND_SEVERITY_SEVERE
- interaction_efficiency_penalty = 2
- limp_slowdown = 6
- threshold_minimum = 60
- threshold_penalty = 30
- treatable_by = list(/obj/item/stack/sticky_tape/surgical, /obj/item/stack/medical/bone_gel)
- status_effect_type = /datum/status_effect/wound/blunt/severe
- scar_keyword = "bluntsevere"
- brain_trauma_group = BRAIN_TRAUMA_MILD
- trauma_cycle_cooldown = 1.5 MINUTES
- internal_bleeding_chance = 40
- wound_flags = (BONE_WOUND | ACCEPTS_SPLINT | MANGLES_BONE)
- regen_ticks_needed = 120 // ticks every 2 seconds, 240 seconds, so roughly 4 minutes default
-
-/// Compound Fracture (Critical Blunt)
-/datum/wound/blunt/critical
- name = "Compound Fracture"
- desc = "Patient's bones have suffered multiple gruesome fractures, causing significant pain and near uselessness of limb."
- treat_text = "Immediate binding of affected limb, followed by surgical intervention ASAP."
- examine_desc = "is mangled and pulped, seemingly held together by tissue alone"
- occur_text = "cracks apart, exposing broken bones to open air"
-
- severity = WOUND_SEVERITY_CRITICAL
- interaction_efficiency_penalty = 4
- limp_slowdown = 9
- sound_effect = 'sound/effects/wounds/crack2.ogg'
- threshold_minimum = 115
- threshold_penalty = 50
- disabling = TRUE
- treatable_by = list(/obj/item/stack/sticky_tape/surgical, /obj/item/stack/medical/bone_gel)
- status_effect_type = /datum/status_effect/wound/blunt/critical
- scar_keyword = "bluntcritical"
- brain_trauma_group = BRAIN_TRAUMA_SEVERE
- trauma_cycle_cooldown = 2.5 MINUTES
- internal_bleeding_chance = 60
- wound_flags = (BONE_WOUND | ACCEPTS_SPLINT | MANGLES_BONE)
- regen_ticks_needed = 240 // ticks every 2 seconds, 480 seconds, so roughly 8 minutes default
-
-// doesn't make much sense for "a" bone to stick out of your head
-/datum/wound/blunt/critical/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE, attack_direction = null, wound_source = "Unknown")
- if(L.body_zone == BODY_ZONE_HEAD)
- occur_text = "splits open, exposing a bare, cracked skull through the flesh and blood"
- examine_desc = "has an unsettling indent, with bits of skull poking out"
- . = ..()
-
-/// if someone is using bone gel on our wound
-/datum/wound/blunt/proc/gel(obj/item/stack/medical/bone_gel/gel, mob/user)
- if(gelled)
- to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [parse_zone(limb.body_zone)] is already coated with bone gel!"))
- return
-
- user.visible_message(span_danger("[user] begins hastily applying [gel] to [victim]'s' [parse_zone(limb.body_zone)]..."), span_warning("You begin hastily applying [gel] to [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)], disregarding the warning label..."))
-
- if(!do_after(user, base_treat_time * 1.5 * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, PROC_REF(still_exists))))
- return
-
- gel.use(1)
- victim.emote("scream")
- if(user != victim)
- user.visible_message(span_notice("[user] finishes applying [gel] to [victim]'s [parse_zone(limb.body_zone)], emitting a fizzing noise!"), span_notice("You finish applying [gel] to [victim]'s [parse_zone(limb.body_zone)]!"), ignored_mobs=victim)
- to_chat(victim, span_userdanger("[user] finishes applying [gel] to your [parse_zone(limb.body_zone)], and you can feel the bones exploding with pain as they begin melting and reforming!"))
- else
- var/painkiller_bonus = 0
- if(victim.get_drunk_amount() > 10)
- painkiller_bonus += 10
- if(victim.reagents.has_reagent(/datum/reagent/medicine/morphine))
- painkiller_bonus += 20
- if(victim.reagents.has_reagent(/datum/reagent/determination))
- painkiller_bonus += 10
- if(victim.reagents.has_reagent(/datum/reagent/consumable/ethanol/painkiller))
- painkiller_bonus += 5
- if(victim.reagents.has_reagent(/datum/reagent/medicine/mine_salve))
- painkiller_bonus += 20
-
- if(prob(25 + (20 * (severity - 2)) - painkiller_bonus)) // 25%/45% chance to fail self-applying with severe and critical wounds, modded by painkillers
- victim.visible_message(span_danger("[victim] fails to finish applying [gel] to [victim.p_their()] [parse_zone(limb.body_zone)], passing out from the pain!"), span_notice("You pass out from the pain of applying [gel] to your [parse_zone(limb.body_zone)] before you can finish!"))
- victim.AdjustUnconscious(5 SECONDS)
- return
- victim.visible_message(span_notice("[victim] finishes applying [gel] to [victim.p_their()] [parse_zone(limb.body_zone)], grimacing from the pain!"), span_notice("You finish applying [gel] to your [parse_zone(limb.body_zone)], and your bones explode in pain!"))
-
- limb.receive_damage(25, wound_bonus=CANT_WOUND)
- victim.adjustStaminaLoss(100)
- if(!gelled)
- gelled = TRUE
-
-/// if someone is using surgical tape on our wound
-/datum/wound/blunt/proc/tape(obj/item/stack/sticky_tape/surgical/tape, mob/user)
- if(!gelled)
- to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [parse_zone(limb.body_zone)] must be coated with bone gel to perform this emergency operation!"))
- return
- if(taped)
- to_chat(user, span_warning("[user == victim ? "Your" : "[victim]'s"] [parse_zone(limb.body_zone)] is already wrapped in [tape.name] and reforming!"))
- return
-
- user.visible_message(span_danger("[user] begins applying [tape] to [victim]'s' [parse_zone(limb.body_zone)]..."), span_warning("You begin applying [tape] to [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)]..."))
-
- if(!do_after(user, base_treat_time * (user == victim ? 1.5 : 1), target = victim, extra_checks=CALLBACK(src, PROC_REF(still_exists))))
- return
-
- if(victim == user)
- regen_ticks_needed *= 1.5
-
- tape.use(1)
- if(user != victim)
- user.visible_message(span_notice("[user] finishes applying [tape] to [victim]'s [parse_zone(limb.body_zone)], emitting a fizzing noise!"), span_notice("You finish applying [tape] to [victim]'s [parse_zone(limb.body_zone)]!"), ignored_mobs=victim)
- to_chat(victim, span_green("[user] finishes applying [tape] to your [parse_zone(limb.body_zone)], you immediately begin to feel your bones start to reform!"))
- else
- victim.visible_message(span_notice("[victim] finishes applying [tape] to [victim.p_their()] [parse_zone(limb.body_zone)], !"), span_green("You finish applying [tape] to your [parse_zone(limb.body_zone)], and you immediately begin to feel your bones start to reform!"))
-
- taped = TRUE
- processes = TRUE
-
-/datum/wound/blunt/treat(obj/item/used_item, mob/user)
- if(istype(used_item, /obj/item/stack/medical/bone_gel))
- gel(used_item, user)
- else if(istype(used_item, /obj/item/stack/sticky_tape/surgical))
- tape(used_item, user)
-
-/datum/wound/blunt/get_scanner_description(mob/user)
- . = ..()
-
- . += ""
-
- if(!gelled)
- . += "Alternative Treatment: Apply bone gel directly to injured limb, then apply surgical tape to begin bone regeneration. This is both excruciatingly painful and slow, and only recommended in dire circumstances.\n"
- else if(!taped)
- . += span_notice("Continue Alternative Treatment: Apply surgical tape directly to injured limb to begin bone regeneration. Note, this is both excruciatingly painful and slow, though sleep or laying down will speed recovery.\n")
- else
- . += span_notice("Note: Bone regeneration in effect. Bone is [round(regen_ticks_current*100/regen_ticks_needed)]% regenerated.\n")
-
- if(limb.body_zone == BODY_ZONE_HEAD)
- . += "Cranial Trauma Detected: Patient will suffer random bouts of [severity == WOUND_SEVERITY_SEVERE ? "mild" : "severe"] brain traumas until bone is repaired."
- else if(limb.body_zone == BODY_ZONE_CHEST && victim.blood_volume)
- . += "Ribcage Trauma Detected: Further trauma to chest is likely to worsen internal bleeding until bone is repaired."
- . += "
"
-
-/datum/wound/blunt/get_limb_examine_description()
- return span_warning("The bones in this limb appear badly cracked.")
diff --git a/modular_skyrat/modules/medical/code/wounds/burns.dm b/modular_skyrat/modules/medical/code/wounds/burns.dm
deleted file mode 100644
index 45eb0f2b7dc..00000000000
--- a/modular_skyrat/modules/medical/code/wounds/burns.dm
+++ /dev/null
@@ -1,311 +0,0 @@
-
-/*
- Burn wounds
-*/
-
-// TODO: well, a lot really, but specifically I want to add potential fusing of clothing/equipment on the affected area, and limb infections, though those may go in body part code
-/datum/wound/burn
- name = "Burn Wound"
- a_or_from = "from"
- wound_type = WOUND_BURN
- processes = TRUE
- sound_effect = 'sound/effects/wounds/sizzle1.ogg'
- wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE)
-
- treatable_by = list(/obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh) // sterilizer and alcohol will require reagent treatments, coming soon
-
- // Flesh damage vars
- /// How much damage to our flesh we currently have. Once both this and infestation reach 0, the wound is considered healed
- var/flesh_damage = 5
- /// Our current counter for how much flesh regeneration we have stacked from regenerative mesh/synthflesh/whatever, decrements each tick and lowers flesh_damage
- var/flesh_healing = 0
-
- // Infestation vars (only for severe and critical)
- /// How quickly infection breeds on this burn if we don't have disinfectant
- var/infestation_rate = 0
- /// Our current level of infection
- var/infestation = 0
- /// Our current level of sanitization/anti-infection, from disinfectants/alcohol/UV lights. While positive, totally pauses and slowly reverses infestation effects each tick
- var/sanitization = 0
-
- /// Once we reach infestation beyond WOUND_INFESTATION_SEPSIS, we get this many warnings before the limb is completely paralyzed (you'd have to ignore a really bad burn for a really long time for this to happen)
- var/strikes_to_lose_limb = 3
-
-
-/datum/wound/burn/handle_process()
- . = ..()
- if(strikes_to_lose_limb == 0) // we've already hit sepsis, nothing more to do
- victim.adjustToxLoss(0.5)
- if(prob(1))
- victim.visible_message(span_danger("The infection on the remnants of [victim]'s [parse_zone(limb.body_zone)] shift and bubble nauseatingly!"), span_warning("You can feel the infection on the remnants of your [parse_zone(limb.body_zone)] coursing through your veins!"), vision_distance = COMBAT_MESSAGE_RANGE)
- return
-
- if(victim.reagents)
- if(victim.reagents.has_reagent(/datum/reagent/medicine/spaceacillin))
- sanitization += 0.9
- if(victim.reagents.has_reagent(/datum/reagent/space_cleaner/sterilizine))
- sanitization += 0.9
- if(victim.reagents.has_reagent(/datum/reagent/medicine/mine_salve))
- sanitization += 0.3
- flesh_healing += 0.5
-
- var/bandage_factor = 1 // good bandages multiply the length of flesh healing
- if(limb.current_gauze && limb.current_gauze.seep_gauze(WOUND_BURN_SANITIZATION_RATE, GAUZE_STAIN_PUS))
- bandage_factor = limb.current_gauze.sanitisation_factor
-
-
- // if we have little/no infection, the limb doesn't have much burn damage, and our nutrition is good, heal some flesh
- if(infestation <= WOUND_INFECTION_MODERATE && (limb.burn_dam < 5) && (victim.nutrition >= NUTRITION_LEVEL_FED))
- flesh_healing += 0.2
-
- if(flesh_healing > 0)
- flesh_damage = max(0, flesh_damage - 0.5)
- flesh_healing = max(0, flesh_healing - (0.5 * bandage_factor)) // good bandages multiply the length of flesh healing
-
- // here's the check to see if we're cleared up
- if((flesh_damage <= 0) && (infestation <= 1))
- to_chat(victim, span_green("The burns on your [parse_zone(limb.body_zone)] have cleared up!"))
- qdel(src)
- return
-
- // sanitization is checked after the clearing check but before the actual ill-effects, because we freeze the effects of infection while we have sanitization
- if(sanitization > 0)
- infestation = max(0, infestation - WOUND_BURN_SANITIZATION_RATE)
- sanitization = max(0, sanitization - (WOUND_BURN_SANITIZATION_RATE * bandage_factor))
- return
-
- infestation += infestation_rate
-
- switch(infestation)
- if(0 to WOUND_INFECTION_MODERATE)
- if(WOUND_INFECTION_MODERATE to WOUND_INFECTION_SEVERE)
- if(prob(30))
- victim.adjustToxLoss(0.2)
- if(prob(6))
- to_chat(victim, span_warning("The blisters on your [parse_zone(limb.body_zone)] ooze a strange pus..."))
- if(WOUND_INFECTION_SEVERE to WOUND_INFECTION_CRITICAL)
- if(!disabling && prob(2))
- to_chat(victim, span_warning("Your [parse_zone(limb.body_zone)] completely locks up, as you struggle for control against the infection!"))
- set_disabling(TRUE)
- else if(disabling && prob(8))
- to_chat(victim, span_notice("You regain sensation in your [parse_zone(limb.body_zone)], but it's still in terrible shape!"))
- set_disabling(FALSE)
- else if(prob(20))
- victim.adjustToxLoss(0.5)
- if(WOUND_INFECTION_CRITICAL to WOUND_INFECTION_SEPTIC)
- if(!disabling && prob(3))
- to_chat(victim, span_warning("You suddenly lose all sensation of the festering infection in your [parse_zone(limb.body_zone)]!"))
- set_disabling(TRUE)
- else if(disabling && prob(3))
- to_chat(victim, span_notice("You can barely feel your [parse_zone(limb.body_zone)] again, and you have to strain to retain motor control!"))
- set_disabling(FALSE)
- else if(prob(1))
- to_chat(victim, span_warning("You contemplate life without your [parse_zone(limb.body_zone)]..."))
- victim.adjustToxLoss(0.75)
- else if(prob(4))
- victim.adjustToxLoss(1)
- if(WOUND_INFECTION_SEPTIC to INFINITY)
- if(prob(infestation))
- switch(strikes_to_lose_limb)
- if(3 to INFINITY)
- to_chat(victim, span_deadsay("The skin on your [parse_zone(limb.body_zone)] is literally dripping off, you feel awful!"))
- if(2)
- to_chat(victim, span_deadsay("The infection in your [parse_zone(limb.body_zone)] is literally dripping off, you feel horrible!"))
- if(1)
- to_chat(victim, span_deadsay("Infection has just about completely claimed your [parse_zone(limb.body_zone)]!"))
- if(0)
- to_chat(victim, span_deadsay("The last of the nerve endings in your [parse_zone(limb.body_zone)] wither away, as the infection completely paralyzes your joint connector."))
- threshold_penalty = 120 // piss easy to destroy
- var/datum/brain_trauma/severe/paralysis/sepsis = new (limb.body_zone)
- victim.gain_trauma(sepsis)
- strikes_to_lose_limb--
-
-/datum/wound/burn/get_examine_description(mob/user)
- if(strikes_to_lose_limb <= 0)
- return span_deadsay("[victim.p_Their()] [parse_zone(limb.body_zone)] has locked up completely and is non-functional. Amputate or augment limb immediately, or place the patient in a cryotube.")
-
- var/list/condition = list("[victim.p_Their()] [parse_zone(limb.body_zone)] [examine_desc]")
- if(limb.current_gauze)
- var/bandage_condition
- switch(limb.current_gauze.absorption_capacity)
- if(0 to 1.25)
- bandage_condition = "nearly ruined"
- if(1.25 to 2.75)
- bandage_condition = "badly worn"
- if(2.75 to 4)
- bandage_condition = "slightly pus-stained"
- if(4 to INFINITY)
- bandage_condition = "clean"
-
- condition += " underneath a dressing of [bandage_condition] [limb.current_gauze.name]"
- else
- switch(infestation)
- if(WOUND_INFECTION_MODERATE to WOUND_INFECTION_SEVERE)
- condition += ", with small spots of discoloration along the nearby veins!"
- if(WOUND_INFECTION_SEVERE to WOUND_INFECTION_CRITICAL)
- condition += ", with growing clouds of infection."
- if(WOUND_INFECTION_CRITICAL to WOUND_INFECTION_SEPTIC)
- condition += ", with streaks of rotten, pulsating infection!"
- if(WOUND_INFECTION_SEPTIC to INFINITY)
- return span_deadsay("[victim.p_Their()] [parse_zone(limb.body_zone)] is a mess of charred skin and infected rot!")
- else
- condition += "!"
-
- return "[condition.Join()]"
-
-/datum/wound/burn/get_scanner_description(mob/user)
- if(strikes_to_lose_limb == 0)
- var/oopsie = "Type: [name]\nSeverity: [severity_text()]"
- oopsie += "Infection Level: The bodypart has suffered complete sepsis and must be removed. Amputate or augment limb immediately.
"
- return oopsie
-
- . = ..()
- . += ""
-
- if(infestation <= sanitization && flesh_damage <= flesh_healing)
- . += "No further treatment required: Burns will heal shortly."
- else
- switch(infestation)
- if(WOUND_INFECTION_MODERATE to WOUND_INFECTION_SEVERE)
- . += "Infection Level: Moderate\n"
- if(WOUND_INFECTION_SEVERE to WOUND_INFECTION_CRITICAL)
- . += "Infection Level: Severe\n"
- if(WOUND_INFECTION_CRITICAL to WOUND_INFECTION_SEPTIC)
- . += "Infection Level: CRITICAL\n"
- if(WOUND_INFECTION_SEPTIC to INFINITY)
- . += "Infection Level: LOSS IMMINENT\n"
- if(infestation > sanitization)
- . += "\tSurgical debridement, antibiotics/sterilizers, or regenerative mesh will rid infection. Paramedic UV penlights are also effective.\n"
-
- if(flesh_damage > 0)
- . += "Flesh damage detected: Application of ointment, regenerative mesh, Synthflesh, or ingestion of \"Miner's Salve\" will repair damaged flesh. Good nutrition, rest, and keeping the wound clean can also slowly repair flesh.\n"
- . += "
"
-
-/datum/wound/burn/get_limb_examine_description()
- return span_warning("The flesh on this limb appears badly cooked.")
-
-/*
- new burn common procs
-*/
-
-/// if someone is using ointment or mesh on our burns
-/datum/wound/burn/proc/ointmentmesh(obj/item/stack/medical/treatment_item, mob/user)
- user.visible_message(span_notice("[user] begins applying [treatment_item] to [victim]'s [parse_zone(limb.body_zone)]..."), span_notice("You begin applying [treatment_item] to [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)]..."))
- if(!do_after(user, (user == victim ? treatment_item.self_delay : treatment_item.other_delay), extra_checks = CALLBACK(src, PROC_REF(still_exists))))
- return
-
- limb.heal_damage(treatment_item.heal_brute, treatment_item.heal_burn)
- user.visible_message(span_green("[user] applies [treatment_item] to [victim]."), span_green("You apply [treatment_item] to [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)]."))
- treatment_item.use(1)
- sanitization += treatment_item.sanitization
- flesh_healing += treatment_item.flesh_regeneration
-
- if((infestation <= 0 || sanitization >= infestation) && (flesh_damage <= 0 || flesh_healing > flesh_damage))
- to_chat(user, span_notice("You've done all you can with [treatment_item], now you must wait for the flesh on [victim]'s [parse_zone(limb.body_zone)] to recover."))
- else
- try_treating(treatment_item, user)
-
-/// Paramedic UV penlights
-/datum/wound/burn/proc/uv(obj/item/flashlight/pen/paramedic/penlight_used, mob/user)
- if(!COOLDOWN_FINISHED(penlight_used, uv_cooldown))
- to_chat(user, span_notice("[penlight_used] is still recharging!"))
- return
- if(infestation <= 0 || infestation < sanitization)
- to_chat(user, span_notice("There's no infection to treat on [victim]'s [parse_zone(limb.body_zone)]!"))
- return
-
- user.visible_message(span_notice("[user] flashes the burns on [victim]'s [limb] with [penlight_used]."), span_notice("You flash the burns on [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)] with [penlight_used]."), vision_distance=COMBAT_MESSAGE_RANGE)
- sanitization += penlight_used.uv_power
- COOLDOWN_START(penlight_used, uv_cooldown, penlight_used.uv_cooldown_length)
-
-/datum/wound/burn/treat(obj/item/treatment_item, mob/user)
- if(istype(treatment_item, /obj/item/stack/medical/ointment))
- ointmentmesh(treatment_item, user)
- else if(istype(treatment_item, /obj/item/stack/medical/mesh))
- var/obj/item/stack/medical/mesh/mesh_check = treatment_item
- if(!mesh_check.is_open)
- to_chat(user, span_warning("You need to open [mesh_check] first."))
- return
- ointmentmesh(mesh_check, user)
- else if(istype(treatment_item, /obj/item/flashlight/pen/paramedic))
- uv(treatment_item, user)
-
-// people complained about burns not healing on stasis beds, so in addition to checking if it's cured, they also get the special ability to very slowly heal on stasis beds if they have the healing effects stored
-/datum/wound/burn/on_stasis()
- . = ..()
- if(flesh_healing > 0)
- flesh_damage = max(0, flesh_damage - 0.2)
- if((flesh_damage <= 0) && (infestation <= WOUND_INFECTION_MODERATE))
- to_chat(victim, span_green("The burns on your [parse_zone(limb.body_zone)] have cleared up!"))
- qdel(src)
- return
- if(sanitization > 0)
- infestation = max(0, infestation - WOUND_BURN_SANITIZATION_RATE * 0.2)
-
-/datum/wound/burn/on_synthflesh(amount)
- flesh_healing += amount * 0.5 // 20u patch will heal 10 flesh standard
-
-// we don't even care about first degree burns, straight to second
-/datum/wound/burn/moderate
- name = "Second Degree Burns"
- desc = "Patient is suffering considerable burns with mild skin penetration, weakening limb integrity and increased burning sensations."
- treat_text = "Recommended application of topical ointment or regenerative mesh to affected region."
- examine_desc = "is badly burned and breaking out in blisters"
- occur_text = "breaks out with violent red burns"
- severity = WOUND_SEVERITY_MODERATE
- damage_mulitplier_penalty = 1.1
- threshold_minimum = 40
- threshold_penalty = 30 // burns cause significant decrease in limb integrity compared to other wounds
- status_effect_type = /datum/status_effect/wound/burn/moderate
- flesh_damage = 5
- scar_keyword = "burnmoderate"
-
-/datum/wound/burn/severe
- name = "Third Degree Burns"
- desc = "Patient is suffering extreme burns with full skin penetration, creating serious risk of infection and greatly reduced limb integrity."
- treat_text = "Recommended immediate disinfection and excision of any infected skin, followed by bandaging and ointment. If the limb has locked up, it must be amputated, augmented or treated with cryogenics."
- examine_desc = "appears seriously charred, with aggressive red splotches"
- occur_text = "chars rapidly, exposing ruined tissue and spreading angry red burns"
- severity = WOUND_SEVERITY_SEVERE
- damage_mulitplier_penalty = 1.2
- threshold_minimum = 80
- threshold_penalty = 40
- status_effect_type = /datum/status_effect/wound/burn/severe
- treatable_by = list(/obj/item/flashlight/pen/paramedic, /obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh)
- infestation_rate = 0.05 // appx 13 minutes to reach sepsis without any treatment
- flesh_damage = 12.5
- scar_keyword = "burnsevere"
-
-/datum/wound/burn/critical
- name = "Catastrophic Burns"
- desc = "Patient is suffering near complete loss of tissue and significantly charred muscle and bone, creating life-threatening risk of infection and negligible limb integrity."
- treat_text = "Immediate surgical debriding of any infected skin, followed by potent tissue regeneration formula and bandaging. If the limb has locked up, it must be amputated, augmented or treated with cryogenics."
- examine_desc = "is a ruined mess of blanched bone, melted fat, and charred tissue"
- occur_text = "vaporizes as flesh, bone, and fat melt together in a horrifying mess"
- severity = WOUND_SEVERITY_CRITICAL
- damage_mulitplier_penalty = 1.3
- sound_effect = 'sound/effects/wounds/sizzle2.ogg'
- threshold_minimum = 140
- threshold_penalty = 80
- status_effect_type = /datum/status_effect/wound/burn/critical
- treatable_by = list(/obj/item/flashlight/pen/paramedic, /obj/item/stack/medical/ointment, /obj/item/stack/medical/mesh)
- infestation_rate = 0.15 // appx 4.33 minutes to reach sepsis without any treatment
- flesh_damage = 20
- scar_keyword = "burncritical"
-
-///special severe wound caused by sparring interference or other god related punishments.
-/datum/wound/burn/severe/brand
- name = "Holy Brand"
- desc = "Patient is suffering extreme burns from a strange brand marking, creating serious risk of infection and greatly reduced limb integrity."
- examine_desc = "appears to have holy symbols painfully branded into their flesh, leaving severe burns."
- occur_text = "chars rapidly into a strange pattern of holy symbols, burned into the flesh."
-
-/// special severe wound caused by the cursed slot machine.
-/datum/wound/burn/severe/cursed_brand
- name = "Ancient Brand"
- desc = "Patient is suffering extreme burns with oddly ornate brand markings, creating serious risk of infection and greatly reduced limb integrity."
- examine_desc = "appears to have ornate symbols painfully branded into their flesh, leaving severe burns"
- occur_text = "chars rapidly into a pattern that can only be described as an agglomeration of several financial symbols, burned into the flesh"
-
-/datum/wound/burn/severe/cursed_brand/get_limb_examine_description()
- return span_warning("The flesh on this limb has several ornate symbols burned into it, with pitting throughout.")
diff --git a/modular_skyrat/modules/medical/code/wounds/medical.dm b/modular_skyrat/modules/medical/code/wounds/medical.dm
new file mode 100644
index 00000000000..80662956e5f
--- /dev/null
+++ b/modular_skyrat/modules/medical/code/wounds/medical.dm
@@ -0,0 +1,147 @@
+#define SELF_AID_REMOVE_DELAY 5 SECONDS
+#define OTHER_AID_REMOVE_DELAY 2 SECONDS
+
+/obj/item/stack/medical/gauze
+ /// The amount of direct hits our limb can take before we fall off.
+ var/integrity = 2
+ /// The bodypart we are attached to. Nullable if we aren't applied to anything.
+ var/obj/item/bodypart/bodypart
+ /// If we are splinting a limb, this is the overlay prefix we will use.
+ var/splint_prefix = "splint"
+ /// If we are bandaging a limb, this is the overlay prefix we will use.
+ var/gauze_prefix = "gauze"
+ /// If it is at all possible for us to splint a limb.
+ var/can_splint = TRUE
+
+/obj/item/bodypart/apply_gauze(obj/item/stack/gauze)
+ RegisterSignal(src, COMSIG_BODYPART_GAUZED, PROC_REF(got_gauzed))
+
+ . = ..()
+
+ UnregisterSignal(src, COMSIG_BODYPART_GAUZED)
+
+/// Signal handler that allows us to modularly detect if we were applied to a limb or not.
+/obj/item/bodypart/proc/got_gauzed(datum/signal_source, obj/item/stack/medical/gauze/new_gauze)
+ SIGNAL_HANDLER
+
+ if (istype(current_gauze, /obj/item/stack/medical/gauze))
+ var/obj/item/stack/medical/gauze/applied_gauze = current_gauze
+ applied_gauze.set_limb(src) // new_gauze isnt actually the gauze that was applied weirdly
+
+/obj/item/stack/medical/gauze/Destroy()
+ bodypart?.current_gauze = null
+ bodypart?.owner?.update_bandage_overlays()
+ set_limb(null)
+ return ..()
+
+/**
+ * rip_off() called when someone rips it off
+ *
+ * It will return the bandage if it's considered pristine
+ *
+ */
+/obj/item/stack/medical/gauze/proc/rip_off()
+ if (is_pristine())
+ . = new src.type(null, 1)
+ bodypart?.owner?.update_bandage_overlays()
+ qdel(src)
+
+/// Returns either [splint_prefix] or [gauze_prefix] depending on if we are splinting or not. Suffixes it with a digitigrade flag if applicable for the limb.
+/obj/item/stack/medical/gauze/proc/get_overlay_prefix()
+ var/splinting = is_splinting()
+
+ var/prefix
+ if (splinting)
+ prefix = splint_prefix
+ else
+ prefix = gauze_prefix
+
+ var/suffix = bodypart.body_zone
+ if(bodypart.bodytype & BODYTYPE_DIGITIGRADE)
+ suffix += "_digitigrade"
+
+ return "[prefix]_[suffix]"
+
+/// Returns if we can splint, and if any wound on our bodypart gives a splint overlay.
+/obj/item/stack/medical/gauze/proc/is_splinting()
+ SHOULD_BE_PURE(TRUE)
+
+ if (!can_splint)
+ return FALSE
+
+ for (var/datum/wound/iterated_wound as anything in bodypart.wounds)
+ if (iterated_wound.wound_flags & SPLINT_OVERLAY)
+ return TRUE
+
+ return FALSE
+
+/**
+ * is_pristine() called by rip_off()
+ *
+ * Used to determine whether the bandage can be re-used and won't qdel itself
+ *
+ */
+
+/obj/item/stack/medical/gauze/proc/is_pristine()
+ return (integrity == initial(integrity))
+
+/**
+ * get_hit() called when the bandage gets damaged
+ *
+ * This proc will subtract integrity and delete the bandage with a to_chat message to whoever was bandaged
+ *
+ */
+
+/obj/item/stack/medical/gauze/proc/get_hit()
+ integrity--
+ if(integrity <= 0)
+ if(bodypart.owner)
+ to_chat(bodypart.owner, span_warning("The [name] on your [bodypart.name] tears and falls off!"))
+ qdel(src)
+
+/obj/item/stack/medical/gauze/Topic(href, href_list)
+ . = ..()
+ if(href_list["remove"])
+ if(!bodypart.owner)
+ return
+ if(!iscarbon(usr))
+ return
+ if(!in_range(usr, bodypart.owner))
+ return
+ var/mob/living/carbon/C = usr
+ var/self = (C == bodypart.owner)
+ C.visible_message(span_notice("[C] begins removing [name] from [self ? "[bodypart.owner.p_Their()]" : "[bodypart.owner]'s" ] [bodypart.name]..."), span_notice("You begin to remove [name] from [self ? "your" : "[bodypart.owner]'s"] [bodypart.name]..."))
+ if(!do_after(C, (self ? SELF_AID_REMOVE_DELAY : OTHER_AID_REMOVE_DELAY), target=bodypart.owner))
+ return
+ if(QDELETED(src))
+ return
+ C.visible_message(span_notice("[C] removes [name] from [self ? "[bodypart.owner.p_Their()]" : "[bodypart.owner]'s" ] [bodypart.name]."), span_notice("You remove [name] from [self ? "your" : "[bodypart.owner]'s" ] [bodypart.name]."))
+ var/obj/item/gotten = rip_off()
+ if(gotten && !C.put_in_hands(gotten))
+ gotten.forceMove(get_turf(C))
+
+/// Sets bodypart to limb, and then updates owner's bandage overlays. Limb is nullable.
+/obj/item/stack/medical/gauze/proc/set_limb(limb)
+ bodypart = limb
+ bodypart?.owner?.update_bandage_overlays()
+
+/// Returns the name of ourself when used in a "owner is [usage_prefix] by [name]" examine_more situation/
+/obj/item/stack/proc/get_gauze_description()
+ return "[name]"
+
+/// Returns the usage prefix of ourself when used in a "owner is [usage_prefix] by [name]" examine_more situation/
+/obj/item/stack/proc/get_gauze_usage_prefix()
+ return "bandaged"
+
+/obj/item/stack/medical/gauze/get_gauze_usage_prefix()
+ if (is_splinting())
+ return "fastened"
+ else
+ return ..()
+
+/// Returns TRUE if we can generate an overlay, false otherwise.
+/obj/item/stack/medical/gauze/proc/has_overlay()
+ return (!isnull(gauze_prefix) && !isnull(splint_prefix))
+
+/obj/item/stack/medical/gauze/improvised
+ splint_prefix = "splint_improv"
diff --git a/modular_skyrat/modules/medical/code/wounds/muscle.dm b/modular_skyrat/modules/medical/code/wounds/muscle.dm
index 2090da83bb8..7c6b0e11b3b 100644
--- a/modular_skyrat/modules/medical/code/wounds/muscle.dm
+++ b/modular_skyrat/modules/medical/code/wounds/muscle.dm
@@ -6,15 +6,58 @@
/datum/wound/muscle
name = "Muscle Wound"
sound_effect = 'sound/effects/wounds/blood1.ogg'
- wound_type = WOUND_MUSCLE
- wound_flags = (FLESH_WOUND | ACCEPTS_SPLINT)
- viable_zones = list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
+ wound_type = WOUND_BLUNT
+ wound_flags = (ACCEPTS_GAUZE | SPLINT_OVERLAY)
+
+ wound_series = WOUND_SERIES_MUSCLE_DAMAGE
+
processes = TRUE
/// How much do we need to regen. Will regen faster if we're splinted and or laying down
var/regen_ticks_needed
/// Our current counter for healing
var/regen_ticks_current = 0
+/datum/wound_pregen_data/muscle
+ abstract = TRUE
+
+ viable_zones = list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
+ required_limb_biostate = BIO_FLESH
+
+/datum/wound_pregen_data/muscle/can_be_applied_to(obj/item/bodypart/limb, wound_type, datum/wound/old_wound, random_roll)
+ if (!istype(limb) || !limb.owner)
+ return FALSE
+
+ if (random_roll && !can_be_randomly_generated)
+ return FALSE
+
+ if (HAS_TRAIT(limb.owner, TRAIT_NEVER_WOUNDED) || (limb.owner.status_flags & GODMODE))
+ return FALSE
+ // THIS IS HIGHLY TEMPORARY A PROC WILL COME FROM UPSTREAM THAT SHOULD REPLACE THIS!! REPLACE IT!!!!!!!!!!!! REMOVE THE OVERRIDE 8/31/23 ~Niko
+ if (wound_type != (WOUND_BLUNT) && wound_type != (WOUND_SLASH) && wound_type != (WOUND_PIERCE))
+ return FALSE
+ else
+ for (var/datum/wound/preexisting_wound as anything in limb.wounds)
+ if (preexisting_wound.wound_series == initial(wound_path_to_generate.wound_series))
+ if (preexisting_wound.severity >= initial(wound_path_to_generate.severity))
+ return FALSE
+
+ if (!ignore_cannot_bleed && ((required_limb_biostate & BIO_BLOODED) && !limb.can_bleed()))
+ return FALSE
+
+ if (!biostate_valid(limb.biological_state))
+ return FALSE
+
+ if (!(limb.body_zone in viable_zones))
+ return FALSE
+
+ // we accept promotions and demotions, but no point in redundancy. This should have already been checked wherever the wound was rolled and applied for (see: bodypart damage code), but we do an extra check
+ // in case we ever directly add wounds
+ if (!duplicates_allowed)
+ for (var/datum/wound/preexisting_wound as anything in limb.wounds)
+ if (preexisting_wound.type == wound_path_to_generate && (preexisting_wound != old_wound))
+ return FALSE
+ return TRUE
+
/*
Overwriting of base procs
*/
@@ -51,8 +94,8 @@
if(victim.IsSleeping())
regen_ticks_current += 0.5
- if(limb.current_splint)
- regen_ticks_current += (1-limb.current_splint.splint_factor)
+ if(limb.current_gauze)
+ regen_ticks_current += (1-limb.current_gauze.splint_factor)
if(regen_ticks_current > regen_ticks_needed)
if(!victim || !limb)
@@ -83,26 +126,26 @@
return COMPONENT_CANCEL_ATTACK_CHAIN
/datum/wound/muscle/get_examine_description(mob/user)
- if(!limb.current_splint)
+ if(!limb.current_gauze)
return ..()
var/list/msg = list()
- if(!limb.current_splint)
+ if(!limb.current_gauze)
msg += "[victim.p_Their()] [parse_zone(limb.body_zone)] [examine_desc]"
else
- var/sling_condition = ""
+ var/absorption_capacity = ""
// how much life we have left in these bandages
- switch(limb.current_splint.sling_condition)
+ switch(limb.current_gauze.absorption_capacity)
if(0 to 1.25)
- sling_condition = "just barely"
+ absorption_capacity = "just barely"
if(1.25 to 2.75)
- sling_condition = "loosely"
+ absorption_capacity = "loosely"
if(2.75 to 4)
- sling_condition = "mostly"
+ absorption_capacity = "mostly"
if(4 to INFINITY)
- sling_condition = "tightly"
+ absorption_capacity = "tightly"
- msg += "[victim.p_Their()] [parse_zone(limb.body_zone)] is [sling_condition] fastened with a [limb.current_splint.name]!"
+ msg += "[victim.p_Their()] [parse_zone(limb.body_zone)] is [absorption_capacity] fastened with a [limb.current_gauze.name]!"
return "[msg.Join()]"
@@ -113,19 +156,19 @@
/datum/wound/muscle/proc/update_inefficiencies()
SIGNAL_HANDLER
if(limb.body_zone in list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
- if(limb.current_splint)
- limp_slowdown = initial(limp_slowdown) * limb.current_splint.splint_factor
+ if(limb.current_gauze)
+ limp_slowdown = initial(limp_slowdown) * limb.current_gauze.splint_factor
else
limp_slowdown = initial(limp_slowdown)
victim.apply_status_effect(/datum/status_effect/limp)
else if(limb.body_zone in list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
- if(limb.current_splint)
- interaction_efficiency_penalty = 1 + ((interaction_efficiency_penalty - 1) * limb.current_splint.splint_factor)
+ if(limb.current_gauze)
+ interaction_efficiency_penalty = 1 + ((interaction_efficiency_penalty - 1) * limb.current_gauze.splint_factor)
else
interaction_efficiency_penalty = interaction_efficiency_penalty
if(initial(disabling))
- if(limb.current_splint && limb.current_splint.helps_disabled)
+ if(limb.current_gauze)
set_disabling(FALSE)
else
set_disabling(TRUE)
@@ -147,6 +190,11 @@
status_effect_type = /datum/status_effect/wound/muscle/moderate
regen_ticks_needed = 90
+/datum/wound_pregen_data/muscle/tear
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/muscle/moderate
+
/*
Severe (Ruptured Tendon)
*/
@@ -167,6 +215,11 @@
status_effect_type = /datum/status_effect/wound/muscle/severe
regen_ticks_needed = 150
+/datum/wound_pregen_data/muscle/tendon
+ abstract = FALSE
+
+ wound_path_to_generate = /datum/wound/muscle/severe
+
/datum/status_effect/wound/muscle
/datum/status_effect/wound/muscle/on_apply()
diff --git a/modular_skyrat/modules/medical/code/wounds/pierce.dm b/modular_skyrat/modules/medical/code/wounds/pierce.dm
deleted file mode 100644
index c41855402d0..00000000000
--- a/modular_skyrat/modules/medical/code/wounds/pierce.dm
+++ /dev/null
@@ -1,198 +0,0 @@
-
-/*
- Piercing wounds
-*/
-
-/datum/wound/pierce
- name = "Piercing Wound"
- sound_effect = 'sound/weapons/slice.ogg'
- processes = TRUE
- wound_type = WOUND_PIERCE
- treatable_by = list(/obj/item/stack/medical/suture)
- treatable_tool = TOOL_CAUTERY
- base_treat_time = 3 SECONDS
- wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE)
-
- /// How much blood we start losing when this wound is first applied
- var/initial_flow
- /// If gauzed, what percent of the internal bleeding actually clots of the total absorption rate
- var/gauzed_clot_rate
-
- /// When hit on this bodypart, we have this chance of losing some blood + the incoming damage
- var/internal_bleeding_chance
- /// If we let off blood when hit, the max blood lost is this * the incoming damage
- var/internal_bleeding_coefficient
-
-/datum/wound/slash/show_wound_topic(mob/user)
- return (user == victim && blood_flow)
-
-/datum/wound/slash/Topic(href, href_list)
- . = ..()
- if(href_list["wound_topic"])
- if(!usr == victim)
- return
- victim.self_grasp_bleeding_limb(limb)
-
-/datum/wound/pierce/wound_injury(datum/wound/old_wound, attack_direction)
- set_blood_flow(initial_flow)
-
-/datum/wound/pierce/receive_damage(wounding_type, wounding_dmg, wound_bonus)
- if(victim.stat == DEAD || wounding_dmg < 5)
- return
- if(victim.blood_volume && prob(internal_bleeding_chance + wounding_dmg))
- if(limb.current_splint && limb.current_splint.splint_factor)
- wounding_dmg *= (1 - limb.current_splint.splint_factor)
- var/blood_bled = rand(1, wounding_dmg * internal_bleeding_coefficient) // 12 brute toolbox can cause up to 15/18/21 bloodloss on mod/sev/crit
- switch(blood_bled)
- if(1 to 6)
- victim.bleed(blood_bled, TRUE)
- if(7 to 13)
- victim.visible_message(span_smalldanger("Blood droplets fly from the hole in [victim]'s [parse_zone(limb.body_zone)]."), span_danger("You cough up a bit of blood from the blow to your [parse_zone(limb.body_zone)]."), vision_distance=COMBAT_MESSAGE_RANGE)
- victim.bleed(blood_bled, TRUE)
- if(14 to 19)
- victim.visible_message(span_smalldanger("A small stream of blood spurts from the hole in [victim]'s [parse_zone(limb.body_zone)]!"), span_danger("You spit out a string of blood from the blow to your [parse_zone(limb.body_zone)]!"), vision_distance=COMBAT_MESSAGE_RANGE)
- new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
- victim.bleed(blood_bled)
- if(20 to INFINITY)
- victim.visible_message(span_danger("A spray of blood streams from the gash in [victim]'s [parse_zone(limb.body_zone)]!"), span_danger("You choke up on a spray of blood from the blow to your [parse_zone(limb.body_zone)]!"), vision_distance=COMBAT_MESSAGE_RANGE)
- victim.bleed(blood_bled)
- new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir)
- victim.add_splatter_floor(get_step(victim.loc, victim.dir))
-
-/datum/wound/pierce/get_bleed_rate_of_change()
- if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS))
- return BLOOD_FLOW_INCREASING
- if(limb.current_gauze)
- return BLOOD_FLOW_DECREASING
- return BLOOD_FLOW_STEADY
-
-/datum/wound/pierce/handle_process()
- set_blood_flow(min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW))
-
- if(victim.bodytemperature < (BODYTEMP_NORMAL - 10))
- adjust_blood_flow(-0.2)
- if(prob(5))
- to_chat(victim, span_notice("You feel the [lowertext(name)] in your [parse_zone(limb.body_zone)] firming up from the cold!"))
-
- if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS))
- adjust_blood_flow(0.5) // old heparin used to just add +2 bleed stacks per tick, this adds 0.5 bleed flow to all open cuts which is probably even stronger as long as you can cut them first
-
- if(limb.current_gauze && limb.current_gauze.seep_gauze(limb.current_gauze.absorption_rate, GAUZE_STAIN_BLOOD))
- adjust_blood_flow(-(limb.current_gauze.absorption_rate * gauzed_clot_rate))
-
- if(blood_flow <= 0)
- qdel(src)
-
-/datum/wound/pierce/on_stasis()
- . = ..()
- if(blood_flow <= 0)
- qdel(src)
-
-/datum/wound/pierce/check_grab_treatments(obj/item/I, mob/user)
- if(I.get_temperature()) // if we're using something hot but not a cautery, we need to be aggro grabbing them first, so we don't try treating someone we're eswording
- return TRUE
-
-/datum/wound/pierce/treat(obj/item/treatment_item, mob/user)
- if(istype(treatment_item, /obj/item/stack/medical/suture))
- suture(treatment_item, user)
- else if(treatment_item.tool_behaviour == TOOL_CAUTERY || treatment_item.get_temperature())
- tool_cauterize(treatment_item, user)
-
-/datum/wound/pierce/on_xadone(power)
- . = ..()
- adjust_blood_flow(-(0.03 * power)) // i think it's like a minimum of 3 power, so .09 blood_flow reduction per tick is pretty good for 0 effort
-
-/datum/wound/pierce/on_synthflesh(power)
- . = ..()
- adjust_blood_flow(-(0.05 * power)) // 20u * 0.05 = -1 blood flow, less than with slashes but still good considering smaller bleed rates
-
-/// If someone is using a suture to close this puncture
-/datum/wound/pierce/proc/suture(obj/item/stack/medical/suture/used_suture, mob/user)
- var/self_penalty_mult = (user == victim ? 1.4 : 1)
- user.visible_message(span_notice("[user] begins stitching [victim]'s [parse_zone(limb.body_zone)] with [used_suture]..."), span_notice("You begin stitching [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)] with [used_suture]..."))
- if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
- return
- user.visible_message(span_green("[user] stitches up some of the bleeding on [victim]."), span_green("You stitch up some of the bleeding on [user == victim ? "yourself" : "[victim]"]."))
- var/blood_sutured = used_suture.stop_bleeding / self_penalty_mult
- adjust_blood_flow(-blood_sutured)
- limb.heal_damage(used_suture.heal_brute, used_suture.heal_burn)
- used_suture.use(1)
-
- if(blood_flow > 0)
- try_treating(used_suture, user)
- else
- to_chat(user, span_green("You successfully close the hole in [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)]."))
-
-/// If someone is using either a cautery tool or something with heat to cauterize this pierce
-/datum/wound/pierce/proc/tool_cauterize(obj/item/used_cautery, mob/user)
- var/improv_penalty_mult = (used_cautery.tool_behaviour == TOOL_CAUTERY ? 1 : 1.25) // 25% longer and less effective if you don't use a real cautery
- var/self_penalty_mult = (user == victim ? 1.5 : 1) // 50% longer and less effective if you do it to yourself
-
- user.visible_message(span_danger("[user] begins cauterizing [victim]'s [parse_zone(limb.body_zone)] with [used_cautery]..."), span_warning("You begin cauterizing [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)] with [used_cautery]..."))
- if(!do_after(user, base_treat_time * self_penalty_mult * improv_penalty_mult, target=victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
- return
-
- user.visible_message(span_green("[user] cauterizes some of the bleeding on [victim]."), span_green("You cauterize some of the bleeding on [victim]."))
- limb.receive_damage(burn = 2 + severity, wound_bonus = CANT_WOUND)
- if(prob(30))
- victim.emote("scream")
- var/blood_cauterized = (0.6 / (self_penalty_mult * improv_penalty_mult))
- adjust_blood_flow(-blood_cauterized)
-
- if(blood_flow > 0)
- try_treating(used_cautery, user)
-
-/datum/wound/pierce/moderate
- name = "Minor Breakage"
- desc = "Patient's skin has been broken open, causing severe bruising and minor internal bleeding in affected area."
- treat_text = "Treat affected site with bandaging or exposure to extreme cold. In dire cases, brief exposure to vacuum may suffice." // space is cold in ss13, so it's like an ice pack!
- examine_desc = "has a small, circular hole, gently bleeding"
- occur_text = "spurts out a thin stream of blood"
- sound_effect = 'sound/effects/wounds/pierce1.ogg'
- severity = WOUND_SEVERITY_MODERATE
- initial_flow = 1.5
- gauzed_clot_rate = 0.8
- internal_bleeding_chance = 30
- internal_bleeding_coefficient = 1.25
- threshold_minimum = 30
- threshold_penalty = 20
- status_effect_type = /datum/status_effect/wound/pierce/moderate
- scar_keyword = "piercemoderate"
-
-/datum/wound/pierce/severe
- name = "Open Puncture"
- desc = "Patient's internal tissue is penetrated, causing sizeable internal bleeding and reduced limb stability."
- treat_text = "Repair punctures in skin by suture or cautery, extreme cold may also work."
- examine_desc = "is pierced clear through, with bits of tissue obscuring the open hole"
- occur_text = "looses a violent spray of blood, revealing a pierced wound"
- sound_effect = 'sound/effects/wounds/pierce2.ogg'
- severity = WOUND_SEVERITY_SEVERE
- initial_flow = 2.25
- gauzed_clot_rate = 0.6
- internal_bleeding_chance = 60
- internal_bleeding_coefficient = 1.5
- threshold_minimum = 50
- threshold_penalty = 35
- status_effect_type = /datum/status_effect/wound/pierce/severe
- scar_keyword = "piercesevere"
-
-/datum/wound/pierce/critical
- name = "Ruptured Cavity"
- desc = "Patient's internal tissue and circulatory system is shredded, causing significant internal bleeding and damage to internal organs."
- treat_text = "Surgical repair of puncture wound, followed by supervised resanguination."
- examine_desc = "is ripped clear through, barely held together by exposed bone"
- occur_text = "blasts apart, sending chunks of viscera flying in all directions"
- sound_effect = 'sound/effects/wounds/pierce3.ogg'
- severity = WOUND_SEVERITY_CRITICAL
- initial_flow = 3
- gauzed_clot_rate = 0.4
- internal_bleeding_chance = 80
- internal_bleeding_coefficient = 1.75
- threshold_minimum = 100
- threshold_penalty = 50
- status_effect_type = /datum/status_effect/wound/pierce/critical
- scar_keyword = "piercecritical"
- wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE | MANGLES_FLESH)
-
-/datum/wound/pierce/get_limb_examine_description()
- return span_warning("The flesh on this limb appears badly perforated.")
diff --git a/modular_skyrat/modules/medical/code/wounds/slash.dm b/modular_skyrat/modules/medical/code/wounds/slash.dm
deleted file mode 100644
index 345381ac503..00000000000
--- a/modular_skyrat/modules/medical/code/wounds/slash.dm
+++ /dev/null
@@ -1,324 +0,0 @@
-
-/*
- Slashing wounds
-*/
-
-/datum/wound/slash
- name = "Slashing (Cut) Wound"
- sound_effect = 'sound/weapons/slice.ogg'
- processes = TRUE
- wound_type = WOUND_SLASH
- treatable_by = list(/obj/item/stack/medical/suture)
- treatable_by_grabbed = list(/obj/item/gun/energy/laser)
- treatable_tool = TOOL_CAUTERY
- base_treat_time = 3 SECONDS
- wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE)
-
- /// How much blood we start losing when this wound is first applied
- var/initial_flow
- /// When we have less than this amount of flow, either from treatment or clotting, we demote to a lower cut or are healed of the wound
- var/minimum_flow
- /// How much our blood_flow will naturally decrease per second, not only do larger cuts bleed more blood faster, they clot slower (higher number = clot quicker, negative = opening up)
- var/clot_rate
-
- /// Once the blood flow drops below minimum_flow, we demote it to this type of wound. If there's none, we're all better
- var/demotes_to
-
- /// The maximum flow we've had so far
- var/highest_flow
-
- /// A bad system I'm using to track the worst scar we earned (since we can demote, we want the biggest our wound has been, not what it was when it was cured (probably moderate))
- var/datum/scar/highest_scar
-
-/datum/wound/slash/show_wound_topic(mob/user)
- return (user == victim && blood_flow)
-
-/datum/wound/slash/Topic(href, href_list)
- . = ..()
- if(href_list["wound_topic"])
- if(!usr == victim)
- return
- victim.self_grasp_bleeding_limb(limb)
-
-/datum/wound/slash/wound_injury(datum/wound/slash/old_wound = null, attack_direction)
- if(old_wound)
- set_blood_flow(max(old_wound.blood_flow, initial_flow))
- if(old_wound.severity > severity && old_wound.highest_scar)
- highest_scar = old_wound.highest_scar
- old_wound.highest_scar = null
- else
- set_blood_flow(initial_flow)
- if(attack_direction && victim.blood_volume > BLOOD_VOLUME_OKAY)
- victim.spray_blood(attack_direction, severity)
-
- if(!highest_scar)
- highest_scar = new
- highest_scar.generate(limb, src, add_to_scars=FALSE)
-
-/datum/wound/slash/remove_wound(ignore_limb, replaced)
- if(!replaced && highest_scar)
- already_scarred = TRUE
- highest_scar.lazy_attach(limb)
- return ..()
-
-/datum/wound/slash/get_examine_description(mob/user)
- if(!limb.current_gauze)
- return ..()
-
- var/list/msg = list("The cuts on [victim.p_their()] [parse_zone(limb.body_zone)] are wrapped with ")
- // how much life we have left in these bandages
- switch(limb.current_gauze.absorption_capacity)
- if(0 to 1.25)
- msg += "nearly ruined"
- if(1.25 to 2.75)
- msg += "badly worn"
- if(2.75 to 4)
- msg += "slightly bloodied"
- if(4 to INFINITY)
- msg += "clean"
- msg += " [limb.current_gauze.name]!"
-
- return "[msg.Join()]"
-
-/datum/wound/slash/receive_damage(wounding_type, wounding_dmg, wound_bonus)
- if(victim.stat != DEAD && wound_bonus != CANT_WOUND && wounding_type == WOUND_SLASH) // can't stab dead bodies to make it bleed faster this way
- adjust_blood_flow(WOUND_SLASH_DAMAGE_FLOW_COEFF * wounding_dmg)
-
-/datum/wound/slash/drag_bleed_amount()
- // say we have 3 severe cuts with 3 blood flow each, pretty reasonable
- // compare with being at 100 brute damage before, where you bled (brute/100 * 2), = 2 blood per tile
- var/bleed_amt = min(blood_flow * 0.1, 1) // 3 * 3 * 0.1 = 0.9 blood total, less than before! the share here is .3 blood of course.
-
- if(limb.current_gauze && limb.current_gauze.seep_gauze(bleed_amt * 0.33, GAUZE_STAIN_BLOOD)) // gauze stops all bleeding from dragging on this limb, but wears the gauze out quicker
- return 0
-
- return bleed_amt
-
-/datum/wound/slash/get_bleed_rate_of_change()
- if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS))
- return BLOOD_FLOW_INCREASING
- if(limb.current_gauze || clot_rate > 0)
- return BLOOD_FLOW_DECREASING
- if(clot_rate < 0)
- return BLOOD_FLOW_INCREASING
-
-/datum/wound/slash/handle_process()
- set_blood_flow(min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW))
-
- if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS))
- adjust_blood_flow(0.5) // old heparin used to just add +2 bleed stacks per tick, this adds 0.5 bleed flow to all open cuts which is probably even stronger as long as you can cut them first
-
- if(limb.current_gauze)
- if(clot_rate > 0)
- adjust_blood_flow(-clot_rate)
- if(limb.current_gauze && limb.current_gauze.seep_gauze(limb.current_gauze.absorption_rate, GAUZE_STAIN_BLOOD))
- adjust_blood_flow(-limb.current_gauze.absorption_rate)
- else
- adjust_blood_flow(-clot_rate)
-
- if(blood_flow > highest_flow)
- highest_flow = blood_flow
-
- if(blood_flow < minimum_flow)
- if(demotes_to)
- replace_wound(demotes_to)
- else
- to_chat(victim, span_green("The cut on your [parse_zone(limb.body_zone)] has stopped bleeding!"))
- qdel(src)
-
-
-/datum/wound/slash/on_stasis()
- if(blood_flow >= minimum_flow)
- return
- if(demotes_to)
- replace_wound(demotes_to)
- return
- qdel(src)
-
-/* BEWARE, THE BELOW NONSENSE IS MADNESS. bones.dm looks more like what I have in mind and is sufficiently clean, don't pay attention to this messiness */
-
-/datum/wound/slash/check_grab_treatments(obj/item/treatment_item, mob/user)
- if(istype(treatment_item, /obj/item/gun/energy/laser))
- return TRUE
- if(treatment_item.get_temperature()) // if we're using something hot but not a cautery, we need to be aggro grabbing them first, so we don't try treating someone we're eswording
- return TRUE
-
-/datum/wound/slash/treat(obj/item/treatment_item, mob/user)
- if(istype(treatment_item, /obj/item/gun/energy/laser))
- las_cauterize(treatment_item, user)
- else if(treatment_item.tool_behaviour == TOOL_CAUTERY || treatment_item.get_temperature())
- tool_cauterize(treatment_item, user)
- else if(istype(treatment_item, /obj/item/stack/medical/suture))
- suture(treatment_item, user)
-
-/datum/wound/slash/try_handling(mob/living/carbon/human/user)
- if(user.pulling != victim || user.zone_selected != limb.body_zone || !user.combat_mode || !isfelinid(user) || !victim.can_inject(user, TRUE))
- return FALSE
- if(DOING_INTERACTION_WITH_TARGET(user, victim))
- to_chat(user, span_warning("You're already interacting with [victim]!"))
- return
- if(user.is_mouth_covered())
- to_chat(user, span_warning("Your mouth is covered, you can't lick [victim]'s wounds!"))
- return
- if(!user.get_organ_slot(ORGAN_SLOT_TONGUE))
- to_chat(user, span_warning("You can't lick wounds without a tongue!")) // f in chat
- return
-
- lick_wounds(user)
- return TRUE
-
-/// if a felinid is licking this cut to reduce bleeding
-/datum/wound/slash/proc/lick_wounds(mob/living/carbon/human/user)
- // transmission is one way patient -> felinid since google said cat saliva is antiseptic or whatever, and also because felinids are already risking getting beaten for this even without people suspecting they're spreading a deathvirus
- for(var/i in victim.diseases)
- var/datum/disease/iter_disease = i
- if(iter_disease.spread_flags & (DISEASE_SPREAD_SPECIAL | DISEASE_SPREAD_NON_CONTAGIOUS))
- continue
- user.ForceContractDisease(iter_disease)
-
- user.visible_message(span_notice("[user] begins licking the wounds on [victim]'s [parse_zone(limb.body_zone)]."), span_notice("You begin licking the wounds on [victim]'s [parse_zone(limb.body_zone)]..."), ignored_mobs=victim)
- to_chat(victim, span_notice("[user] begins to lick the wounds on your [parse_zone(limb.body_zone)]."))
- if(!do_after(user, base_treat_time, target=victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
- return
-
- user.visible_message(span_notice("[user] licks the wounds on [victim]'s [parse_zone(limb.body_zone)]."), span_notice("You lick some of the wounds on [victim]'s [parse_zone(limb.body_zone)]"), ignored_mobs=victim)
- to_chat(victim, span_green("[user] licks the wounds on your [parse_zone(limb.body_zone)]!"))
- adjust_blood_flow(-0.5)
-
- if(blood_flow > minimum_flow)
- try_handling(user)
- else if(demotes_to)
- to_chat(user, span_green("You successfully lower the severity of [victim]'s cuts."))
-
-/datum/wound/slash/on_xadone(power)
- . = ..()
- adjust_blood_flow(-(0.03 * power)) // i think it's like a minimum of 3 power, so .09 blood_flow reduction per tick is pretty good for 0 effort
-
-/datum/wound/slash/on_synthflesh(power)
- . = ..()
- adjust_blood_flow(-(0.075 * power)) // 20u * 0.075 = -1.5 blood flow, pretty good for how little effort it is
-
-/// If someone's putting a laser gun up to our cut to cauterize it
-/datum/wound/slash/proc/las_cauterize(obj/item/gun/energy/laser/lasgun, mob/user)
- var/self_penalty_mult = (user == victim ? 1.25 : 1)
- user.visible_message(span_warning("[user] begins aiming [lasgun] directly at [victim]'s [parse_zone(limb.body_zone)]..."), span_userdanger("You begin aiming [lasgun] directly at [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)]..."))
- if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
- return
- var/damage = lasgun.chambered.loaded_projectile.damage
- lasgun.chambered.loaded_projectile.wound_bonus -= 30
- lasgun.chambered.loaded_projectile.damage *= self_penalty_mult
- if(!lasgun.process_fire(victim, victim, TRUE, null, limb.body_zone))
- return
- victim.emote("scream")
- adjust_blood_flow(-1 * (damage / (5 * self_penalty_mult))) // 20 / 5 = 4 bloodflow removed, p good
- victim.visible_message(span_warning("The cuts on [victim]'s [parse_zone(limb.body_zone)] scar over!"))
-
-/// If someone is using either a cautery tool or something with heat to cauterize this cut
-/datum/wound/slash/proc/tool_cauterize(obj/item/used_cautery, mob/user)
- var/improv_penalty_mult = (used_cautery.tool_behaviour == TOOL_CAUTERY ? 1 : 1.25) // 25% longer and less effective if you don't use a real cautery
- var/self_penalty_mult = (user == victim ? 1.5 : 1) // 50% longer and less effective if you do it to yourself
-
- user.visible_message(span_danger("[user] begins cauterizing [victim]'s [parse_zone(limb.body_zone)] with [used_cautery]..."), span_warning("You begin cauterizing [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)] with [used_cautery]..."))
- if(!do_after(user, base_treat_time * self_penalty_mult * improv_penalty_mult, target=victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
- return
-
- user.visible_message(span_green("[user] cauterizes some of the bleeding on [victim]."), span_green("You cauterize some of the bleeding on [victim]."))
- limb.receive_damage(burn = 2 + severity, wound_bonus = CANT_WOUND)
- if(prob(30))
- victim.emote("scream")
- var/blood_cauterized = (0.6 / (self_penalty_mult * improv_penalty_mult))
- adjust_blood_flow(-blood_cauterized)
-
- if(blood_flow > minimum_flow)
- try_treating(used_cautery, user)
- else if(demotes_to)
- to_chat(user, span_green("You successfully lower the severity of [user == victim ? "your" : "[victim]'s"] cuts."))
-
-/// If someone is using a suture to close this cut
-/datum/wound/slash/proc/suture(obj/item/stack/medical/suture/used_suture, mob/user)
- var/self_penalty_mult = (user == victim ? 1.4 : 1)
- user.visible_message(span_notice("[user] begins stitching [victim]'s [parse_zone(limb.body_zone)] with [used_suture]..."), span_notice("You begin stitching [user == victim ? "your" : "[victim]'s"] [parse_zone(limb.body_zone)] with [used_suture]..."))
-
- if(!do_after(user, base_treat_time * self_penalty_mult, target=victim, extra_checks = CALLBACK(src, PROC_REF(still_exists))))
- return
- user.visible_message(span_green("[user] stitches up some of the bleeding on [victim]."), span_green("You stitch up some of the bleeding on [user == victim ? "yourself" : "[victim]"]."))
- var/blood_sutured = used_suture.stop_bleeding / self_penalty_mult
- adjust_blood_flow(-blood_sutured)
- limb.heal_damage(used_suture.heal_brute, used_suture.heal_burn)
- used_suture.use(1)
-
- if(blood_flow > minimum_flow)
- try_treating(used_suture, user)
- else if(demotes_to)
- to_chat(user, span_green("You successfully lower the severity of [user == victim ? "your" : "[victim]'s"] cuts."))
-
-
-/datum/wound/slash/moderate
- name = "Rough Abrasion"
- desc = "Patient's skin has been badly scraped, generating moderate blood loss."
- treat_text = "Application of clean bandages or first-aid grade sutures, followed by food and rest."
- examine_desc = "has an open cut"
- occur_text = "is cut open, slowly leaking blood"
- sound_effect = 'sound/effects/wounds/blood1.ogg'
- severity = WOUND_SEVERITY_MODERATE
- initial_flow = 2
- minimum_flow = 0.5
- clot_rate = 0.05
- threshold_minimum = 20
- threshold_penalty = 10
- status_effect_type = /datum/status_effect/wound/slash/moderate
- scar_keyword = "slashmoderate"
-
-/datum/wound/slash/severe
- name = "Open Laceration"
- desc = "Patient's skin is ripped clean open, allowing significant blood loss."
- treat_text = "Speedy application of first-aid grade sutures and clean bandages, followed by vitals monitoring to ensure recovery."
- examine_desc = "has a severe cut"
- occur_text = "is ripped open, veins spurting blood"
- sound_effect = 'sound/effects/wounds/blood2.ogg'
- severity = WOUND_SEVERITY_SEVERE
- initial_flow = 3.25
- minimum_flow = 2.75
- clot_rate = 0.03
- threshold_minimum = 50
- threshold_penalty = 25
- demotes_to = /datum/wound/slash/moderate
- status_effect_type = /datum/status_effect/wound/slash/severe
- scar_keyword = "slashsevere"
-
-/datum/wound/slash/critical
- name = "Weeping Avulsion"
- desc = "Patient's skin is completely torn open, along with significant loss of tissue. Extreme blood loss will lead to quick death without intervention."
- treat_text = "Immediate bandaging and either suturing or cauterization, followed by supervised resanguination."
- examine_desc = "is carved down to the bone, spraying blood wildly"
- occur_text = "is torn open, spraying blood wildly"
- sound_effect = 'sound/effects/wounds/blood3.ogg'
- severity = WOUND_SEVERITY_CRITICAL
- initial_flow = 4
- minimum_flow = 3.85
- clot_rate = -0.015 // critical cuts actively get worse instead of better
- threshold_minimum = 80
- threshold_penalty = 40
- demotes_to = /datum/wound/slash/severe
- status_effect_type = /datum/status_effect/wound/slash/critical
- scar_keyword = "slashcritical"
- wound_flags = (FLESH_WOUND | ACCEPTS_GAUZE | MANGLES_FLESH)
-
-/datum/wound/slash/moderate/many_cuts
- name = "Numerous Small Slashes"
- desc = "Patient's skin has numerous small slashes and cuts, generating moderate blood loss."
- examine_desc = "has a ton of small cuts"
- occur_text = "is cut numerous times, leaving many small slashes."
-
-// Subtype for cleave (heretic spell)
-/datum/wound/slash/critical/cleave
- name = "Burning Avulsion"
- examine_desc = "is ruptured, spraying blood wildly"
- clot_rate = 0.01
-
-/datum/wound/slash/critical/cleave/update_descriptions()
- if(no_bleeding)
- occur_text = "is ruptured"
-
-/datum/wound/slash/get_limb_examine_description()
- return span_warning("The flesh on this limb appears badly lacerated.")
diff --git a/modular_skyrat/modules/mutants/code/mutant_component.dm b/modular_skyrat/modules/mutants/code/mutant_component.dm
index 99233cb2656..4e78065eb37 100644
--- a/modular_skyrat/modules/mutants/code/mutant_component.dm
+++ b/modular_skyrat/modules/mutants/code/mutant_component.dm
@@ -100,7 +100,7 @@
if(SPT_PROB(10, seconds_per_tick))
var/obj/item/bodypart/wound_area = host.get_bodypart(BODY_ZONE_CHEST)
if(wound_area)
- var/datum/wound/slash/moderate/rotting_wound = new
+ var/datum/wound/slash/flesh/moderate/rotting_wound = new
rotting_wound.apply_wound(wound_area)
host.emote(pick(list("cough", "sneeze", "scream")))
if(timer_id)
diff --git a/modular_skyrat/modules/robohand/code/bodypart_autosurgeon.dm b/modular_skyrat/modules/robohand/code/bodypart_autosurgeon.dm
index 61f1e618a2e..46de28831c2 100644
--- a/modular_skyrat/modules/robohand/code/bodypart_autosurgeon.dm
+++ b/modular_skyrat/modules/robohand/code/bodypart_autosurgeon.dm
@@ -91,4 +91,3 @@
/obj/item/autosurgeon/bodypart/r_arm_robotic/Initialize(mapload)
. = ..()
storedbodypart.icon = 'modular_skyrat/master_files/icons/mob/augmentation/hi2ipc.dmi'
- storedbodypart.organic_render = FALSE
diff --git a/sound/attributions.txt b/sound/attributions.txt
index 97e5faa5913..09ac2bd5642 100644
--- a/sound/attributions.txt
+++ b/sound/attributions.txt
@@ -88,7 +88,6 @@ https://freesound.org/people/squareal/sounds/237375/
ding_short.ogg is from Natty23 (CC 4)
https://freesound.org/people/Natty23/sounds/411747/
-
jingle.ogg is from Zapsplat (https://www.zapsplat.com/license-type/standard-license/)
https://www.zapsplat.com/sound-effect-category/sleigh-bells/
diff --git a/tgstation.dme b/tgstation.dme
index eac0e377ae2..9811b1d7093 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -432,6 +432,7 @@
#include "code\__DEFINES\~skyrat_defines\turfs.dm"
#include "code\__DEFINES\~skyrat_defines\vox_defines.dm"
#include "code\__DEFINES\~skyrat_defines\vv.dm"
+#include "code\__DEFINES\~skyrat_defines\wounds.dm"
#include "code\__DEFINES\~skyrat_defines\_globalvars\bitfields.dm"
#include "code\__DEFINES\~skyrat_defines\_globalvars\logging.dm"
#include "code\__DEFINES\~skyrat_defines\_globalvars\lists\mapping.dm"
@@ -1701,13 +1702,16 @@
#include "code\datums\wires\syndicatebomb.dm"
#include "code\datums\wires\tesla_coil.dm"
#include "code\datums\wires\vending.dm"
+#include "code\datums\wounds\_wound_static_data.dm"
#include "code\datums\wounds\_wounds.dm"
+#include "code\datums\wounds\blunt.dm"
#include "code\datums\wounds\bones.dm"
#include "code\datums\wounds\burns.dm"
#include "code\datums\wounds\loss.dm"
#include "code\datums\wounds\pierce.dm"
#include "code\datums\wounds\slash.dm"
#include "code\datums\wounds\scars\_scars.dm"
+#include "code\datums\wounds\scars\_static_scar_data.dm"
#include "code\game\alternate_appearance.dm"
#include "code\game\atom_defense.dm"
#include "code\game\atoms.dm"
@@ -6885,19 +6889,14 @@
#include "modular_skyrat\modules\marines\code\modsuit_modules.dm"
#include "modular_skyrat\modules\marines\code\smartgun.dm"
#include "modular_skyrat\modules\medical\code\anesthetic_machine.dm"
-#include "modular_skyrat\modules\medical\code\bodypart.dm"
-#include "modular_skyrat\modules\medical\code\bodypart_aid.dm"
-#include "modular_skyrat\modules\medical\code\carbon_defense.dm"
#include "modular_skyrat\modules\medical\code\carbon_examine.dm"
#include "modular_skyrat\modules\medical\code\carbon_update_icons.dm"
-#include "modular_skyrat\modules\medical\code\medical_stacks.dm"
+#include "modular_skyrat\modules\medical\code\grasp.dm"
#include "modular_skyrat\modules\medical\code\smartdarts.dm"
#include "modular_skyrat\modules\medical\code\wounds\_wounds.dm"
-#include "modular_skyrat\modules\medical\code\wounds\bones.dm"
-#include "modular_skyrat\modules\medical\code\wounds\burns.dm"
+#include "modular_skyrat\modules\medical\code\wounds\bleed.dm"
+#include "modular_skyrat\modules\medical\code\wounds\medical.dm"
#include "modular_skyrat\modules\medical\code\wounds\muscle.dm"
-#include "modular_skyrat\modules\medical\code\wounds\pierce.dm"
-#include "modular_skyrat\modules\medical\code\wounds\slash.dm"
#include "modular_skyrat\modules\medical_designs\medical_designs.dm"
#include "modular_skyrat\modules\medievalcrate_skyrat\code\vintageitems.dm"
#include "modular_skyrat\modules\mentor\code\_globalvars.dm"
diff --git a/tools/pull_request_hooks/tests/flakyTestPayloads/monkey_business.txt b/tools/pull_request_hooks/tests/flakyTestPayloads/monkey_business.txt
index bc7cbc26924..a52375357a0 100644
--- a/tools/pull_request_hooks/tests/flakyTestPayloads/monkey_business.txt
+++ b/tools/pull_request_hooks/tests/flakyTestPayloads/monkey_business.txt
@@ -168,12 +168,12 @@
2022-11-01T15:23:05.7999555Z hint: Using 'master' as the name for the initial branch. This default branch name
2022-11-01T15:23:05.8000657Z hint: is subject to change. To configure the initial branch name to use in all
2022-11-01T15:23:05.8001229Z hint: of your new repositories, which will suppress this warning, call:
-2022-11-01T15:23:05.8001635Z hint:
+2022-11-01T15:23:05.8001635Z hint:
2022-11-01T15:23:05.8002546Z hint: git config --global init.defaultBranch
-2022-11-01T15:23:05.8003017Z hint:
+2022-11-01T15:23:05.8003017Z hint:
2022-11-01T15:23:05.8003562Z hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
2022-11-01T15:23:05.8004498Z hint: 'development'. The just-created branch can be renamed via this command:
-2022-11-01T15:23:05.8006177Z hint:
+2022-11-01T15:23:05.8006177Z hint:
2022-11-01T15:23:05.8006532Z hint: git branch -m
2022-11-01T15:23:05.8016074Z Initialized empty Git repository in /home/runner/work/tgstation/tgstation/.git/
2022-11-01T15:23:05.8029083Z [command]/usr/bin/git remote add origin https://github.com/tgstation/tgstation
@@ -190,213 +190,213 @@
2022-11-01T15:23:05.9154264Z ##[endgroup]
2022-11-01T15:23:05.9155507Z ##[group]Fetching the repository
2022-11-01T15:23:05.9167693Z [command]/usr/bin/git -c protocol.version=2 fetch --no-tags --prune --progress --no-recurse-submodules --depth=1 origin +90d58213531368fd97e9955fe80b75ad69c20f24:refs/remotes/pull/70980/merge
-2022-11-01T15:23:06.8635625Z remote: Enumerating objects: 12567, done.
-2022-11-01T15:23:06.8636451Z remote: Counting objects: 0% (1/12567)
-2022-11-01T15:23:06.8650219Z remote: Counting objects: 1% (126/12567)
-2022-11-01T15:23:06.8660754Z remote: Counting objects: 2% (252/12567)
-2022-11-01T15:23:06.8672560Z remote: Counting objects: 3% (378/12567)
-2022-11-01T15:23:06.8672977Z remote: Counting objects: 4% (503/12567)
-2022-11-01T15:23:06.8673376Z remote: Counting objects: 5% (629/12567)
-2022-11-01T15:23:06.8675482Z remote: Counting objects: 6% (755/12567)
-2022-11-01T15:23:06.8675791Z remote: Counting objects: 7% (880/12567)
-2022-11-01T15:23:06.9160118Z remote: Counting objects: 8% (1006/12567)
-2022-11-01T15:23:06.9160767Z remote: Counting objects: 9% (1132/12567)
-2022-11-01T15:23:06.9161166Z remote: Counting objects: 10% (1257/12567)
-2022-11-01T15:23:06.9161566Z remote: Counting objects: 11% (1383/12567)
-2022-11-01T15:23:06.9161964Z remote: Counting objects: 12% (1509/12567)
-2022-11-01T15:23:06.9162324Z remote: Counting objects: 13% (1634/12567)
-2022-11-01T15:23:06.9162700Z remote: Counting objects: 14% (1760/12567)
-2022-11-01T15:23:06.9163069Z remote: Counting objects: 15% (1886/12567)
-2022-11-01T15:23:06.9163437Z remote: Counting objects: 16% (2011/12567)
-2022-11-01T15:23:06.9163808Z remote: Counting objects: 17% (2137/12567)
-2022-11-01T15:23:06.9164357Z remote: Counting objects: 18% (2263/12567)
-2022-11-01T15:23:06.9165066Z remote: Counting objects: 19% (2388/12567)
-2022-11-01T15:23:06.9165451Z remote: Counting objects: 20% (2514/12567)
-2022-11-01T15:23:06.9165800Z remote: Counting objects: 21% (2640/12567)
-2022-11-01T15:23:06.9166097Z remote: Counting objects: 22% (2765/12567)
-2022-11-01T15:23:06.9166459Z remote: Counting objects: 23% (2891/12567)
-2022-11-01T15:23:06.9166827Z remote: Counting objects: 24% (3017/12567)
-2022-11-01T15:23:06.9167178Z remote: Counting objects: 25% (3142/12567)
-2022-11-01T15:23:06.9167700Z remote: Counting objects: 26% (3268/12567)
-2022-11-01T15:23:06.9168060Z remote: Counting objects: 27% (3394/12567)
-2022-11-01T15:23:06.9168413Z remote: Counting objects: 28% (3519/12567)
-2022-11-01T15:23:06.9168685Z remote: Counting objects: 29% (3645/12567)
-2022-11-01T15:23:06.9169293Z remote: Counting objects: 30% (3771/12567)
-2022-11-01T15:23:06.9169550Z remote: Counting objects: 31% (3896/12567)
-2022-11-01T15:23:06.9169791Z remote: Counting objects: 32% (4022/12567)
-2022-11-01T15:23:06.9170049Z remote: Counting objects: 33% (4148/12567)
-2022-11-01T15:23:06.9170305Z remote: Counting objects: 34% (4273/12567)
-2022-11-01T15:23:06.9170563Z remote: Counting objects: 35% (4399/12567)
-2022-11-01T15:23:06.9170803Z remote: Counting objects: 36% (4525/12567)
-2022-11-01T15:23:06.9171062Z remote: Counting objects: 37% (4650/12567)
-2022-11-01T15:23:06.9171316Z remote: Counting objects: 38% (4776/12567)
-2022-11-01T15:23:06.9171714Z remote: Counting objects: 39% (4902/12567)
-2022-11-01T15:23:06.9171963Z remote: Counting objects: 40% (5027/12567)
-2022-11-01T15:23:06.9172211Z remote: Counting objects: 41% (5153/12567)
-2022-11-01T15:23:06.9172447Z remote: Counting objects: 42% (5279/12567)
-2022-11-01T15:23:06.9172868Z remote: Counting objects: 43% (5404/12567)
-2022-11-01T15:23:06.9173464Z remote: Counting objects: 44% (5530/12567)
-2022-11-01T15:23:06.9173834Z remote: Counting objects: 45% (5656/12567)
-2022-11-01T15:23:06.9174083Z remote: Counting objects: 46% (5781/12567)
-2022-11-01T15:23:06.9174458Z remote: Counting objects: 47% (5907/12567)
-2022-11-01T15:23:06.9174828Z remote: Counting objects: 48% (6033/12567)
-2022-11-01T15:23:06.9175193Z remote: Counting objects: 49% (6158/12567)
-2022-11-01T15:23:06.9175686Z remote: Counting objects: 50% (6284/12567)
-2022-11-01T15:23:06.9176096Z remote: Counting objects: 51% (6410/12567)
-2022-11-01T15:23:06.9176806Z remote: Counting objects: 52% (6535/12567)
-2022-11-01T15:23:06.9177226Z remote: Counting objects: 53% (6661/12567)
-2022-11-01T15:23:06.9383126Z remote: Counting objects: 54% (6787/12567)
-2022-11-01T15:23:06.9383471Z remote: Counting objects: 55% (6912/12567)
-2022-11-01T15:23:06.9383912Z remote: Counting objects: 56% (7038/12567)
-2022-11-01T15:23:06.9384205Z remote: Counting objects: 57% (7164/12567)
-2022-11-01T15:23:06.9384882Z remote: Counting objects: 58% (7289/12567)
-2022-11-01T15:23:06.9385322Z remote: Counting objects: 59% (7415/12567)
-2022-11-01T15:23:06.9385593Z remote: Counting objects: 60% (7541/12567)
-2022-11-01T15:23:06.9386047Z remote: Counting objects: 61% (7666/12567)
-2022-11-01T15:23:06.9386320Z remote: Counting objects: 62% (7792/12567)
-2022-11-01T15:23:06.9386602Z remote: Counting objects: 63% (7918/12567)
-2022-11-01T15:23:06.9387066Z remote: Counting objects: 64% (8043/12567)
-2022-11-01T15:23:06.9387318Z remote: Counting objects: 65% (8169/12567)
-2022-11-01T15:23:06.9387584Z remote: Counting objects: 66% (8295/12567)
-2022-11-01T15:23:06.9387858Z remote: Counting objects: 67% (8420/12567)
-2022-11-01T15:23:06.9388109Z remote: Counting objects: 68% (8546/12567)
-2022-11-01T15:23:06.9388374Z remote: Counting objects: 69% (8672/12567)
-2022-11-01T15:23:06.9388777Z remote: Counting objects: 70% (8797/12567)
-2022-11-01T15:23:06.9389026Z remote: Counting objects: 71% (8923/12567)
-2022-11-01T15:23:06.9389293Z remote: Counting objects: 72% (9049/12567)
-2022-11-01T15:23:06.9389558Z remote: Counting objects: 73% (9174/12567)
-2022-11-01T15:23:06.9389987Z remote: Counting objects: 74% (9300/12567)
-2022-11-01T15:23:06.9390230Z remote: Counting objects: 75% (9426/12567)
-2022-11-01T15:23:06.9390484Z remote: Counting objects: 76% (9551/12567)
-2022-11-01T15:23:06.9390738Z remote: Counting objects: 77% (9677/12567)
-2022-11-01T15:23:06.9390979Z remote: Counting objects: 78% (9803/12567)
-2022-11-01T15:23:06.9391235Z remote: Counting objects: 79% (9928/12567)
-2022-11-01T15:23:06.9391796Z remote: Counting objects: 80% (10054/12567)
-2022-11-01T15:23:06.9392047Z remote: Counting objects: 81% (10180/12567)
-2022-11-01T15:23:06.9392314Z remote: Counting objects: 82% (10305/12567)
-2022-11-01T15:23:06.9392577Z remote: Counting objects: 83% (10431/12567)
-2022-11-01T15:23:06.9392824Z remote: Counting objects: 84% (10557/12567)
-2022-11-01T15:23:06.9393085Z remote: Counting objects: 85% (10682/12567)
-2022-11-01T15:23:06.9394375Z remote: Counting objects: 86% (10808/12567)
-2022-11-01T15:23:06.9394631Z remote: Counting objects: 87% (10934/12567)
-2022-11-01T15:23:06.9394877Z remote: Counting objects: 88% (11059/12567)
-2022-11-01T15:23:06.9395134Z remote: Counting objects: 89% (11185/12567)
-2022-11-01T15:23:06.9395389Z remote: Counting objects: 90% (11311/12567)
-2022-11-01T15:23:06.9395622Z remote: Counting objects: 91% (11436/12567)
-2022-11-01T15:23:06.9395877Z remote: Counting objects: 92% (11562/12567)
-2022-11-01T15:23:06.9396132Z remote: Counting objects: 93% (11688/12567)
-2022-11-01T15:23:06.9396564Z remote: Counting objects: 94% (11813/12567)
-2022-11-01T15:23:06.9396804Z remote: Counting objects: 95% (11939/12567)
-2022-11-01T15:23:06.9397061Z remote: Counting objects: 96% (12065/12567)
-2022-11-01T15:23:06.9397319Z remote: Counting objects: 97% (12190/12567)
-2022-11-01T15:23:06.9397557Z remote: Counting objects: 98% (12316/12567)
-2022-11-01T15:23:06.9397810Z remote: Counting objects: 99% (12442/12567)
-2022-11-01T15:23:06.9398208Z remote: Counting objects: 100% (12567/12567)
-2022-11-01T15:23:06.9398661Z remote: Counting objects: 100% (12567/12567), done.
-2022-11-01T15:23:06.9398965Z remote: Compressing objects: 0% (1/10988)
-2022-11-01T15:23:06.9399257Z remote: Compressing objects: 1% (110/10988)
-2022-11-01T15:23:06.9439997Z remote: Compressing objects: 2% (220/10988)
-2022-11-01T15:23:06.9561627Z remote: Compressing objects: 3% (330/10988)
-2022-11-01T15:23:06.9680955Z remote: Compressing objects: 4% (440/10988)
-2022-11-01T15:23:06.9723040Z remote: Compressing objects: 5% (550/10988)
-2022-11-01T15:23:06.9876931Z remote: Compressing objects: 6% (660/10988)
-2022-11-01T15:23:07.0170815Z remote: Compressing objects: 7% (770/10988)
-2022-11-01T15:23:07.0504059Z remote: Compressing objects: 8% (880/10988)
-2022-11-01T15:23:07.0836116Z remote: Compressing objects: 9% (989/10988)
-2022-11-01T15:23:07.1460729Z remote: Compressing objects: 10% (1099/10988)
-2022-11-01T15:23:07.6608683Z remote: Compressing objects: 11% (1209/10988)
-2022-11-01T15:23:07.7588422Z remote: Compressing objects: 12% (1319/10988)
-2022-11-01T15:23:07.9494647Z remote: Compressing objects: 13% (1429/10988)
-2022-11-01T15:23:07.9527972Z remote: Compressing objects: 13% (1508/10988)
-2022-11-01T15:23:07.9668498Z remote: Compressing objects: 14% (1539/10988)
-2022-11-01T15:23:08.0219248Z remote: Compressing objects: 15% (1649/10988)
-2022-11-01T15:23:08.0283852Z remote: Compressing objects: 16% (1759/10988)
-2022-11-01T15:23:08.0452608Z remote: Compressing objects: 17% (1868/10988)
-2022-11-01T15:23:08.0618448Z remote: Compressing objects: 18% (1978/10988)
-2022-11-01T15:23:08.0889220Z remote: Compressing objects: 19% (2088/10988)
-2022-11-01T15:23:08.1162946Z remote: Compressing objects: 20% (2198/10988)
-2022-11-01T15:23:08.1247220Z remote: Compressing objects: 21% (2308/10988)
-2022-11-01T15:23:08.1520626Z remote: Compressing objects: 22% (2418/10988)
-2022-11-01T15:23:08.2139765Z remote: Compressing objects: 23% (2528/10988)
-2022-11-01T15:23:08.2412924Z remote: Compressing objects: 24% (2638/10988)
-2022-11-01T15:23:08.2597478Z remote: Compressing objects: 25% (2747/10988)
-2022-11-01T15:23:08.2752211Z remote: Compressing objects: 26% (2857/10988)
-2022-11-01T15:23:08.2966161Z remote: Compressing objects: 27% (2967/10988)
-2022-11-01T15:23:08.3926822Z remote: Compressing objects: 28% (3077/10988)
-2022-11-01T15:23:08.3927793Z remote: Compressing objects: 29% (3187/10988)
-2022-11-01T15:23:08.4094739Z remote: Compressing objects: 30% (3297/10988)
-2022-11-01T15:23:08.4338176Z remote: Compressing objects: 31% (3407/10988)
-2022-11-01T15:23:08.4632502Z remote: Compressing objects: 32% (3517/10988)
-2022-11-01T15:23:08.4940329Z remote: Compressing objects: 33% (3627/10988)
-2022-11-01T15:23:08.5404129Z remote: Compressing objects: 34% (3736/10988)
-2022-11-01T15:23:08.5814756Z remote: Compressing objects: 35% (3846/10988)
-2022-11-01T15:23:08.6091092Z remote: Compressing objects: 36% (3956/10988)
-2022-11-01T15:23:08.6446921Z remote: Compressing objects: 37% (4066/10988)
-2022-11-01T15:23:08.6900873Z remote: Compressing objects: 38% (4176/10988)
-2022-11-01T15:23:08.7213081Z remote: Compressing objects: 39% (4286/10988)
-2022-11-01T15:23:08.7502723Z remote: Compressing objects: 40% (4396/10988)
-2022-11-01T15:23:08.7869698Z remote: Compressing objects: 41% (4506/10988)
-2022-11-01T15:23:08.8103626Z remote: Compressing objects: 42% (4615/10988)
-2022-11-01T15:23:08.8451299Z remote: Compressing objects: 43% (4725/10988)
-2022-11-01T15:23:08.8774688Z remote: Compressing objects: 44% (4835/10988)
-2022-11-01T15:23:08.9003331Z remote: Compressing objects: 45% (4945/10988)
-2022-11-01T15:23:08.9070180Z remote: Compressing objects: 45% (5034/10988)
-2022-11-01T15:23:08.9344499Z remote: Compressing objects: 46% (5055/10988)
-2022-11-01T15:23:08.9568190Z remote: Compressing objects: 47% (5165/10988)
-2022-11-01T15:23:08.9805763Z remote: Compressing objects: 48% (5275/10988)
-2022-11-01T15:23:09.0037568Z remote: Compressing objects: 49% (5385/10988)
-2022-11-01T15:23:09.0301310Z remote: Compressing objects: 50% (5494/10988)
-2022-11-01T15:23:09.0582321Z remote: Compressing objects: 51% (5604/10988)
-2022-11-01T15:23:09.0808327Z remote: Compressing objects: 52% (5714/10988)
-2022-11-01T15:23:09.1124129Z remote: Compressing objects: 53% (5824/10988)
-2022-11-01T15:23:09.1387087Z remote: Compressing objects: 54% (5934/10988)
-2022-11-01T15:23:09.1647455Z remote: Compressing objects: 55% (6044/10988)
-2022-11-01T15:23:09.1915056Z remote: Compressing objects: 56% (6154/10988)
-2022-11-01T15:23:09.2255320Z remote: Compressing objects: 57% (6264/10988)
-2022-11-01T15:23:09.2457326Z remote: Compressing objects: 58% (6374/10988)
-2022-11-01T15:23:09.2755910Z remote: Compressing objects: 59% (6483/10988)
-2022-11-01T15:23:09.3017305Z remote: Compressing objects: 60% (6593/10988)
-2022-11-01T15:23:09.3325069Z remote: Compressing objects: 61% (6703/10988)
-2022-11-01T15:23:09.3546803Z remote: Compressing objects: 62% (6813/10988)
-2022-11-01T15:23:09.3801684Z remote: Compressing objects: 63% (6923/10988)
-2022-11-01T15:23:09.4067963Z remote: Compressing objects: 64% (7033/10988)
-2022-11-01T15:23:09.5472387Z remote: Compressing objects: 65% (7143/10988)
-2022-11-01T15:23:09.5473083Z remote: Compressing objects: 66% (7253/10988)
-2022-11-01T15:23:09.5473536Z remote: Compressing objects: 67% (7362/10988)
-2022-11-01T15:23:09.5473940Z remote: Compressing objects: 68% (7472/10988)
-2022-11-01T15:23:09.5474375Z remote: Compressing objects: 69% (7582/10988)
-2022-11-01T15:23:09.5474794Z remote: Compressing objects: 70% (7692/10988)
-2022-11-01T15:23:09.5475212Z remote: Compressing objects: 71% (7802/10988)
-2022-11-01T15:23:09.5475789Z remote: Compressing objects: 72% (7912/10988)
-2022-11-01T15:23:09.5476209Z remote: Compressing objects: 73% (8022/10988)
-2022-11-01T15:23:09.5477532Z remote: Compressing objects: 74% (8132/10988)
-2022-11-01T15:23:09.5478233Z remote: Compressing objects: 75% (8241/10988)
-2022-11-01T15:23:09.5478582Z remote: Compressing objects: 76% (8351/10988)
-2022-11-01T15:23:09.5479163Z remote: Compressing objects: 77% (8461/10988)
-2022-11-01T15:23:09.5479885Z remote: Compressing objects: 78% (8571/10988)
-2022-11-01T15:23:09.5480434Z remote: Compressing objects: 79% (8681/10988)
-2022-11-01T15:23:09.5480899Z remote: Compressing objects: 80% (8791/10988)
-2022-11-01T15:23:09.5481594Z remote: Compressing objects: 81% (8901/10988)
-2022-11-01T15:23:09.5482284Z remote: Compressing objects: 82% (9011/10988)
-2022-11-01T15:23:09.5482865Z remote: Compressing objects: 83% (9121/10988)
-2022-11-01T15:23:09.5483308Z remote: Compressing objects: 84% (9230/10988)
-2022-11-01T15:23:09.5483685Z remote: Compressing objects: 85% (9340/10988)
-2022-11-01T15:23:09.5484385Z remote: Compressing objects: 86% (9450/10988)
-2022-11-01T15:23:09.5485582Z remote: Compressing objects: 87% (9560/10988)
-2022-11-01T15:23:09.5486089Z remote: Compressing objects: 88% (9670/10988)
-2022-11-01T15:23:09.5486597Z remote: Compressing objects: 89% (9780/10988)
-2022-11-01T15:23:09.5487116Z remote: Compressing objects: 90% (9890/10988)
-2022-11-01T15:23:09.5487742Z remote: Compressing objects: 91% (10000/10988)
-2022-11-01T15:23:09.5488235Z remote: Compressing objects: 92% (10109/10988)
-2022-11-01T15:23:09.5488673Z remote: Compressing objects: 93% (10219/10988)
-2022-11-01T15:23:09.5489383Z remote: Compressing objects: 94% (10329/10988)
-2022-11-01T15:23:09.5489745Z remote: Compressing objects: 95% (10439/10988)
-2022-11-01T15:23:09.5490195Z remote: Compressing objects: 96% (10549/10988)
-2022-11-01T15:23:09.5490745Z remote: Compressing objects: 97% (10659/10988)
-2022-11-01T15:23:09.5491127Z remote: Compressing objects: 98% (10769/10988)
-2022-11-01T15:23:09.5491596Z remote: Compressing objects: 99% (10879/10988)
-2022-11-01T15:23:09.5492106Z remote: Compressing objects: 100% (10988/10988)
-2022-11-01T15:23:09.5492683Z remote: Compressing objects: 100% (10988/10988), done.
+2022-11-01T15:23:06.8635625Z remote: Enumerating objects: 12567, done.
+2022-11-01T15:23:06.8636451Z remote: Counting objects: 0% (1/12567)
+2022-11-01T15:23:06.8650219Z remote: Counting objects: 1% (126/12567)
+2022-11-01T15:23:06.8660754Z remote: Counting objects: 2% (252/12567)
+2022-11-01T15:23:06.8672560Z remote: Counting objects: 3% (378/12567)
+2022-11-01T15:23:06.8672977Z remote: Counting objects: 4% (503/12567)
+2022-11-01T15:23:06.8673376Z remote: Counting objects: 5% (629/12567)
+2022-11-01T15:23:06.8675482Z remote: Counting objects: 6% (755/12567)
+2022-11-01T15:23:06.8675791Z remote: Counting objects: 7% (880/12567)
+2022-11-01T15:23:06.9160118Z remote: Counting objects: 8% (1006/12567)
+2022-11-01T15:23:06.9160767Z remote: Counting objects: 9% (1132/12567)
+2022-11-01T15:23:06.9161166Z remote: Counting objects: 10% (1257/12567)
+2022-11-01T15:23:06.9161566Z remote: Counting objects: 11% (1383/12567)
+2022-11-01T15:23:06.9161964Z remote: Counting objects: 12% (1509/12567)
+2022-11-01T15:23:06.9162324Z remote: Counting objects: 13% (1634/12567)
+2022-11-01T15:23:06.9162700Z remote: Counting objects: 14% (1760/12567)
+2022-11-01T15:23:06.9163069Z remote: Counting objects: 15% (1886/12567)
+2022-11-01T15:23:06.9163437Z remote: Counting objects: 16% (2011/12567)
+2022-11-01T15:23:06.9163808Z remote: Counting objects: 17% (2137/12567)
+2022-11-01T15:23:06.9164357Z remote: Counting objects: 18% (2263/12567)
+2022-11-01T15:23:06.9165066Z remote: Counting objects: 19% (2388/12567)
+2022-11-01T15:23:06.9165451Z remote: Counting objects: 20% (2514/12567)
+2022-11-01T15:23:06.9165800Z remote: Counting objects: 21% (2640/12567)
+2022-11-01T15:23:06.9166097Z remote: Counting objects: 22% (2765/12567)
+2022-11-01T15:23:06.9166459Z remote: Counting objects: 23% (2891/12567)
+2022-11-01T15:23:06.9166827Z remote: Counting objects: 24% (3017/12567)
+2022-11-01T15:23:06.9167178Z remote: Counting objects: 25% (3142/12567)
+2022-11-01T15:23:06.9167700Z remote: Counting objects: 26% (3268/12567)
+2022-11-01T15:23:06.9168060Z remote: Counting objects: 27% (3394/12567)
+2022-11-01T15:23:06.9168413Z remote: Counting objects: 28% (3519/12567)
+2022-11-01T15:23:06.9168685Z remote: Counting objects: 29% (3645/12567)
+2022-11-01T15:23:06.9169293Z remote: Counting objects: 30% (3771/12567)
+2022-11-01T15:23:06.9169550Z remote: Counting objects: 31% (3896/12567)
+2022-11-01T15:23:06.9169791Z remote: Counting objects: 32% (4022/12567)
+2022-11-01T15:23:06.9170049Z remote: Counting objects: 33% (4148/12567)
+2022-11-01T15:23:06.9170305Z remote: Counting objects: 34% (4273/12567)
+2022-11-01T15:23:06.9170563Z remote: Counting objects: 35% (4399/12567)
+2022-11-01T15:23:06.9170803Z remote: Counting objects: 36% (4525/12567)
+2022-11-01T15:23:06.9171062Z remote: Counting objects: 37% (4650/12567)
+2022-11-01T15:23:06.9171316Z remote: Counting objects: 38% (4776/12567)
+2022-11-01T15:23:06.9171714Z remote: Counting objects: 39% (4902/12567)
+2022-11-01T15:23:06.9171963Z remote: Counting objects: 40% (5027/12567)
+2022-11-01T15:23:06.9172211Z remote: Counting objects: 41% (5153/12567)
+2022-11-01T15:23:06.9172447Z remote: Counting objects: 42% (5279/12567)
+2022-11-01T15:23:06.9172868Z remote: Counting objects: 43% (5404/12567)
+2022-11-01T15:23:06.9173464Z remote: Counting objects: 44% (5530/12567)
+2022-11-01T15:23:06.9173834Z remote: Counting objects: 45% (5656/12567)
+2022-11-01T15:23:06.9174083Z remote: Counting objects: 46% (5781/12567)
+2022-11-01T15:23:06.9174458Z remote: Counting objects: 47% (5907/12567)
+2022-11-01T15:23:06.9174828Z remote: Counting objects: 48% (6033/12567)
+2022-11-01T15:23:06.9175193Z remote: Counting objects: 49% (6158/12567)
+2022-11-01T15:23:06.9175686Z remote: Counting objects: 50% (6284/12567)
+2022-11-01T15:23:06.9176096Z remote: Counting objects: 51% (6410/12567)
+2022-11-01T15:23:06.9176806Z remote: Counting objects: 52% (6535/12567)
+2022-11-01T15:23:06.9177226Z remote: Counting objects: 53% (6661/12567)
+2022-11-01T15:23:06.9383126Z remote: Counting objects: 54% (6787/12567)
+2022-11-01T15:23:06.9383471Z remote: Counting objects: 55% (6912/12567)
+2022-11-01T15:23:06.9383912Z remote: Counting objects: 56% (7038/12567)
+2022-11-01T15:23:06.9384205Z remote: Counting objects: 57% (7164/12567)
+2022-11-01T15:23:06.9384882Z remote: Counting objects: 58% (7289/12567)
+2022-11-01T15:23:06.9385322Z remote: Counting objects: 59% (7415/12567)
+2022-11-01T15:23:06.9385593Z remote: Counting objects: 60% (7541/12567)
+2022-11-01T15:23:06.9386047Z remote: Counting objects: 61% (7666/12567)
+2022-11-01T15:23:06.9386320Z remote: Counting objects: 62% (7792/12567)
+2022-11-01T15:23:06.9386602Z remote: Counting objects: 63% (7918/12567)
+2022-11-01T15:23:06.9387066Z remote: Counting objects: 64% (8043/12567)
+2022-11-01T15:23:06.9387318Z remote: Counting objects: 65% (8169/12567)
+2022-11-01T15:23:06.9387584Z remote: Counting objects: 66% (8295/12567)
+2022-11-01T15:23:06.9387858Z remote: Counting objects: 67% (8420/12567)
+2022-11-01T15:23:06.9388109Z remote: Counting objects: 68% (8546/12567)
+2022-11-01T15:23:06.9388374Z remote: Counting objects: 69% (8672/12567)
+2022-11-01T15:23:06.9388777Z remote: Counting objects: 70% (8797/12567)
+2022-11-01T15:23:06.9389026Z remote: Counting objects: 71% (8923/12567)
+2022-11-01T15:23:06.9389293Z remote: Counting objects: 72% (9049/12567)
+2022-11-01T15:23:06.9389558Z remote: Counting objects: 73% (9174/12567)
+2022-11-01T15:23:06.9389987Z remote: Counting objects: 74% (9300/12567)
+2022-11-01T15:23:06.9390230Z remote: Counting objects: 75% (9426/12567)
+2022-11-01T15:23:06.9390484Z remote: Counting objects: 76% (9551/12567)
+2022-11-01T15:23:06.9390738Z remote: Counting objects: 77% (9677/12567)
+2022-11-01T15:23:06.9390979Z remote: Counting objects: 78% (9803/12567)
+2022-11-01T15:23:06.9391235Z remote: Counting objects: 79% (9928/12567)
+2022-11-01T15:23:06.9391796Z remote: Counting objects: 80% (10054/12567)
+2022-11-01T15:23:06.9392047Z remote: Counting objects: 81% (10180/12567)
+2022-11-01T15:23:06.9392314Z remote: Counting objects: 82% (10305/12567)
+2022-11-01T15:23:06.9392577Z remote: Counting objects: 83% (10431/12567)
+2022-11-01T15:23:06.9392824Z remote: Counting objects: 84% (10557/12567)
+2022-11-01T15:23:06.9393085Z remote: Counting objects: 85% (10682/12567)
+2022-11-01T15:23:06.9394375Z remote: Counting objects: 86% (10808/12567)
+2022-11-01T15:23:06.9394631Z remote: Counting objects: 87% (10934/12567)
+2022-11-01T15:23:06.9394877Z remote: Counting objects: 88% (11059/12567)
+2022-11-01T15:23:06.9395134Z remote: Counting objects: 89% (11185/12567)
+2022-11-01T15:23:06.9395389Z remote: Counting objects: 90% (11311/12567)
+2022-11-01T15:23:06.9395622Z remote: Counting objects: 91% (11436/12567)
+2022-11-01T15:23:06.9395877Z remote: Counting objects: 92% (11562/12567)
+2022-11-01T15:23:06.9396132Z remote: Counting objects: 93% (11688/12567)
+2022-11-01T15:23:06.9396564Z remote: Counting objects: 94% (11813/12567)
+2022-11-01T15:23:06.9396804Z remote: Counting objects: 95% (11939/12567)
+2022-11-01T15:23:06.9397061Z remote: Counting objects: 96% (12065/12567)
+2022-11-01T15:23:06.9397319Z remote: Counting objects: 97% (12190/12567)
+2022-11-01T15:23:06.9397557Z remote: Counting objects: 98% (12316/12567)
+2022-11-01T15:23:06.9397810Z remote: Counting objects: 99% (12442/12567)
+2022-11-01T15:23:06.9398208Z remote: Counting objects: 100% (12567/12567)
+2022-11-01T15:23:06.9398661Z remote: Counting objects: 100% (12567/12567), done.
+2022-11-01T15:23:06.9398965Z remote: Compressing objects: 0% (1/10988)
+2022-11-01T15:23:06.9399257Z remote: Compressing objects: 1% (110/10988)
+2022-11-01T15:23:06.9439997Z remote: Compressing objects: 2% (220/10988)
+2022-11-01T15:23:06.9561627Z remote: Compressing objects: 3% (330/10988)
+2022-11-01T15:23:06.9680955Z remote: Compressing objects: 4% (440/10988)
+2022-11-01T15:23:06.9723040Z remote: Compressing objects: 5% (550/10988)
+2022-11-01T15:23:06.9876931Z remote: Compressing objects: 6% (660/10988)
+2022-11-01T15:23:07.0170815Z remote: Compressing objects: 7% (770/10988)
+2022-11-01T15:23:07.0504059Z remote: Compressing objects: 8% (880/10988)
+2022-11-01T15:23:07.0836116Z remote: Compressing objects: 9% (989/10988)
+2022-11-01T15:23:07.1460729Z remote: Compressing objects: 10% (1099/10988)
+2022-11-01T15:23:07.6608683Z remote: Compressing objects: 11% (1209/10988)
+2022-11-01T15:23:07.7588422Z remote: Compressing objects: 12% (1319/10988)
+2022-11-01T15:23:07.9494647Z remote: Compressing objects: 13% (1429/10988)
+2022-11-01T15:23:07.9527972Z remote: Compressing objects: 13% (1508/10988)
+2022-11-01T15:23:07.9668498Z remote: Compressing objects: 14% (1539/10988)
+2022-11-01T15:23:08.0219248Z remote: Compressing objects: 15% (1649/10988)
+2022-11-01T15:23:08.0283852Z remote: Compressing objects: 16% (1759/10988)
+2022-11-01T15:23:08.0452608Z remote: Compressing objects: 17% (1868/10988)
+2022-11-01T15:23:08.0618448Z remote: Compressing objects: 18% (1978/10988)
+2022-11-01T15:23:08.0889220Z remote: Compressing objects: 19% (2088/10988)
+2022-11-01T15:23:08.1162946Z remote: Compressing objects: 20% (2198/10988)
+2022-11-01T15:23:08.1247220Z remote: Compressing objects: 21% (2308/10988)
+2022-11-01T15:23:08.1520626Z remote: Compressing objects: 22% (2418/10988)
+2022-11-01T15:23:08.2139765Z remote: Compressing objects: 23% (2528/10988)
+2022-11-01T15:23:08.2412924Z remote: Compressing objects: 24% (2638/10988)
+2022-11-01T15:23:08.2597478Z remote: Compressing objects: 25% (2747/10988)
+2022-11-01T15:23:08.2752211Z remote: Compressing objects: 26% (2857/10988)
+2022-11-01T15:23:08.2966161Z remote: Compressing objects: 27% (2967/10988)
+2022-11-01T15:23:08.3926822Z remote: Compressing objects: 28% (3077/10988)
+2022-11-01T15:23:08.3927793Z remote: Compressing objects: 29% (3187/10988)
+2022-11-01T15:23:08.4094739Z remote: Compressing objects: 30% (3297/10988)
+2022-11-01T15:23:08.4338176Z remote: Compressing objects: 31% (3407/10988)
+2022-11-01T15:23:08.4632502Z remote: Compressing objects: 32% (3517/10988)
+2022-11-01T15:23:08.4940329Z remote: Compressing objects: 33% (3627/10988)
+2022-11-01T15:23:08.5404129Z remote: Compressing objects: 34% (3736/10988)
+2022-11-01T15:23:08.5814756Z remote: Compressing objects: 35% (3846/10988)
+2022-11-01T15:23:08.6091092Z remote: Compressing objects: 36% (3956/10988)
+2022-11-01T15:23:08.6446921Z remote: Compressing objects: 37% (4066/10988)
+2022-11-01T15:23:08.6900873Z remote: Compressing objects: 38% (4176/10988)
+2022-11-01T15:23:08.7213081Z remote: Compressing objects: 39% (4286/10988)
+2022-11-01T15:23:08.7502723Z remote: Compressing objects: 40% (4396/10988)
+2022-11-01T15:23:08.7869698Z remote: Compressing objects: 41% (4506/10988)
+2022-11-01T15:23:08.8103626Z remote: Compressing objects: 42% (4615/10988)
+2022-11-01T15:23:08.8451299Z remote: Compressing objects: 43% (4725/10988)
+2022-11-01T15:23:08.8774688Z remote: Compressing objects: 44% (4835/10988)
+2022-11-01T15:23:08.9003331Z remote: Compressing objects: 45% (4945/10988)
+2022-11-01T15:23:08.9070180Z remote: Compressing objects: 45% (5034/10988)
+2022-11-01T15:23:08.9344499Z remote: Compressing objects: 46% (5055/10988)
+2022-11-01T15:23:08.9568190Z remote: Compressing objects: 47% (5165/10988)
+2022-11-01T15:23:08.9805763Z remote: Compressing objects: 48% (5275/10988)
+2022-11-01T15:23:09.0037568Z remote: Compressing objects: 49% (5385/10988)
+2022-11-01T15:23:09.0301310Z remote: Compressing objects: 50% (5494/10988)
+2022-11-01T15:23:09.0582321Z remote: Compressing objects: 51% (5604/10988)
+2022-11-01T15:23:09.0808327Z remote: Compressing objects: 52% (5714/10988)
+2022-11-01T15:23:09.1124129Z remote: Compressing objects: 53% (5824/10988)
+2022-11-01T15:23:09.1387087Z remote: Compressing objects: 54% (5934/10988)
+2022-11-01T15:23:09.1647455Z remote: Compressing objects: 55% (6044/10988)
+2022-11-01T15:23:09.1915056Z remote: Compressing objects: 56% (6154/10988)
+2022-11-01T15:23:09.2255320Z remote: Compressing objects: 57% (6264/10988)
+2022-11-01T15:23:09.2457326Z remote: Compressing objects: 58% (6374/10988)
+2022-11-01T15:23:09.2755910Z remote: Compressing objects: 59% (6483/10988)
+2022-11-01T15:23:09.3017305Z remote: Compressing objects: 60% (6593/10988)
+2022-11-01T15:23:09.3325069Z remote: Compressing objects: 61% (6703/10988)
+2022-11-01T15:23:09.3546803Z remote: Compressing objects: 62% (6813/10988)
+2022-11-01T15:23:09.3801684Z remote: Compressing objects: 63% (6923/10988)
+2022-11-01T15:23:09.4067963Z remote: Compressing objects: 64% (7033/10988)
+2022-11-01T15:23:09.5472387Z remote: Compressing objects: 65% (7143/10988)
+2022-11-01T15:23:09.5473083Z remote: Compressing objects: 66% (7253/10988)
+2022-11-01T15:23:09.5473536Z remote: Compressing objects: 67% (7362/10988)
+2022-11-01T15:23:09.5473940Z remote: Compressing objects: 68% (7472/10988)
+2022-11-01T15:23:09.5474375Z remote: Compressing objects: 69% (7582/10988)
+2022-11-01T15:23:09.5474794Z remote: Compressing objects: 70% (7692/10988)
+2022-11-01T15:23:09.5475212Z remote: Compressing objects: 71% (7802/10988)
+2022-11-01T15:23:09.5475789Z remote: Compressing objects: 72% (7912/10988)
+2022-11-01T15:23:09.5476209Z remote: Compressing objects: 73% (8022/10988)
+2022-11-01T15:23:09.5477532Z remote: Compressing objects: 74% (8132/10988)
+2022-11-01T15:23:09.5478233Z remote: Compressing objects: 75% (8241/10988)
+2022-11-01T15:23:09.5478582Z remote: Compressing objects: 76% (8351/10988)
+2022-11-01T15:23:09.5479163Z remote: Compressing objects: 77% (8461/10988)
+2022-11-01T15:23:09.5479885Z remote: Compressing objects: 78% (8571/10988)
+2022-11-01T15:23:09.5480434Z remote: Compressing objects: 79% (8681/10988)
+2022-11-01T15:23:09.5480899Z remote: Compressing objects: 80% (8791/10988)
+2022-11-01T15:23:09.5481594Z remote: Compressing objects: 81% (8901/10988)
+2022-11-01T15:23:09.5482284Z remote: Compressing objects: 82% (9011/10988)
+2022-11-01T15:23:09.5482865Z remote: Compressing objects: 83% (9121/10988)
+2022-11-01T15:23:09.5483308Z remote: Compressing objects: 84% (9230/10988)
+2022-11-01T15:23:09.5483685Z remote: Compressing objects: 85% (9340/10988)
+2022-11-01T15:23:09.5484385Z remote: Compressing objects: 86% (9450/10988)
+2022-11-01T15:23:09.5485582Z remote: Compressing objects: 87% (9560/10988)
+2022-11-01T15:23:09.5486089Z remote: Compressing objects: 88% (9670/10988)
+2022-11-01T15:23:09.5486597Z remote: Compressing objects: 89% (9780/10988)
+2022-11-01T15:23:09.5487116Z remote: Compressing objects: 90% (9890/10988)
+2022-11-01T15:23:09.5487742Z remote: Compressing objects: 91% (10000/10988)
+2022-11-01T15:23:09.5488235Z remote: Compressing objects: 92% (10109/10988)
+2022-11-01T15:23:09.5488673Z remote: Compressing objects: 93% (10219/10988)
+2022-11-01T15:23:09.5489383Z remote: Compressing objects: 94% (10329/10988)
+2022-11-01T15:23:09.5489745Z remote: Compressing objects: 95% (10439/10988)
+2022-11-01T15:23:09.5490195Z remote: Compressing objects: 96% (10549/10988)
+2022-11-01T15:23:09.5490745Z remote: Compressing objects: 97% (10659/10988)
+2022-11-01T15:23:09.5491127Z remote: Compressing objects: 98% (10769/10988)
+2022-11-01T15:23:09.5491596Z remote: Compressing objects: 99% (10879/10988)
+2022-11-01T15:23:09.5492106Z remote: Compressing objects: 100% (10988/10988)
+2022-11-01T15:23:09.5492683Z remote: Compressing objects: 100% (10988/10988), done.
2022-11-01T15:23:09.8456233Z Receiving objects: 0% (1/12567)
2022-11-01T15:23:10.1991946Z Receiving objects: 1% (126/12567)
2022-11-01T15:23:10.2129001Z Receiving objects: 2% (252/12567), 1.64 MiB | 3.13 MiB/s
@@ -505,7 +505,7 @@
2022-11-01T15:23:18.1101897Z Receiving objects: 97% (12190/12567), 131.07 MiB | 18.99 MiB/s
2022-11-01T15:23:18.1271902Z Receiving objects: 98% (12316/12567), 131.07 MiB | 18.99 MiB/s
2022-11-01T15:23:18.1310792Z Receiving objects: 99% (12442/12567), 131.07 MiB | 18.99 MiB/s
-2022-11-01T15:23:18.1311930Z remote: Total 12567 (delta 1595), reused 7195 (delta 1446), pack-reused 0
+2022-11-01T15:23:18.1311930Z remote: Total 12567 (delta 1595), reused 7195 (delta 1446), pack-reused 0
2022-11-01T15:23:18.1338739Z Receiving objects: 100% (12567/12567), 131.07 MiB | 18.99 MiB/s
2022-11-01T15:23:18.1339954Z Receiving objects: 100% (12567/12567), 139.23 MiB | 16.22 MiB/s, done.
2022-11-01T15:23:18.1385156Z Resolving deltas: 0% (0/1595)
@@ -657,22 +657,22 @@
2022-11-01T15:23:20.3892548Z Updating files: 100% (11595/11595)
2022-11-01T15:23:20.3892853Z Updating files: 100% (11595/11595), done.
2022-11-01T15:23:20.4056043Z Note: switching to 'refs/remotes/pull/70980/merge'.
-2022-11-01T15:23:20.4056307Z
+2022-11-01T15:23:20.4056307Z
2022-11-01T15:23:20.4056668Z You are in 'detached HEAD' state. You can look around, make experimental
2022-11-01T15:23:20.4057485Z changes and commit them, and you can discard any commits you make in this
2022-11-01T15:23:20.4058470Z state without impacting any branches by switching back to a branch.
-2022-11-01T15:23:20.4058838Z
+2022-11-01T15:23:20.4058838Z
2022-11-01T15:23:20.4059084Z If you want to create a new branch to retain commits you create, you may
2022-11-01T15:23:20.4060410Z do so (now or later) by using -c with the switch command. Example:
-2022-11-01T15:23:20.4060709Z
+2022-11-01T15:23:20.4060709Z
2022-11-01T15:23:20.4061092Z git switch -c
-2022-11-01T15:23:20.4061268Z
+2022-11-01T15:23:20.4061268Z
2022-11-01T15:23:20.4061433Z Or undo this operation with:
-2022-11-01T15:23:20.4061641Z
+2022-11-01T15:23:20.4061641Z
2022-11-01T15:23:20.4061781Z git switch -
-2022-11-01T15:23:20.4061964Z
+2022-11-01T15:23:20.4061964Z
2022-11-01T15:23:20.4062222Z Turn off this advice by setting config variable advice.detachedHead to false
-2022-11-01T15:23:20.4062504Z
+2022-11-01T15:23:20.4062504Z
2022-11-01T15:23:20.4062736Z HEAD is now at 90d5821 Merge 1cb3ad143b2bd2b6467c31b7f52299c77448f1ee into 6ccb95a4ea337422d5d29cd85f5267e4c867ccff
2022-11-01T15:23:20.4116386Z ##[endgroup]
2022-11-01T15:23:20.4158288Z [command]/usr/bin/git log -1 --format='%H'
@@ -707,9 +707,9 @@
2022-11-01T15:23:29.0146860Z [36;1mbash tools/ci/install_rust_g.sh[0m
2022-11-01T15:23:29.0208114Z shell: /usr/bin/bash -e {0}
2022-11-01T15:23:29.0208371Z ##[endgroup]
-2022-11-01T15:23:29.3467028Z
+2022-11-01T15:23:29.3467028Z
2022-11-01T15:23:29.3467957Z WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
-2022-11-01T15:23:29.3470221Z
+2022-11-01T15:23:29.3470221Z
2022-11-01T15:23:29.4665471Z Hit:1 http://azure.archive.ubuntu.com/ubuntu focal InRelease
2022-11-01T15:23:29.4669512Z Get:2 http://azure.archive.ubuntu.com/ubuntu focal-updates InRelease [114 kB]
2022-11-01T15:23:29.4687773Z Get:3 http://azure.archive.ubuntu.com/ubuntu focal-backports InRelease [108 kB]
@@ -735,9 +735,9 @@
2022-11-01T15:23:48.4655905Z Building dependency tree...
2022-11-01T15:23:48.4674811Z Reading state information...
2022-11-01T15:23:48.6158045Z 30 packages can be upgraded. Run 'apt list --upgradable' to see them.
-2022-11-01T15:23:48.6289670Z
+2022-11-01T15:23:48.6289670Z
2022-11-01T15:23:48.6290570Z WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
-2022-11-01T15:23:48.6290875Z
+2022-11-01T15:23:48.6290875Z
2022-11-01T15:23:48.7009344Z Reading package lists...
2022-11-01T15:23:48.9786347Z Building dependency tree...
2022-11-01T15:23:48.9806498Z Reading state information...
@@ -765,7 +765,7 @@
2022-11-01T15:23:51.2386768Z Preconfiguring packages ...
2022-11-01T15:23:51.3495462Z Fetched 4528 kB in 1s (3176 kB/s)
2022-11-01T15:23:51.3919752Z Selecting previously unselected package gcc-11-base:i386.
-2022-11-01T15:23:51.4344862Z (Reading database ...
+2022-11-01T15:23:51.4344862Z (Reading database ...
2022-11-01T15:23:51.4345195Z (Reading database ... 5%
2022-11-01T15:23:51.4345492Z (Reading database ... 10%
2022-11-01T15:23:51.4346277Z (Reading database ... 15%
@@ -852,98 +852,98 @@
2022-11-01T15:24:20.0904985Z Setting up BYOND.
2022-11-01T15:24:20.1285049Z % Total % Received % Xferd Average Speed Time Time Time Current
2022-11-01T15:24:20.1288558Z Dload Upload Total Spent Left Speed
-2022-11-01T15:24:20.1289906Z
+2022-11-01T15:24:20.1289906Z
2022-11-01T15:24:20.2648629Z 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
2022-11-01T15:24:20.2651476Z 100 4021k 100 4021k 0 0 28.8M 0 --:--:-- --:--:-- --:--:-- 28.8M
2022-11-01T15:24:20.2868719Z Archive: byond.zip
2022-11-01T15:24:20.2869523Z creating: byond/
2022-11-01T15:24:20.2872392Z creating: byond/key/
2022-11-01T15:24:20.2872809Z creating: byond/web/
-2022-11-01T15:24:20.2873278Z inflating: byond/web/child.dms
-2022-11-01T15:24:20.2873868Z inflating: byond/web/button.dms
-2022-11-01T15:24:20.2874291Z inflating: byond/web/input.dms
-2022-11-01T15:24:20.2874708Z inflating: byond/web/text.dms
-2022-11-01T15:24:20.2990682Z inflating: byond/web/webclient.dart.js
-2022-11-01T15:24:20.2991338Z inflating: byond/web/verbmenu.dms
-2022-11-01T15:24:20.2992247Z inflating: byond/web/defaultSkin.dms
-2022-11-01T15:24:20.2994907Z inflating: byond/web/hotbar.dms
-2022-11-01T15:24:20.2995370Z inflating: byond/web/label.dms
-2022-11-01T15:24:20.2997432Z inflating: byond/web/alert.dms
-2022-11-01T15:24:20.3045767Z inflating: byond/web/message.dms
-2022-11-01T15:24:20.3046084Z inflating: byond/web/drag.png
-2022-11-01T15:24:20.3046357Z inflating: byond/web/map.dms
-2022-11-01T15:24:20.3046639Z inflating: byond/web/splashlogo.png
-2022-11-01T15:24:20.3046920Z inflating: byond/web/drop.png
-2022-11-01T15:24:20.3109752Z inflating: byond/web/ext.js
-2022-11-01T15:24:20.3110039Z inflating: byond/web/file.dms
-2022-11-01T15:24:20.3110743Z inflating: byond/web/grid.dms
-2022-11-01T15:24:20.3112568Z inflating: byond/web/bar.dms
-2022-11-01T15:24:20.3116279Z inflating: byond/web/dpad.dms
-2022-11-01T15:24:20.3117768Z inflating: byond/web/output.dms
-2022-11-01T15:24:20.3118380Z inflating: byond/web/tab.dms
-2022-11-01T15:24:20.3121184Z inflating: byond/web/info.dms
-2022-11-01T15:24:20.3125342Z inflating: byond/web/color.dms
-2022-11-01T15:24:20.3127736Z inflating: byond/web/gamepad.dms
-2022-11-01T15:24:20.3129918Z inflating: byond/web/browser.dms
-2022-11-01T15:24:20.3130867Z inflating: byond/web/status.dms
-2022-11-01T15:24:20.3131904Z inflating: byond/web/any.dms
-2022-11-01T15:24:20.3133198Z inflating: byond/web/pane.dms
-2022-11-01T15:24:20.3134980Z inflating: byond/web/pop.dms
-2022-11-01T15:24:20.3136094Z inflating: byond/license.txt
-2022-11-01T15:24:20.3136925Z inflating: byond/legal.txt
-2022-11-01T15:24:20.3138018Z inflating: byond/Makefile
+2022-11-01T15:24:20.2873278Z inflating: byond/web/child.dms
+2022-11-01T15:24:20.2873868Z inflating: byond/web/button.dms
+2022-11-01T15:24:20.2874291Z inflating: byond/web/input.dms
+2022-11-01T15:24:20.2874708Z inflating: byond/web/text.dms
+2022-11-01T15:24:20.2990682Z inflating: byond/web/webclient.dart.js
+2022-11-01T15:24:20.2991338Z inflating: byond/web/verbmenu.dms
+2022-11-01T15:24:20.2992247Z inflating: byond/web/defaultSkin.dms
+2022-11-01T15:24:20.2994907Z inflating: byond/web/hotbar.dms
+2022-11-01T15:24:20.2995370Z inflating: byond/web/label.dms
+2022-11-01T15:24:20.2997432Z inflating: byond/web/alert.dms
+2022-11-01T15:24:20.3045767Z inflating: byond/web/message.dms
+2022-11-01T15:24:20.3046084Z inflating: byond/web/drag.png
+2022-11-01T15:24:20.3046357Z inflating: byond/web/map.dms
+2022-11-01T15:24:20.3046639Z inflating: byond/web/splashlogo.png
+2022-11-01T15:24:20.3046920Z inflating: byond/web/drop.png
+2022-11-01T15:24:20.3109752Z inflating: byond/web/ext.js
+2022-11-01T15:24:20.3110039Z inflating: byond/web/file.dms
+2022-11-01T15:24:20.3110743Z inflating: byond/web/grid.dms
+2022-11-01T15:24:20.3112568Z inflating: byond/web/bar.dms
+2022-11-01T15:24:20.3116279Z inflating: byond/web/dpad.dms
+2022-11-01T15:24:20.3117768Z inflating: byond/web/output.dms
+2022-11-01T15:24:20.3118380Z inflating: byond/web/tab.dms
+2022-11-01T15:24:20.3121184Z inflating: byond/web/info.dms
+2022-11-01T15:24:20.3125342Z inflating: byond/web/color.dms
+2022-11-01T15:24:20.3127736Z inflating: byond/web/gamepad.dms
+2022-11-01T15:24:20.3129918Z inflating: byond/web/browser.dms
+2022-11-01T15:24:20.3130867Z inflating: byond/web/status.dms
+2022-11-01T15:24:20.3131904Z inflating: byond/web/any.dms
+2022-11-01T15:24:20.3133198Z inflating: byond/web/pane.dms
+2022-11-01T15:24:20.3134980Z inflating: byond/web/pop.dms
+2022-11-01T15:24:20.3136094Z inflating: byond/license.txt
+2022-11-01T15:24:20.3136925Z inflating: byond/legal.txt
+2022-11-01T15:24:20.3138018Z inflating: byond/Makefile
2022-11-01T15:24:20.3138748Z creating: byond/man/
2022-11-01T15:24:20.3140374Z creating: byond/man/man6/
-2022-11-01T15:24:20.3140865Z inflating: byond/man/man6/DreamDaemon.6
-2022-11-01T15:24:20.3142127Z inflating: byond/man/man6/DreamMaker.6
+2022-11-01T15:24:20.3140865Z inflating: byond/man/man6/DreamDaemon.6
+2022-11-01T15:24:20.3142127Z inflating: byond/man/man6/DreamMaker.6
2022-11-01T15:24:20.3149532Z creating: byond/lib/
2022-11-01T15:24:20.3149763Z creating: byond/host/
-2022-11-01T15:24:20.3150009Z inflating: byond/host/readme.html
-2022-11-01T15:24:20.3150561Z inflating: byond/host/readme-unix.txt
+2022-11-01T15:24:20.3150009Z inflating: byond/host/readme.html
+2022-11-01T15:24:20.3150561Z inflating: byond/host/readme-unix.txt
2022-11-01T15:24:20.3150816Z creating: byond/host/home/
2022-11-01T15:24:20.3151052Z creating: byond/host/home/root/
2022-11-01T15:24:20.3151304Z creating: byond/host/home/root/byond/
2022-11-01T15:24:20.3151781Z creating: byond/host/home/root/byond/tools/
2022-11-01T15:24:20.3152089Z creating: byond/host/home/root/byond/tools/root/
-2022-11-01T15:24:20.3153050Z inflating: byond/host/home/root/byond/tools/root/root.dmb
+2022-11-01T15:24:20.3153050Z inflating: byond/host/home/root/byond/tools/root/root.dmb
2022-11-01T15:24:20.3154330Z creating: byond/host/shared/
2022-11-01T15:24:20.3155440Z creating: byond/host/shared/byond/
2022-11-01T15:24:20.3156763Z creating: byond/host/shared/byond/tools/
2022-11-01T15:24:20.3157942Z creating: byond/host/shared/byond/tools/ftp/
-2022-11-01T15:24:20.3159544Z inflating: byond/host/shared/byond/tools/ftp/ftp.dmb
+2022-11-01T15:24:20.3159544Z inflating: byond/host/shared/byond/tools/ftp/ftp.dmb
2022-11-01T15:24:20.3159981Z creating: byond/host/shared/byond/tools/admin/
-2022-11-01T15:24:20.3172339Z inflating: byond/host/shared/byond/tools/admin/admin.dmb
+2022-11-01T15:24:20.3172339Z inflating: byond/host/shared/byond/tools/admin/admin.dmb
2022-11-01T15:24:20.3172798Z creating: byond/host/shared-web/
2022-11-01T15:24:20.3173421Z creating: byond/host/shared-web/web/
2022-11-01T15:24:20.3173784Z creating: byond/host/shared-web/web/tools/
2022-11-01T15:24:20.3174165Z creating: byond/host/shared-web/web/tools/admin/
-2022-11-01T15:24:20.3176681Z inflating: byond/host/shared-web/web/tools/admin/index.dmb
-2022-11-01T15:24:20.3186829Z inflating: byond/host/host.dmb
-2022-11-01T15:24:20.3187123Z inflating: byond/host/host.start
-2022-11-01T15:24:20.3188445Z inflating: byond/host/hostconf.orig
-2022-11-01T15:24:20.3189903Z inflating: byond/host/hostconf.txt
-2022-11-01T15:24:20.3191949Z inflating: byond/readme.txt
+2022-11-01T15:24:20.3176681Z inflating: byond/host/shared-web/web/tools/admin/index.dmb
+2022-11-01T15:24:20.3186829Z inflating: byond/host/host.dmb
+2022-11-01T15:24:20.3187123Z inflating: byond/host/host.start
+2022-11-01T15:24:20.3188445Z inflating: byond/host/hostconf.orig
+2022-11-01T15:24:20.3189903Z inflating: byond/host/hostconf.txt
+2022-11-01T15:24:20.3191949Z inflating: byond/readme.txt
2022-11-01T15:24:20.3192209Z creating: byond/bin/
-2022-11-01T15:24:20.3193769Z inflating: byond/bin/byondexec
-2022-11-01T15:24:20.3195439Z inflating: byond/bin/DreamDownload
-2022-11-01T15:24:20.3908232Z inflating: byond/bin/libbyond.so
-2022-11-01T15:24:20.4069319Z inflating: byond/bin/libext.so
-2022-11-01T15:24:20.4073220Z inflating: byond/bin/DreamDaemon
-2022-11-01T15:24:20.4080176Z inflating: byond/bin/DreamMaker
+2022-11-01T15:24:20.3193769Z inflating: byond/bin/byondexec
+2022-11-01T15:24:20.3195439Z inflating: byond/bin/DreamDownload
+2022-11-01T15:24:20.3908232Z inflating: byond/bin/libbyond.so
+2022-11-01T15:24:20.4069319Z inflating: byond/bin/libext.so
+2022-11-01T15:24:20.4073220Z inflating: byond/bin/DreamDaemon
+2022-11-01T15:24:20.4080176Z inflating: byond/bin/DreamMaker
2022-11-01T15:24:20.4080431Z creating: byond/cfg/
-2022-11-01T15:24:20.4080676Z inflating: byond/cfg/release.txt
+2022-11-01T15:24:20.4080676Z inflating: byond/cfg/release.txt
2022-11-01T15:24:20.4266638Z ***************************
2022-11-01T15:24:20.4273089Z Now run the following command:
-2022-11-01T15:24:20.4285743Z
+2022-11-01T15:24:20.4285743Z
2022-11-01T15:24:20.4296269Z source /home/runner/BYOND/byond/bin/byondsetup
-2022-11-01T15:24:20.4307061Z
+2022-11-01T15:24:20.4307061Z
2022-11-01T15:24:20.4314771Z If it generates errors, your shell is not compatible with 'sh', so you will
2022-11-01T15:24:20.4321421Z have to edit byondsetup and make it work with your shell. If the script works, you should be able to run DreamDaemon.
-2022-11-01T15:24:20.4332109Z
+2022-11-01T15:24:20.4332109Z
2022-11-01T15:24:20.4340024Z IMPORTANT: once you have the script working, you must add the above line
2022-11-01T15:24:20.4346843Z to your startup script. The name of your startup script depends on the
2022-11-01T15:24:20.4352983Z shell you use. Typical ones are .profile or .bash_profile.
-2022-11-01T15:24:20.4363091Z
+2022-11-01T15:24:20.4363091Z
2022-11-01T15:24:20.4371649Z Once everything is working, you can find out more about the software
2022-11-01T15:24:20.4381742Z by doing 'man DreamDaemon'. A host server has also been included
2022-11-01T15:24:20.4389897Z so edit host/hostconf.txt and boot up your world server!
@@ -973,7 +973,7 @@
2022-11-01T15:25:42.0446892Z Welcome BYOND! (5.0 Public Version 514.1588)
2022-11-01T15:26:04.0921674Z 865 global variables
2022-11-01T15:26:04.9224562Z World loaded at 15:26:04!
-2022-11-01T15:26:04.9749013Z Running /tg/ revision:
+2022-11-01T15:26:04.9749013Z Running /tg/ revision:
2022-11-01T15:26:04.9749563Z No commit information
2022-11-01T15:26:04.9837092Z Loading config file config.txt...
2022-11-01T15:26:04.9841145Z Loading config file maps.txt...
@@ -1054,252 +1054,252 @@
2022-11-01T15:28:07.7750369Z Initializations complete within 121.7 seconds!
2022-11-01T15:28:07.7824332Z Game start took 0s
2022-11-01T15:28:18.9688166Z ##[group]/datum/unit_test/log_mapping
-2022-11-01T15:28:18.9688840Z
+2022-11-01T15:28:18.9688840Z
2022-11-01T15:28:18.9691942Z [1;32mPASS[0m /datum/unit_test/log_mapping 0s
2022-11-01T15:28:18.9692629Z ##[endgroup]
2022-11-01T15:28:19.0858950Z ##[group]/datum/unit_test/ablative_hood_hud
-2022-11-01T15:28:19.1163124Z
+2022-11-01T15:28:19.1163124Z
2022-11-01T15:28:19.1164826Z [1;32mPASS[0m /datum/unit_test/ablative_hood_hud 0.1s
2022-11-01T15:28:19.1165814Z ##[endgroup]
2022-11-01T15:28:19.1391399Z ##[group]/datum/unit_test/ablative_hood_hud_with_helmet
-2022-11-01T15:28:19.1679738Z
+2022-11-01T15:28:19.1679738Z
2022-11-01T15:28:19.1680798Z [1;32mPASS[0m /datum/unit_test/ablative_hood_hud_with_helmet 0s
2022-11-01T15:28:19.1684214Z ##[endgroup]
2022-11-01T15:28:19.1915312Z ##[group]/datum/unit_test/achievements
-2022-11-01T15:28:19.2020908Z
+2022-11-01T15:28:19.2020908Z
2022-11-01T15:28:19.2021795Z [1;32mPASS[0m /datum/unit_test/achievements 0.1s
2022-11-01T15:28:19.2022783Z ##[endgroup]
2022-11-01T15:28:19.2454845Z ##[group]/datum/unit_test/anchored_mobs
-2022-11-01T15:28:19.2456383Z
+2022-11-01T15:28:19.2456383Z
2022-11-01T15:28:19.2457685Z [1;32mPASS[0m /datum/unit_test/anchored_mobs 0s
2022-11-01T15:28:19.2458601Z ##[endgroup]
2022-11-01T15:28:19.2632595Z ##[group]/datum/unit_test/anonymous_themes
-2022-11-01T15:28:19.4123645Z
+2022-11-01T15:28:19.4123645Z
2022-11-01T15:28:19.4125365Z [1;32mPASS[0m /datum/unit_test/anonymous_themes 0.2s
2022-11-01T15:28:19.4128592Z ##[endgroup]
2022-11-01T15:28:19.6372545Z ##[group]/datum/unit_test/autowiki
-2022-11-01T15:28:21.1559221Z
+2022-11-01T15:28:21.1559221Z
2022-11-01T15:28:21.1560055Z [1;32mPASS[0m /datum/unit_test/autowiki 1.5s
2022-11-01T15:28:21.1560742Z ##[endgroup]
2022-11-01T15:28:22.6418059Z ##[group]/datum/unit_test/autowiki_include_template
-2022-11-01T15:28:22.6418298Z
+2022-11-01T15:28:22.6418298Z
2022-11-01T15:28:22.6419112Z [1;32mPASS[0m /datum/unit_test/autowiki_include_template 0s
2022-11-01T15:28:22.6419629Z ##[endgroup]
2022-11-01T15:28:22.6592281Z ##[group]/datum/unit_test/barsigns_icon
-2022-11-01T15:28:22.6850472Z
+2022-11-01T15:28:22.6850472Z
2022-11-01T15:28:22.6851042Z [1;32mPASS[0m /datum/unit_test/barsigns_icon 0s
2022-11-01T15:28:22.6851783Z ##[endgroup]
2022-11-01T15:28:22.7025607Z ##[group]/datum/unit_test/barsigns_name
-2022-11-01T15:28:22.7025827Z
+2022-11-01T15:28:22.7025827Z
2022-11-01T15:28:22.7026411Z [1;32mPASS[0m /datum/unit_test/barsigns_name 0s
2022-11-01T15:28:22.7026869Z ##[endgroup]
2022-11-01T15:28:22.7196300Z ##[group]/datum/unit_test/bespoke_id
-2022-11-01T15:28:22.7196495Z
+2022-11-01T15:28:22.7196495Z
2022-11-01T15:28:22.7196933Z [1;32mPASS[0m /datum/unit_test/bespoke_id 0s
2022-11-01T15:28:22.7197373Z ##[endgroup]
2022-11-01T15:28:22.7528217Z ##[group]/datum/unit_test/binary_insert
-2022-11-01T15:28:22.7528455Z
+2022-11-01T15:28:22.7528455Z
2022-11-01T15:28:22.7528943Z [1;32mPASS[0m /datum/unit_test/binary_insert 0s
2022-11-01T15:28:22.7529444Z ##[endgroup]
2022-11-01T15:28:22.7720960Z ##[group]/datum/unit_test/bloody_footprints
-2022-11-01T15:28:22.8157307Z
+2022-11-01T15:28:22.8157307Z
2022-11-01T15:28:22.8158188Z [1;32mPASS[0m /datum/unit_test/bloody_footprints 0.1s
2022-11-01T15:28:22.8158909Z ##[endgroup]
2022-11-01T15:28:22.9653160Z ##[group]/datum/unit_test/breath_sanity
-2022-11-01T15:28:23.0154449Z
+2022-11-01T15:28:23.0154449Z
2022-11-01T15:28:23.0155311Z [1;32mPASS[0m /datum/unit_test/breath_sanity 0.1s
2022-11-01T15:28:23.0155975Z ##[endgroup]
2022-11-01T15:28:23.0421572Z ##[group]/datum/unit_test/breath_sanity_plasmamen
-2022-11-01T15:28:23.0966156Z
+2022-11-01T15:28:23.0966156Z
2022-11-01T15:28:23.0966990Z [1;32mPASS[0m /datum/unit_test/breath_sanity_plasmamen 0s
2022-11-01T15:28:23.0967848Z ##[endgroup]
2022-11-01T15:28:23.1238973Z ##[group]/datum/unit_test/breath_sanity_ashwalker
-2022-11-01T15:28:23.1864867Z
+2022-11-01T15:28:23.1864867Z
2022-11-01T15:28:23.1865526Z [1;32mPASS[0m /datum/unit_test/breath_sanity_ashwalker 0s
2022-11-01T15:28:23.1866107Z ##[endgroup]
2022-11-01T15:28:23.2143094Z ##[group]/datum/unit_test/cable_powernets
-2022-11-01T15:28:23.2143293Z
+2022-11-01T15:28:23.2143293Z
2022-11-01T15:28:23.2143753Z [1;32mPASS[0m /datum/unit_test/cable_powernets 0s
2022-11-01T15:28:23.2144353Z ##[endgroup]
2022-11-01T15:28:23.2296359Z ##[group]/datum/unit_test/card_mismatch
-2022-11-01T15:28:23.2339244Z
+2022-11-01T15:28:23.2339244Z
2022-11-01T15:28:23.2339785Z [1;32mPASS[0m /datum/unit_test/card_mismatch 0s
2022-11-01T15:28:23.2340711Z ##[endgroup]
2022-11-01T15:28:23.3389441Z ##[group]/datum/unit_test/chain_pull_through_space
-2022-11-01T15:28:23.3417372Z
+2022-11-01T15:28:23.3417372Z
2022-11-01T15:28:23.3428322Z [1;32mPASS[0m /datum/unit_test/chain_pull_through_space 0s
2022-11-01T15:28:23.3429414Z ##[endgroup]
2022-11-01T15:28:23.4797614Z ##[group]/datum/unit_test/chat_filter_sanity
-2022-11-01T15:28:23.4802389Z
+2022-11-01T15:28:23.4802389Z
2022-11-01T15:28:23.4803303Z [1;32mPASS[0m /datum/unit_test/chat_filter_sanity 0s
2022-11-01T15:28:23.4803804Z ##[endgroup]
2022-11-01T15:28:23.4985708Z ##[group]/datum/unit_test/circuit_component_category
-2022-11-01T15:28:23.4985973Z
+2022-11-01T15:28:23.4985973Z
2022-11-01T15:28:23.4986498Z [1;32mPASS[0m /datum/unit_test/circuit_component_category 0s
2022-11-01T15:28:23.4987054Z ##[endgroup]
2022-11-01T15:28:23.5170927Z ##[group]/datum/unit_test/closets
-2022-11-01T15:28:25.4385541Z
+2022-11-01T15:28:25.4385541Z
2022-11-01T15:28:25.4386681Z [1;32mPASS[0m /datum/unit_test/closets 1.9s
2022-11-01T15:28:25.4387368Z ##[endgroup]
2022-11-01T15:28:28.6598884Z ##[group]/datum/unit_test/harm_punch
-2022-11-01T15:28:28.7131885Z
+2022-11-01T15:28:28.7131885Z
2022-11-01T15:28:28.7132943Z [1;32mPASS[0m /datum/unit_test/harm_punch 0.1s
2022-11-01T15:28:28.7134837Z ##[endgroup]
2022-11-01T15:28:28.7421766Z ##[group]/datum/unit_test/harm_melee
-2022-11-01T15:28:28.7933680Z
+2022-11-01T15:28:28.7933680Z
2022-11-01T15:28:28.7934808Z [1;32mPASS[0m /datum/unit_test/harm_melee 0s
2022-11-01T15:28:28.7935540Z ##[endgroup]
2022-11-01T15:28:28.8380921Z ##[group]/datum/unit_test/harm_different_damage
-2022-11-01T15:28:28.8975633Z
+2022-11-01T15:28:28.8975633Z
2022-11-01T15:28:28.8976869Z [1;32mPASS[0m /datum/unit_test/harm_different_damage 0s
2022-11-01T15:28:28.8977671Z ##[endgroup]
2022-11-01T15:28:28.9761803Z ##[group]/datum/unit_test/attack_chain
-2022-11-01T15:28:29.0318227Z
+2022-11-01T15:28:29.0318227Z
2022-11-01T15:28:29.0319454Z [1;32mPASS[0m /datum/unit_test/attack_chain 0.1s
2022-11-01T15:28:29.0320200Z ##[endgroup]
2022-11-01T15:28:29.0662718Z ##[group]/datum/unit_test/disarm
-2022-11-01T15:28:29.1273517Z
+2022-11-01T15:28:29.1273517Z
2022-11-01T15:28:29.1275850Z [1;32mPASS[0m /datum/unit_test/disarm 0.1s
2022-11-01T15:28:29.1276795Z ##[endgroup]
2022-11-01T15:28:29.1606515Z ##[group]/datum/unit_test/component_duping
-2022-11-01T15:28:29.1606753Z
+2022-11-01T15:28:29.1606753Z
2022-11-01T15:28:29.1607266Z [1;32mPASS[0m /datum/unit_test/component_duping 0s
2022-11-01T15:28:29.1607745Z ##[endgroup]
2022-11-01T15:28:29.1774627Z ##[group]/datum/unit_test/confusion_symptom
-2022-11-01T15:28:29.2032018Z
+2022-11-01T15:28:29.2032018Z
2022-11-01T15:28:29.2033145Z [1;32mPASS[0m /datum/unit_test/confusion_symptom 0.1s
2022-11-01T15:28:29.2033987Z ##[endgroup]
2022-11-01T15:28:29.2246157Z ##[group]/datum/unit_test/connect_loc_basic
-2022-11-01T15:28:29.2248367Z
+2022-11-01T15:28:29.2248367Z
2022-11-01T15:28:29.2249487Z [1;32mPASS[0m /datum/unit_test/connect_loc_basic 0s
2022-11-01T15:28:29.2250109Z ##[endgroup]
2022-11-01T15:28:29.2416396Z ##[group]/datum/unit_test/connect_loc_change_turf
-2022-11-01T15:28:29.2424538Z
+2022-11-01T15:28:29.2424538Z
2022-11-01T15:28:29.2425333Z [1;32mPASS[0m /datum/unit_test/connect_loc_change_turf 0s
2022-11-01T15:28:29.2425972Z ##[endgroup]
2022-11-01T15:28:29.2592394Z ##[group]/datum/unit_test/connect_loc_multiple_on_turf
-2022-11-01T15:28:29.2599395Z
+2022-11-01T15:28:29.2599395Z
2022-11-01T15:28:29.2599862Z [1;32mPASS[0m /datum/unit_test/connect_loc_multiple_on_turf 0s
2022-11-01T15:28:29.2600716Z ##[endgroup]
2022-11-01T15:28:29.2917858Z ##[group]/datum/unit_test/crayon_naming
-2022-11-01T15:28:29.2996631Z
+2022-11-01T15:28:29.2996631Z
2022-11-01T15:28:29.2997310Z [1;32mPASS[0m /datum/unit_test/crayon_naming 0s
2022-11-01T15:28:29.2997930Z ##[endgroup]
2022-11-01T15:28:29.3177352Z ##[group]/datum/unit_test/dcs_get_id_from_arguments
-2022-11-01T15:28:29.3178559Z
+2022-11-01T15:28:29.3178559Z
2022-11-01T15:28:29.3182903Z [1;32mPASS[0m /datum/unit_test/dcs_get_id_from_arguments 0s
2022-11-01T15:28:29.3183682Z ##[endgroup]
2022-11-01T15:28:29.3371899Z ##[group]/datum/unit_test/designs
-2022-11-01T15:28:29.3438160Z
+2022-11-01T15:28:29.3438160Z
2022-11-01T15:28:29.3438713Z [1;32mPASS[0m /datum/unit_test/designs 0s
2022-11-01T15:28:29.3439280Z ##[endgroup]
2022-11-01T15:28:29.3630774Z ##[group]/datum/unit_test/dummy_spawn_species
-2022-11-01T15:28:29.7865710Z
+2022-11-01T15:28:29.7865710Z
2022-11-01T15:28:29.7866984Z [1;32mPASS[0m /datum/unit_test/dummy_spawn_species 0.4s
2022-11-01T15:28:29.7868408Z ##[endgroup]
2022-11-01T15:28:30.2064941Z ##[group]/datum/unit_test/dummy_spawn_outfit
2022-11-01T15:28:30.2287943Z Job type /datum/job/ai could not be retrieved from SSjob
-2022-11-01T15:28:30.5729399Z
+2022-11-01T15:28:30.5729399Z
2022-11-01T15:28:30.5730637Z [1;32mPASS[0m /datum/unit_test/dummy_spawn_outfit 0.3s
2022-11-01T15:28:30.5731452Z ##[endgroup]
2022-11-01T15:28:30.8929561Z ##[group]/datum/unit_test/dynamic_roundstart_ruleset_sanity
-2022-11-01T15:28:30.8930214Z
+2022-11-01T15:28:30.8930214Z
2022-11-01T15:28:30.8933249Z [1;32mPASS[0m /datum/unit_test/dynamic_roundstart_ruleset_sanity 0s
2022-11-01T15:28:30.8933929Z ##[endgroup]
2022-11-01T15:28:30.9093619Z ##[group]/datum/unit_test/dynamic_unique_antag_flags
-2022-11-01T15:28:30.9094243Z
+2022-11-01T15:28:30.9094243Z
2022-11-01T15:28:30.9097412Z [1;32mPASS[0m /datum/unit_test/dynamic_unique_antag_flags 0s
2022-11-01T15:28:30.9098086Z ##[endgroup]
2022-11-01T15:28:30.9259102Z ##[group]/datum/unit_test/egg_glands
-2022-11-01T15:28:30.9738261Z
+2022-11-01T15:28:30.9738261Z
2022-11-01T15:28:30.9739529Z [1;32mPASS[0m /datum/unit_test/egg_glands 0s
2022-11-01T15:28:30.9742814Z ##[endgroup]
2022-11-01T15:28:30.9910488Z ##[group]/datum/unit_test/emoting
-2022-11-01T15:28:31.0191020Z
+2022-11-01T15:28:31.0191020Z
2022-11-01T15:28:31.0192873Z [1;32mPASS[0m /datum/unit_test/emoting 0.1s
2022-11-01T15:28:31.0196009Z ##[endgroup]
2022-11-01T15:28:31.0470998Z ##[group]/datum/unit_test/food_edibility_check
-2022-11-01T15:28:32.3907505Z
+2022-11-01T15:28:32.3907505Z
2022-11-01T15:28:32.3908587Z [1;32mPASS[0m /datum/unit_test/food_edibility_check 1.3s
2022-11-01T15:28:32.3909262Z ##[endgroup]
2022-11-01T15:28:33.7158865Z ##[group]/datum/unit_test/atmospheric_gas_transfer
-2022-11-01T15:28:33.7169071Z
+2022-11-01T15:28:33.7169071Z
2022-11-01T15:28:33.7171453Z [1;32mPASS[0m /datum/unit_test/atmospheric_gas_transfer 0s
2022-11-01T15:28:33.7173553Z ##[endgroup]
2022-11-01T15:28:33.7346695Z ##[group]/datum/unit_test/get_turf_pixel
-2022-11-01T15:28:33.7367134Z
+2022-11-01T15:28:33.7367134Z
2022-11-01T15:28:33.7368982Z [1;32mPASS[0m /datum/unit_test/get_turf_pixel 0s
2022-11-01T15:28:33.7371248Z ##[endgroup]
2022-11-01T15:28:33.7556559Z ##[group]/datum/unit_test/greyscale_item_icon_states
-2022-11-01T15:28:33.7624830Z
+2022-11-01T15:28:33.7624830Z
2022-11-01T15:28:33.7626511Z [1;32mPASS[0m /datum/unit_test/greyscale_item_icon_states 0s
2022-11-01T15:28:33.7628685Z ##[endgroup]
2022-11-01T15:28:33.7811590Z ##[group]/datum/unit_test/greyscale_color_count
-2022-11-01T15:28:33.7978824Z
+2022-11-01T15:28:33.7978824Z
2022-11-01T15:28:33.7981042Z [1;32mPASS[0m /datum/unit_test/greyscale_color_count 0s
2022-11-01T15:28:33.7981873Z ##[endgroup]
2022-11-01T15:28:33.8551069Z ##[group]/datum/unit_test/hallucination_icons
-2022-11-01T15:28:34.1090174Z
+2022-11-01T15:28:34.1090174Z
2022-11-01T15:28:34.1096431Z [1;32mPASS[0m /datum/unit_test/hallucination_icons 0.3s
2022-11-01T15:28:34.1099789Z ##[endgroup]
2022-11-01T15:28:34.3281283Z ##[group]/datum/unit_test/heretic_knowledge
-2022-11-01T15:28:34.3305016Z
+2022-11-01T15:28:34.3305016Z
2022-11-01T15:28:34.3306029Z [1;32mPASS[0m /datum/unit_test/heretic_knowledge 0s
2022-11-01T15:28:34.3306904Z ##[endgroup]
2022-11-01T15:28:34.3483924Z ##[group]/datum/unit_test/heretic_main_paths
-2022-11-01T15:28:34.3484902Z
+2022-11-01T15:28:34.3484902Z
2022-11-01T15:28:34.3487952Z [1;32mPASS[0m /datum/unit_test/heretic_main_paths 0s
2022-11-01T15:28:34.3491126Z ##[endgroup]
2022-11-01T15:28:34.3668321Z ##[group]/datum/unit_test/heretic_rituals
-2022-11-01T15:28:34.4513883Z
+2022-11-01T15:28:34.4513883Z
2022-11-01T15:28:34.4515231Z [1;32mPASS[0m /datum/unit_test/heretic_rituals 0.1s
2022-11-01T15:28:34.4518615Z ##[endgroup]
2022-11-01T15:28:34.5255676Z ##[group]/datum/unit_test/hanukkah_2123
-2022-11-01T15:28:34.5256380Z
+2022-11-01T15:28:34.5256380Z
2022-11-01T15:28:34.5258696Z [1;32mPASS[0m /datum/unit_test/hanukkah_2123 0s
2022-11-01T15:28:34.5306060Z ##[endgroup]
2022-11-01T15:28:34.5435626Z ##[group]/datum/unit_test/ramadan_2165
-2022-11-01T15:28:34.5435839Z
+2022-11-01T15:28:34.5435839Z
2022-11-01T15:28:34.5436316Z [1;32mPASS[0m /datum/unit_test/ramadan_2165 0s
2022-11-01T15:28:34.5436790Z ##[endgroup]
2022-11-01T15:28:34.5758281Z ##[group]/datum/unit_test/thanksgiving_2020
-2022-11-01T15:28:34.5758510Z
+2022-11-01T15:28:34.5758510Z
2022-11-01T15:28:34.5759790Z [1;32mPASS[0m /datum/unit_test/thanksgiving_2020 0s
2022-11-01T15:28:34.5760323Z ##[endgroup]
2022-11-01T15:28:34.5922636Z ##[group]/datum/unit_test/mother_3683
-2022-11-01T15:28:34.5923203Z
+2022-11-01T15:28:34.5923203Z
2022-11-01T15:28:34.5923668Z [1;32mPASS[0m /datum/unit_test/mother_3683 0s
2022-11-01T15:28:34.5924152Z ##[endgroup]
2022-11-01T15:28:34.6258731Z ##[group]/datum/unit_test/hello_2020
-2022-11-01T15:28:34.6258967Z
+2022-11-01T15:28:34.6258967Z
2022-11-01T15:28:34.6259461Z [1;32mPASS[0m /datum/unit_test/hello_2020 0s
2022-11-01T15:28:34.6260389Z ##[endgroup]
2022-11-01T15:28:34.6425516Z ##[group]/datum/unit_test/new_year_1983
-2022-11-01T15:28:34.6425720Z
+2022-11-01T15:28:34.6425720Z
2022-11-01T15:28:34.6426174Z [1;32mPASS[0m /datum/unit_test/new_year_1983 0s
2022-11-01T15:28:34.6426620Z ##[endgroup]
2022-11-01T15:28:34.6759224Z ##[group]/datum/unit_test/moth_week_2020
-2022-11-01T15:28:34.6792170Z
+2022-11-01T15:28:34.6792170Z
2022-11-01T15:28:34.6792723Z [1;32mPASS[0m /datum/unit_test/moth_week_2020 0s
2022-11-01T15:28:34.6793240Z ##[endgroup]
2022-11-01T15:28:34.6958289Z ##[group]/datum/unit_test/human_through_recycler
-2022-11-01T15:28:34.7370291Z
+2022-11-01T15:28:34.7370291Z
2022-11-01T15:28:34.7371226Z [1;32mPASS[0m /datum/unit_test/human_through_recycler 0.1s
2022-11-01T15:28:34.7372112Z ##[endgroup]
2022-11-01T15:28:34.8623820Z ##[group]/datum/unit_test/hydroponics_extractor_storage
-2022-11-01T15:28:34.8996006Z
+2022-11-01T15:28:34.8996006Z
2022-11-01T15:28:34.8996940Z [1;32mPASS[0m /datum/unit_test/hydroponics_extractor_storage 0s
2022-11-01T15:28:34.8997589Z ##[endgroup]
2022-11-01T15:28:34.9278188Z ##[group]/datum/unit_test/hydroponics_harvest
-2022-11-01T15:28:35.0009791Z
+2022-11-01T15:28:35.0009791Z
2022-11-01T15:28:35.0010716Z [1;32mPASS[0m /datum/unit_test/hydroponics_harvest 0.1s
2022-11-01T15:28:35.0012013Z ##[endgroup]
2022-11-01T15:28:35.0747162Z ##[group]/datum/unit_test/hydroponics_self_mutation
-2022-11-01T15:28:35.1406271Z
+2022-11-01T15:28:35.1406271Z
2022-11-01T15:28:35.1407332Z [1;32mPASS[0m /datum/unit_test/hydroponics_self_mutation 0.1s
2022-11-01T15:28:35.1408057Z ##[endgroup]
2022-11-01T15:28:35.2102485Z ##[group]/datum/unit_test/hydroponics_validate_genes
-2022-11-01T15:28:35.2762621Z
+2022-11-01T15:28:35.2762621Z
2022-11-01T15:28:35.2763561Z [1;32mPASS[0m /datum/unit_test/hydroponics_validate_genes 0s
2022-11-01T15:28:35.2764288Z ##[endgroup]
2022-11-01T15:28:35.3749912Z ##[group]/datum/unit_test/defined_inhand_icon_states
@@ -1420,200 +1420,200 @@
2022-11-01T15:28:36.6241586Z /obj/item/bonesetter does not have an inhand_icon_state value - Possible matching sprites for "bonesetter" found in: 'icons/mob/inhands/equipment/medical_lefthand.dmi' & 'icons/mob/inhands/equipment/medical_righthand.dmi'
2022-11-01T15:28:36.6242563Z /obj/item/blood_filter does not have an inhand_icon_state value - Possible matching sprites for "bloodfilter" found in: 'icons/mob/inhands/equipment/medical_lefthand.dmi' & 'icons/mob/inhands/equipment/medical_righthand.dmi'
2022-11-01T15:28:36.6243567Z /obj/item/mecha_ammo/flashbang does not have an inhand_icon_state value - Possible matching sprites for "flashbang" found in: 'icons/mob/inhands/equipment/security_righthand.dmi' & 'icons/mob/inhands/equipment/security_lefthand.dmi'
-2022-11-01T15:28:36.6243984Z
+2022-11-01T15:28:36.6243984Z
2022-11-01T15:28:36.6244251Z [1;32mPASS[0m /datum/unit_test/defined_inhand_icon_states 1.3s
2022-11-01T15:28:36.6245107Z ##[endgroup]
2022-11-01T15:28:38.3781123Z ##[group]/datum/unit_test/keybinding_init
-2022-11-01T15:28:38.3781642Z
+2022-11-01T15:28:38.3781642Z
2022-11-01T15:28:38.3782256Z [1;32mPASS[0m /datum/unit_test/keybinding_init 0s
2022-11-01T15:28:38.3782848Z ##[endgroup]
2022-11-01T15:28:38.3952800Z ##[group]/datum/unit_test/knockoff_component
-2022-11-01T15:28:38.4583090Z
+2022-11-01T15:28:38.4583090Z
2022-11-01T15:28:38.4584605Z [1;32mPASS[0m /datum/unit_test/knockoff_component 0.1s
2022-11-01T15:28:38.4585463Z ##[endgroup]
2022-11-01T15:28:38.5388034Z ##[group]/datum/unit_test/limbsanity
-2022-11-01T15:28:38.6201426Z
+2022-11-01T15:28:38.6201426Z
2022-11-01T15:28:38.6202784Z [1;32mPASS[0m /datum/unit_test/limbsanity 0.1s
2022-11-01T15:28:38.6203543Z ##[endgroup]
2022-11-01T15:28:38.6375016Z ##[group]/datum/unit_test/load_map_security
2022-11-01T15:28:38.6378905Z map directory not in whitelist: data/load_map_security_temp for map runtimestation
-2022-11-01T15:28:38.6380282Z
+2022-11-01T15:28:38.6380282Z
2022-11-01T15:28:38.6381773Z [1;32mPASS[0m /datum/unit_test/load_map_security 0s
2022-11-01T15:28:38.6382439Z ##[endgroup]
2022-11-01T15:28:38.6552883Z ##[group]/datum/unit_test/machine_disassembly
-2022-11-01T15:28:38.6594171Z
+2022-11-01T15:28:38.6594171Z
2022-11-01T15:28:38.6595097Z [1;32mPASS[0m /datum/unit_test/machine_disassembly 0s
2022-11-01T15:28:38.6595719Z ##[endgroup]
2022-11-01T15:28:38.6872178Z ##[group]/datum/unit_test/mecha_damage
-2022-11-01T15:28:38.7397615Z
+2022-11-01T15:28:38.7397615Z
2022-11-01T15:28:38.7398654Z [1;32mPASS[0m /datum/unit_test/mecha_damage 0.1s
2022-11-01T15:28:38.7399283Z ##[endgroup]
2022-11-01T15:28:38.7754903Z ##[group]/datum/unit_test/test_human_base
-2022-11-01T15:28:38.8529341Z
+2022-11-01T15:28:38.8529341Z
2022-11-01T15:28:38.8530478Z [1;32mPASS[0m /datum/unit_test/test_human_base 0.1s
2022-11-01T15:28:38.8531256Z ##[endgroup]
2022-11-01T15:28:38.9752946Z ##[group]/datum/unit_test/test_human_bone
-2022-11-01T15:28:39.0547873Z
+2022-11-01T15:28:39.0547873Z
2022-11-01T15:28:39.0550271Z [1;32mPASS[0m /datum/unit_test/test_human_bone 0.1s
2022-11-01T15:28:39.0551284Z ##[endgroup]
2022-11-01T15:28:39.1298729Z ##[group]/datum/unit_test/merge_type
-2022-11-01T15:28:39.1300463Z
+2022-11-01T15:28:39.1300463Z
2022-11-01T15:28:39.1301413Z [1;32mPASS[0m /datum/unit_test/merge_type 0s
2022-11-01T15:28:39.1302403Z ##[endgroup]
2022-11-01T15:28:39.1477365Z ##[group]/datum/unit_test/metabolization
-2022-11-01T15:28:39.3901954Z
+2022-11-01T15:28:39.3901954Z
2022-11-01T15:28:39.3903433Z [1;32mPASS[0m /datum/unit_test/metabolization 0.2s
2022-11-01T15:28:39.3906497Z ##[endgroup]
2022-11-01T15:28:39.7294447Z ##[group]/datum/unit_test/on_mob_end_metabolize
-2022-11-01T15:28:39.7598821Z
+2022-11-01T15:28:39.7598821Z
2022-11-01T15:28:39.7600420Z [1;32mPASS[0m /datum/unit_test/on_mob_end_metabolize 0s
2022-11-01T15:28:39.7649553Z ##[endgroup]
2022-11-01T15:28:39.7835943Z ##[group]/datum/unit_test/addictions
-2022-11-01T15:28:39.8761920Z
+2022-11-01T15:28:39.8761920Z
2022-11-01T15:28:39.8763025Z [1;32mPASS[0m /datum/unit_test/addictions 0.1s
2022-11-01T15:28:39.8764090Z ##[endgroup]
2022-11-01T15:28:39.9657360Z ##[group]/datum/unit_test/actions_moved_on_mind_transfer
-2022-11-01T15:28:39.9971522Z
+2022-11-01T15:28:39.9971522Z
2022-11-01T15:28:39.9972744Z [1;32mPASS[0m /datum/unit_test/actions_moved_on_mind_transfer 0s
2022-11-01T15:28:39.9974074Z ##[endgroup]
2022-11-01T15:28:40.0547546Z ##[group]/datum/unit_test/mob_faction
-2022-11-01T15:28:44.4337194Z
+2022-11-01T15:28:44.4337194Z
2022-11-01T15:28:44.4338995Z [1;32mPASS[0m /datum/unit_test/mob_faction 4.4s
2022-11-01T15:28:44.4343946Z ##[endgroup]
2022-11-01T15:28:50.4570438Z ##[group]/datum/unit_test/mob_spawn
-2022-11-01T15:28:50.4788560Z
+2022-11-01T15:28:50.4788560Z
2022-11-01T15:28:50.4789841Z [1;32mPASS[0m /datum/unit_test/mob_spawn 0s
2022-11-01T15:28:50.4791361Z ##[endgroup]
2022-11-01T15:28:50.6427929Z ##[group]/datum/unit_test/modsuit_checks
-2022-11-01T15:28:50.8774698Z
+2022-11-01T15:28:50.8774698Z
2022-11-01T15:28:50.8776366Z [1;32mPASS[0m /datum/unit_test/modsuit_checks 0.2s
2022-11-01T15:28:50.8777936Z ##[endgroup]
2022-11-01T15:28:51.1124046Z ##[group]/datum/unit_test/modular_map_loader
-2022-11-01T15:28:51.1141260Z
+2022-11-01T15:28:51.1141260Z
2022-11-01T15:28:51.1142098Z [1;32mPASS[0m /datum/unit_test/modular_map_loader 0s
2022-11-01T15:28:51.1142848Z ##[endgroup]
2022-11-01T15:28:51.1326741Z ##[group]/datum/unit_test/mouse_bite_cable
-2022-11-01T15:28:51.1380480Z
+2022-11-01T15:28:51.1380480Z
2022-11-01T15:28:51.1381073Z [1;32mPASS[0m /datum/unit_test/mouse_bite_cable 0s
2022-11-01T15:28:51.1381752Z ##[endgroup]
2022-11-01T15:28:51.1577018Z ##[group]/datum/unit_test/novaflower_burn
-2022-11-01T15:28:51.2169264Z
+2022-11-01T15:28:51.2169264Z
2022-11-01T15:28:51.2170162Z [1;32mPASS[0m /datum/unit_test/novaflower_burn 0.1s
2022-11-01T15:28:51.2170901Z ##[endgroup]
2022-11-01T15:28:51.2996852Z ##[group]/datum/unit_test/ntnetwork
-2022-11-01T15:28:51.3019053Z
+2022-11-01T15:28:51.3019053Z
2022-11-01T15:28:51.3019857Z [1;32mPASS[0m /datum/unit_test/ntnetwork 0.1s
2022-11-01T15:28:51.3020531Z ##[endgroup]
2022-11-01T15:28:51.3196087Z ##[group]/datum/unit_test/nuke_cinematic
-2022-11-01T15:28:56.0755977Z
+2022-11-01T15:28:56.0755977Z
2022-11-01T15:28:56.0763029Z [1;32mPASS[0m /datum/unit_test/nuke_cinematic 4.7s
2022-11-01T15:28:56.0764783Z ##[endgroup]
2022-11-01T15:28:56.3446321Z ##[group]/datum/unit_test/objectives_category
-2022-11-01T15:28:56.3446835Z
+2022-11-01T15:28:56.3446835Z
2022-11-01T15:28:56.3447470Z [1;32mPASS[0m /datum/unit_test/objectives_category 0s
2022-11-01T15:28:56.3448136Z ##[endgroup]
2022-11-01T15:28:56.3614737Z ##[group]/datum/unit_test/operating_table
-2022-11-01T15:28:56.4176620Z
+2022-11-01T15:28:56.4176620Z
2022-11-01T15:28:56.4177598Z [1;32mPASS[0m /datum/unit_test/operating_table 0.1s
2022-11-01T15:28:56.4178689Z ##[endgroup]
2022-11-01T15:28:56.4981266Z ##[group]/datum/unit_test/outfit_sanity
-2022-11-01T15:29:06.6657414Z
+2022-11-01T15:29:06.6657414Z
2022-11-01T15:29:06.6658439Z [1;32mPASS[0m /datum/unit_test/outfit_sanity 10.2s
2022-11-01T15:29:06.6659196Z ##[endgroup]
2022-11-01T15:29:16.7908070Z ##[group]/datum/unit_test/paintings
-2022-11-01T15:29:16.8212273Z
+2022-11-01T15:29:16.8212273Z
2022-11-01T15:29:16.8213346Z [1;32mPASS[0m /datum/unit_test/paintings 0.1s
2022-11-01T15:29:16.8214069Z ##[endgroup]
2022-11-01T15:29:16.8389425Z ##[group]/datum/unit_test/pills
-2022-11-01T15:29:16.8676028Z
+2022-11-01T15:29:16.8676028Z
2022-11-01T15:29:16.8677434Z [1;32mPASS[0m /datum/unit_test/pills 0s
2022-11-01T15:29:16.8678165Z ##[endgroup]
2022-11-01T15:29:16.9417567Z ##[group]/datum/unit_test/plane_double_transform
-2022-11-01T15:29:16.9735002Z
+2022-11-01T15:29:16.9735002Z
2022-11-01T15:29:16.9735721Z [1;32mPASS[0m /datum/unit_test/plane_double_transform 0s
2022-11-01T15:29:16.9736359Z ##[endgroup]
2022-11-01T15:29:17.0062562Z ##[group]/datum/unit_test/plane_dupe_detector
-2022-11-01T15:29:17.0065142Z
+2022-11-01T15:29:17.0065142Z
2022-11-01T15:29:17.0067978Z [1;32mPASS[0m /datum/unit_test/plane_dupe_detector 0s
2022-11-01T15:29:17.0071640Z ##[endgroup]
2022-11-01T15:29:17.0244509Z ##[group]/datum/unit_test/plantgrowth
-2022-11-01T15:29:17.0776528Z
+2022-11-01T15:29:17.0776528Z
2022-11-01T15:29:17.0779718Z [1;32mPASS[0m /datum/unit_test/plantgrowth 0s
2022-11-01T15:29:17.0781279Z ##[endgroup]
2022-11-01T15:29:17.0965505Z ##[group]/datum/unit_test/preference_species
-2022-11-01T15:29:17.0966443Z
+2022-11-01T15:29:17.0966443Z
2022-11-01T15:29:17.0969864Z [1;32mPASS[0m /datum/unit_test/preference_species 0s
2022-11-01T15:29:17.0973093Z ##[endgroup]
2022-11-01T15:29:17.1152354Z ##[group]/datum/unit_test/preferences_implement_everything
-2022-11-01T15:29:23.4577951Z
+2022-11-01T15:29:23.4577951Z
2022-11-01T15:29:23.4578850Z [1;32mPASS[0m /datum/unit_test/preferences_implement_everything 6.3s
2022-11-01T15:29:23.4579521Z ##[endgroup]
2022-11-01T15:29:29.7830207Z ##[group]/datum/unit_test/preferences_valid_savefile_key
-2022-11-01T15:29:29.7830930Z
+2022-11-01T15:29:29.7830930Z
2022-11-01T15:29:29.7833510Z [1;32mPASS[0m /datum/unit_test/preferences_valid_savefile_key 0s
2022-11-01T15:29:29.7834275Z ##[endgroup]
2022-11-01T15:29:29.8033816Z ##[group]/datum/unit_test/preferences_valid_main_feature_name
-2022-11-01T15:29:29.8034550Z
+2022-11-01T15:29:29.8034550Z
2022-11-01T15:29:29.8035744Z [1;32mPASS[0m /datum/unit_test/preferences_valid_main_feature_name 0s
2022-11-01T15:29:29.8089387Z ##[endgroup]
2022-11-01T15:29:29.8234720Z ##[group]/datum/unit_test/projectile_movetypes
-2022-11-01T15:29:29.8234940Z
+2022-11-01T15:29:29.8234940Z
2022-11-01T15:29:29.8235533Z [1;32mPASS[0m /datum/unit_test/projectile_movetypes 0s
2022-11-01T15:29:29.8236221Z ##[endgroup]
2022-11-01T15:29:29.8415787Z ##[group]/datum/unit_test/gun_go_bang
-2022-11-01T15:29:29.9160628Z
+2022-11-01T15:29:29.9160628Z
2022-11-01T15:29:29.9161545Z [1;32mPASS[0m /datum/unit_test/gun_go_bang 0.1s
2022-11-01T15:29:29.9162229Z ##[endgroup]
2022-11-01T15:29:30.0035502Z ##[group]/datum/unit_test/quirk_icons
-2022-11-01T15:29:30.0035718Z
+2022-11-01T15:29:30.0035718Z
2022-11-01T15:29:30.0036645Z [1;32mPASS[0m /datum/unit_test/quirk_icons 0s
2022-11-01T15:29:30.0037121Z ##[endgroup]
2022-11-01T15:29:30.0231538Z ##[group]/datum/unit_test/range_return
-2022-11-01T15:29:30.0231750Z
+2022-11-01T15:29:30.0231750Z
2022-11-01T15:29:30.0232212Z [1;32mPASS[0m /datum/unit_test/range_return 0s
2022-11-01T15:29:30.0232658Z ##[endgroup]
2022-11-01T15:29:30.0427797Z ##[group]/datum/unit_test/frame_stacking
-2022-11-01T15:29:30.1020458Z
+2022-11-01T15:29:30.1020458Z
2022-11-01T15:29:30.1021324Z [1;32mPASS[0m /datum/unit_test/frame_stacking 0.1s
2022-11-01T15:29:30.1022036Z ##[endgroup]
2022-11-01T15:29:30.1824738Z ##[group]/datum/unit_test/reagent_id_typos
-2022-11-01T15:29:30.1842378Z
+2022-11-01T15:29:30.1842378Z
2022-11-01T15:29:30.1842930Z [1;32mPASS[0m /datum/unit_test/reagent_id_typos 0s
2022-11-01T15:29:30.1843838Z ##[endgroup]
2022-11-01T15:29:30.2065945Z ##[group]/datum/unit_test/reagent_mob_expose
-2022-11-01T15:29:30.2431485Z
+2022-11-01T15:29:30.2431485Z
2022-11-01T15:29:30.2432396Z [1;32mPASS[0m /datum/unit_test/reagent_mob_expose 0s
2022-11-01T15:29:30.2433748Z ##[endgroup]
2022-11-01T15:29:30.2736664Z ##[group]/datum/unit_test/reagent_mob_procs
-2022-11-01T15:29:30.3087817Z
+2022-11-01T15:29:30.3087817Z
2022-11-01T15:29:30.3088677Z [1;32mPASS[0m /datum/unit_test/reagent_mob_procs 0.1s
2022-11-01T15:29:30.3089382Z ##[endgroup]
2022-11-01T15:29:30.3347974Z ##[group]/datum/unit_test/reagent_names
-2022-11-01T15:29:31.2354819Z
+2022-11-01T15:29:31.2354819Z
2022-11-01T15:29:31.2355678Z [1;32mPASS[0m /datum/unit_test/reagent_names 0.9s
2022-11-01T15:29:31.2356318Z ##[endgroup]
2022-11-01T15:29:32.1042828Z ##[group]/datum/unit_test/reagent_recipe_collisions
-2022-11-01T15:29:32.5727294Z
+2022-11-01T15:29:32.5727294Z
2022-11-01T15:29:32.5728917Z [1;32mPASS[0m /datum/unit_test/reagent_recipe_collisions 0.4s
2022-11-01T15:29:32.5730155Z ##[endgroup]
2022-11-01T15:29:32.9927755Z ##[group]/datum/unit_test/reagent_transfer
-2022-11-01T15:29:32.9934109Z
+2022-11-01T15:29:32.9934109Z
2022-11-01T15:29:32.9935981Z [1;32mPASS[0m /datum/unit_test/reagent_transfer 0s
2022-11-01T15:29:32.9936895Z ##[endgroup]
2022-11-01T15:29:33.0126783Z ##[group]/datum/unit_test/stop_drop_and_roll
-2022-11-01T15:29:33.0390175Z
+2022-11-01T15:29:33.0390175Z
2022-11-01T15:29:33.0391562Z [1;32mPASS[0m /datum/unit_test/stop_drop_and_roll 0s
2022-11-01T15:29:33.0394218Z ##[endgroup]
2022-11-01T15:29:33.0646804Z ##[group]/datum/unit_test/container_resist
-2022-11-01T15:29:33.1054797Z
+2022-11-01T15:29:33.1054797Z
2022-11-01T15:29:33.1056167Z [1;32mPASS[0m /datum/unit_test/container_resist 0.1s
2022-11-01T15:29:33.1057687Z ##[endgroup]
2022-11-01T15:29:33.1496944Z ##[group]/datum/unit_test/get_message_mods
-2022-11-01T15:29:33.1778888Z
+2022-11-01T15:29:33.1778888Z
2022-11-01T15:29:33.1780246Z [1;32mPASS[0m /datum/unit_test/get_message_mods 0s
2022-11-01T15:29:33.1781311Z ##[endgroup]
2022-11-01T15:29:33.2061026Z ##[group]/datum/unit_test/say_signal
-2022-11-01T15:29:33.2078006Z
+2022-11-01T15:29:33.2078006Z
2022-11-01T15:29:33.2079823Z [1;32mPASS[0m /datum/unit_test/say_signal 0s
2022-11-01T15:29:33.2083007Z ##[endgroup]
2022-11-01T15:29:33.2288010Z ##[group]/datum/unit_test/screenshot_antag_icons
@@ -1647,12 +1647,12 @@
2022-11-01T15:29:33.5122130Z screenshot_antag_icons_blobinfection was put in data/screenshots_new
2022-11-01T15:29:33.5146398Z screenshot_antag_icons_obsessed was put in data/screenshots_new
2022-11-01T15:29:33.5153740Z screenshot_antag_icons_malfaimidround was put in data/screenshots_new
-2022-11-01T15:29:33.5154025Z
+2022-11-01T15:29:33.5154025Z
2022-11-01T15:29:33.5154740Z [1;32mPASS[0m /datum/unit_test/screenshot_antag_icons 0.3s
2022-11-01T15:29:33.5155554Z ##[endgroup]
2022-11-01T15:29:33.7840161Z ##[group]/datum/unit_test/screenshot_basic
2022-11-01T15:29:33.7846135Z screenshot_basic_red was put in data/screenshots_new
-2022-11-01T15:29:33.7850103Z
+2022-11-01T15:29:33.7850103Z
2022-11-01T15:29:33.7851242Z [1;32mPASS[0m /datum/unit_test/screenshot_basic 0s
2022-11-01T15:29:33.7851736Z ##[endgroup]
2022-11-01T15:29:33.8047719Z ##[group]/datum/unit_test/screenshot_humanoids
@@ -1709,112 +1709,112 @@
2022-11-01T15:30:06.7544848Z screenshot_humanoids__datum_species_vampire was put in data/screenshots_new
2022-11-01T15:30:07.6424794Z screenshot_humanoids__datum_species_zombie was put in data/screenshots_new
2022-11-01T15:30:08.5972035Z screenshot_humanoids__datum_species_zombie_infectious was put in data/screenshots_new
-2022-11-01T15:30:08.5972336Z
+2022-11-01T15:30:08.5972336Z
2022-11-01T15:30:08.5972854Z [1;32mPASS[0m /datum/unit_test/screenshot_humanoids 34.7s
2022-11-01T15:30:08.5973526Z ##[endgroup]
2022-11-01T15:30:44.2099567Z ##[group]/datum/unit_test/screenshot_saturnx
2022-11-01T15:30:44.5011065Z screenshot_saturnx_invisibility was put in data/screenshots_new
-2022-11-01T15:30:44.5011333Z
+2022-11-01T15:30:44.5011333Z
2022-11-01T15:30:44.5012180Z [1;32mPASS[0m /datum/unit_test/screenshot_saturnx 0.3s
2022-11-01T15:30:44.5012769Z ##[endgroup]
2022-11-01T15:30:44.7785909Z ##[group]/datum/unit_test/security_officer_roundstart_distribution
-2022-11-01T15:30:44.9017426Z
+2022-11-01T15:30:44.9017426Z
2022-11-01T15:30:44.9018614Z [1;32mPASS[0m /datum/unit_test/security_officer_roundstart_distribution 0.2s
2022-11-01T15:30:44.9019313Z ##[endgroup]
2022-11-01T15:30:45.0427506Z ##[group]/datum/unit_test/security_officer_latejoin_distribution
-2022-11-01T15:30:45.5391742Z
+2022-11-01T15:30:45.5391742Z
2022-11-01T15:30:45.5392426Z [1;32mPASS[0m /datum/unit_test/security_officer_latejoin_distribution 0.5s
2022-11-01T15:30:45.5393125Z ##[endgroup]
2022-11-01T15:30:46.2210379Z ##[group]/datum/unit_test/security_levels
-2022-11-01T15:30:46.2210589Z
+2022-11-01T15:30:46.2210589Z
2022-11-01T15:30:46.2216058Z [1;32mPASS[0m /datum/unit_test/security_levels 0s
2022-11-01T15:30:46.2216555Z ##[endgroup]
2022-11-01T15:30:46.2399271Z ##[group]/datum/unit_test/servingtray
-2022-11-01T15:30:46.2779259Z
+2022-11-01T15:30:46.2779259Z
2022-11-01T15:30:46.2780125Z [1;32mPASS[0m /datum/unit_test/servingtray 0s
2022-11-01T15:30:46.2780972Z ##[endgroup]
2022-11-01T15:30:46.3048093Z ##[group]/datum/unit_test/simple_animal_freeze
-2022-11-01T15:30:46.3059709Z
+2022-11-01T15:30:46.3059709Z
2022-11-01T15:30:46.3060267Z [1;32mPASS[0m /datum/unit_test/simple_animal_freeze 0s
2022-11-01T15:30:46.3060938Z ##[endgroup]
2022-11-01T15:30:46.3241320Z ##[group]/datum/unit_test/siunit
-2022-11-01T15:30:46.3241508Z
+2022-11-01T15:30:46.3241508Z
2022-11-01T15:30:46.3241961Z [1;32mPASS[0m /datum/unit_test/siunit 0s
2022-11-01T15:30:46.3242362Z ##[endgroup]
2022-11-01T15:30:46.3753674Z ##[group]/datum/unit_test/slips
-2022-11-01T15:30:46.4300467Z
+2022-11-01T15:30:46.4300467Z
2022-11-01T15:30:46.4301480Z [1;32mPASS[0m /datum/unit_test/slips 0.1s
2022-11-01T15:30:46.4302301Z ##[endgroup]
2022-11-01T15:30:46.5100922Z ##[group]/datum/unit_test/spawn_humans
-2022-11-01T15:30:51.5880046Z
+2022-11-01T15:30:51.5880046Z
2022-11-01T15:30:51.5881071Z [1;32mPASS[0m /datum/unit_test/spawn_humans 5s
2022-11-01T15:30:51.5881789Z ##[endgroup]
2022-11-01T15:30:51.6350612Z ##[group]/datum/unit_test/spawn_mobs
-2022-11-01T15:30:51.7210346Z
+2022-11-01T15:30:51.7210346Z
2022-11-01T15:30:51.7211375Z [1;32mPASS[0m /datum/unit_test/spawn_mobs 0.1s
2022-11-01T15:30:51.7212072Z ##[endgroup]
2022-11-01T15:30:51.8820435Z ##[group]/datum/unit_test/species_change_clothing
-2022-11-01T15:30:51.9839314Z
+2022-11-01T15:30:51.9839314Z
2022-11-01T15:30:51.9840163Z [1;32mPASS[0m /datum/unit_test/species_change_clothing 0.1s
2022-11-01T15:30:51.9840797Z ##[endgroup]
2022-11-01T15:30:52.0595249Z ##[group]/datum/unit_test/species_change_organs
-2022-11-01T15:30:52.1312087Z
+2022-11-01T15:30:52.1312087Z
2022-11-01T15:30:52.1313114Z [1;32mPASS[0m /datum/unit_test/species_change_organs 0.1s
2022-11-01T15:30:52.1313735Z ##[endgroup]
2022-11-01T15:30:52.2788548Z ##[group]/datum/unit_test/species_config_sanity
-2022-11-01T15:30:52.2788764Z
+2022-11-01T15:30:52.2788764Z
2022-11-01T15:30:52.2789218Z [1;32mPASS[0m /datum/unit_test/species_config_sanity 0s
2022-11-01T15:30:52.2789672Z ##[endgroup]
2022-11-01T15:30:52.2965591Z ##[group]/datum/unit_test/species_unique_id
-2022-11-01T15:30:52.2965794Z
+2022-11-01T15:30:52.2965794Z
2022-11-01T15:30:52.2966648Z [1;32mPASS[0m /datum/unit_test/species_unique_id 0s
2022-11-01T15:30:52.2967087Z ##[endgroup]
2022-11-01T15:30:52.3145296Z ##[group]/datum/unit_test/species_whitelist_check
-2022-11-01T15:30:52.3145500Z
+2022-11-01T15:30:52.3145500Z
2022-11-01T15:30:52.3145979Z [1;32mPASS[0m /datum/unit_test/species_whitelist_check 0s
2022-11-01T15:30:52.3146421Z ##[endgroup]
2022-11-01T15:30:52.3319686Z ##[group]/datum/unit_test/spell_invocations
-2022-11-01T15:30:52.3320202Z
+2022-11-01T15:30:52.3320202Z
2022-11-01T15:30:52.3320653Z [1;32mPASS[0m /datum/unit_test/spell_invocations 0s
2022-11-01T15:30:52.3321098Z ##[endgroup]
2022-11-01T15:30:52.3490883Z ##[group]/datum/unit_test/mind_swap_spell
-2022-11-01T15:30:52.4036851Z
+2022-11-01T15:30:52.4036851Z
2022-11-01T15:30:52.4037676Z [1;32mPASS[0m /datum/unit_test/mind_swap_spell 0.1s
2022-11-01T15:30:52.4038275Z ##[endgroup]
2022-11-01T15:30:52.4828774Z ##[group]/datum/unit_test/spell_names
-2022-11-01T15:30:52.4828988Z
+2022-11-01T15:30:52.4828988Z
2022-11-01T15:30:52.4829550Z [1;32mPASS[0m /datum/unit_test/spell_names 0s
2022-11-01T15:30:52.4829982Z ##[endgroup]
2022-11-01T15:30:52.5000265Z ##[group]/datum/unit_test/shapeshift_spell_validity
-2022-11-01T15:30:52.5004478Z
+2022-11-01T15:30:52.5004478Z
2022-11-01T15:30:52.5005145Z [1;32mPASS[0m /datum/unit_test/shapeshift_spell_validity 0.1s
2022-11-01T15:30:52.5005621Z ##[endgroup]
2022-11-01T15:30:52.5165907Z ##[group]/datum/unit_test/shapeshift_spell
-2022-11-01T15:30:52.8039754Z
+2022-11-01T15:30:52.8039754Z
2022-11-01T15:30:52.8040573Z [1;32mPASS[0m /datum/unit_test/shapeshift_spell 0.3s
2022-11-01T15:30:52.8041200Z ##[endgroup]
2022-11-01T15:30:53.0783548Z ##[group]/datum/unit_test/shapeshift_holoparasites
-2022-11-01T15:30:53.1126288Z
+2022-11-01T15:30:53.1126288Z
2022-11-01T15:30:53.1127333Z [1;32mPASS[0m /datum/unit_test/shapeshift_holoparasites 0.1s
2022-11-01T15:30:53.1128391Z ##[endgroup]
2022-11-01T15:30:53.1559214Z ##[group]/datum/unit_test/spritesheets
-2022-11-01T15:30:53.1593744Z
+2022-11-01T15:30:53.1593744Z
2022-11-01T15:30:53.1596242Z [1;32mPASS[0m /datum/unit_test/spritesheets 0s
2022-11-01T15:30:53.1599434Z ##[endgroup]
2022-11-01T15:30:53.1775369Z ##[group]/datum/unit_test/stack_singular_name
-2022-11-01T15:30:53.1777955Z
+2022-11-01T15:30:53.1777955Z
2022-11-01T15:30:53.1780282Z [1;32mPASS[0m /datum/unit_test/stack_singular_name 0s
2022-11-01T15:30:53.1781032Z ##[endgroup]
2022-11-01T15:30:53.1978111Z ##[group]/datum/unit_test/stomach
-2022-11-01T15:30:53.2306019Z
+2022-11-01T15:30:53.2306019Z
2022-11-01T15:30:53.2308397Z [1;32mPASS[0m /datum/unit_test/stomach 0.1s
2022-11-01T15:30:53.2311132Z ##[endgroup]
2022-11-01T15:30:53.2563959Z ##[group]/datum/unit_test/strip_menu_ui_status
-2022-11-01T15:30:53.3090477Z
+2022-11-01T15:30:53.3090477Z
2022-11-01T15:30:53.3091739Z [1;32mPASS[0m /datum/unit_test/strip_menu_ui_status 0.1s
2022-11-01T15:30:53.3094850Z ##[endgroup]
2022-11-01T15:30:53.3492514Z ##[group]/datum/unit_test/subsystem_init
-2022-11-01T15:30:53.3493184Z
+2022-11-01T15:30:53.3493184Z
2022-11-01T15:30:53.3495636Z [1;32mPASS[0m /datum/unit_test/subsystem_init 0s
2022-11-01T15:30:53.3498157Z ##[endgroup]
2022-11-01T15:30:53.3664175Z ##[group]/datum/unit_test/suit_storage_icons
@@ -2078,83 +2078,83 @@
2022-11-01T15:30:55.7752422Z 258 - /obj/item/storage/lockbox/medal using invalid icon_state, "medalbox+l"
2022-11-01T15:30:55.7752898Z 259 - /obj/item/crowbar/red/caravan using invalid icon_state, "crowbar_caravan"
2022-11-01T15:30:55.7757058Z 260 - /obj/item/crowbar/drone using invalid icon_state, "crowbar_cyborg"
-2022-11-01T15:30:55.7784906Z
+2022-11-01T15:30:55.7784906Z
2022-11-01T15:30:55.7785304Z [1;32mPASS[0m /datum/unit_test/suit_storage_icons 2.4s
2022-11-01T15:30:55.7786128Z ##[endgroup]
2022-11-01T15:30:58.1989647Z ##[group]/datum/unit_test/amputation
-2022-11-01T15:30:58.2542620Z
+2022-11-01T15:30:58.2542620Z
2022-11-01T15:30:58.2543982Z [1;32mPASS[0m /datum/unit_test/amputation 0.1s
2022-11-01T15:30:58.2545007Z ##[endgroup]
2022-11-01T15:30:58.2861052Z ##[group]/datum/unit_test/brain_surgery
-2022-11-01T15:30:58.3393398Z
+2022-11-01T15:30:58.3393398Z
2022-11-01T15:30:58.3395072Z [1;32mPASS[0m /datum/unit_test/brain_surgery 0.1s
2022-11-01T15:30:58.3396351Z ##[endgroup]
2022-11-01T15:30:58.3713295Z ##[group]/datum/unit_test/head_transplant
-2022-11-01T15:30:58.4648885Z
+2022-11-01T15:30:58.4648885Z
2022-11-01T15:30:58.4650964Z [1;32mPASS[0m /datum/unit_test/head_transplant 0.1s
2022-11-01T15:30:58.4652113Z ##[endgroup]
2022-11-01T15:30:58.5529908Z ##[group]/datum/unit_test/multiple_surgeries
-2022-11-01T15:30:58.6322272Z
+2022-11-01T15:30:58.6322272Z
2022-11-01T15:30:58.6323733Z [1;32mPASS[0m /datum/unit_test/multiple_surgeries 0.1s
2022-11-01T15:30:58.6324863Z ##[endgroup]
2022-11-01T15:30:58.7192842Z ##[group]/datum/unit_test/start_tend_wounds
-2022-11-01T15:30:58.7696686Z
+2022-11-01T15:30:58.7696686Z
2022-11-01T15:30:58.7697933Z [1;32mPASS[0m /datum/unit_test/start_tend_wounds 0s
2022-11-01T15:30:58.7699007Z ##[endgroup]
2022-11-01T15:30:58.8006481Z ##[group]/datum/unit_test/tend_wounds
-2022-11-01T15:30:58.9098267Z
+2022-11-01T15:30:58.9098267Z
2022-11-01T15:30:58.9099817Z [1;32mPASS[0m /datum/unit_test/tend_wounds 0.1s
2022-11-01T15:30:58.9100900Z ##[endgroup]
2022-11-01T15:30:59.0574781Z ##[group]/datum/unit_test/auto_teleporter_linking
-2022-11-01T15:30:59.0986969Z
+2022-11-01T15:30:59.0986969Z
2022-11-01T15:30:59.0988029Z [1;32mPASS[0m /datum/unit_test/auto_teleporter_linking 0s
2022-11-01T15:30:59.0989210Z ##[endgroup]
2022-11-01T15:30:59.1397849Z ##[group]/datum/unit_test/tgui_create_message
-2022-11-01T15:30:59.1398053Z
+2022-11-01T15:30:59.1398053Z
2022-11-01T15:30:59.1398515Z [1;32mPASS[0m /datum/unit_test/tgui_create_message 0s
2022-11-01T15:30:59.1398931Z ##[endgroup]
2022-11-01T15:30:59.1585159Z ##[group]/datum/unit_test/timer_sanity
-2022-11-01T15:30:59.1585371Z
+2022-11-01T15:30:59.1585371Z
2022-11-01T15:30:59.1585837Z [1;32mPASS[0m /datum/unit_test/timer_sanity 0s
2022-11-01T15:30:59.1586293Z ##[endgroup]
2022-11-01T15:30:59.1763570Z ##[group]/datum/unit_test/traitor
-2022-11-01T15:31:01.0798012Z
+2022-11-01T15:31:01.0798012Z
2022-11-01T15:31:01.0799101Z [1;32mPASS[0m /datum/unit_test/traitor 1.9s
2022-11-01T15:31:01.0799858Z ##[endgroup]
2022-11-01T15:31:05.2187120Z ##[group]/datum/unit_test/verify_config_tags
-2022-11-01T15:31:05.2190123Z
+2022-11-01T15:31:05.2190123Z
2022-11-01T15:31:05.2191991Z [1;32mPASS[0m /datum/unit_test/verify_config_tags 0s
2022-11-01T15:31:05.2193777Z ##[endgroup]
2022-11-01T15:31:05.2366479Z ##[group]/datum/unit_test/wizard_loadout
-2022-11-01T15:31:05.3463154Z
+2022-11-01T15:31:05.3463154Z
2022-11-01T15:31:05.3463988Z [1;32mPASS[0m /datum/unit_test/wizard_loadout 0.1s
2022-11-01T15:31:05.3465519Z ##[endgroup]
2022-11-01T15:31:05.4918147Z ##[group]/datum/unit_test/find_reference_sanity
-2022-11-01T15:31:05.4922156Z
+2022-11-01T15:31:05.4922156Z
2022-11-01T15:31:05.4923183Z [1;32mPASS[0m /datum/unit_test/find_reference_sanity 0s
2022-11-01T15:31:05.4924120Z ##[endgroup]
2022-11-01T15:31:05.5122652Z ##[group]/datum/unit_test/find_reference_baseline
-2022-11-01T15:31:05.5126059Z
+2022-11-01T15:31:05.5126059Z
2022-11-01T15:31:05.5126875Z [1;32mPASS[0m /datum/unit_test/find_reference_baseline 0s
2022-11-01T15:31:05.5127655Z ##[endgroup]
2022-11-01T15:31:05.5361446Z ##[group]/datum/unit_test/find_reference_exotic
-2022-11-01T15:31:05.5367626Z
+2022-11-01T15:31:05.5367626Z
2022-11-01T15:31:05.5369228Z [1;32mPASS[0m /datum/unit_test/find_reference_exotic 0s
2022-11-01T15:31:05.5369940Z ##[endgroup]
2022-11-01T15:31:05.5551795Z ##[group]/datum/unit_test/find_reference_esoteric
-2022-11-01T15:31:05.5558725Z
+2022-11-01T15:31:05.5558725Z
2022-11-01T15:31:05.5559583Z [1;32mPASS[0m /datum/unit_test/find_reference_esoteric 0s
2022-11-01T15:31:05.5560670Z ##[endgroup]
2022-11-01T15:31:05.5737466Z ##[group]/datum/unit_test/find_reference_null_key_entry
-2022-11-01T15:31:05.5741407Z
+2022-11-01T15:31:05.5741407Z
2022-11-01T15:31:05.5742596Z [1;32mPASS[0m /datum/unit_test/find_reference_null_key_entry 0s
2022-11-01T15:31:05.5743489Z ##[endgroup]
2022-11-01T15:31:05.6053804Z ##[group]/datum/unit_test/find_reference_assoc_investigation
-2022-11-01T15:31:05.6057935Z
+2022-11-01T15:31:05.6057935Z
2022-11-01T15:31:05.6058863Z [1;32mPASS[0m /datum/unit_test/find_reference_assoc_investigation 0s
2022-11-01T15:31:05.6060051Z ##[endgroup]
2022-11-01T15:31:05.6233030Z ##[group]/datum/unit_test/find_reference_static_investigation
-2022-11-01T15:31:05.8520469Z
+2022-11-01T15:31:05.8520469Z
2022-11-01T15:31:05.8521954Z [1;32mPASS[0m /datum/unit_test/find_reference_static_investigation 0.2s
2022-11-01T15:31:05.8523118Z ##[endgroup]
2022-11-01T15:31:06.0724951Z ##[group]/datum/unit_test/monkey_business
@@ -2166,8 +2166,8 @@
2022-11-01T15:31:23.2325062Z /datum/forensics (/datum/forensics): New(the blood splatter (/obj/effect/decal/cleanable/blood/hitsplatter), null, null, /list (/list), null)
2022-11-01T15:31:23.2325582Z the blood splatter (/obj/effect/decal/cleanable/blood/hitsplatter): add blood DNA(/list (/list))
2022-11-01T15:31:23.2326006Z Anthony Hayhurst (461) (/mob/living/carbon/human): spray blood(2, 1)
-2022-11-01T15:31:23.2326395Z Rough Abrasion (/datum/wound/slash/moderate): wound injury(null, 2)
-2022-11-01T15:31:23.2327172Z Rough Abrasion (/datum/wound/slash/moderate): apply wound(the monkey left leg (/obj/item/bodypart/l_leg/monkey), 0, null, 0, 2)
+2022-11-01T15:31:23.2326395Z Rough Abrasion (/datum/wound/slash/flesh/moderate): wound injury(null, 2)
+2022-11-01T15:31:23.2327172Z Rough Abrasion (/datum/wound/slash/flesh/moderate): apply wound(the monkey left leg (/obj/item/bodypart/l_leg/monkey), 0, null, 0, 2)
2022-11-01T15:31:23.2327747Z the monkey left leg (/obj/item/bodypart/l_leg/monkey): check wounding(2, 8, 5, 15, 2)
2022-11-01T15:31:23.2328155Z the monkey left leg (/obj/item/bodypart/l_leg/monkey): receive damage(8, 0, 0, 0, 1, null, 5, 15, 1, 2)
2022-11-01T15:31:23.2328594Z Monkey (/datum/species/monkey): apply damage(8, "brute", "l_leg", 0, Anthony Hayhurst (461) (/mob/living/carbon/human), 0, 0, 5, 15, 1, 2)
@@ -2191,8 +2191,8 @@
/datum/forensics (/datum/forensics): New(the blood splatter (/obj/effect/decal/cleanable/blood/hitsplatter), null, null, /list (/list), null)
the blood splatter (/obj/effect/decal/cleanable/blood/hitsplatter): add blood DNA(/list (/list))
Anthony Hayhurst (461) (/mob/living/carbon/human): spray blood(2, 1)
- Rough Abrasion (/datum/wound/slash/moderate): wound injury(null, 2)
- Rough Abrasion (/datum/wound/slash/moderate): apply wound(the monkey left leg (/obj/item/bodypart/l_leg/monkey), 0, null, 0, 2)
+ Rough Abrasion (/datum/wound/slash/flesh/moderate): wound injury(null, 2)
+ Rough Abrasion (/datum/wound/slash/flesh/moderate): apply wound(the monkey left leg (/obj/item/bodypart/l_leg/monkey), 0, null, 0, 2)
the monkey left leg (/obj/item/bodypart/l_leg/monkey): check wounding(2, 8, 5, 15, 2)
the monkey left leg (/obj/item/bodypart/l_leg/monkey): receive damage(8, 0, 0, 0, 1, null, 5, 15, 1, 2)
Monkey (/datum/species/monkey): apply damage(8, "brute", "l_leg", 0, Anthony Hayhurst (461) (/mob/living/carbon/human), 0, 0, 5, 15, 1, 2)
@@ -2217,8 +2217,8 @@
2022-11-01T15:31:44.6333171Z /datum/forensics (/datum/forensics): New(the blood splatter (/obj/effect/decal/cleanable/blood/hitsplatter), null, null, /list (/list), null)
2022-11-01T15:31:44.6333653Z the blood splatter (/obj/effect/decal/cleanable/blood/hitsplatter): add blood DNA(/list (/list))
2022-11-01T15:31:44.6334238Z Anthony Hayhurst (461) (/mob/living/carbon/human): spray blood(2, 1)
-2022-11-01T15:31:44.6334605Z Rough Abrasion (/datum/wound/slash/moderate): wound injury(null, 2)
-2022-11-01T15:31:44.6335055Z Rough Abrasion (/datum/wound/slash/moderate): apply wound(the monkey left leg (/obj/item/bodypart/l_leg/monkey), 0, null, 0, 2)
+2022-11-01T15:31:44.6334605Z Rough Abrasion (/datum/wound/slash/flesh/moderate): wound injury(null, 2)
+2022-11-01T15:31:44.6335055Z Rough Abrasion (/datum/wound/slash/flesh/moderate): apply wound(the monkey left leg (/obj/item/bodypart/l_leg/monkey), 0, null, 0, 2)
2022-11-01T15:31:44.6335679Z the monkey left leg (/obj/item/bodypart/l_leg/monkey): check wounding(2, 8, 5, 15, 2)
2022-11-01T15:31:44.6336429Z the monkey left leg (/obj/item/bodypart/l_leg/monkey): receive damage(8, 0, 0, 0, 1, null, 5, 15, 1, 2)
2022-11-01T15:31:44.6336913Z Monkey (/datum/species/monkey): apply damage(8, "brute", "l_leg", 0, Anthony Hayhurst (461) (/mob/living/carbon/human), 0, 0, 5, 15, 1, 2)
@@ -2236,7 +2236,7 @@
2022-11-01T15:31:44.6343234Z Master (/datum/controller/master): StartProcessing(0) at _forensics.dm:232
2022-11-01T15:31:44.6345243Z ##[error][1;31mFAIL[0m /datum/unit_test/monkey_business 38.6s
2022-11-01T15:31:46.9833542Z ##[group]/datum/unit_test/create_and_destroy
-2022-11-01T15:37:15.1785471Z
+2022-11-01T15:37:15.1785471Z
2022-11-01T15:37:15.1787041Z [1;32mPASS[0m /datum/unit_test/create_and_destroy 328.2s
2022-11-01T15:37:15.1788074Z ##[endgroup]
2022-11-01T15:37:15.2115771Z Shutting down Chat subsystem...
@@ -2377,12 +2377,12 @@
2022-11-01T15:37:31.3325316Z Total size of all the files uploaded is 138917 bytes
2022-11-01T15:37:31.3326061Z File upload process has finished. Finalizing the artifact upload
2022-11-01T15:37:31.4289346Z Artifact has been finalized. All files have been successfully uploaded!
-2022-11-01T15:37:31.4291368Z
+2022-11-01T15:37:31.4291368Z
2022-11-01T15:37:31.4293992Z The raw size of all the files that were specified for upload is 139272 bytes
2022-11-01T15:37:31.4298141Z The size of all the files that were uploaded is 138917 bytes. This takes into account any gzip compression used to reduce the upload size, time and storage
-2022-11-01T15:37:31.4301961Z
-2022-11-01T15:37:31.4303707Z Note: The size of downloaded zips can differ significantly from the reported size. For more information see: https://github.com/actions/upload-artifact#zipped-artifact-downloads
-2022-11-01T15:37:31.4304326Z
+2022-11-01T15:37:31.4301961Z
+2022-11-01T15:37:31.4303707Z Note: The size of downloaded zips can differ significantly from the reported size. For more information see: https://github.com/actions/upload-artifact#zipped-artifact-downloads
+2022-11-01T15:37:31.4304326Z
2022-11-01T15:37:31.4305332Z Artifact test_artifacts_tramstation has been successfully uploaded!
2022-11-01T15:37:31.4451625Z Post job cleanup.
2022-11-01T15:37:31.5950708Z [command]/usr/bin/git version
@@ -2436,12 +2436,12 @@
2022-11-01T15:37:31.7590084Z 2022-11-01 15:22:42+00:00 [Note] [Entrypoint]: Starting temporary server
2022-11-01T15:37:31.7590409Z 2022-11-01 15:22:43+00:00 [Note] [Entrypoint]: Temporary server started.
2022-11-01T15:37:31.7590742Z '/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
-2022-11-01T15:37:31.7590984Z
+2022-11-01T15:37:31.7590984Z
2022-11-01T15:37:31.7591244Z 2022-11-01 15:22:46+00:00 [Note] [Entrypoint]: Stopping temporary server
2022-11-01T15:37:31.7591577Z 2022-11-01 15:22:47+00:00 [Note] [Entrypoint]: Temporary server stopped
-2022-11-01T15:37:31.7592516Z
+2022-11-01T15:37:31.7592516Z
2022-11-01T15:37:31.7592791Z 2022-11-01 15:22:47+00:00 [Note] [Entrypoint]: MySQL init process done. Ready for start up.
-2022-11-01T15:37:31.7593063Z
+2022-11-01T15:37:31.7593063Z
2022-11-01T15:37:31.7608136Z Stop and remove container: e281b5d836644f53b33d06a88663b086_mysqllatest_c6a68e
2022-11-01T15:37:31.7616365Z ##[command]/usr/bin/docker rm --force cd1d0f20f8f882176c274fb882d88cea0d4e9a7b2aebc33f1123c02f7b908aa1
2022-11-01T15:37:32.0241098Z cd1d0f20f8f882176c274fb882d88cea0d4e9a7b2aebc33f1123c02f7b908aa1