Conditioning Skill And Mass (#22747)

This PR does a few new things:

1. Adds a Mass var for Movables (/Mob, /Obj) which is literally required
for me to do anything at all with Kinematics (Very routine basic
physics)
2. Adds a derived "effective mass" statistic which is generated via
signal hook, allowing sources like Skills, Drugs, Cybernetics etc to
pitch in and contribute to a user's "Strength" in certain situations
without directly modifying mass.
3. Adds a mass modifier var for species datums, while painstakingly
calibrating each and every single species with consultation from every
lore team. A baseline human gets 72.0kg of Human Reference Mass. Any
species applied to it will multiply this by a constant that
algebraically cancels out the Human Reference Mass and replaces it with
a Species Reference Mass. Changing a species via the usual procs will
reset and then re-apply the correct values.
4. Refactored Lift/Drag/Fireman to have limits and penalties based on
relative effective mass
5. Finally, to make use of all this, I've added a new Conditioning
Skill, which modifies effective mass.

The standard assumption made for Lift/Carry is based in an assumption
that a typical character should realistically be able to
lift/carry/fireman a person 1.25x their mass. Previously the fireman
carry mechanic was heavily hardcoded, and didn't have much in the way of
granularity. If I wanted to RP a character that was a bodybuilder, there
wasn't really a way to do this. With this PR, there's now a fairly large
variety of interesting breakpoints.

This also allows there to be more granularity between different species
as desired by our lore teams. For example, a Zhan is in general stronger
than a M'sai. To give an example in the breakpoints for two different
species:

Human Lift Breakpoints:
Rank 1: 90kg (lift a Skrell, Human, Offworlder, M'sai, KA, or ZA)
Rank 2: 112.5kg (Lift a Zhan, Shell, or Diona Coeus)
Rank 3: 135kg (Lift a (Non-Industrial) IPC, Unathi)
Rank 4: 157.5kg (No new breakpoints, though you get less a movespeed
penalty from lugging around any of the above)
Can Never Lift: Industrial, Bullwark, Diona, Vaurca Ta'

Zhan Tajara Lift Breakpoints:
Rank 1: 116kg (Skrell, Human, Offworlder, M'sai, Ka, Za, Zhan, Shell, or
Diona Coeus)
Rank 2: 145kg (Non-Industrial IPC, Unathi)
Rank 3: 174kg (No new breakpoints, though you get less penalties from
the above)
Rank 4: 203kg (Juuuust barely lift an Industrial or Diona with heavy
slowdown)

<img width="1078" height="436" alt="image"
src="https://github.com/user-attachments/assets/a6802515-a827-4dc1-8734-55b604c589ab"
/>

Conditioning as a Skill sits in the Occupational category, which has
been carefully chosen and designed around to create a fairly compelling
web of opportunity costs. As a skill, it's very desireable for basically
any person that wants to play a "Muscular character" and also enjoys
fireman carrying people around, which makes it particularly useful for
hangar techs. By contrast a Paramedic might not actually need this
skill, since they can bypass the usual limits by just using rollerbeds.

---------

Signed-off-by: VMSolidus <evilexecutive@gmail.com>
This commit is contained in:
VMSolidus
2026-07-12 18:06:51 +00:00
committed by GitHub
parent f66d3f8849
commit 48d8a06d1c
31 changed files with 256 additions and 34 deletions
@@ -1,6 +1,3 @@
/datum/species
var/list/default_emotes = list()
/mob/living/carbon/update_emotes()
. = ..(skip_sort=1)
if(species)
+3 -2
View File
@@ -422,8 +422,9 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list(
item = G.throw_held() //throw the person instead of the grab
if(ismob(item) && G.state >= GRAB_NECK)
var/mob/M = item
if(M.mob_weight > get_mob_strength())
to_chat(src, SPAN_WARNING("[M] is far too heavy for you to throw around!"))
var/grabber_strength = get_effective_mass() * mob_strength
if(M.mass > grabber_strength)
to_chat(src, SPAN_WARNING("[M] is heavier (or more unwieldy) than your limit of [grabber_strength]kg, you cannot throw them!"))
return
throw_range = round(throw_range * (src.mob_size/M.mob_size))
-10
View File
@@ -27,16 +27,6 @@
autohiss_mode = AUTOHISS_OFF
to_chat(src, "Auto-hiss is now OFF.")
/datum/species
var/has_autohiss = FALSE
var/list/autohiss_basic_map = null
var/list/autohiss_extra_map = null
var/list/autohiss_exempt = null
var/list/autohiss_basic_extend = null
var/list/autohiss_extra_extend = null
var/autohiss_extender = "..."
var/ignore_subsequent = FALSE
/datum/species/unathi
autohiss_basic_map = list(
"s" = list("ss", "sss", "ssss")
@@ -65,3 +65,5 @@
/// Hallucinations currently affecting the mob. Not to be confused with singular "hallucination" which is a NUM variable like confused/drowsy/eye_blind etc
var/list/hallucinations = list()
var/shock_stage = 0
mass = REFERENCE_MASS_HUMAN
@@ -1508,7 +1508,7 @@
else
to_chat(usr, SPAN_WARNING("You failed to check the pulse. Try again."))
/mob/living/carbon/human/proc/set_species(var/new_species, var/default_colour, var/kpg=0, var/change_hair = TRUE)
/mob/living/carbon/human/proc/set_species(new_species, default_colour, kpg = 0, change_hair = TRUE)
cached_bodytype = null
if(!dna)
if(!new_species)
@@ -1635,6 +1635,7 @@
client.init_verbs()
update_emotes()
mass = initial(mass) * species.mass_modifier
if(species)
return TRUE
@@ -172,6 +172,11 @@
/// Pref holder for the speech bubble style.
var/speech_bubble_type
// Some player characters are of type human and some are of type ../carbon
// Confusingly human includes most (but not all) aliens.
// For redundancy I'm stating this here as well as in /carbon
mass = REFERENCE_MASS_HUMAN
var/med_record = ""
var/sec_record = ""
var/list/incidents = list()
@@ -51,14 +51,13 @@
if((mutations & mRun))
tally = 0
if(isitem(pulling) && !(species.flags & NO_EQUIP_SPEEDMODS))
var/obj/item/P = pulling
tally += P.slowdown
var/effective_mass = get_effective_mass()
if(pulling && pulling.mass > mass)
tally += pulling.mass / effective_mass
var/obj/item/grab/grab = get_type_in_hands(/obj/item/grab)
if(istype(grab) && ishuman(grab.affecting))
if(grab.affecting.mob_weight > get_mob_strength())
tally += grab.affecting.mob_weight - get_mob_strength()
if(istype(grab) && ismovable(grab.affecting) && grab.affecting.mass > mass)
tally += grab.affecting.mass / effective_mass
var/turf/T = get_turf(src)
if(T) // changelings don't get movement costs
@@ -79,7 +78,6 @@
if(!isnull(facing_dir) && facing_dir != dir)
tally += 3
tally = round(tally, 0.1)
return tally
@@ -472,10 +472,33 @@
/// A list of species components that should only EVER apply to this species. This is because some components must be removed if the species changes (imagine changing from IPC to human as a merc).
var/list/species_components
var/list/default_emotes = list()
// Vars used for Autohiss
var/has_autohiss = FALSE
var/list/autohiss_basic_map = null
var/list/autohiss_extra_map = null
var/list/autohiss_exempt = null
var/list/autohiss_basic_extend = null
var/list/autohiss_extra_extend = null
var/autohiss_extender = "..."
var/ignore_subsequent = FALSE
/**
* The "Mass Modifier" used to set the starting mass of a player character for a given species.
* This should always be written as REFERENCE_MASS_SPECIES / REFERENCE_MASS_HUMAN
* This division by REFERENCE_MASS_HUMAN will be algebraically cancelled out,
* when multiplied by the humanoid character's standard mass (which happens to be REFERENCE_MASS_HUMAN)
*
* This is a pure number ratio (kg / kg), it has no SI Units.
*/
var/mass_modifier = REFERENCE_MASS_HUMAN / REFERENCE_MASS_HUMAN
/datum/species/proc/get_eyes(var/mob/living/carbon/human/H)
return
/datum/species/New()
ENFORCE_POSITIVE_SPECIES_MASS(mass_modifier)
if(hud_type)
hud = new hud_type()
else
@@ -148,6 +148,8 @@ They are very slow, reasonably strong, and quite durable. They also require ligh
tail_animation = 'icons/mob/species/diona/tail.dmi'
selectable_tails = list("No Tail", "Unathi Tail")
mass_modifier = REFERENCE_MASS_DIONA / REFERENCE_MASS_HUMAN
/datum/species/diona/can_understand(var/mob/other)
var/mob/living/carbon/alien/diona/D = other
if(istype(D))
@@ -25,3 +25,4 @@ In return, they are generally substantially more fragile, being especially susce
pain_mod = 2
brute_mod = 1.1
burn_mod = 1.3
mass_modifier = REFERENCE_MASS_DIONA_COEUS / REFERENCE_MASS_HUMAN
@@ -24,6 +24,7 @@
hazard_low_pressure = 10
examine_color = "#C2AE95"
mass_modifier = REFERENCE_MASS_HUMAN_OFFWORLDER / REFERENCE_MASS_HUMAN
/datum/species/human/offworlder/equip_later_gear(var/mob/living/carbon/human/H)
if(istype(H.get_equipped_item(slot_back), /obj/item/storage/backpack) && H.equip_to_slot_or_del(new /obj/item/storage/pill_bottle/rmt(H.back), slot_in_backpack))
@@ -164,6 +164,7 @@
)
species_components = list(/datum/component/synthetic_endoskeleton)
mass_modifier = REFERENCE_MASS_IPC / REFERENCE_MASS_HUMAN
// Special snowflake machine vars.
var/sprint_temperature_factor = 1.05
@@ -77,6 +77,7 @@
bodyfall_sound = SFX_BODYFALL
use_alt_hair_layer = FALSE
mass_modifier = REFERENCE_MASS_IPC_SHELL / REFERENCE_MASS_HUMAN
/datum/species/machine/shell/get_species(var/reference, var/mob/living/carbon/human/H, var/records)
if(reference)
@@ -122,6 +123,8 @@
/datum/unarmed_attack/terminator,
/datum/unarmed_attack/bite/strong)
mass_modifier = REFERENCE_MASS_IPC_SHELL / REFERENCE_MASS_HUMAN
/datum/species/machine/shell/rogue/check_tag(var/mob/living/carbon/human/new_machine, var/client/player)
return
@@ -205,6 +208,7 @@
)
machine_ui_theme = "hephaestus"
mass_modifier = REFERENCE_MASS_IPC_INDUSTRIAL / REFERENCE_MASS_HUMAN
/datum/species/machine/industrial/get_light_color()
return LIGHT_COLOR_TUNGSTEN
@@ -406,6 +410,8 @@
melee = ARMOR_MELEE_KEVLAR
)
mass_modifier = REFERENCE_MASS_IPC_INDUSTRIAL / REFERENCE_MASS_HUMAN
/mob/living/carbon/human/proc/discard_limb()
set name = "Discard Limb"
set category = "Object"
@@ -111,6 +111,7 @@
has_psionics = PSI_RANK_SENSITIVE
character_creation_psi_points = 2
mass_modifier = REFERENCE_MASS_SKRELL / REFERENCE_MASS_HUMAN
/datum/species/skrell/handle_trail(var/mob/living/carbon/human/H, var/turf/T)
var/list/trail_info = ..()
@@ -23,3 +23,5 @@
fast_pulse = 80 // Species default 70
v_fast_pulse = 100 // Species default 90
max_pulse = 140 // Species default 130
mass_modifier = REFERENCE_MASS_SKRELL_AXIORI / REFERENCE_MASS_HUMAN
@@ -130,6 +130,8 @@
meat_type = /obj/item/reagent_containers/food/snacks/meat/adhomai
valid_prosthetics = list(PROSTHETIC_TESLA)
mass_modifier = REFERENCE_MASS_TAJARA / REFERENCE_MASS_HUMAN
/datum/species/tajaran/after_equip(var/mob/living/carbon/human/H)
. = ..()
if(H.shoes)
@@ -50,6 +50,8 @@
/singleton/origin_item/culture/offworld_tajara/zhan
)
mass_modifier = REFERENCE_MASS_TAJARA_ZHAN / REFERENCE_MASS_HUMAN
/datum/species/tajaran/m_sai
name = SPECIES_TAJARA_MSAI
name_plural = "M'sai Tajara"
@@ -100,6 +102,8 @@
/singleton/origin_item/culture/offworld_tajara/msai
)
mass_modifier = REFERENCE_MASS_TAJARA_MSAI / REFERENCE_MASS_HUMAN
/datum/species/tajaran/tesla_body
name = SPECIES_TAJARA_TESLA_BODY
name_plural = "Tesla Rejuvenation Suit Tajara"
@@ -199,6 +203,7 @@
push_flags = (~HEAVY) ^ ROBOT
possible_external_organs_modifications = list("Normal", "Amputated") //We don't have any alternate limbs for Tesla suits
valid_prosthetics = null
mass_modifier = REFERENCE_MASS_TAJARA_TESLA / REFERENCE_MASS_HUMAN
/datum/species/tajaran/tesla_body/New()
..()
@@ -137,6 +137,7 @@
possible_external_organs_modifications = list("Normal","Amputated","Prosthesis", "Diona Nymph")
valid_prosthetics = list(PROSTHETIC_AUTAKH)
mass_modifier = REFERENCE_MASS_UNATHI / REFERENCE_MASS_HUMAN
/datum/species/unathi/after_equip(var/mob/living/carbon/human/H)
. = ..()
@@ -171,6 +171,8 @@
"C'thur: Unbound Mouv" = "#96B4FF", "C'thur: Bound Mouv" = "#5A96FF",
"C'thur: Unbound Xetl" = "#370078", "C'thur: Bound Xetl" = "#3C0F5F"
)
mob_strength = 1.35 // Requested by Vaurca lore to make them a bit more different
mass_modifier = REFERENCE_MASS_VAURCA_KA / REFERENCE_MASS_HUMAN
/datum/species/bug/before_equip(var/mob/living/carbon/human/H)
. = ..()
@@ -66,6 +66,8 @@
"C'thur: Unbound Xetl" = "#370078"
)
mass_modifier = REFERENCE_MASS_VAURCA_ZA / REFERENCE_MASS_HUMAN
/datum/species/bug/type_b/type_bb
name = SPECIES_VAURCA_ATTENDANT
name_plural = "Type BB"
@@ -220,6 +222,8 @@
"C'thur: Mouv" = "#7D75FF"
)
mass_modifier = REFERENCE_MASS_VAURCA_TA / REFERENCE_MASS_HUMAN
/datum/species/bug/type_c/New()
..()
equip_adjust = list(
@@ -308,6 +312,7 @@
default_h_style = "Bald"
possible_external_organs_modifications = list("Normal", "Amputated") //We don't have any limb modfications for this species
valid_prosthetics = null
mass_modifier = REFERENCE_MASS_VAURCA_BA / REFERENCE_MASS_HUMAN
/datum/species/bug/type_big/handle_post_spawn(var/mob/living/carbon/human/H)
H.mutations |= HULK
@@ -407,6 +412,8 @@ Bulwarks are much larger and have significantly thicker carapaces than most Vaur
"C'thur: Unbound Xetl" = "#3F0876", "C'thur: Bound Xetl" = "#330563"
)
mass_modifier = REFERENCE_MASS_VAURCA_RA / REFERENCE_MASS_HUMAN
/datum/species/bug/type_e/New()
..()
equip_adjust = list(
+3 -2
View File
@@ -443,8 +443,9 @@
to_chat(H, SPAN_WARNING("You can only fireman carry humanoids!"))
return
var/mob/living/carbon/human/affected_human = affecting
if(affected_human.mob_weight > H.get_mob_strength())
to_chat(H, SPAN_WARNING("\The [affected_human] is way too big to fireman carry!"))
var/grabber_strength = H.get_effective_mass() * H.mob_strength
if(affected_human.mass > grabber_strength)
to_chat(H, SPAN_WARNING("\The [affected_human] is heavier than your Lift Limit of [grabber_strength]kg, you cannot fireman carry then!"))
return
if(state < GRAB_AGGRESSIVE)
to_chat(H, SPAN_WARNING("You need an aggressive grab before you can fireman carry someone!"))
-4
View File
@@ -1393,7 +1393,3 @@ GLOBAL_LIST_INIT(organ_rel_size, list(
message_notifications.Cut(1, 2)
message_notifications[key_check] = world.time + next_message_time
/// Gets a mob's strength.
/mob/proc/get_mob_strength()
return mob_weight + mob_strength