mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-20 12:35:33 +01:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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("↳ 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user