Merge remote-tracking branch 'tgstation/master' into upstream-2025-11-29

# Conflicts:
#	_maps/RandomRuins/SpaceRuins/derelict_sulaco.dmm
#	_maps/RandomRuins/SpaceRuins/garbagetruck2.dmm
#	_maps/map_files/CatwalkStation/CatwalkStation_2023.dmm
#	_maps/map_files/tramstation/tramstation.dmm
#	code/_onclick/hud/new_player.dm
#	code/datums/components/squashable.dm
#	code/datums/diseases/advance/symptoms/heal.dm
#	code/datums/diseases/chronic_illness.dm
#	code/datums/status_effects/buffs.dm
#	code/datums/status_effects/debuffs/drunk.dm
#	code/datums/status_effects/debuffs/stamcrit.dm
#	code/game/machinery/computer/crew.dm
#	code/game/objects/items/devices/scanners/health_analyzer.dm
#	code/game/objects/items/wall_mounted.dm
#	code/game/turfs/closed/indestructible.dm
#	code/modules/admin/view_variables/filterrific.dm
#	code/modules/antagonists/heretic/influences.dm
#	code/modules/cargo/orderconsole.dm
#	code/modules/client/preferences.dm
#	code/modules/events/space_vines/vine_mutations.dm
#	code/modules/mob/dead/new_player/new_player.dm
#	code/modules/mob/living/carbon/human/death.dm
#	code/modules/mob/living/carbon/human/species_types/jellypeople.dm
#	code/modules/mob/living/damage_procs.dm
#	code/modules/mob/living/living.dm
#	code/modules/mob_spawn/ghost_roles/mining_roles.dm
#	code/modules/mob_spawn/mob_spawn.dm
#	code/modules/projectiles/ammunition/energy/laser.dm
#	code/modules/projectiles/guns/ballistic/launchers.dm
#	code/modules/projectiles/guns/energy/laser.dm
#	code/modules/reagents/chemistry/machinery/chem_dispenser.dm
#	code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm
#	code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm
#	code/modules/reagents/chemistry/reagents/medicine_reagents.dm
#	code/modules/surgery/healing.dm
#	code/modules/unit_tests/designs.dm
#	icons/mob/inhands/items_lefthand.dmi
#	icons/mob/inhands/items_righthand.dmi
#	tgui/packages/tgui/interfaces/ChemDispenser.tsx
This commit is contained in:
nevimer
2025-11-29 22:49:21 -05:00
1185 changed files with 39068 additions and 32028 deletions
@@ -47,7 +47,7 @@
unsuitable_heat_damage = 20
ai_controller = /datum/ai_controller/basic_controller/alien
blood_volume = BLOOD_VOLUME_NORMAL
default_blood_volume = BLOOD_VOLUME_NORMAL
///List of loot items to drop when deleted, if this is set then we apply DEL_ON_DEATH
var/list/loot
+1 -1
View File
@@ -166,7 +166,7 @@
/mob/living/basic/Life(seconds_per_tick = SSMOBS_DT, times_fired)
. = ..()
if(staminaloss > 0)
adjustStaminaLoss(-stamina_recovery * seconds_per_tick, forced = TRUE)
adjust_stamina_loss(-stamina_recovery * seconds_per_tick, forced = TRUE)
/mob/living/basic/get_default_say_verb()
return length(speak_emote) ? pick(speak_emote) : ..()
@@ -1,5 +1,6 @@
/// Root of shared behaviour for mobs spawned by blobs, is abstract and should not be spawned
/mob/living/basic/blob_minion
abstract_type = /mob/living/basic/blob_minion
name = "Blob Error"
desc = "A nonfunctional fungal creature created by bad code or celestial mistake. Point and laugh."
icon = 'icons/mob/nonhuman-player/blob.dmi'
@@ -7,7 +8,6 @@
base_icon_state = "blob_head"
unique_name = TRUE
status_flags = CANPUSH
pass_flags = PASSBLOB
faction = list(ROLE_BLOB)
combat_mode = TRUE
bubble_icon = "blob"
@@ -25,6 +25,11 @@
var/death_cloud_size = BLOBMOB_CLOUD_NONE
var/loot = /obj/item/food/spore_sack
/mob/living/basic/blob_minion/New(loc, blob_borne)
. = ..()
if(blob_borne)
pass_flags = PASSBLOB
/mob/living/basic/blob_minion/Initialize(mapload)
. = ..()
add_traits(list(TRAIT_BLOB_ALLY, TRAIT_MUTE), INNATE_TRAIT)
@@ -52,6 +52,7 @@
/mob/living/basic/blob_minion/spore/proc/zombify(mob/living/carbon/human/target)
visible_message(span_warning("The corpse of [target.name] suddenly rises!"))
var/mob/living/basic/blob_minion/zombie/blombie = change_mob_type(zombie_type, loc, new_name = initial(zombie_type.name))
blombie.pass_flags |= PASSBLOB //No way to pass the blob_borne info through change_mob_type() to Initilize(), so we just circumvent it here.
blombie.faction |= faction //inherit the spore's faction in case it was spawned with a different one (eg gold core)
blombie.set_name()
if (istype(blombie)) // In case of badmin
+4 -4
View File
@@ -74,7 +74,7 @@
qdel(victim.get_organ_slot(ORGAN_SLOT_LUNGS))
qdel(victim.get_organ_slot(ORGAN_SLOT_HEART))
qdel(victim.get_organ_slot(ORGAN_SLOT_LIVER))
victim.adjustBruteLoss(500)
victim.adjust_brute_loss(500)
victim.death() //make sure they die
victim.apply_status_effect(/datum/status_effect/gutted)
return TRUE
@@ -87,12 +87,12 @@
/mob/living/basic/boss/ex_act(severity, target)
switch (severity)
if (EXPLODE_DEVASTATE)
adjustBruteLoss(250)
adjust_brute_loss(250)
if (EXPLODE_HEAVY)
adjustBruteLoss(100)
adjust_brute_loss(100)
if (EXPLODE_LIGHT)
adjustBruteLoss(50)
adjust_brute_loss(50)
return TRUE
+2 -1
View File
@@ -9,6 +9,7 @@ GLOBAL_LIST_INIT(command_strings, list(
#define SENTIENT_BOT_RESET_TIMER 45 SECONDS
/mob/living/basic/bot
abstract_type = /mob/living/basic/bot
icon = 'icons/mob/silicon/aibots.dmi'
layer = MOB_LAYER
gender = NEUTER
@@ -770,7 +771,7 @@ GLOBAL_LIST_INIT(command_strings, list(
update_appearance()
/mob/living/basic/bot/rust_heretic_act()
adjustBruteLoss(400)
adjust_brute_loss(400)
/mob/living/basic/bot/proc/attempt_access(mob/bot, obj/door_attempt)
SIGNAL_HANDLER
+1 -1
View File
@@ -251,7 +251,7 @@
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
action_cooldown = BOT_COMMISSIONED_SALUTE_DELAY
/datum/ai_behavior/find_and_set/valid_authority/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/valid_authority/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
for(var/mob/living/nearby_mob in oview(search_range, controller.pawn))
if(!HAS_TRAIT(nearby_mob, TRAIT_COMMISSIONED))
continue
@@ -69,7 +69,7 @@
/datum/ai_behavior/find_and_set/in_list/clean_targets
action_cooldown = 3 SECONDS
/datum/ai_behavior/find_and_set/in_list/clean_targets/search_tactic(datum/ai_controller/basic_controller/bot/controller, locate_paths, search_range)
/datum/ai_behavior/find_and_set/in_list/clean_targets/search_tactic(datum/ai_controller/basic_controller/bot/controller, locate_paths, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/list/found = typecache_filter_list(oview(search_range, controller.pawn), locate_paths)
var/list/ignore_list = controller.blackboard[BB_TEMPORARY_IGNORE_LIST]
for(var/atom/found_item in found)
@@ -101,7 +101,7 @@
action_cooldown = 30 SECONDS
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/datum/ai_behavior/find_and_set/spray_target/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/spray_target/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/list/ignore_list = controller.blackboard[BB_TEMPORARY_IGNORE_LIST]
for(var/mob/living/carbon/human/human_target in oview(search_range, controller.pawn))
if(LAZYACCESS(ignore_list, human_target))
@@ -178,7 +178,7 @@
action_cooldown = 30 SECONDS
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/datum/ai_behavior/find_and_set/friendly_janitor/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/friendly_janitor/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/mob/living/living_pawn = controller.pawn
for(var/mob/living/carbon/human/human_target in oview(search_range, living_pawn))
if(human_target.stat != CONSCIOUS || isnull(human_target.mind))
+3 -3
View File
@@ -25,7 +25,7 @@
habitable_atmos = list("min_oxy" = 5, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
minimum_survivable_temperature = (T0C - 10)
maximum_survivable_temperature = (T0C + 100)
blood_volume = BLOOD_VOLUME_NORMAL
default_blood_volume = BLOOD_VOLUME_NORMAL
faction = list(FACTION_CLOWN)
ai_controller = /datum/ai_controller/basic_controller/clown
///list of stuff we drop on death
@@ -470,10 +470,10 @@
health += 10
if(istype(eaten_atom, /obj/item/food/grown/banana))
var/obj/item/food/grown/banana/banana_morsel = eaten_atom
adjustBruteLoss(-(banana_morsel.seed.potency / 100 ) * maxHealth * 0.2)
adjust_brute_loss(-(banana_morsel.seed.potency / 100 ) * maxHealth * 0.2)
prank_pouch += banana_morsel.generate_trash(src)
else
adjustBruteLoss(-maxHealth * 0.1)
adjust_brute_loss(-maxHealth * 0.1)
qdel(eaten_atom)
playsound(loc,'sound/items/eatfood.ogg', rand(30,50), TRUE)
@@ -27,7 +27,7 @@
lighting_cutoff_blue = 20
ai_controller = /datum/ai_controller/basic_controller/vatbeast
faction = list(FACTION_HOSTILE)
blood_volume = BLOOD_VOLUME_NORMAL
default_blood_volume = BLOOD_VOLUME_NORMAL
/// What can you feed a vatbeast to tame it?
var/static/list/enjoyed_food = list(
/obj/item/food/carrotfries,
@@ -258,7 +258,7 @@
Stun(70)
to_chat(src, span_danger("<b>ER@%R: MME^RY CO#RU9T!</b> R&$b@0tin)..."))
if(severity == 1)
adjustBruteLoss(heavy_emp_damage)
adjust_brute_loss(heavy_emp_damage)
to_chat(src, span_userdanger("HeAV% DA%^MMA+G TO I/O CIR!%UUT!"))
/mob/living/basic/drone/proc/alarm_triggered(datum/source, alarm_type, area/source_area)
@@ -16,7 +16,7 @@
drone.visible_message(span_notice("[drone] begins to cannibalize parts from [src]."), span_notice("You begin to cannibalize parts from [src]..."))
if(do_after(drone, 6 SECONDS, 0, target = src))
drone.visible_message(span_notice("[drone] repairs itself using [src]'s remains!"), span_notice("You repair yourself using [src]'s remains."))
drone.adjustBruteLoss(-src.maxHealth)
drone.adjust_brute_loss(-src.maxHealth)
new /obj/effect/decal/cleanable/blood/splatter/oil(get_turf(src))
ghostize(can_reenter_corpse = FALSE)
qdel(src)
@@ -93,7 +93,7 @@
to_chat(user, span_warning("You need to remain still to tighten [src]'s screws!"))
return ITEM_INTERACT_SUCCESS
adjustBruteLoss(-getBruteLoss())
adjust_brute_loss(-get_brute_loss())
visible_message(span_notice("[user] tightens [src == user ? "[user.p_their()]" : "[src]'s"] loose screws!"), span_notice("[src == user ? "You tighten" : "[user] tightens"] your loose screws."))
return ITEM_INTERACT_SUCCESS
@@ -64,7 +64,7 @@
/datum/ai_behavior/find_and_set/bee_hive
action_cooldown = 10 SECONDS
/datum/ai_behavior/find_and_set/bee_hive/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/bee_hive/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/list/valid_hives = list()
var/mob/living/bee_pawn = controller.pawn
@@ -25,7 +25,7 @@
health = 50
maxHealth = 50
gold_core_spawnable = FRIENDLY_SPAWN
blood_volume = BLOOD_VOLUME_NORMAL
default_blood_volume = BLOOD_VOLUME_NORMAL
ai_controller = /datum/ai_controller/basic_controller/cow
/// what this cow munches on, and what can be used to tame it.
var/list/food_types = list(/obj/item/food/grown/wheat)
@@ -19,7 +19,7 @@
attack_sound = 'sound/items/weapons/punch1.ogg'
health = 75
maxHealth = 75
blood_volume = BLOOD_VOLUME_NORMAL
default_blood_volume = BLOOD_VOLUME_NORMAL
ai_controller = /datum/ai_controller/basic_controller/deer
/// Things that will scare us into being stationary. Vehicles are scary to deers because they might have headlights.
var/static/list/stationary_scary_things = list(/obj/vehicle)
@@ -31,7 +31,7 @@
minimum_survivable_temperature = COLD_ROOM_TEMP - 75 // enough so that they can survive the cold room spawn with plenty of room for comfort
blood_volume = BLOOD_VOLUME_NORMAL
default_blood_volume = BLOOD_VOLUME_NORMAL
ai_controller = /datum/ai_controller/basic_controller/goat
/// How often will we develop an evil gleam in our eye?
@@ -72,7 +72,7 @@
if(!(living_target.mob_biotypes & MOB_PLANT))
return
living_target.adjustBruteLoss(20)
living_target.adjust_brute_loss(20)
playsound(src, 'sound/items/eatfood.ogg', rand(30, 50), TRUE)
var/obj/item/bodypart/edible_bodypart
@@ -55,7 +55,7 @@
/// Only set things geese will try to eat
/datum/ai_behavior/find_and_set/in_list/goose_food
/datum/ai_behavior/find_and_set/in_list/goose_food/search_tactic(datum/ai_controller/controller, locate_paths, search_range)
/datum/ai_behavior/find_and_set/in_list/goose_food/search_tactic(datum/ai_controller/controller, locate_paths, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/list/found = typecache_filter_list(oview(search_range, controller.pawn), locate_paths)
if(!length(found))
return
@@ -25,7 +25,7 @@
health = 50
maxHealth = 50
gold_core_spawnable = FRIENDLY_SPAWN
blood_volume = BLOOD_VOLUME_NORMAL
default_blood_volume = BLOOD_VOLUME_NORMAL
ai_controller = /datum/ai_controller/basic_controller/pig
/datum/emote/pig
@@ -22,7 +22,7 @@
health = 50
maxHealth = 50
gold_core_spawnable = FRIENDLY_SPAWN
blood_volume = BLOOD_VOLUME_NORMAL
default_blood_volume = BLOOD_VOLUME_NORMAL
ai_controller = /datum/ai_controller/basic_controller/pony
/// Do we register a unique rider?
var/unique_tamer = FALSE
@@ -23,7 +23,7 @@
health = 50
maxHealth = 50
gold_core_spawnable = FRIENDLY_SPAWN
blood_volume = BLOOD_VOLUME_NORMAL
default_blood_volume = BLOOD_VOLUME_NORMAL
ai_controller = /datum/ai_controller/basic_controller/sheep
/// Were we sacrificed by cultists?
@@ -191,9 +191,9 @@
gib()
return TRUE
if (EXPLODE_HEAVY)
adjustBruteLoss(60)
adjust_brute_loss(60)
if (EXPLODE_LIGHT)
adjustBruteLoss(30)
adjust_brute_loss(30)
return TRUE
@@ -294,7 +294,7 @@
summoner.visible_message(span_bolddanger("Blood sprays from [summoner] as [src] takes damage!"))
if(summoner.stat == UNCONSCIOUS || summoner.stat == HARD_CRIT)
to_chat(summoner, span_bolddanger("Your head pounds, you can't take the strain of sustaining [src] in this condition!"))
summoner.adjustOrganLoss(ORGAN_SLOT_BRAIN, amount * 0.5)
summoner.adjust_organ_loss(ORGAN_SLOT_BRAIN, amount * 0.5)
/// When our owner is deleted, we go too.
/mob/living/basic/guardian/proc/on_summoner_deletion(mob/living/source)
@@ -34,7 +34,7 @@
/mob/living/basic/guardian/protector/ex_act(severity)
if(severity >= EXPLODE_DEVASTATE)
adjustBruteLoss(400) //if in protector mode, will do 20 damage and not actually necessarily kill the summoner
adjust_brute_loss(400) //if in protector mode, will do 20 damage and not actually necessarily kill the summoner
return TRUE
return ..()
@@ -23,7 +23,7 @@
return modifier * damage_coeff[damage_type]
return modifier
/mob/living/basic/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, required_bodytype)
/mob/living/basic/adjust_brute_loss(amount, updating_health = TRUE, forced = FALSE, required_bodytype)
if(!can_adjust_brute_loss(amount, forced, required_bodytype))
return 0
if(forced)
@@ -31,7 +31,7 @@
else if(damage_coeff[BRUTE])
. = adjust_health(amount * damage_coeff[BRUTE] * CONFIG_GET(number/damage_multiplier), updating_health, forced)
/mob/living/basic/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE, required_bodytype)
/mob/living/basic/adjust_fire_loss(amount, updating_health = TRUE, forced = FALSE, required_bodytype)
if(!can_adjust_fire_loss(amount, forced, required_bodytype))
return 0
if(forced)
@@ -39,7 +39,7 @@
else if(damage_coeff[BURN])
. = adjust_health(amount * damage_coeff[BURN] * CONFIG_GET(number/damage_multiplier), updating_health, forced)
/mob/living/basic/adjustOxyLoss(amount, updating_health = TRUE, forced = FALSE, required_biotype, required_respiration_type)
/mob/living/basic/adjust_oxy_loss(amount, updating_health = TRUE, forced = FALSE, required_biotype, required_respiration_type)
if(!can_adjust_oxy_loss(amount, forced, required_biotype, required_respiration_type))
return 0
if(forced)
@@ -47,7 +47,7 @@
else if(damage_coeff[OXY])
. = adjust_health(amount * damage_coeff[OXY] * CONFIG_GET(number/damage_multiplier), updating_health, forced)
/mob/living/basic/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE, required_biotype)
/mob/living/basic/adjust_tox_loss(amount, updating_health = TRUE, forced = FALSE, required_biotype)
if(!can_adjust_tox_loss(amount, forced, required_biotype))
return 0
if(forced)
@@ -55,7 +55,7 @@
else if(damage_coeff[TOX])
. = adjust_health(amount * damage_coeff[TOX] * CONFIG_GET(number/damage_multiplier), updating_health, forced)
/mob/living/basic/adjustStaminaLoss(amount, updating_stamina = TRUE, forced = FALSE, required_biotype)
/mob/living/basic/adjust_stamina_loss(amount, updating_stamina = TRUE, forced = FALSE, required_biotype)
if(!can_adjust_stamina_loss(amount, forced, required_biotype))
return 0
. = staminaloss
@@ -23,4 +23,4 @@
/mob/living/basic/heretic_summon/ash_spirit/Life(seconds_per_tick, times_fired)
. = ..()
adjustBruteLoss(-3) // 3 health passively healing
adjust_brute_loss(-3) // 3 health passively healing
@@ -111,8 +111,8 @@
back.on_arm_eaten()
return
adjustBruteLoss(-maxHealth * 0.5, FALSE)
adjustFireLoss(-maxHealth * 0.5, FALSE)
adjust_brute_loss(-maxHealth * 0.5, FALSE)
adjust_fire_loss(-maxHealth * 0.5, FALSE)
if(health < maxHealth * 0.8)
return
@@ -44,7 +44,7 @@
return
var/turf/our_turf = get_turf(src)
if(HAS_TRAIT(our_turf, TRAIT_RUSTY))
adjustBruteLoss(-3 * seconds_per_tick)
adjust_brute_loss(-3 * seconds_per_tick)
return ..()
@@ -87,7 +87,7 @@
if(!do_after(src, 5 SECONDS, target))
return
target.gib(DROP_ALL_REMAINS)
adjustBruteLoss(-1 * heal_on_cannibalize)
adjust_brute_loss(-1 * heal_on_cannibalize)
///Ash whelp, the "lava" variant of ice whelps.
/mob/living/basic/mining/ice_whelp/ash
@@ -0,0 +1,42 @@
/// Standard Illusion behavior is primarily dependent on their context, whether they exist as a decoy or someone meant to retaliate against a threat (of varied origin)
/// For the time being however, the AI is very simple and doesn't rely on any advanced tactics. Just go to thing it was assigned to attack and attack it (if assigned, else wander around)
/// However, the action we undergo is based on the subtype of illusion we are and that's done on the mob subtype level.
/datum/ai_controller/basic_controller/illusion
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
)
ai_traits = DEFAULT_AI_FLAGS
ai_movement = /datum/ai_movement/basic_avoidance
idle_behavior = /datum/idle_behavior/idle_random_walk
planning_subtrees = list(
/datum/ai_planning_subtree/escape_captivity,
/datum/ai_planning_subtree/basic_melee_attack_subtree,
)
/// Escape subtype of illusions are made to flee from threats rather than attack them. They do not undergo any retaliation behavior.
/// We also want to account for the possibility of new threats attacking us and fleeing from those too, more randomness is ideal.
/datum/ai_controller/basic_controller/illusion/escape
blackboard = list(
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, // we don't need the special illusion one here
)
ai_traits = DEFAULT_AI_FLAGS
ai_movement = /datum/ai_movement/basic_avoidance
planning_subtrees = list(
/datum/ai_planning_subtree/escape_captivity,
/datum/ai_planning_subtree/target_retaliate/to_flee,
/datum/ai_planning_subtree/flee_target/from_flee_key,
)
/// Retaliate subtypes of escape illusions can fight back against threats that attack them, making them more dangerous.
/datum/ai_controller/basic_controller/illusion/escape/retaliate
planning_subtrees = list(
/datum/ai_planning_subtree/escape_captivity,
/datum/ai_planning_subtree/flee_target,
/datum/ai_planning_subtree/target_retaliate,
/datum/ai_planning_subtree/basic_melee_attack_subtree,
)
@@ -0,0 +1,112 @@
/// Pretty genericky mob that just manifests itself as any sort of input living mob, used in several ways
/// Has a basic AI that helps it attack targets that are assigned to it, but there's more flavor in the subtypes.
/mob/living/basic/illusion
name = "illusion"
desc = "It's a fake!"
icon = 'icons/effects/effects.dmi'
icon_state = "static"
icon_living = "static"
icon_dead = "null"
gender = NEUTER
mob_biotypes = NONE
melee_damage_lower = 5
melee_damage_upper = 5
combat_mode = TRUE
attack_verb_continuous = "gores"
attack_verb_simple = "gore"
maxHealth = 100
health = 100
speed = 0
faction = list(FACTION_ILLUSION)
basic_mob_flags = DEL_ON_DEATH
death_message = "vanishes into thin air! It was a fake!"
ai_controller = /datum/ai_controller/basic_controller/illusion
/// Weakref to what we're copying
var/datum/weakref/parent_mob_ref
/// Prob of getting a clone on attack
var/multiply_chance = 0
/// The blackboard key we want to set for our target
var/target_key = BB_BASIC_MOB_CURRENT_TARGET
/mob/living/basic/illusion/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(on_preattack))
RegisterSignal(src, COMSIG_MOB_AFTER_APPLY_DAMAGE, PROC_REF(on_damage_taken))
/mob/living/basic/illusion/examine(mob/user)
var/mob/living/parent_mob = parent_mob_ref?.resolve()
if(parent_mob)
return parent_mob.examine(user)
return ..()
/// Signal handler for when we attack something. Hook for replicating on standard behavior, with additional behavior on subtypes.
/mob/living/basic/illusion/proc/on_preattack(mob/living/source, atom/attacked_target)
SIGNAL_HANDLER
try_replicate()
/// Signal handler for when we are attacked.
/mob/living/basic/illusion/proc/on_damage_taken(mob/living/source)
SIGNAL_HANDLER
try_replicate()
/// Full setup for illusion mobs to lessen code duplication in the individual files.
/mob/living/basic/illusion/proc/full_setup(mob/living/original, mob/living/target_mob = null, list/faction = null, life = 5 SECONDS, hp = 100, damage = 0, replicate = 0)
mock_as(original, life, hp, damage, replicate)
set_faction(faction)
set_target(target_mob)
/// Gives the illusion a target to focus on in whatever behavior it wants to engage as.
/mob/living/basic/illusion/proc/set_target(mob/living/target_mob)
if(target_mob == null)
return
ai_controller.set_blackboard_key(target_key, target_mob)
/// Sets the faction of the illusion
/mob/living/basic/illusion/proc/set_faction(list/new_faction)
if(!new_faction) // can be list with no length or null
return
faction = new_faction.Copy()
/// Does the actual work of setting up the illusion's appearance and some other functionality.
/mob/living/basic/illusion/proc/mock_as(mob/living/original, life, hp, damage, replicate)
if(QDELETED(original))
return
parent_mob_ref = WEAKREF(original)
appearance = original.appearance
setDir(original.dir)
maxHealth = hp
updatehealth() // re-cap health to new value
melee_damage_lower = damage
melee_damage_upper = damage
multiply_chance = replicate
faction -= FACTION_NEUTRAL
transform = initial(transform)
pixel_x = base_pixel_x
pixel_y = base_pixel_y
addtimer(CALLBACK(src, TYPE_PROC_REF(/mob/living, death)), life)
/// See if we are able to replicate, and if so, do it.
/mob/living/basic/illusion/proc/try_replicate()
if(prob(multiply_chance))
replicate()
/// Actually perform the replication of this illusion.
/mob/living/basic/illusion/proc/replicate()
var/mob/living/parent_mob = parent_mob_ref.resolve()
if(QDELETED(parent_mob))
return
var/mob/living/basic/illusion/new_clone = new(loc)
new_clone.full_setup(
parent_mob,
target_mob = ai_controller.blackboard[target_key],
faction = faction,
life = 8 SECONDS,
hp = health / 2,
damage = melee_damage_upper,
replicate = multiply_chance / 2,
)
@@ -0,0 +1,35 @@
/// instead of hitting with heavy object, we shove 'em
/mob/living/basic/illusion/shover
/mob/living/basic/illusion/shover/on_preattack(mob/living/source, atom/attacked_target)
. = ..()
if(disarm(attacked_target))
return COMPONENT_HOSTILE_NO_ATTACK
/// designed to run away as fast as possible
/mob/living/basic/illusion/escape
target_key = BB_BASIC_MOB_FLEE_TARGET
ai_controller = /datum/ai_controller/basic_controller/illusion/escape
/mob/living/basic/illusion/escape/Initialize(mapload)
. = ..()
AddElement(/datum/element/ai_retaliate)
/// will run away but isn't afraid to get some punches in as it gets out of dodge
/mob/living/basic/illusion/escape/retaliate
ai_controller = /datum/ai_controller/basic_controller/illusion/escape/retaliate
/mob/living/basic/illusion/escape/on_preattack(mob/living/source, atom/attacked_target)
. = ..()
var/mob/living/parent_mob = parent_mob_ref?.resolve()
if(attacked_target == parent_mob) // we don't want to get our wires crossed and attack our owner ever.
return COMPONENT_HOSTILE_NO_ATTACK
/// a mirage with a little more flair. not meant to move just to look cool
/mob/living/basic/illusion/mirage
ai_controller = null
density = FALSE
/mob/living/basic/illusion/mirage/death(gibbed)
do_sparks(rand(3, 6), FALSE, src)
return ..()
@@ -66,7 +66,7 @@
. = ..()
if(volume <= 5)
return
if(poisoned_mob.adjustToxLoss(2.5 * REM * seconds_per_tick, updating_health = FALSE))
if(poisoned_mob.adjust_tox_loss(2.5 * REM * seconds_per_tick, updating_health = FALSE))
return UPDATE_MOB_HEALTH
// bubble ability structure
@@ -336,7 +336,7 @@
var/mob/living/living_target = target_atom
living_target.adjust_fire_stacks(0.2)
living_target.ignite_mob()
living_target.adjustFireLoss(30)
living_target.adjust_fire_loss(30)
playsound(target_turf, 'sound/effects/magic/lightningbolt.ogg', 50, TRUE)
if(!is_seedling)
@@ -40,7 +40,7 @@
/datum/ai_behavior/find_and_set/treatable_hydro
action_cooldown = 5 SECONDS
/datum/ai_behavior/find_and_set/treatable_hydro/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/treatable_hydro/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/list/possible_trays = list()
var/mob/living/living_pawn = controller.pawn
var/waterlevel_threshold = controller.blackboard[BB_WATERLEVEL_THRESHOLD]
@@ -102,7 +102,7 @@
/datum/ai_behavior/find_and_set/beamable_hydroplants
action_cooldown = 15 SECONDS
/datum/ai_behavior/find_and_set/beamable_hydroplants/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/beamable_hydroplants/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/list/possible_trays = list()
for(var/obj/machinery/hydroponics/hydro in oview(search_range, controller.pawn))
@@ -110,7 +110,7 @@
if(isliving(AM))
var/mob/living/L = AM
if(!isvineimmune(L))
L.adjustBruteLoss(5)
L.adjust_brute_loss(5)
to_chat(L, span_alert("You cut yourself on the thorny vines."))
/**
@@ -197,7 +197,7 @@
else if(vines_in_range)
alert_shown = FALSE
adjustBruteLoss(vines_in_range ? -weed_heal : no_weed_damage) //every life tick take 20 damage if not near vines or heal 10 if near vines, 5 times out of weeds = u ded
adjust_brute_loss(vines_in_range ? -weed_heal : no_weed_damage) //every life tick take 20 damage if not near vines or heal 10 if near vines, 5 times out of weeds = u ded
/datum/action/cooldown/mob_cooldown/projectile_attack/vine_tangle
name = "Tangle"
@@ -47,7 +47,7 @@
continue
balloon_alert(victim, "grabbed")
visible_message(span_danger("[src] grabs hold of [victim]!"))
victim.adjustBruteLoss(rand(min_damage, max_damage))
victim.adjust_brute_loss(rand(min_damage, max_damage))
if (victim.apply_status_effect(/datum/status_effect/incapacitating/stun/goliath_tentacled, grapple_time, src))
buckle_mob(victim, TRUE)
SEND_SIGNAL(victim, COMSIG_GOLIATH_TENTACLED_GRABBED)
@@ -240,8 +240,8 @@
grown.tamed()
for(var/friend in ai_controller?.blackboard?[BB_FRIENDS_LIST])
grown.befriend(friend)
grown.setBruteLoss(getBruteLoss())
grown.setFireLoss(getFireLoss())
grown.set_brute_loss(get_brute_loss())
grown.set_fire_loss(get_fire_loss())
qdel(src) //We called change_mob_type without 'delete_old_mob = TRUE' since we had to pass down friends and damage
/mob/living/basic/mining/lobstrosity/juvenile/lava
@@ -1,5 +1,6 @@
///prototype for mining mobs
/mob/living/basic/mining
abstract_type = /mob/living/basic/mining
icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
combat_mode = TRUE
status_flags = NONE //don't inherit standard basicmob flags
@@ -250,7 +250,7 @@ GLOBAL_LIST_INIT(mook_commands, list(
/datum/ai_behavior/find_and_set/music_audience
/datum/ai_behavior/find_and_set/music_audience/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/music_audience/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/atom/home = controller.blackboard[BB_HOME_VILLAGE]
for(var/mob/living/carbon/human/target in oview(search_range, controller.pawn))
if(target.stat > UNCONSCIOUS || !target.mind)
@@ -289,7 +289,7 @@ GLOBAL_LIST_INIT(mook_commands, list(
return
controller.queue_behavior(/datum/ai_behavior/find_and_set/find_chief, BB_MOOK_TRIBAL_CHIEF, /mob/living/basic/mining/mook/worker/tribal_chief)
/datum/ai_behavior/find_and_set/find_chief/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/find_chief/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/mob/living/chief = locate(locate_path) in oview(search_range, controller.pawn)
if(isnull(chief))
return null
@@ -209,7 +209,7 @@ GLOBAL_LIST_EMPTY(raptor_population)
/mob/living/basic/raptor/proc/add_breeding_component()
var/static/list/partner_types = typecacheof(list(/mob/living/basic/raptor))
var/static/list/baby_types = list(/obj/item/food/egg = 1) ///raptor_egg = 1)
var/static/list/baby_types = list(/obj/item/food/egg/raptor_egg = 1)
AddComponent(\
/datum/component/breed, \
can_breed_with = partner_types, \
@@ -237,9 +237,6 @@ GLOBAL_LIST_INIT(raptor_colors, init_raptor_colors())
if (!istype(user) || user.stat || user.body_position == LYING_DOWN || isnull(user.client))
return FALSE
if (user.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS))
return FALSE
var/turf/location = get_turf(user)
if (!istype(location))
return FALSE
@@ -119,7 +119,7 @@
user.balloon_alert(user, "at full integrity!")
return TRUE
if(welder.use_tool(src, user, 0, volume=40))
adjustBruteLoss(-15)
adjust_brute_loss(-15)
user.balloon_alert(user, "successfully repaired!")
return TRUE
@@ -47,7 +47,7 @@
/datum/ai_behavior/find_and_set/clear_bombing_zone
/datum/ai_behavior/find_and_set/clear_bombing_zone/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/clear_bombing_zone/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
for(var/obj/effect/temp_visual/minebot_target/target in oview(search_range, controller.pawn))
if(isclosedturf(get_turf(target)))
continue
@@ -62,7 +62,7 @@
/datum/ai_behavior/find_and_set/miner_to_befriend
/datum/ai_behavior/find_and_set/miner_to_befriend/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/miner_to_befriend/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
for(var/mob/living/carbon/human/target in oview(search_range, controller.pawn))
if(HAS_TRAIT(target, TRAIT_ROCK_STONER))
return target
@@ -112,7 +112,7 @@
return SUBTREE_RETURN_FINISH_PLANNING
controller.queue_behavior(/datum/ai_behavior/find_and_set/unconscious_human, BB_NEARBY_DEAD_MINER, /mob/living/carbon/human)
/datum/ai_behavior/find_and_set/unconscious_human/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/unconscious_human/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
for(var/mob/living/carbon/human/target in oview(search_range, controller.pawn))
if(target.stat >= UNCONSCIOUS && target.mind)
return target
@@ -36,7 +36,7 @@
//AI
/obj/item/slimepotion/slime/sentience/mining
/obj/item/slimepotion/sentience/mining
name = "minebot AI upgrade"
desc = "Can be used to grant sentience to minebots. It's incompatible with minebot armor and melee upgrades, and will override them."
icon_state = "door_electronics"
@@ -51,7 +51,7 @@
///cooldown boost to add
var/base_cooldown_add = 10
/obj/item/slimepotion/slime/sentience/mining/after_success(mob/living/user, mob/living/basic_mob)
/obj/item/slimepotion/sentience/mining/after_success(mob/living/user, mob/living/basic_mob)
if(!istype(basic_mob, /mob/living/basic/mining_drone))
return
var/mob/living/basic/mining_drone/minebot = basic_mob
@@ -44,7 +44,7 @@
if(SPT_PROB(reside_chance, seconds_per_tick))
controller.queue_behavior(/datum/ai_behavior/find_and_set/valid_home, BB_CAT_HOME, /obj/structure/cat_house)
/datum/ai_behavior/find_and_set/valid_home/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/valid_home/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
for(var/obj/structure/cat_house/home in oview(search_range, controller.pawn))
if(home.resident_cat)
continue
@@ -95,7 +95,7 @@
controller.queue_behavior(/datum/ai_behavior/find_and_set/cat_tresspasser, BB_TRESSPASSER_TARGET, /mob/living/basic/pet/cat)
/datum/ai_behavior/find_and_set/cat_tresspasser/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/cat_tresspasser/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/list/ignore_types = controller.blackboard[BB_BABIES_CHILD_TYPES]
for(var/mob/living/basic/pet/cat/potential_enemy in oview(search_range, controller.pawn))
if(potential_enemy.gender != MALE)
@@ -244,7 +244,7 @@
/datum/ai_behavior/find_and_set/valid_kitten
/datum/ai_behavior/find_and_set/valid_kitten/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/valid_kitten/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/mob/living/kitten = locate(locate_path) in oview(search_range, controller.pawn)
//kitten already has food near it, go feed another hungry kitten
@@ -56,7 +56,7 @@
controller.queue_behavior(/datum/ai_behavior/find_and_set/human_beg, BB_HUMAN_BEG_TARGET, /mob/living/carbon/human)
/datum/ai_behavior/find_and_set/human_beg/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/human_beg/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/list/locate_items = controller.blackboard[BB_HUNTABLE_PREY]
for(var/mob/living/carbon/human/human_target in oview(search_range, controller.pawn))
if(human_target.stat != CONSCIOUS || isnull(human_target.mind))
@@ -517,7 +517,7 @@
visible_message(span_warning("[src] arises again, revived by the dark magicks!"), \
span_cult_large("RISE"))
revive(ADMIN_HEAL_ALL) //also means that a dead Nars-Ian can consume a pet and revive
adjustBruteLoss(-maxHealth)
adjust_brute_loss(-maxHealth)
//LISA! SQUEEEEEEEEE~
/mob/living/basic/pet/dog/corgi/lisa
@@ -125,7 +125,7 @@
return
if(health < maxHealth)
adjustBruteLoss(-4 * seconds_per_tick) //Fast life regen
adjust_brute_loss(-4 * seconds_per_tick) //Fast life regen
for(var/mob/living/carbon/humanoid_entities in view(3, src)) //Mood aura which stay as long you do not wear Sanallite as hat or carry(I will try to make it work with hat someday(obviously weaker than normal one))
humanoid_entities.add_mood_event("kobun", /datum/mood_event/kobun)
@@ -42,7 +42,7 @@
/datum/ai_behavior/find_and_set/find_playmate
/datum/ai_behavior/find_and_set/find_playmate/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/find_playmate/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
for(var/mob/living/basic/orbie/playmate in oview(search_range, controller.pawn))
if(playmate == controller.pawn || playmate.stat == DEAD || isnull(playmate.ai_controller))
continue
@@ -350,7 +350,7 @@ GLOBAL_LIST_INIT(strippable_parrot_items, create_strippable_list(list(
return TRUE // we still ate it
if(health < maxHealth)
adjustBruteLoss(-10)
adjust_brute_loss(-10)
speech_probability_rate *= 1.27
speech_shuffle_rate += 10
update_speech_blackboards()
@@ -27,7 +27,7 @@
/datum/ai_behavior/find_and_set/hoard_location
/datum/ai_behavior/find_and_set/hoard_location/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/hoard_location/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
for(var/turf/open/candidate in oview(search_range, controller.pawn))
if(is_space_or_openspace(candidate))
continue
@@ -41,7 +41,7 @@
action_cooldown = 5 SECONDS
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/datum/ai_behavior/find_and_set/hoard_item/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/hoard_item/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
if(!controller.blackboard_key_exists(BB_HOARD_LOCATION))
return null
var/turf/nest_turf = controller.blackboard[BB_HOARD_LOCATION]
@@ -1,4 +1,5 @@
/mob/living/basic/pet/penguin
abstract_type = /mob/living/basic/pet/penguin
icon = 'icons/mob/simple/penguins.dmi'
gender = FEMALE
@@ -51,7 +51,7 @@
/datum/ai_planning_subtree/fish/drilled_ice
find_fishable_behavior = /datum/ai_behavior/find_and_set/in_list/drilled_ice
/datum/ai_behavior/find_and_set/in_list/drilled_ice/search_tactic(datum/ai_controller/controller, locate_paths, search_range)
/datum/ai_behavior/find_and_set/in_list/drilled_ice/search_tactic(datum/ai_controller/controller, locate_paths, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
for(var/atom/possible_ice as anything in RANGE_TURFS(search_range, controller.pawn))
if(!istype(possible_ice, /turf/open/misc/ice))
continue
+2 -1
View File
@@ -1,8 +1,9 @@
/mob/living/basic/pet
abstract_type = /mob/living/basic/pet
icon = 'icons/mob/simple/pets.dmi'
mob_size = MOB_SIZE_SMALL
mob_biotypes = MOB_ORGANIC|MOB_BEAST
blood_volume = BLOOD_VOLUME_NORMAL
default_blood_volume = BLOOD_VOLUME_NORMAL
basic_mob_flags = SENDS_DEATH_MOODLETS
/// if the mob is protected from being renamed by collars.
var/unique_pet = FALSE
@@ -48,7 +48,7 @@
action_cooldown = 5 SECONDS
behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/datum/ai_behavior/find_and_set/friendly_cultist/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/friendly_cultist/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/mob/living/living_pawn = controller.pawn
for(var/mob/living/carbon/possible_cultist in oview(search_range, controller.pawn))
if(IS_CULTIST(possible_cultist) && !(living_pawn.faction.Find(REF(possible_cultist))))
@@ -72,7 +72,7 @@
/datum/ai_behavior/find_and_set/occupied_rune
/datum/ai_behavior/find_and_set/occupied_rune/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/occupied_rune/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/datum/team/cult/cult_team = controller.blackboard[BB_CULT_TEAM]
if(isnull(cult_team))
return null
@@ -140,7 +140,7 @@
/datum/ai_behavior/find_and_set/dead_cultist
/datum/ai_behavior/find_and_set/dead_cultist/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/dead_cultist/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/datum/team/cult/cult_team = controller.blackboard[BB_CULT_TEAM]
if(isnull(cult_team))
return null
@@ -8,6 +8,7 @@ GLOBAL_LIST_INIT(animatable_blacklist, typecacheof(list(
)))
/mob/living/basic/mimic
abstract_type = /mob/living/basic/mimic
response_help_continuous = "touches"
response_help_simple = "touch"
response_disarm_continuous = "pushes"
@@ -287,7 +288,7 @@ GLOBAL_LIST_INIT(animatable_blacklist, typecacheof(list(
if(!.) //dead or deleted
return
if(idledamage && !ckey && !ai_controller?.blackboard[BB_BASIC_MOB_CURRENT_TARGET]) //Objects eventually revert to normal if no one is around to terrorize
adjustBruteLoss(0.5 * seconds_per_tick)
adjust_brute_loss(0.5 * seconds_per_tick)
for(var/mob/living/victim in contents) //a fix for animated statues from the flesh to stone spell
death()
return
@@ -103,7 +103,7 @@
///Handles the adverse effects of water on slimes
/mob/living/basic/slime/proc/apply_water()
adjustBruteLoss(rand(15,20))
adjust_brute_loss(rand(15,20))
discipline_slime()
///Stops the slime from feeding, and might remove rabidity and targets
+1 -1
View File
@@ -59,7 +59,7 @@
if(nutrition == 0) //adjust nutrition ensures it can't go below 0
if(SPT_PROB(50, seconds_per_tick))
adjustBruteLoss(rand(0,5))
adjust_brute_loss(rand(0,5))
return
if (SLIME_GROW_NUTRITION <= nutrition)
+1 -1
View File
@@ -345,7 +345,7 @@
target_slime.adjust_nutrition(-stolen_nutrition)
our_slime.adjust_nutrition(stolen_nutrition)
if(target_slime.health > 0)
our_slime.adjustBruteLoss(is_adult_slime ? -20 : -10)
our_slime.adjust_brute_loss(is_adult_slime ? -20 : -10)
///Spawns a crossed slimecore item
@@ -10,6 +10,9 @@
icon_living = "headslug"
icon_dead = "headslug_dead"
gender = NEUTER
pass_flags = PASSTABLE | PASSMOB
mob_size = MOB_SIZE_SMALL
density = FALSE
health = 50
maxHealth = 50
max_stamina = 120
@@ -158,9 +158,9 @@
investigate_log("has died from a devastating explosion.", INVESTIGATE_DEATHS)
death()
if(EXPLODE_HEAVY)
adjustBruteLoss(60)
adjust_brute_loss(60)
if(EXPLODE_LIGHT)
adjustBruteLoss(30)
adjust_brute_loss(30)
return TRUE
@@ -72,7 +72,7 @@
return
if(istype(attack_target, /obj/item/food/grown/carrot))
adjustBruteLoss(-5)
adjust_brute_loss(-5)
to_chat(src, span_warning("You eat [attack_target]! It restores some health!"))
qdel(attack_target)
return TRUE
@@ -1,9 +1,9 @@
/datum/ai_behavior/find_and_set/hive_partner
/datum/ai_behavior/find_and_set/hive_partner/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/hive_partner/search_tactic(datum/ai_controller/controller, locate_path, search_range = 10)
var/mob/living/living_pawn = controller.pawn
var/list/hive_partners = list()
for(var/mob/living/target in oview(10, living_pawn))
for(var/mob/living/target in oview(search_range, living_pawn))
if(!istype(target, locate_path))
continue
if(target.stat == DEAD)
@@ -101,7 +101,7 @@
if (!(heal_biotypes & target.mob_biotypes))
return FALSE
if (!iscarbon(target))
return target.getBruteLoss() > 0 || target.getFireLoss() > 0
return target.get_brute_loss() > 0 || target.get_fire_loss() > 0
var/mob/living/carbon/carbon_target = target
for (var/obj/item/bodypart/part in carbon_target.bodyparts)
if (!part.brute_dam && !part.burn_dam)
@@ -110,7 +110,7 @@
var/level_gain = (consumed.powerlevel - powerlevel)
if(level_gain >= 0 && !ckey && !consumed.bruised)//Player shrooms can't level up to become robust gods.
consumed.level_up(level_gain)
adjustBruteLoss(-consumed.maxHealth)
adjust_brute_loss(-consumed.maxHealth)
qdel(consumed)
/mob/living/basic/mushroom/revive(full_heal_flags = NONE, excess_healing = 0, force_grab_ghost = FALSE)
@@ -144,11 +144,11 @@
if(stat == DEAD)
revive(HEAL_ALL)
else
adjustBruteLoss(-5)
adjust_brute_loss(-5)
COOLDOWN_START(src, recovery_cooldown, 5 MINUTES)
/mob/living/basic/mushroom/proc/level_up(level_gain)
adjustBruteLoss(-maxHealth) //They'll always heal, even if they don't gain a level
adjust_brute_loss(-maxHealth) //They'll always heal, even if they don't gain a level
if(powerlevel > 9)
return
if(level_gain == 0)
@@ -87,7 +87,7 @@
/datum/ai_behavior/find_and_set/empty_paper
action_cooldown = 10 SECONDS
/datum/ai_behavior/find_and_set/empty_paper/search_tactic(datum/ai_controller/controller, locate_path, search_range)
/datum/ai_behavior/find_and_set/empty_paper/search_tactic(datum/ai_controller/controller, locate_path, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/list/empty_papers = list()
for(var/obj/item/paper/target_paper in oview(search_range, controller.pawn))
@@ -123,7 +123,7 @@
SIGNAL_HANDLER
if(!(attack_flags & (ATTACKER_STAMINA_ATTACK|ATTACKER_SHOVING)))
attacker.adjustBruteLoss(20)
attacker.adjust_brute_loss(20)
to_chat(attacker, span_warning("The clone casts a spell to damage you before he dies!"))
@@ -278,7 +278,7 @@
if(mob.reagents)
mob.reagents.add_reagent(/datum/reagent/toxin/plasma, 5)
else
mob.adjustToxLoss(5)
mob.adjust_tox_loss(5)
for(var/obj/structure/spacevine/vine in victim) //Fucking with botanists, the ability.
vine.add_atom_colour("#823abb", TEMPORARY_COLOUR_PRIORITY)
new /obj/effect/temp_visual/revenant(vine.loc)
@@ -303,7 +303,7 @@
if (severity != EXPLODE_DEVASTATE)
return
var/damage_coefficient = rand(devastation_damage_min_percentage, devastation_damage_max_percentage)
adjustBruteLoss(initial(maxHealth)*damage_coefficient)
adjust_brute_loss(initial(maxHealth)*damage_coefficient)
return COMPONENT_CANCEL_EX_ACT // we handled it
/// Subtype used by the midround/event
@@ -155,8 +155,8 @@
grown.faction = faction.Copy()
grown.directive = directive
grown.set_name()
grown.setBruteLoss(getBruteLoss())
grown.setFireLoss(getFireLoss())
grown.set_brute_loss(get_brute_loss())
grown.set_fire_loss(get_fire_loss())
qdel(src)
/**
@@ -53,7 +53,7 @@
name = "Pirate Gunner"
mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/ranged
corpse = /obj/effect/mob_spawn/corpse/human/pirate/ranged
r_hand = /obj/item/gun/energy/laser
r_hand = /obj/item/gun/energy/laser/soul
ai_controller = /datum/ai_controller/basic_controller/trooper/ranged
/// Type of bullet we use
var/projectiletype = /obj/projectile/beam/laser
@@ -218,7 +218,8 @@
desc = "A small, twin-bladed machine capable of inflicting very deadly lacerations."
icon_state = "viscerator_attack"
icon_living = "viscerator_attack"
pass_flags = PASSTABLE | PASSMOB
density = FALSE
pass_flags = PASSTABLE | PASSMOB | PASSMACHINE | PASSFLAPS
combat_mode = TRUE
mob_biotypes = MOB_ROBOTIC
basic_mob_flags = DEL_ON_DEATH
@@ -22,7 +22,7 @@
/datum/ai_behavior/find_and_set/in_list/mothroach_food
/datum/ai_behavior/find_and_set/in_list/mothroach_food/search_tactic(datum/ai_controller/controller, locate_paths, search_range)
/datum/ai_behavior/find_and_set/in_list/mothroach_food/search_tactic(datum/ai_controller/controller, locate_paths, search_range = SEARCH_TACTIC_DEFAULT_RANGE)
var/list/found = typecache_filter_list(oview(search_range, controller.pawn), locate_paths)
var/mob/living/living_pawn = controller.pawn
found -= living_pawn.loc
+214 -96
View File
@@ -6,55 +6,160 @@
BLOOD SYSTEM
****************************************************/
/// Returns whether this mob can have blood.
/// Use the CAN_HAVE_BLOOD(mob) macro instead, this is used to update the cached value.
/mob/living/proc/can_have_blood()
return default_blood_volume > 0
/mob/living/carbon/can_have_blood()
return !HAS_TRAIT(src, TRAIT_NOBLOOD)
/// Returns the blood volume of the mob.
/// Apply modifiers when reading blood volume for oxyloss damage, HUDs and analyzers.
/// Don't apply modifiers when using blood itself, like in spells and reagent transfers.
/mob/living/proc/get_blood_volume(apply_modifiers = FALSE)
return CAN_HAVE_BLOOD(src) ? blood_volume : 0 // Overriding blood setting code can cause blood_volume to be non-zero even when a mob shouldn't have blood.
/mob/living/carbon/get_blood_volume(apply_modifiers = FALSE)
if (!CAN_HAVE_BLOOD(src))
return 0 // Overriding blood setting code can cause blood_volume to be non-zero even when a mob shouldn't have blood.
if (!apply_modifiers)
return blood_volume // Default behavior, returns the real blood volume.
if (HAS_TRAIT(src, TRAIT_GODMODE))
return default_blood_volume // Makes TRAIT_GODMODE grant immunity to the effects of bleeding. (oxyloss, passing out, etc.)
var/amount = blood_volume
// Handled here instead of in the saline reagent datum, because this way the modification order is consistent.
// E.g. if you have an effect that modifies blood volume over the dilution cap, then saline should do nothing.
var/datum/reagent/medicine/salglu_solution/saline = reagents?.has_reagent(/datum/reagent/medicine/salglu_solution)
if (saline && amount < saline.dilution_cap)
var/datum/blood_type/blood_type = get_bloodtype()
if (blood_type?.restoration_chem == saline.required_restoration_chem)
amount = min(amount + saline.volume * saline.dilution_per_unit, BLOOD_VOLUME_NORMAL)
return amount
/// Sets the base blood volume of the mob, returns the blood volume of the mob after.
/mob/living/proc/set_blood_volume(amount, minimum = 0, maximum = BLOOD_VOLUME_MAXIMUM, cached_blood_volume = null)
if (!isnum(cached_blood_volume))
cached_blood_volume = get_blood_volume()
if (!CAN_HAVE_BLOOD(src) && amount != 0)
return cached_blood_volume
if (amount == cached_blood_volume)
return cached_blood_volume
blood_volume = clamp(amount, minimum, maximum)
var/updated_blood_volume = get_blood_volume()
if (cached_blood_volume != updated_blood_volume)
living_flags |= QUEUE_BLOOD_UPDATE
return updated_blood_volume
/// Adjusts the base blood volume of the mob and returns the change.
/// Increases in blood volume give a positive return value and vice versa.
/// Maximum only applies on positive amounts and vice versa.
/mob/living/proc/adjust_blood_volume(amount, minimum = 0, maximum = BLOOD_VOLUME_MAXIMUM)
if (!CAN_HAVE_BLOOD(src) || amount == 0)
return 0
var/cached_blood_volume = get_blood_volume()
if (amount < 0)
if (cached_blood_volume <= minimum)
// Already at or below the minimum, don't decrease further.
return 0
// Decreases shouldn't jump the pre-existing value to the maximum.
maximum = INFINITY
else
if (cached_blood_volume >= maximum)
// Already at or above the maximum, don't increase further.
return 0
// Increases shouldn't jump the pre-existing value to the minimum.
minimum = -INFINITY
var/updated_blood_volume = set_blood_volume(cached_blood_volume + amount, minimum = minimum, maximum = maximum, cached_blood_volume = cached_blood_volume)
return updated_blood_volume - cached_blood_volume
/// Updates effects that rely on blood volume, like blood HUDs.
/mob/living/proc/update_blood_effects()
living_flags &= ~QUEUE_BLOOD_UPDATE
/// Updates effects that rely on whether the mob can have blood.
/mob/living/proc/update_blood_status()
var/had_blood = CAN_HAVE_BLOOD(src)
living_flags = can_have_blood() ? (living_flags | LIVING_CAN_HAVE_BLOOD) : (living_flags & ~LIVING_CAN_HAVE_BLOOD)
var/has_blood = CAN_HAVE_BLOOD(src)
if (had_blood == has_blood)
return
var/old_blood_volume = get_blood_volume()
set_blood_volume(has_blood ? default_blood_volume : 0)
var/new_blood_volume = get_blood_volume()
SEND_SIGNAL(src, COMSIG_LIVING_UPDATE_BLOOD_STATUS, had_blood, has_blood, old_blood_volume, new_blood_volume)
// Takes care blood loss and regeneration
/mob/living/carbon/human/handle_blood(seconds_per_tick, times_fired)
// Under these circumstances blood handling is not necessary
if(bodytemperature < BLOOD_STOP_TEMP || HAS_TRAIT(src, TRAIT_FAKEDEATH) || HAS_TRAIT(src, TRAIT_HUSK))
if(bodytemperature < BLOOD_STOP_TEMP || HAS_TRAIT(src, TRAIT_FAKEDEATH))
return
// Run the signal, still allowing mobs with noblood to "handle blood" in their own way
var/sigreturn = SEND_SIGNAL(src, COMSIG_HUMAN_ON_HANDLE_BLOOD, seconds_per_tick, times_fired)
if((sigreturn & HANDLE_BLOOD_HANDLED) || HAS_TRAIT(src, TRAIT_NOBLOOD))
if((sigreturn & HANDLE_BLOOD_HANDLED) || !CAN_HAVE_BLOOD(src))
return
//Blood regeneration if there is some space
if(!(sigreturn & HANDLE_BLOOD_NO_NUTRITION_DRAIN))
if(blood_volume < BLOOD_VOLUME_NORMAL && !HAS_TRAIT(src, TRAIT_NOHUNGER))
var/nutrition_ratio = round(nutrition / NUTRITION_LEVEL_WELL_FED, 0.2)
if(satiety > 80)
nutrition_ratio *= 1.25
adjust_nutrition(-nutrition_ratio * HUNGER_FACTOR * seconds_per_tick)
blood_volume = min(blood_volume + (BLOOD_REGEN_FACTOR * physiology.blood_regen_mod * nutrition_ratio * seconds_per_tick), BLOOD_VOLUME_NORMAL)
if(!(sigreturn & HANDLE_BLOOD_NO_NUTRITION_DRAIN) && get_blood_volume() < BLOOD_VOLUME_NORMAL && !HAS_TRAIT(src, TRAIT_NOHUNGER))
var/nutrition_ratio = round(nutrition / NUTRITION_LEVEL_WELL_FED, 0.2)
//Bloodloss from wounds
var/temp_bleed = 0
for(var/obj/item/bodypart/iter_part as anything in bodyparts)
temp_bleed += iter_part.cached_bleed_rate * seconds_per_tick
if(satiety > 80)
nutrition_ratio *= 1.25
if(iter_part.generic_bleedstacks) // If you don't have any bleedstacks, don't try and heal them
iter_part.adjustBleedStacks(-1, 0)
var/blood_to_restore = BLOOD_REGEN_FACTOR * physiology.blood_regen_mod * nutrition_ratio * seconds_per_tick
var/blood_restored = adjust_blood_volume(blood_to_restore, maximum = BLOOD_VOLUME_NORMAL)
if(temp_bleed)
bleed(temp_bleed)
bleed_warn(temp_bleed)
if (blood_restored > 0)
adjust_nutrition(-nutrition_ratio * HUNGER_FACTOR * seconds_per_tick * (blood_restored / blood_to_restore))
var/bleed_rate = get_bleed_rate()
if(bleed_rate)
bleed(bleed_rate * seconds_per_tick)
bleed_warn(bleed_rate)
for (var/obj/item/bodypart/bodypart as anything in bodyparts)
if (bodypart.generic_bleedstacks)
bodypart.adjustBleedStacks(-1, 0)
//Effects of bloodloss
if(sigreturn & HANDLE_BLOOD_NO_OXYLOSS)
return
// Takes into account modifiers like saline-glucose solution in the blood
var/modified_blood_volume = get_blood_volume(apply_modifiers = TRUE)
// Some effects are halved mid-combat.
var/determined_mod = has_status_effect(/datum/status_effect/determined) ? 0.5 : 0
var/word = pick("dizzy","woozy","faint")
switch(blood_volume)
switch(modified_blood_volume)
// Way too much blood!
if(BLOOD_VOLUME_EXCESS to BLOOD_VOLUME_MAX_LETHAL)
if(SPT_PROB(7.5, seconds_per_tick))
to_chat(src, span_userdanger("Blood starts to tear your skin apart. You're going to burst!"))
investigate_log("has been gibbed by having too much blood.", INVESTIGATE_DEATHS)
inflate_gib()
// Way too much blood!
if(BLOOD_VOLUME_EXCESS to BLOOD_VOLUME_MAX_LETHAL)
if(SPT_PROB(5, seconds_per_tick))
to_chat(src, span_warning("You feel your skin swelling."))
// Too much blood
if(BLOOD_VOLUME_MAXIMUM to BLOOD_VOLUME_EXCESS)
if(SPT_PROB(5, seconds_per_tick))
@@ -66,9 +171,9 @@
if(prob(50))
to_chat(src, span_danger("You feel [word]. It's getting a bit hard to breathe."))
losebreath += 0.5 * determined_mod * seconds_per_tick
else if(getStaminaLoss() < 25 * determined_mod)
else if(get_stamina_loss() < 25 * determined_mod)
to_chat(src, span_danger("You feel [word]. It's getting a bit hard to focus."))
adjustStaminaLoss(10 * determined_mod * REM * seconds_per_tick)
adjust_stamina_loss(10 * determined_mod * REM * seconds_per_tick)
// Pretty low blood, getting dangerous!
if(BLOOD_VOLUME_RISKY to BLOOD_VOLUME_OKAY)
if(SPT_PROB(5, seconds_per_tick))
@@ -77,9 +182,9 @@
if(prob(50))
to_chat(src, span_bolddanger("You feel very [word]. It's getting hard to breathe!"))
losebreath += 1 * determined_mod * seconds_per_tick
else if(getStaminaLoss() < 40 * determined_mod)
else if(get_stamina_loss() < 40 * determined_mod)
to_chat(src, span_bolddanger("You feel very [word]. It's getting hard to stay awake!"))
adjustStaminaLoss(15 * determined_mod * REM * seconds_per_tick)
adjust_stamina_loss(15 * determined_mod * REM * seconds_per_tick)
// Very low blood, danger!!
if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_RISKY)
if(SPT_PROB(5, seconds_per_tick))
@@ -88,9 +193,9 @@
if(prob(50))
to_chat(src, span_userdanger("You feel extremely [word]! It's getting very hard to breathe!"))
losebreath += 1.5 * determined_mod * seconds_per_tick
else if(getStaminaLoss() < 80 * determined_mod)
else if(get_stamina_loss() < 80 * determined_mod)
to_chat(src, span_userdanger("You feel extremely [word]! It's getting very hard to stay awake!"))
adjustStaminaLoss(20 * determined_mod * REM * seconds_per_tick)
adjust_stamina_loss(20 * determined_mod * REM * seconds_per_tick)
// Critically low blood, death is near! Adrenaline won't help you here.
if(BLOOD_VOLUME_SURVIVE to BLOOD_VOLUME_BAD)
if(SPT_PROB(7.5, seconds_per_tick))
@@ -103,35 +208,35 @@
death()
// Blood ratio! if you have 280 blood, this equals 0.5 as that's half of the current value, 560.
var/effective_blood_ratio = blood_volume / BLOOD_VOLUME_NORMAL
var/effective_blood_ratio = modified_blood_volume / BLOOD_VOLUME_NORMAL
var/target_oxyloss = max((1 - effective_blood_ratio) * 100, 0)
// If your ratio is less than one (you're missing any blood) and your oxyloss is under missing blood %, start getting oxy damage.
// This damage accrues faster the less blood you have.
// If the damage surpasses the KO threshold for oxyloss, then we'll always tick up so you die eventually
if(target_oxyloss > 0 && (getOxyLoss() < target_oxyloss || (target_oxyloss >= OXYLOSS_PASSOUT_THRESHOLD && stat >= UNCONSCIOUS)))
if(target_oxyloss > 0 && (get_oxy_loss() < target_oxyloss || (target_oxyloss >= OXYLOSS_PASSOUT_THRESHOLD && stat >= UNCONSCIOUS)))
// At roughly half blood this equals to 3 oxyloss per tick. At 90% blood it's close to 0.5
var/rounded_oxyloss = round(0.01 * (BLOOD_VOLUME_NORMAL - blood_volume), 0.25) * seconds_per_tick
adjustOxyLoss(rounded_oxyloss, updating_health = TRUE)
var/rounded_oxyloss = round(0.01 * (BLOOD_VOLUME_NORMAL - modified_blood_volume), 0.25) * seconds_per_tick
adjust_oxy_loss(rounded_oxyloss, updating_health = TRUE)
/// Has each bodypart update its bleed/wound overlay icon states
/mob/living/carbon/proc/update_bodypart_bleed_overlays()
for(var/obj/item/bodypart/iter_part as anything in bodyparts)
iter_part.update_part_wound_overlay()
/// Makes a blood drop, leaking amt units of blood from the mob
/mob/living/proc/bleed(amt)
/// Bleeds amount units of blood from the mob, sometimes creating a blood splatter on the floor.
/mob/living/proc/bleed(amount)
if(HAS_TRAIT(src, TRAIT_GODMODE) || !can_bleed())
return
blood_volume = max(blood_volume - amt, 0)
var/amount_bled = -adjust_blood_volume(-amount)
// Blood loss still happens in locker, floor stays clean
if(isturf(loc) && prob(sqrt(amt) * BLOOD_DRIP_RATE_MOD))
add_splatter_floor(loc, (amt <= 10))
if(isturf(loc) && prob(sqrt(amount_bled) * BLOOD_DRIP_RATE_MOD))
add_splatter_floor(loc, (amount_bled <= 10))
/mob/living/carbon/human/bleed(amt)
amt *= physiology.bleed_mod
/mob/living/carbon/human/bleed(amount)
amount *= physiology.bleed_mod
return ..()
/// A helper to see how much blood we're losing per tick
@@ -140,12 +245,11 @@
/mob/living/carbon/get_bleed_rate()
if(HAS_TRAIT(src, TRAIT_GODMODE) || !can_bleed())
return
var/bleed_amt = 0
for(var/X in bodyparts)
var/obj/item/bodypart/iter_bodypart = X
bleed_amt += iter_bodypart.cached_bleed_rate
return bleed_amt
return 0
. = 0
for(var/obj/item/bodypart/bodypart as anything in bodyparts)
. += bodypart.cached_bleed_rate
/mob/living/carbon/human/get_bleed_rate()
return ..() * physiology.bleed_mod
@@ -154,22 +258,22 @@
* bleed_warn() is used to for carbons with an active client to occasionally receive messages warning them about their bleeding status (if applicable)
*
* Arguments:
* * bleed_amt- When we run this from [/mob/living/carbon/human/proc/handle_blood] we already know how much blood we're losing this tick, so we can skip tallying it again with this
* * forced-
* * bleed_rate - When we run this from [/mob/living/carbon/human/proc/handle_blood] we already know how much blood we're losing per second, so we can skip tallying it again with this.
* * skip_cooldown - Skips caring about the bleed message cooldown.
*/
/mob/living/carbon/proc/bleed_warn(bleed_amt = 0, forced = FALSE)
if(!blood_volume || !client)
/mob/living/carbon/proc/bleed_warn(bleed_rate = null, skip_cooldown = FALSE)
if(!CAN_HAVE_BLOOD(src) || !client)
return
if(!COOLDOWN_FINISHED(src, bleeding_message_cd) && !forced)
if(!COOLDOWN_FINISHED(src, bleeding_message_cd) && !skip_cooldown)
return
if(!bleed_amt) // if we weren't provided the amount of blood we lost this tick in the args
bleed_amt = get_bleed_rate()
if(!isnum(bleed_rate))
bleed_rate = get_bleed_rate()
var/bleeding_severity = ""
var/next_cooldown = BLEEDING_MESSAGE_BASE_CD
switch(bleed_amt)
switch(bleed_rate)
if(-INFINITY to 0)
return
if(0 to 1)
@@ -208,15 +312,11 @@
to_chat(src, span_warning("[bleeding_severity][rate_of_change]"))
COOLDOWN_START(src, bleeding_message_cd, next_cooldown)
/mob/living/carbon/human/bleed_warn(bleed_amt = 0, forced = FALSE)
if(!HAS_TRAIT(src, TRAIT_NOBLOOD))
return ..()
/mob/living/proc/restore_blood()
blood_volume = initial(blood_volume)
set_blood_volume(default_blood_volume)
/mob/living/carbon/restore_blood()
blood_volume = BLOOD_VOLUME_NORMAL
. = ..()
for(var/obj/item/bodypart/bodypart_to_restore as anything in bodyparts)
bodypart_to_restore.setBleedStacks(0)
@@ -224,47 +324,54 @@
BLOOD TRANSFERS
****************************************************/
//Gets blood from mob to a container or other mob, preserving all data in it.
/mob/living/proc/transfer_blood_to(atom/movable/receiver, amount, forced, ignore_incompatibility)
if(!blood_volume || !receiver.reagents)
return FALSE
// Transfers blood from mob to a container or another mob, preserving all data in it.
// Returns how much blood was able to be transferred.
/mob/living/proc/transfer_blood_to(atom/movable/receiver, amount, ignore_low_blood = FALSE, ignore_incompatibility = FALSE, transfer_viruses = TRUE)
var/cached_blood_volume = get_blood_volume()
if(blood_volume < BLOOD_VOLUME_BAD && !forced)
return FALSE
if(!cached_blood_volume || !receiver.reagents || amount <= 0)
return 0
if(blood_volume < amount)
amount = blood_volume
if(cached_blood_volume < BLOOD_VOLUME_BAD && !ignore_low_blood)
return 0
var/datum/blood_type/blood_type = get_bloodtype()
if (!blood_type)
return FALSE
return 0
var/blood_reagent = get_blood_reagent()
blood_volume -= amount
var/list/blood_data = get_blood_data()
if (!isliving(receiver))
receiver.reagents.add_reagent(blood_reagent, amount, blood_data, bodytemperature, creation_callback = CALLBACK(src, PROC_REF(on_blood_created), blood_type))
return TRUE
// Caps the amount to how much blood we have.
amount = min(amount, get_blood_volume())
if (!ignore_low_blood)
// Caps the amount to how much we can transfer before reaching low blood.
amount = min(amount, get_blood_volume() - BLOOD_VOLUME_BAD)
var/mob/living/target = receiver
if (target.get_blood_reagent() != blood_reagent)
target.reagents.add_reagent(blood_reagent, amount, blood_data, bodytemperature, creation_callback = CALLBACK(src, PROC_REF(on_blood_created), blood_type))
return TRUE
if (!isliving(receiver) || target.get_blood_reagent() != blood_reagent)
// Further caps the amount to how much blood we were able to add to the target.
amount = receiver.reagents.add_reagent(blood_reagent, amount, blood_data, bodytemperature, creation_callback = CALLBACK(src, PROC_REF(on_blood_created), blood_type))
adjust_blood_volume(-amount)
return amount
if(blood_data["viruses"])
if(blood_data["viruses"] && transfer_viruses)
for(var/datum/disease/blood_disease as anything in blood_data["viruses"])
if((blood_disease.spread_flags & DISEASE_SPREAD_SPECIAL) || (blood_disease.spread_flags & DISEASE_SPREAD_NON_CONTAGIOUS))
continue
target.ForceContractDisease(blood_disease)
if(!ignore_incompatibility && !(blood_type.type_key() in target.get_bloodtype().compatible_types))
target.reagents.add_reagent(/datum/reagent/toxin, amount * 0.5)
return TRUE
// Yes, we cap it to the amount of toxin. This is ridiculously niche, but we do it anyway.
amount = target.reagents.add_reagent(/datum/reagent/toxin, amount * 0.5) * 2
adjust_blood_volume(-amount)
return amount
target.blood_volume = min(target.blood_volume + round(amount, 0.1), BLOOD_VOLUME_MAX_LETHAL)
return TRUE
// And, obviously, cap it to how much blood the target can take if they're living.
amount = target.adjust_blood_volume(amount, maximum = BLOOD_VOLUME_MAX_LETHAL)
adjust_blood_volume(-amount)
return amount
/// Callback that adds blood_reagent to any blood extracted from ourselves
/mob/living/proc/on_blood_created(datum/blood_type/blood_type, datum/reagent/new_blood)
@@ -346,7 +453,7 @@
/mob/living/proc/get_bloodtype()
RETURN_TYPE(/datum/blood_type)
if (!blood_volume)
if (!CAN_HAVE_BLOOD(src))
return
if (!(mob_biotypes & MOB_ORGANIC))
@@ -376,7 +483,7 @@
/// Check if a mob can bleed, and possibly if they're capable of leaving decals on turfs/mobs/items
/mob/living/proc/can_bleed(bleed_flag = NONE)
if (HAS_TRAIT(src, TRAIT_HUSK) || HAS_TRAIT(src, TRAIT_NOBLOOD))
if (!CAN_HAVE_BLOOD(src))
return BLEED_NONE
if (!bleed_flag)
@@ -460,7 +567,7 @@
/// Create a small visual-only blood splatter
/mob/living/proc/create_splatter(splatter_dir = pick(GLOB.cardinals))
// Check for husking and TRAIT_NOBLOOD
// Check for TRAIT_NOBLOOD
if (!can_bleed()) // Even if we can't cover turfs, we still can add DNA to everything our blood hits
return
var/obj/effect/temp_visual/dir_setting/bloodsplatter/splatter = new(get_turf(src), splatter_dir, get_bloodtype()?.get_color())
@@ -479,7 +586,7 @@
if (!splatter_turf)
return
// Check for husking and TRAIT_NOBLOOD
// Check for TRAIT_NOBLOOD
switch (can_bleed(BLOOD_COVER_TURFS))
if (BLEED_NONE)
return
@@ -505,27 +612,37 @@
var/turf/targ = get_ranged_target_turf(src, splatter_direction, splatter_strength)
our_splatter.fly_towards(targ, splatter_strength)
// FIXME: This duplicates blood like crazy. The amount you bleed is way less than the splatter.
// To summarize, you can literally dupe blood and bypass bloodloss with a syringe and a beaker.
// I'm writing this here because it's out of scope for my PR, but was discovered because of it.
/mob/living/proc/make_blood_trail(turf/target_turf, turf/start, was_facing, movement_direction)
if(!has_gravity() || !isturf(start))
if(!has_gravity() || !isturf(start) || !can_bleed())
return
var/cached_blood_volume = get_blood_volume()
if(!cached_blood_volume)
return
// BUBBER EDIT BEGIN - Blood pooling
for(var/obj/effect/decal/cleanable/blood/blood_effect in target_turf)
blood_effect.increase_blood_pool()
// BUBBER EDIT END
var/base_bleed_rate = get_bleed_rate()
var/base_brute = getBruteLoss()
var/base_brute = get_brute_loss()
var/brute_ratio = round(base_brute / (maxHealth * 4), 0.1)
var/bleeding_rate = round(base_bleed_rate / 4, 0.1)
var/bleeding_rate = round(base_bleed_rate / 4, 0.1)
// We only leave a trail if we're below a certain blood threshold
// The more brute damage we have, or the more we're bleeding, the less blood we need to leave a trail
if(blood_volume < max(BLOOD_VOLUME_NORMAL * (1 - max(bleeding_rate, brute_ratio)), 0))
if(cached_blood_volume < max(BLOOD_VOLUME_NORMAL * (1 - max(bleeding_rate, brute_ratio)), 0))
return
var/blood_to_add = BLOOD_AMOUNT_PER_DECAL * 0.1
if(body_position == LYING_DOWN)
blood_to_add += bleed_drag_amount()
blood_volume = max(blood_volume - blood_to_add, 0)
adjust_blood_volume(-blood_to_add)
else
blood_to_add += base_bleed_rate
@@ -533,10 +650,11 @@
if(base_brute >= 300 || base_bleed_rate >= 7)
blood_to_add *= 2
switch (can_bleed(BLOOD_COVER_TURFS))
if (BLEED_NONE)
// Checks if we can add visual blood effects on turfs.
switch(can_bleed(BLOOD_COVER_TURFS))
if(BLEED_NONE)
return
if (BLEED_ADD_DNA)
if(BLEED_ADD_DNA)
return start.add_mob_blood(src)
var/trail_dir = REVERSE_DIR(movement_direction)
@@ -568,7 +686,7 @@
trail_dir &= ~(was_facing & (EAST|WEST))
break
if (continuing_trail || (trail_dir in GLOB.diagonals))
if(continuing_trail || (trail_dir in GLOB.diagonals))
create_blood_trail_component(start, trail_dir, blood_to_add * 0.67, FALSE)
create_blood_trail_component(target_turf, get_dir(start, target_turf), blood_to_add * 0.33, TRUE)
return
@@ -628,7 +746,7 @@
/// Returns how much blood we're losing from being dragged a tile, from [/mob/living/proc/make_blood_trail]
/mob/living/proc/bleed_drag_amount()
var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1)
var/brute_ratio = round(get_brute_loss() / maxHealth, 0.1)
return max(1, brute_ratio * 2)
/mob/living/carbon/bleed_drag_amount()
@@ -63,8 +63,8 @@
switch(severity)
if (EMP_HEAVY)
to_chat(owner, span_boldwarning("You feel [pick("like your brain is being fried", "a sharp pain in your head")]!")) //BUBBER EDIT - added alert text for getting EMP'd.
owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, (20*emp_dmg_mult), emp_dmg_max) //BUBBER EDIT - cap implemented
owner.adjust_organ_loss(ORGAN_SLOT_BRAIN, (20*emp_dmg_mult), emp_dmg_max) //BUBBER EDIT - cap implemented
if (EMP_LIGHT)
to_chat(owner, span_warning("You feel [pick("disoriented", "confused", "dizzy")].")) //BUBBER EDIT - added alert text for getting EMP'd.
owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, (10*emp_dmg_mult), emp_dmg_max) //BUBBER EDIT - cap implemented
owner.adjust_organ_loss(ORGAN_SLOT_BRAIN, (10*emp_dmg_mult), emp_dmg_max) //BUBBER EDIT - cap implemented
@@ -1,4 +1,5 @@
/mob/living/carbon/alien/adult
abstract_type = /mob/living/carbon/alien/adult
name = "alien"
icon_state = "alien"
pass_flags = PASSTABLE
@@ -4,7 +4,7 @@
. = ..()
if(!.)
return
adjustBruteLoss(15)
adjust_brute_loss(15)
var/hitverb = "hit"
if(mob_size < MOB_SIZE_LARGE)
safe_throw_at(get_edge_target_turf(src, get_dir(user, src)), 2, 1, user)
@@ -8,7 +8,7 @@
if(stat == DEAD)
//If we mostly took damage from fire
if(getFireLoss() > 125)
if(get_fire_loss() > 125)
icon_state = "alien[caste]_husked"
else
icon_state = "alien[caste]_dead"
@@ -1,4 +1,5 @@
/mob/living/carbon/alien
abstract_type = /mob/living/carbon/alien
name = "alien"
icon = 'icons/mob/nonhuman-player/alien.dmi'
gender = FEMALE //All xenos are girls!!
@@ -31,7 +31,7 @@ In all, this is a lot like the monkey code. /N
visible_message(span_danger("[user.name] bites [src]!"), \
span_userdanger("[user.name] bites you!"), span_hear("You hear a chomp!"), COMBAT_MESSAGE_RANGE, user)
to_chat(user, span_danger("You bite [src]!"))
adjustBruteLoss(1)
adjust_brute_loss(1)
log_combat(user, src, "attacked")
else
to_chat(user, span_warning("[name] is too injured for that."))
@@ -1,15 +1,15 @@
///alien immune to tox damage
/mob/living/carbon/alien/getToxLoss()
/mob/living/carbon/alien/get_tox_loss()
return FALSE
///alien immune to tox damage
/mob/living/carbon/alien/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE, required_biotype)
/mob/living/carbon/alien/adjust_tox_loss(amount, updating_health = TRUE, forced = FALSE, required_biotype)
return FALSE
///aliens are immune to stamina damage.
/mob/living/carbon/alien/adjustStaminaLoss(amount, updating_stamina = 1, forced = FALSE, required_biotype)
/mob/living/carbon/alien/adjust_stamina_loss(amount, updating_stamina = 1, forced = FALSE, required_biotype)
return FALSE
///aliens are immune to stamina damage.
/mob/living/carbon/alien/setStaminaLoss(amount, updating_stamina = 1, forced = FALSE, required_biotype)
/mob/living/carbon/alien/set_stamina_loss(amount, updating_stamina = 1, forced = FALSE, required_biotype)
return FALSE
+1 -1
View File
@@ -13,7 +13,7 @@
return 0
if(health <= HEALTH_THRESHOLD_CRIT)
adjustOxyLoss(2)
adjust_oxy_loss(2)
var/plasma_used = 0
var/plas_detect_threshold = 0.02
@@ -62,9 +62,9 @@
if(!isalien(owner))
heal_amt *= 0.2
owner.adjustPlasma(0.5 * plasma_rate * delta_time_capped)
owner.adjustBruteLoss(-heal_amt * delta_time_capped)
owner.adjustFireLoss(-heal_amt * delta_time_capped)
owner.adjustOxyLoss(-heal_amt * delta_time_capped)
owner.adjust_brute_loss(-heal_amt * delta_time_capped)
owner.adjust_fire_loss(-heal_amt * delta_time_capped)
owner.adjust_oxy_loss(-heal_amt * delta_time_capped)
else
owner.adjustPlasma(0.1 * plasma_rate * delta_time)
@@ -52,10 +52,10 @@
if(SPT_PROB(2, seconds_per_tick))
to_chat(owner, span_danger("Your stomach hurts."))
if(prob(20))
owner.adjustToxLoss(1)
owner.adjust_tox_loss(1)
if(6)
to_chat(owner, span_danger("You feel something tearing its way out of your chest..."))
owner.adjustToxLoss(5 * seconds_per_tick) // Why is this [TOX]?
owner.adjust_tox_loss(5 * seconds_per_tick) // Why is this [TOX]?
/// Controls Xenomorph Embryo growth. If embryo is fully grown (or overgrown), stop the proc. If not, increase the stage by one and if it's not fully grown (stage 6), add a timer to do this proc again after however long the growth time variable is.
/obj/item/organ/body_egg/alien_embryo/proc/advance_embryo_stage()
@@ -149,7 +149,7 @@
else
new_xeno.visible_message(span_danger("[new_xeno] wriggles out of [owner]!"), span_userdanger("You exit [owner], your previous host."))
owner.log_message("had an alien larva within them escape (without being gibbed).", LOG_ATTACK, log_globally = FALSE)
owner.adjustBruteLoss(40)
owner.adjust_brute_loss(40)
owner.cut_overlay(overlay)
owner.investigate_log("has been gibbed by an alien larva.", INVESTIGATE_DEATHS)
qdel(src)
@@ -30,6 +30,7 @@
special_desc = "This alien is an extremely dangerous life form capable of creating a xenomorph. You would know well not to approach without full body biological protection."
// SKYRAT EDIT ADDITION END
slowdown = 2
clothing_traits = list(TRAIT_SOFTSPOKEN)
var/stat = CONSCIOUS //UNCONSCIOUS is the idle state in this case
var/sterile = FALSE
@@ -194,7 +195,9 @@
if(!sterile)
victim.take_bodypart_damage(strength,0) //done here so that humans in helmets take damage
if(real && !sterile)
victim.Knockdown(5 SECONDS)
victim.Paralyze(1 SECONDS)
victim.adjust_confusion(20 SECONDS)
victim.Knockdown(10 SECONDS)
GoIdle() //so it doesn't jump the people that tear it off
addtimer(CALLBACK(src, PROC_REF(Impregnate), victim), rand(MIN_IMPREGNATION_TIME, MAX_IMPREGNATION_TIME))
+14 -18
View File
@@ -30,16 +30,6 @@
QDEL_NULL(breathing_loop)
GLOB.carbon_list -= src
/mob/living/carbon/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
. = ..()
if(. & ITEM_INTERACT_ANY_BLOCKER)
return .
// Needs to happen after parent call otherwise wounds are prioritized over surgery
for(var/datum/wound/wound as anything in shuffle(all_wounds))
if(wound.try_treating(tool, user))
return ITEM_INTERACT_SUCCESS
return .
/mob/living/carbon/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
. = ..()
var/hurt = TRUE
@@ -349,14 +339,14 @@
var/turf/location = get_turf(src)
if(!blood)
adjust_nutrition(-lost_nutrition)
need_mob_update += adjustToxLoss(-3, updating_health = FALSE)
need_mob_update += adjust_tox_loss(-3, updating_health = FALSE)
for(var/i = 0 to distance)
if(blood)
if(location)
add_splatter_floor(location)
if(vomit_flags & MOB_VOMIT_HARM)
need_mob_update += adjustBruteLoss(3, updating_health = FALSE)
need_mob_update += adjust_brute_loss(3, updating_health = FALSE)
else
if(location)
location.add_vomit_floor(src, vomit_type, vomit_flags, purge_ratio) // call purge when doing detoxicfication to pump more chems out of the stomach.
@@ -428,7 +418,7 @@
var/obj/item/bodypart/BP = X
total_brute += (BP.brute_dam * BP.body_damage_coeff)
total_burn += (BP.burn_dam * BP.body_damage_coeff)
set_health(round(maxHealth - getOxyLoss() - getToxLoss() - total_burn - total_brute, DAMAGE_PRECISION))
set_health(round(maxHealth - get_oxy_loss() - get_tox_loss() - total_burn - total_brute, DAMAGE_PRECISION))
update_stat()
update_stamina()
@@ -610,7 +600,7 @@
clear_fullscreen("oxy")
//Fire and Brute damage overlay (BSSR)
var/hurtdamage = getBruteLoss() + getFireLoss() + damageoverlaytemp
var/hurtdamage = get_brute_loss() + get_fire_loss() + damageoverlaytemp
if(hurtdamage && !HAS_TRAIT(src, TRAIT_NO_DAMAGE_OVERLAY))
var/severity = 0
switch(hurtdamage)
@@ -676,7 +666,7 @@
else
if(shown_stamina_loss == null)
shown_stamina_loss = getStaminaLoss()
shown_stamina_loss = get_stamina_loss()
if(shown_stamina_loss >= stam_crit_threshold)
hud_used.stamina.icon_state = "stamina_crit"
@@ -750,8 +740,7 @@
/mob/living/carbon/revive(full_heal_flags = NONE, excess_healing = 0, force_grab_ghost = FALSE)
if(excess_healing)
if(dna && !HAS_TRAIT(src, TRAIT_NOBLOOD))
blood_volume += (excess_healing * 2) //1 excess = 10 blood
adjust_blood_volume(excess_healing * 2)
for(var/obj/item/organ/target_organ as anything in organs)
if(!target_organ.damage)
@@ -846,7 +835,7 @@
if (HAS_TRAIT(src, TRAIT_DEFIB_BLACKLISTED))
return DEFIB_FAIL_BLACKLISTED
if ((getBruteLoss() >= MAX_REVIVE_BRUTE_DAMAGE) || (getFireLoss() >= MAX_REVIVE_FIRE_DAMAGE))
if ((get_brute_loss() >= MAX_REVIVE_BRUTE_DAMAGE) || (get_fire_loss() >= MAX_REVIVE_FIRE_DAMAGE))
return DEFIB_FAIL_TISSUE_DAMAGE
var/heart_status = can_defib_heart(get_organ_by_type(/obj/item/organ/heart))
@@ -1129,12 +1118,17 @@
/// if any of our bodyparts are bleeding
/mob/living/carbon/proc/is_bleeding()
if(!CAN_HAVE_BLOOD(src))
return FALSE
for(var/obj/item/bodypart/part as anything in bodyparts)
if(part.cached_bleed_rate)
return TRUE
/// get our total bleedrate
/mob/living/carbon/proc/get_total_bleed_rate()
if(!CAN_HAVE_BLOOD(src))
return FALSE
var/total_bleed_rate = 0
for(var/obj/item/bodypart/part as anything in bodyparts)
total_bleed_rate += part.cached_bleed_rate
@@ -1376,4 +1370,6 @@
/mob/living/carbon/get_bloodtype()
RETURN_TYPE(/datum/blood_type)
if(!CAN_HAVE_BLOOD(src))
return
return dna?.blood_type
@@ -253,7 +253,7 @@
return
else
show_message(span_userdanger("The blob attacks!"))
adjustBruteLoss(10)
adjust_brute_loss(10)
///Adds to the parent by also adding functionality to propagate shocks through pulling and doing some fluff effects.
/mob/living/carbon/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE, jitter_time = 20 SECONDS, stutter_time = 4 SECONDS, stun_duration = 4 SECONDS)
@@ -572,7 +572,7 @@
. = FALSE
/mob/living/carbon/adjustOxyLoss(amount, updating_health = TRUE, forced, required_biotype, required_respiration_type)
/mob/living/carbon/adjust_oxy_loss(amount, updating_health = TRUE, forced, required_biotype, required_respiration_type)
if(!forced && HAS_TRAIT(src, TRAIT_NOBREATH))
amount = min(amount, 0) //Prevents oxy damage but not healing
@@ -584,7 +584,7 @@
if(!limb)
return
/mob/living/carbon/setOxyLoss(amount, updating_health = TRUE, forced, required_biotype, required_respiration_type)
/mob/living/carbon/set_oxy_loss(amount, updating_health = TRUE, forced, required_biotype, required_respiration_type)
. = ..()
check_passout()
@@ -592,7 +592,7 @@
* Check to see if we should be passed out from oxyloss
*/
/mob/living/carbon/proc/check_passout()
var/mob_oxyloss = getOxyLoss()
var/mob_oxyloss = get_oxy_loss()
if(mob_oxyloss >= OXYLOSS_PASSOUT_THRESHOLD)
if(!HAS_TRAIT_FROM(src, TRAIT_KNOCKEDOUT, OXYLOSS_TRAIT))
ADD_TRAIT(src, TRAIT_KNOCKEDOUT, OXYLOSS_TRAIT)
@@ -1,6 +1,6 @@
/mob/living/carbon
abstract_type = /mob/living/carbon
blood_volume = BLOOD_VOLUME_NORMAL
default_blood_volume = BLOOD_VOLUME_NORMAL
gender = MALE
pressure_resistance = 15
hud_possible = list(HEALTH_HUD,STATUS_HUD,ANTAG_HUD,GLAND_HUD,DNR_HUD,NANITE_HUD,DIAG_NANITE_FULL_HUD) // BUBBER EDIT ADDITION - DNR_HUD / NANITE_HUD
@@ -49,7 +49,7 @@
///only used by humans.
var/obj/item/clothing/ears = null
/// Carbon, you should really only be accessing this through has_dna() but it's your life
/// DNA is carbon-only, and ideally you should be accessing it through has_dna(), but you can access it directly if you know you're working with a carbon mob
var/datum/dna/dna = null
///last mind to control this mob, for blood-based cloning
var/datum/mind/last_mind = null
+17 -17
View File
@@ -82,13 +82,13 @@
return final_mod
//These procs fetch a cumulative total damage from all bodyparts
/mob/living/carbon/getBruteLoss()
/mob/living/carbon/get_brute_loss()
var/amount = 0
for(var/obj/item/bodypart/bodypart as anything in bodyparts)
amount += bodypart.brute_dam
return round(amount, DAMAGE_PRECISION)
/mob/living/carbon/getFireLoss()
/mob/living/carbon/get_fire_loss()
var/amount = 0
for(var/obj/item/bodypart/bodypart as anything in bodyparts)
amount += bodypart.burn_dam
@@ -102,7 +102,7 @@
* Arguments:
* * required_bodytype - The bodytype(s) to match against.
*/
/mob/living/carbon/proc/getBruteLossForType(required_bodytype = ALL)
/mob/living/carbon/proc/get_brute_loss_for_type(required_bodytype = ALL)
var/amount = 0
for(var/obj/item/bodypart/bodypart as anything in bodyparts)
if(!(bodypart.bodytype & required_bodytype))
@@ -117,7 +117,7 @@
* Arguments:
* * required_bodytype - The bodytype(s) to match against.
*/
/mob/living/carbon/proc/getFireLossForType(required_bodytype = ALL)
/mob/living/carbon/proc/get_fire_loss_for_type(required_bodytype = ALL)
var/amount = 0
for(var/obj/item/bodypart/bodypart as anything in bodyparts)
if(!(bodypart.bodytype & required_bodytype))
@@ -125,7 +125,7 @@
amount += bodypart.burn_dam
return round(amount, DAMAGE_PRECISION)
/mob/living/carbon/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, required_bodytype)
/mob/living/carbon/adjust_brute_loss(amount, updating_health = TRUE, forced = FALSE, required_bodytype)
if(!can_adjust_brute_loss(amount, forced, required_bodytype))
return 0
if(amount > 0)
@@ -133,16 +133,16 @@
else
. = heal_overall_damage(brute = abs(amount), required_bodytype = required_bodytype, updating_health = updating_health, forced = forced)
/mob/living/carbon/setBruteLoss(amount, updating_health = TRUE, forced = FALSE, required_bodytype)
/mob/living/carbon/set_brute_loss(amount, updating_health = TRUE, forced = FALSE, required_bodytype)
if(!forced && HAS_TRAIT(src, TRAIT_GODMODE))
return FALSE
var/current = getBruteLoss()
var/current = get_brute_loss()
var/diff = amount - current
if(!diff)
return FALSE
return adjustBruteLoss(diff, updating_health, forced, required_bodytype)
return adjust_brute_loss(diff, updating_health, forced, required_bodytype)
/mob/living/carbon/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE, required_bodytype)
/mob/living/carbon/adjust_fire_loss(amount, updating_health = TRUE, forced = FALSE, required_bodytype)
if(!can_adjust_fire_loss(amount, forced, required_bodytype))
return 0
if(amount > 0)
@@ -150,16 +150,16 @@
else
. = heal_overall_damage(burn = abs(amount), required_bodytype = required_bodytype, updating_health = updating_health, forced = forced)
/mob/living/carbon/setFireLoss(amount, updating_health = TRUE, forced = FALSE, required_bodytype)
/mob/living/carbon/set_fire_loss(amount, updating_health = TRUE, forced = FALSE, required_bodytype)
if(!forced && HAS_TRAIT(src, TRAIT_GODMODE))
return FALSE
var/current = getFireLoss()
var/current = get_fire_loss()
var/diff = amount - current
if(!diff)
return FALSE
return adjustFireLoss(diff, updating_health, forced, required_bodytype)
return adjust_fire_loss(diff, updating_health, forced, required_bodytype)
/mob/living/carbon/human/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE, required_biotype = ALL)
/mob/living/carbon/human/adjust_tox_loss(amount, updating_health = TRUE, forced = FALSE, required_biotype = ALL)
. = ..()
if(. >= 0) // 0 = no damage, + values = healed damage
return .
@@ -167,7 +167,7 @@
if(AT_TOXIN_VOMIT_THRESHOLD(src))
apply_status_effect(/datum/status_effect/tox_vomit)
/mob/living/carbon/human/setToxLoss(amount, updating_health, forced, required_biotype)
/mob/living/carbon/human/set_tox_loss(amount, updating_health, forced, required_biotype)
. = ..()
if(. >= 0)
return .
@@ -191,7 +191,7 @@
*
* Returns: The net change in damage from apply_organ_damage()
*/
/mob/living/carbon/adjustOrganLoss(slot, amount, maximum, required_organ_flag = NONE)
/mob/living/carbon/adjust_organ_loss(slot, amount, maximum, required_organ_flag = NONE)
var/obj/item/organ/affected_organ = get_organ_slot(slot)
if(!affected_organ || HAS_TRAIT(src, TRAIT_GODMODE))
return FALSE
@@ -201,7 +201,7 @@
/**
* If an organ exists in the slot requested, and we are capable of taking damage (we don't have TRAIT_GODMODE), call the set damage proc on that organ, which can
* set or clear the failing variable on that organ, making it either cease or start functions again, unlike adjustOrganLoss.
* set or clear the failing variable on that organ, making it either cease or start functions again, unlike adjust_organ_loss.
*
* Arguments:
* * slot - organ slot, like [ORGAN_SLOT_HEART]
@@ -210,7 +210,7 @@
*
* Returns: The net change in damage from set_organ_damage()
*/
/mob/living/carbon/setOrganLoss(slot, amount, required_organ_flag = NONE)
/mob/living/carbon/set_organ_loss(slot, amount, required_organ_flag = NONE)
var/obj/item/organ/affected_organ = get_organ_slot(slot)
if(!affected_organ || HAS_TRAIT(src, TRAIT_GODMODE))
return FALSE
+3 -3
View File
@@ -106,7 +106,7 @@
if(user == src && has_status_effect(/datum/status_effect/grouped/screwy_hud/fake_crit))//fake damage
temp = 50
else
temp = getBruteLoss()
temp = get_brute_loss()
var/list/damage_desc = get_majority_bodypart_damage_desc()
if(temp)
if(temp < 25)
@@ -116,7 +116,7 @@
else
. += span_bolddanger("[t_He] [t_has] severe [damage_desc[BRUTE]]!")
temp = getFireLoss()
temp = get_fire_loss()
if(temp)
if(temp < 25)
. += span_danger("[t_He] [t_has] minor [damage_desc[BURN]].")
@@ -143,7 +143,7 @@
if(DISGUST_LEVEL_DISGUSTED to INFINITY)
. += "[t_He] look[p_s()] extremely disgusted."
var/apparent_blood_volume = blood_volume
var/apparent_blood_volume = CAN_HAVE_BLOOD(src) ? get_blood_volume(apply_modifiers = TRUE) : BLOOD_VOLUME_NORMAL
if(HAS_TRAIT(src, TRAIT_USES_SKINTONES) && ishuman(src))
var/mob/living/carbon/human/husrc = src // gross istypesrc but easier than refactoring even further for now
if(husrc.skin_tone == "albino")
@@ -146,7 +146,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/list/inherent_traits = list()
/// List of biotypes the mob belongs to. Used by diseases.
var/inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID
/// The type of respiration the mob is capable of doing. Used by adjustOxyLoss.
/// The type of respiration the mob is capable of doing. Used by adjust_oxy_loss.
var/inherent_respiration_type = RESPIRATION_OXYGEN
///List of factions the mob gain upon gaining this species.
var/list/inherent_factions
@@ -365,8 +365,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
* Normalizes blood in a human if it is excessive. If it is above BLOOD_VOLUME_NORMAL, this will clamp it to that value. It will not give the human more blodo than they have less than this value.
*/
/datum/species/proc/normalize_blood(mob/living/carbon/human/blood_possessing_human)
var/normalized_blood_values = max(blood_possessing_human.blood_volume, 0, BLOOD_VOLUME_NORMAL)
blood_possessing_human.blood_volume = normalized_blood_values
blood_possessing_human.set_blood_volume(min(blood_possessing_human.get_blood_volume(), BLOOD_VOLUME_NORMAL))
/**
* Proc called when a carbon becomes this species.
@@ -563,7 +562,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
/datum/species/proc/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired)
SHOULD_CALL_PARENT(TRUE)
if(HAS_TRAIT(H, TRAIT_NOBREATH) && (H.health < H.crit_threshold) && !HAS_TRAIT(H, TRAIT_NOCRITDAMAGE))
H.adjustBruteLoss(0.5 * seconds_per_tick)
H.adjust_brute_loss(0.5 * seconds_per_tick)
/datum/species/proc/can_equip(obj/item/I, slot, disable_warning, mob/living/carbon/human/H, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE, indirect_action = FALSE)
if(no_equip_flags & slot && !(I.is_mod_shell_component() && (modsuit_slot_exceptions & slot))) // SKYRAT EDIT ADDITION - ORIGINAL: if(no_equip_flags & slot)
@@ -852,10 +851,10 @@ GLOBAL_LIST_EMPTY(features_by_species)
limb_accuracy = floor(limb_accuracy * pummel_bonus)
//Get our puncher's combined brute and burn damage.
var/puncher_brute_and_burn = (user.getFireLoss() + user.getBruteLoss())
var/puncher_brute_and_burn = (user.get_fire_loss() + user.get_brute_loss())
//Get our targets combined brute and burn damage.
var/target_brute_and_burn = (target.getFireLoss() + target.getBruteLoss())
var/target_brute_and_burn = (target.get_fire_loss() + target.get_brute_loss())
// In a brawl, drunkenness can make you swing more wildly and with more force, and thus catch your opponent off guard, but it could also totally throw you off if you're too intoxicated
// But god is it going to make you sick moving too much while drunk
@@ -1265,7 +1264,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
humi.apply_damage(burn_damage, BURN, spread_damage = TRUE, wound_clothing = FALSE)
// For cold damage, we cap at the threshold if you're dead
if(humi.getFireLoss() >= abs(HEALTH_THRESHOLD_DEAD) && humi.stat == DEAD)
if(humi.get_fire_loss() >= abs(HEALTH_THRESHOLD_DEAD) && humi.stat == DEAD)
return
// Apply some burn / brute damage to the body (Dependent if the person is hulk or not)
@@ -1346,7 +1345,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
H.clear_alert(ALERT_PRESSURE)
else
var/pressure_damage = min(((adjusted_pressure / HAZARD_HIGH_PRESSURE) - 1) * PRESSURE_DAMAGE_COEFFICIENT, MAX_HIGH_PRESSURE_DAMAGE) * H.physiology.pressure_mod * H.physiology.brute_mod * seconds_per_tick
H.adjustBruteLoss(pressure_damage, required_bodytype = BODYTYPE_ORGANIC)
H.adjust_brute_loss(pressure_damage, required_bodytype = BODYTYPE_ORGANIC)
H.throw_alert(ALERT_PRESSURE, /atom/movable/screen/alert/highpressure, 2)
// High pressure, show an alert
@@ -1372,7 +1371,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
H.clear_alert(ALERT_PRESSURE)
else
var/pressure_damage = LOW_PRESSURE_DAMAGE * H.physiology.pressure_mod * H.physiology.brute_mod * seconds_per_tick
H.adjustBruteLoss(pressure_damage, required_bodytype = BODYTYPE_ORGANIC)
H.adjust_brute_loss(pressure_damage, required_bodytype = BODYTYPE_ORGANIC)
H.throw_alert(ALERT_PRESSURE, /atom/movable/screen/alert/lowpressure, 2)
/**
@@ -29,12 +29,12 @@ GLOBAL_LIST_EMPTY(dead_players_during_shift)
if(SSticker.HasRoundStarted())
SSblackbox.ReportDeath(src)
log_message("has died with Round Removal [client?.prefs.read_preference(/datum/preference/toggle/be_round_removed) ? "enabled" : "disabled or unavailable"] (BRUTE: [src.getBruteLoss()], BURN: [src.getFireLoss()], TOX: [src.getToxLoss()], OXY: [src.getOxyLoss()]", LOG_ATTACK) // BUBBER EDIT - Round Removal OPT-IN LOGGING
log_message("has died with Round Removal [client?.prefs.read_preference(/datum/preference/toggle/be_round_removed) ? "enabled" : "disabled or unavailable"] (BRUTE: [src.get_brute_loss()], BURN: [src.get_fire_loss()], TOX: [src.get_tox_loss()], OXY: [src.get_oxy_loss()]", LOG_ATTACK) // BUBBER EDIT - Round Removal OPT-IN LOGGING
if(key) // Prevents log spamming of keyless mob deaths (like xenobio monkeys)
investigate_log("has died at [loc_name(src)].<br>\
BRUTE: [src.getBruteLoss()] BURN: [src.getFireLoss()] TOX: [src.getToxLoss()] OXY: [src.getOxyLoss()] STAM: [src.getStaminaLoss()]<br>\
BRUTE: [src.get_brute_loss()] BURN: [src.get_fire_loss()] TOX: [src.get_tox_loss()] OXY: [src.get_oxy_loss()] STAM: [src.get_stamina_loss()]<br>\
<b>Brain damage</b>: [src.get_organ_loss(ORGAN_SLOT_BRAIN) || "0"]<br>\
<b>[get_bloodtype()?.get_blood_name() || "Blood"] volume</b>: [src.blood_volume]cl ([round((src.blood_volume / BLOOD_VOLUME_NORMAL) * 100, 0.1)]%)<br>\
<b>[get_bloodtype()?.get_blood_name() || "Blood"] volume</b>: [src.get_blood_volume(apply_modifiers = TRUE)]cl ([round((src.get_blood_volume(apply_modifiers = TRUE) / BLOOD_VOLUME_NORMAL) * 100, 0.1)]%)<br>\
<b>Reagents</b>:<br>[reagents_readout()]", INVESTIGATE_DEATHS)
to_chat(src, span_warning("You have died. Barring complete bodyloss, you can in most cases be revived by other players. \
If you do not wish to be brought back, use the \"Do Not Resuscitate\" button at the bottom of your screen."))
@@ -33,14 +33,14 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
var/obj/item/organ/current_organ = get_organ_slot(slot) //Time to cache it lads
if(current_organ)
current_organ.Remove(src, special = TRUE) //Please don't somehow kill our dummy
SSwardrobe.stash_object(current_organ)
SSwardrobe.recycle_object(current_organ)
var/datum/species/current_species = dna.species
for(var/organ_path in current_species.mutant_organs)
var/obj/item/organ/current_organ = get_organ_by_type(organ_path)
if(current_organ)
current_organ.Remove(src, special = TRUE) //Please don't somehow kill our dummy
SSwardrobe.stash_object(current_organ)
SSwardrobe.recycle_object(current_organ)
//Instead of just deleting our equipment, we save what we can and reinsert it into SSwardrobe's store
//Hopefully this makes preference reloading not the worst thing ever
@@ -55,8 +55,6 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
if(!isitem(checking)) //What the fuck are you on
to_nuke += checking
continue
if(checking.item_flags & DO_NOT_WARDROBE) // Skip any items like MOD parts, which are created in the contents of a stashed item and should not be destroyed
continue
var/list/contents = checking.contents
if(length(contents))
@@ -68,7 +66,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
if(ismob(checking.loc))
var/mob/checkings_owner = checking.loc
checkings_owner.temporarilyRemoveItemFromInventory(checking, TRUE) //Clear out of there yeah?
SSwardrobe.stash_object(checking)
SSwardrobe.recycle_object(checking)
for(var/obj/item/delete as anything in to_nuke)
qdel(delete)
+8 -17
View File
@@ -192,12 +192,12 @@
if(!HAS_TRAIT(human_user, TRAIT_MEDICAL_HUD))
return
if(href_list["evaluation"])
if(!getBruteLoss() && !getFireLoss() && !getOxyLoss() && getToxLoss() < 20)
if(!get_brute_loss() && !get_fire_loss() && !get_oxy_loss() && get_tox_loss() < 20)
to_chat(human_user, "[span_notice("No external injuries detected.")]<br>")
return
var/span = "notice"
var/status = ""
if(getBruteLoss())
if(get_brute_loss())
to_chat(human_user, "<b>Physical trauma analysis:</b>")
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
@@ -213,7 +213,7 @@
span = "userdanger"
if(brutedamage)
to_chat(human_user, "<span class='[span]'>[BP] appears to have [status]</span>")
if(getFireLoss())
if(get_fire_loss())
to_chat(human_user, "<b>Analysis of skin burns:</b>")
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
@@ -229,9 +229,9 @@
span = "userdanger"
if(burndamage)
to_chat(human_user, "<span class='[span]'>[BP] appears to have [status]</span>")
if(getOxyLoss())
if(get_oxy_loss())
to_chat(human_user, span_danger("Patient has signs of suffocation, emergency treatment may be required!"))
if(getToxLoss() > 20)
if(get_tox_loss() > 20)
to_chat(human_user, span_danger("Gathered data is inconsistent with the analysis, possible cause: poisoning."))
if(!human_user.wear_id) //You require access from here on out.
to_chat(human_user, span_warning("ERROR: Invalid access"))
@@ -607,7 +607,7 @@
else if (!target.get_organ_slot(ORGAN_SLOT_LUNGS))
to_chat(target, span_unconscious("You feel a breath of fresh air... but you don't feel any better..."))
else
target.adjustOxyLoss(-min(target.getOxyLoss(), 7))
target.adjust_oxy_loss(-min(target.get_oxy_loss(), 7))
to_chat(target, span_unconscious("You feel a breath of fresh air enter your lungs... It feels good..."))
if (target.health <= target.crit_threshold)
@@ -760,7 +760,7 @@
return ..()
/mob/living/carbon/human/vomit(vomit_flags = VOMIT_CATEGORY_DEFAULT, vomit_type = /obj/effect/decal/cleanable/vomit/toxic, lost_nutrition = 10, distance = 1, purge_ratio = 0.1)
if(!((vomit_flags & MOB_VOMIT_BLOOD) && HAS_TRAIT(src, TRAIT_NOBLOOD) && !HAS_TRAIT(src, TRAIT_TOXINLOVER)))
if(!((vomit_flags & MOB_VOMIT_BLOOD) && !CAN_HAVE_BLOOD(src) && !HAS_TRAIT(src, TRAIT_TOXINLOVER)))
return ..()
if(vomit_flags & MOB_VOMIT_MESSAGE)
@@ -1055,16 +1055,6 @@
else
remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
/mob/living/carbon/human/is_bleeding()
if(HAS_TRAIT(src, TRAIT_NOBLOOD))
return FALSE
return ..()
/mob/living/carbon/human/get_total_bleed_rate()
if(HAS_TRAIT(src, TRAIT_NOBLOOD))
return FALSE
return ..()
/mob/living/carbon/human/get_exp_list(minutes)
. = ..()
if(mind.assigned_role.title in SSjob.name_occupations)
@@ -1120,6 +1110,7 @@
ai_controller = /datum/ai_controller/monkey
/mob/living/carbon/human/species
abstract_type = /mob/living/carbon/human/species
var/race = null
var/use_random_name = TRUE
@@ -207,7 +207,7 @@
else if(!HAS_TRAIT(src, TRAIT_INCAPACITATED))
playsound(loc, 'sound/items/weapons/pierce.ogg', 25, TRUE, -1)
var/shovetarget = get_edge_target_turf(user, get_dir(user, get_step_away(src, user)))
adjustStaminaLoss(35)
adjust_stamina_loss(35)
throw_at(shovetarget, 4, 2, user, force = MOVE_FORCE_OVERPOWERING)
log_combat(user, src, "shoved")
visible_message(span_danger("[user] tackles [src] down!"), \
@@ -580,7 +580,7 @@
for(var/t in missing)
combined_msg += span_boldannounce("&rdsh; Your [parse_zone(t)] is missing!")
var/tox = getToxLoss() + (disgust / 5) + (HAS_TRAIT(src, TRAIT_SELF_AWARE) ? 0 : (rand(-3, 0) * 5))
var/tox = get_tox_loss() + (disgust / 5) + (HAS_TRAIT(src, TRAIT_SELF_AWARE) ? 0 : (rand(-3, 0) * 5))
switch(tox)
if(10 to 20)
combined_msg += span_danger("You feel sick.")
@@ -589,7 +589,8 @@
if(40 to INFINITY)
combined_msg += span_danger("You feel very unwell!")
var/oxy = getOxyLoss() + (losebreath * 4) + (blood_volume < BLOOD_VOLUME_NORMAL ? ((BLOOD_VOLUME_NORMAL - blood_volume) * 0.1) : 0) + (HAS_TRAIT(src, TRAIT_SELF_AWARE) ? 0 : (rand(-3, 0) * 5))
var/cached_blood_volume = get_blood_volume(apply_modifiers = TRUE)
var/oxy = get_oxy_loss() + (losebreath * 4) + (cached_blood_volume < BLOOD_VOLUME_NORMAL ? ((BLOOD_VOLUME_NORMAL - cached_blood_volume) * 0.1) : 0) + (HAS_TRAIT(src, TRAIT_SELF_AWARE) ? 0 : (rand(-3, 0) * 5))
switch(oxy)
if(10 to 20)
combined_msg += span_danger("You feel lightheaded.")
@@ -598,8 +599,8 @@
if(40 to INFINITY)
combined_msg += span_danger("You feel like you're about to pass out!")
if(getStaminaLoss())
if(getStaminaLoss() > 30)
if(get_stamina_loss())
if(get_stamina_loss() > 30)
combined_msg += span_info("You're completely exhausted.")
else
combined_msg += span_info("You feel fatigued.")
@@ -36,7 +36,7 @@
return ..()
if(damage_type & SHAME)
adjustStaminaLoss(200)
adjust_stamina_loss(200)
set_suicide(FALSE)
add_mood_event("shameful_suicide", /datum/mood_event/shameful_suicide)
return FALSE
+4 -4
View File
@@ -82,9 +82,9 @@
return human_lungs.check_breath(breath, src)
if(health >= crit_threshold)
adjustOxyLoss(HUMAN_MAX_OXYLOSS + 1)
adjust_oxy_loss(HUMAN_MAX_OXYLOSS + 1)
else if(!HAS_TRAIT(src, TRAIT_NOCRITDAMAGE))
adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS)
adjust_oxy_loss(HUMAN_CRIT_MAX_OXYLOSS)
failed_last_breath = TRUE
@@ -294,10 +294,10 @@
return
if(we_breath)
adjustOxyLoss(4 * seconds_per_tick)
adjust_oxy_loss(4 * seconds_per_tick)
Unconscious(80)
// Tissues die without blood circulation
adjustBruteLoss(1 * seconds_per_tick)
adjust_brute_loss(1 * seconds_per_tick)
#undef THERMAL_PROTECTION_HEAD
#undef THERMAL_PROTECTION_CHEST
@@ -71,22 +71,29 @@
if(slime.stat == DEAD)
return HANDLE_BLOOD_HANDLED
if(slime.blood_volume <= 0)
slime.blood_volume += JELLY_REGEN_RATE_EMPTY * slime.physiology.blood_regen_mod * seconds_per_tick
slime.adjustBruteLoss(2.5 * seconds_per_tick)
// In the following code, do not cache blood volumes.
// They are repeadetly updated and caching can introduce bugs.
// Blood regen thresholds use your real amount of blood.
if(slime.get_blood_volume() <= 0)
slime.adjust_blood_volume(JELLY_REGEN_RATE_EMPTY * slime.physiology.blood_regen_mod * seconds_per_tick)
slime.adjust_brute_loss(2.5 * seconds_per_tick)
to_chat(slime, span_danger("You feel empty!"))
if(slime.blood_volume < BLOOD_VOLUME_NORMAL)
// Same logic applies here.
if(slime.get_blood_volume() < BLOOD_VOLUME_NORMAL)
if(slime.nutrition >= NUTRITION_LEVEL_STARVING)
slime.blood_volume += JELLY_REGEN_RATE * slime.physiology.blood_regen_mod * seconds_per_tick
if(slime.blood_volume <= BLOOD_VOLUME_LOSE_NUTRITION) // don't lose nutrition if we are above a certain threshold, otherwise slimes on IV drips will still lose nutrition
slime.adjust_blood_volume(JELLY_REGEN_RATE * slime.physiology.blood_regen_mod * seconds_per_tick)
if(slime.get_blood_volume() <= BLOOD_VOLUME_LOSE_NUTRITION) // don't lose nutrition if we are above a certain threshold, otherwise slimes on IV drips will still lose nutrition
slime.adjust_nutrition(-1.25 * seconds_per_tick)
if(slime.blood_volume < BLOOD_VOLUME_OKAY)
// If you're on saline, you don't feel the effects of bloodloss.
if(slime.get_blood_volume(apply_modifiers = TRUE) < BLOOD_VOLUME_OKAY)
if(SPT_PROB(2.5, seconds_per_tick))
to_chat(slime, span_danger("You feel drained!"))
if(slime.blood_volume < BLOOD_VOLUME_BAD)
// Saline can prevent you from cannibalizing yourself.
if(slime.get_blood_volume(apply_modifiers = TRUE) < BLOOD_VOLUME_BAD)
Cannibalize_Body(slime)
regenerate_limbs?.build_all_button_icons(UPDATE_BUTTON_STATUS)
@@ -104,7 +111,7 @@
consumed_limb.drop_limb()
to_chat(H, span_userdanger("Your [consumed_limb] is drawn back into your body, unable to maintain its shape!"))
qdel(consumed_limb)
H.blood_volume += 20 * H.physiology.blood_regen_mod
H.adjust_blood_volume(20 * H.physiology.blood_regen_mod)
/datum/species/jelly/get_species_description()
return "Jellypeople are a strange and alien species with three eyes, made entirely out of gel."
@@ -144,6 +151,8 @@
background_icon_state = "bg_alien"
overlay_icon_state = "bg_alien_border"
var/blood_per_limb = 40
/datum/action/innate/regenerate_limbs/IsAvailable(feedback = FALSE)
. = ..()
if(!.)
@@ -152,7 +161,7 @@
var/list/limbs_to_heal = H.get_missing_limbs()
if(!length(limbs_to_heal))
return FALSE
if(H.blood_volume >= BLOOD_VOLUME_OKAY+40)
if(H.get_blood_volume() >= BLOOD_VOLUME_OKAY + blood_per_limb)
return TRUE
/datum/action/innate/regenerate_limbs/Activate()
@@ -162,17 +171,17 @@
to_chat(H, span_notice("You feel intact enough as it is."))
return
to_chat(H, span_notice("You focus intently on your missing [length(limbs_to_heal) >= 2 ? "limbs" : "limb"]..."))
if(H.blood_volume >= 40*length(limbs_to_heal)+BLOOD_VOLUME_OKAY)
if(H.get_blood_volume() >= blood_per_limb * length(limbs_to_heal) + BLOOD_VOLUME_OKAY)
H.regenerate_limbs()
H.blood_volume -= 40*length(limbs_to_heal)
H.adjust_blood_volume(-blood_per_limb * length(limbs_to_heal))
to_chat(H, span_notice("...and after a moment you finish reforming!"))
return
else if(H.blood_volume >= 40)//We can partially heal some limbs
while(H.blood_volume >= BLOOD_VOLUME_OKAY+40)
else if(H.get_blood_volume() >= blood_per_limb)//We can partially heal some limbs
while(H.get_blood_volume() >= BLOOD_VOLUME_OKAY + blood_per_limb)
var/healed_limb = pick(limbs_to_heal)
H.regenerate_limb(healed_limb)
limbs_to_heal -= healed_limb
H.blood_volume -= 40
H.adjust_blood_volume(-blood_per_limb)
to_chat(H, span_warning("...but there is not enough of you to fix everything! You must attain more mass to heal completely!"))
return
to_chat(H, span_warning("...but there is not enough of you to go around! You must attain more mass to heal!"))
@@ -213,7 +222,7 @@
bodies -= C // This means that the other bodies maintain a link
// so if someone mindswapped into them, they'd still be shared.
bodies = null
C.blood_volume = min(C.blood_volume, BLOOD_VOLUME_NORMAL)
C.set_blood_volume(C.get_blood_volume(), maximum = BLOOD_VOLUME_NORMAL)
UnregisterSignal(C, COMSIG_LIVING_DEATH)
..()
@@ -256,13 +265,13 @@
/datum/species/jelly/slime/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired)
. = ..()
if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
if(H.get_blood_volume() >= BLOOD_VOLUME_SLIME_SPLIT)
if(SPT_PROB(2.5, seconds_per_tick))
to_chat(H, span_notice("You feel very bloated!"))
else if(H.nutrition >= NUTRITION_LEVEL_WELL_FED)
H.blood_volume += 1.5 * seconds_per_tick
if(H.blood_volume <= BLOOD_VOLUME_LOSE_NUTRITION)
H.adjust_blood_volume(1.5 * seconds_per_tick)
if(H.get_blood_volume() <= BLOOD_VOLUME_LOSE_NUTRITION)
H.adjust_nutrition(-1.25 * seconds_per_tick)
/datum/action/innate/split_body
@@ -278,7 +287,7 @@
if(!.)
return
var/mob/living/carbon/human/H = owner
if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
if(H.get_blood_volume() >= BLOOD_VOLUME_SLIME_SPLIT)
return TRUE
return FALSE
@@ -295,7 +304,7 @@
ADD_TRAIT(src, TRAIT_NO_TRANSFORM, REF(src))
if(do_after(owner, delay = 6 SECONDS, target = owner, timed_action_flags = IGNORE_HELD_ITEM))
if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
if(H.get_blood_volume() >= BLOOD_VOLUME_SLIME_SPLIT)
make_dupe()
else
to_chat(H, span_warning("...but there is not enough of you to go around! You must attain more mass to split!"))
@@ -327,7 +336,7 @@
spare.AddComponent(/datum/component/nanites, owner_nanites.nanite_volume)
SEND_SIGNAL(spare, COMSIG_NANITE_SYNC, owner_nanites, TRUE, TRUE) //The trues are to copy activation as well
// BUBBER ADDITION END - NANITES
H.blood_volume *= 0.45
H.set_blood_volume(H.get_blood_volume() * 0.45)
REMOVE_TRAIT(H, TRAIT_NO_TRANSFORM, REF(src))
var/datum/species/jelly/slime/origin_datum = H.dna.species
@@ -406,7 +415,7 @@
occupied = "available"
L["status"] = stat
L["exoticblood"] = body.blood_volume
L["exoticblood"] = body.get_blood_volume()
L["name"] = body.name
L["ref"] = "[REF(body)]"
L["occupied"] = occupied
@@ -52,20 +52,20 @@
if(istype(vampire.loc, /obj/structure/closet/crate/coffin))
var/need_mob_update = FALSE
need_mob_update += vampire.heal_overall_damage(brute = 2 * seconds_per_tick, burn = 2 * seconds_per_tick, updating_health = FALSE, required_bodytype = BODYTYPE_ORGANIC)
need_mob_update += vampire.adjustToxLoss(-2 * seconds_per_tick, updating_health = FALSE,)
need_mob_update += vampire.adjustOxyLoss(-2 * seconds_per_tick, updating_health = FALSE,)
need_mob_update += vampire.adjust_tox_loss(-2 * seconds_per_tick, updating_health = FALSE,)
need_mob_update += vampire.adjust_oxy_loss(-2 * seconds_per_tick, updating_health = FALSE,)
if(need_mob_update)
vampire.updatehealth()
return
vampire.blood_volume -= 0.125 * seconds_per_tick
if(vampire.blood_volume <= BLOOD_VOLUME_SURVIVE)
vampire.adjust_blood_volume(-0.125 * seconds_per_tick)
if(vampire.get_blood_volume(apply_modifiers = TRUE) <= BLOOD_VOLUME_SURVIVE)
to_chat(vampire, span_danger("You ran out of blood!"))
vampire.investigate_log("has been dusted by a lack of blood (vampire).", INVESTIGATE_DEATHS)
vampire.dust()
var/area/A = get_area(vampire)
if(istype(A, /area/station/service/chapel))
to_chat(vampire, span_warning("You don't belong here!"))
vampire.adjustFireLoss(10 * seconds_per_tick)
vampire.adjust_fire_loss(10 * seconds_per_tick)
vampire.adjust_fire_stacks(3 * seconds_per_tick)
vampire.ignite_mob()
@@ -231,14 +231,14 @@
return FALSE
var/mob/living/carbon/victim = user.pulling
if(user.blood_volume >= BLOOD_VOLUME_MAXIMUM)
if(user.get_blood_volume() >= BLOOD_VOLUME_MAXIMUM)
to_chat(user, span_warning("You're already full!"))
return FALSE
if(victim.stat == DEAD)
to_chat(user, span_warning("You need a living victim!"))
return FALSE
var/blood_name = LOWER_TEXT(user.get_bloodtype()?.get_blood_name())
if(!victim.blood_volume || victim.get_blood_reagent() != user.get_blood_reagent())
if(!victim.get_blood_volume() || victim.get_blood_reagent() != user.get_blood_reagent())
if (blood_name)
to_chat(user, span_warning("[victim] doesn't have [blood_name]!"))
else
@@ -255,14 +255,20 @@
return FALSE
if(!do_after(user, 3 SECONDS, target = victim, hidden = TRUE))
return FALSE
var/blood_volume_difference = BLOOD_VOLUME_MAXIMUM - user.blood_volume //How much capacity we have left to absorb blood
var/drained_blood = min(victim.blood_volume, VAMP_DRAIN_AMOUNT, blood_volume_difference)
victim.show_message(span_danger("[user] is draining your blood!"))
to_chat(user, span_notice("You drain some blood!"))
playsound(user, 'sound/items/drink.ogg', 30, TRUE, -2)
victim.blood_volume = clamp(victim.blood_volume - drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
user.blood_volume = clamp(user.blood_volume + drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
if(!victim.blood_volume)
// Since we adjust the user first, we need to take the victim's blood volume into account.
var/amount_drained = min(VAMP_DRAIN_AMOUNT, victim.get_blood_volume())
// Takes into account how much blood the vampire can take.
amount_drained = user.adjust_blood_volume(amount_drained)
victim.adjust_blood_volume(-amount_drained)
if(!victim.get_blood_volume())
to_chat(user, span_notice("You finish off [victim]'s [blood_name] supply."))
return TRUE
@@ -1,6 +1,6 @@
/mob/living/carbon/human/proc/delayed_suicide()
suicide_log()
adjustBruteLoss(max(200 - getToxLoss() - getFireLoss() - getBruteLoss() - getOxyLoss(), 0))
adjust_brute_loss(max(200 - get_tox_loss() - get_fire_loss() - get_brute_loss() - get_oxy_loss(), 0))
investigate_log("has died from committing suicide.", INVESTIGATE_DEATHS)
death(FALSE)
ghostize(FALSE) // Disallows reentering body and disassociates mind
+24 -2
View File
@@ -5,6 +5,8 @@
//Traits that register add and remove
RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_AGENDER), PROC_REF(on_agender_trait_gain))
RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_AGENDER), PROC_REF(on_agender_trait_loss))
RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_NOBLOOD), PROC_REF(on_noblood_trait_gain))
RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_NOBLOOD), PROC_REF(on_noblood_trait_loss))
//Traits that register add only
RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_NOBREATH), PROC_REF(on_nobreath_trait_gain))
@@ -34,6 +36,26 @@
var/datum/dna_block/identity/gender/to_update = GLOB.dna_identity_blocks[/datum/dna_block/identity/gender]
to_update.apply_to_mob(src, src.dna.unique_identity)
/**
* On gain of TRAIT_NOBLOOD
*
* This will make the mob update its blood state.
*/
/mob/living/carbon/proc/on_noblood_trait_gain(datum/source)
SIGNAL_HANDLER
update_blood_status()
/**
* On removal of TRAIT_NOBLOOD
*
* This will make the mob update its blood state.
*/
/mob/living/carbon/proc/on_noblood_trait_loss(datum/source)
SIGNAL_HANDLER
update_blood_status()
/**
* On gain of TRAIT_NOBREATH
*
@@ -42,7 +64,7 @@
/mob/living/carbon/proc/on_nobreath_trait_gain(datum/source)
SIGNAL_HANDLER
setOxyLoss(0, updating_health = TRUE, forced = TRUE)
set_oxy_loss(0, updating_health = TRUE, forced = TRUE)
losebreath = 0
failed_last_breath = FALSE
@@ -97,7 +119,7 @@
/mob/living/carbon/proc/on_toximmune_trait_gain(datum/source)
SIGNAL_HANDLER
setToxLoss(0, updating_health = TRUE, forced = TRUE)
set_tox_loss(0, updating_health = TRUE, forced = TRUE)
/**
* On gain of TRAIT_GENELLESS
+20 -21
View File
@@ -203,7 +203,7 @@
// Simulates breathing zero moles of gas.
has_moles = FALSE
// Extra damage, let God sort em out!
adjustOxyLoss(2)
adjust_oxy_loss(2)
/// Minimum O2 before suffocation.
var/safe_oxygen_min = 16
@@ -254,7 +254,7 @@
failed_last_breath = FALSE
// Vacuum-adapted lungs regenerate oxyloss even when breathing nothing.
if(health >= crit_threshold)
adjustOxyLoss(-5)
adjust_oxy_loss(-5)
else
// Can't breathe! Lungs are missing, and/or breath is empty.
. = FALSE
@@ -288,7 +288,7 @@
oxygen_used = breath_gases[/datum/gas/oxygen][MOLES]
// Heal mob if not in crit.
if(health >= crit_threshold)
adjustOxyLoss(-5)
adjust_oxy_loss(-5)
// Exhale equivalent amount of CO2.
if(o2_pp)
breath_gases[/datum/gas/oxygen][MOLES] -= oxygen_used
@@ -309,10 +309,10 @@
throw_alert(ALERT_TOO_MUCH_CO2, /atom/movable/screen/alert/too_much_co2)
Unconscious(6 SECONDS)
// Lets hurt em a little, let them know we mean business.
adjustOxyLoss(3)
adjust_oxy_loss(3)
// They've been in here 30s now, start to kill them for their own good!
if((world.time - co2overloadtime) > 30 SECONDS)
adjustOxyLoss(8)
adjust_oxy_loss(8)
else
// Reset side-effects.
co2overloadtime = 0
@@ -323,7 +323,7 @@
if(plasma_pp > safe_plas_max)
// Plasma side-effects.
var/ratio = (breath_gases[/datum/gas/plasma][MOLES] / safe_plas_max) * 10
adjustToxLoss(clamp(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE))
adjust_tox_loss(clamp(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE))
if(!HAS_TRAIT(src, TRAIT_ANOSMIA))
throw_alert(ALERT_TOO_MUCH_PLASMA, /atom/movable/screen/alert/too_much_plas)
else
@@ -343,7 +343,7 @@
//-- FREON --//
if(freon_pp)
adjustFireLoss(freon_pp * 0.25)
adjust_fire_loss(freon_pp * 0.25)
//-- MIASMA --//
if(!miasma_pp)
@@ -407,9 +407,9 @@
if(nitrium_pp)
var/need_mob_update = FALSE
if(nitrium_pp > 0.5)
need_mob_update += adjustFireLoss(nitrium_pp * 0.15, updating_health = FALSE)
need_mob_update += adjust_fire_loss(nitrium_pp * 0.15, updating_health = FALSE)
if(nitrium_pp > 5)
need_mob_update += adjustToxLoss(nitrium_pp * 0.05, updating_health = FALSE)
need_mob_update += adjust_tox_loss(nitrium_pp * 0.05, updating_health = FALSE)
if(need_mob_update)
updatehealth()
@@ -448,13 +448,13 @@
// Low pressure.
if(breath_pp)
var/ratio = safe_breath_min / breath_pp
adjustOxyLoss(min(5 * ratio, 3))
adjust_oxy_loss(min(5 * ratio, 3))
return true_pp * ratio / 6
// Zero pressure.
if(health >= crit_threshold)
adjustOxyLoss(3)
adjust_oxy_loss(3)
else
adjustOxyLoss(1)
adjust_oxy_loss(1)
/// Fourth and final link in a breath chain
/mob/living/carbon/proc/handle_breath_temperature(datum/gas_mixture/breath)
@@ -489,8 +489,9 @@
if(!blood_type)
return
if(chem.type == blood_type?.restoration_chem && blood_volume < BLOOD_VOLUME_NORMAL)
blood_volume += BLOOD_REGEN_FACTOR * seconds_per_tick
if(chem.type == blood_type?.restoration_chem && get_blood_volume() < BLOOD_VOLUME_NORMAL)
// Don't clamp this to BLOOD_VOLUME_NORMAL. Reagents have quantization, making an clamped threshold janky.
adjust_blood_volume(BLOOD_REGEN_FACTOR * seconds_per_tick)
reagents.remove_reagent(chem.type, chem.metabolization_rate * seconds_per_tick)
return COMSIG_MOB_STOP_REAGENT_TICK
@@ -507,10 +508,8 @@
if(blood_type.reagent_type != chem.type)
return
var/blood_stream_volume = min(round(reac_volume, CHEMICAL_VOLUME_ROUNDING), BLOOD_VOLUME_MAXIMUM - blood_volume)
if(blood_stream_volume > 0) //remove reagents from mob that has now entered the bloodstream
reagents.remove_reagent(chem.type, blood_stream_volume)
blood_volume += blood_stream_volume
var/blood_added = adjust_blood_volume(round(reac_volume, CHEMICAL_VOLUME_ROUNDING))
reagents.remove_reagent(chem.type, blood_added)
if(chem.data?["blood_type"])
var/datum/blood_type/donor_type = chem.data["blood_type"]
@@ -803,8 +802,8 @@
if(HAS_TRAIT(src, TRAIT_STABLELIVER) || HAS_TRAIT(src, TRAIT_LIVERLESS_METABOLISM))
return
adjustToxLoss(0.6 * seconds_per_tick, forced = TRUE)
adjustOrganLoss(pick(ORGAN_SLOT_HEART, ORGAN_SLOT_LUNGS, ORGAN_SLOT_STOMACH, ORGAN_SLOT_EYES, ORGAN_SLOT_EARS), 0.5* seconds_per_tick)
adjust_tox_loss(0.6 * seconds_per_tick, forced = TRUE)
adjust_organ_loss(pick(ORGAN_SLOT_HEART, ORGAN_SLOT_LUNGS, ORGAN_SLOT_STOMACH, ORGAN_SLOT_EYES, ORGAN_SLOT_EARS), 0.5* seconds_per_tick)
/mob/living/carbon/proc/undergoing_liver_failure()
var/obj/item/organ/liver/liver = get_organ_slot(ORGAN_SLOT_LIVER)
@@ -835,7 +834,7 @@
/mob/living/carbon/proc/needs_heart()
if(HAS_TRAIT(src, TRAIT_STABLEHEART))
return FALSE
if(dna && dna.species && (HAS_TRAIT(src, TRAIT_NOBLOOD) || isnull(dna.species.mutantheart))) //not all carbons have species!
if(dna && dna.species && (!CAN_HAVE_BLOOD(src) || isnull(dna.species.mutantheart))) //not all carbons have species!
return FALSE
return TRUE

Some files were not shown because too many files have changed in this diff Show More