Files
Yogstation/code/modules/mob/living/living.dm
Ling a737b7291e Fix a ton of harddels (#17803)
* Fix a ton of harddels

* Out of scope

* Stupid
2023-02-11 16:35:33 +00:00

1471 lines
46 KiB
Plaintext

/mob/living/Initialize()
. = ..()
if(unique_name)
name = "[name] ([rand(1, 1000)])"
real_name = name
var/datum/atom_hud/data/human/medical/advanced/medhud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
medhud.add_to_hud(src)
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.add_to_hud(src)
faction += "[REF(src)]"
GLOB.mob_living_list += src
initialize_footstep()
if(startDead)
death(FALSE)
/mob/living/proc/initialize_footstep()
AddComponent(/datum/component/footstep)
/mob/living/prepare_huds()
..()
prepare_data_huds()
/mob/living/proc/prepare_data_huds()
med_hud_set_health()
med_hud_set_status()
/mob/living/Destroy()
for(var/datum/status_effect/effect as anything in status_effects)
// The status effect calls on_remove when its mob is deleted
if(effect.on_remove_on_mob_delete)
qdel(effect)
else
effect.be_replaced()
if(ranged_ability)
ranged_ability.remove_ranged_ability(src)
if(buckled)
buckled.unbuckle_mob(src,force=1)
remove_from_all_data_huds()
GLOB.mob_living_list -= src
QDEL_LIST(diseases)
QDEL_LIST(surgeries)
return ..()
/mob/living/onZImpact(turf/T, levels)
ZImpactDamage(T, levels)
return ..()
/mob/living/proc/ZImpactDamage(turf/T, levels)
visible_message(span_danger("[src] crashes into [T] with a sickening noise!"))
adjustBruteLoss((levels * 5) ** 1.5)
Knockdown(levels * 50)
/mob/living/proc/OpenCraftingMenu()
return
//Generic Bump(). Override MobBump() and ObjBump() instead of this.
/mob/living/Bump(atom/A)
if(..()) //we are thrown onto something
return
if (buckled || now_pushing)
return
if(ismob(A))
var/mob/M = A
if(MobBump(M))
return
if(isobj(A))
var/obj/O = A
if(ObjBump(O))
return
if(ismovable(A))
var/atom/movable/AM = A
if(PushAM(AM, move_force))
return
/mob/living/Bumped(atom/movable/AM)
..()
last_bumped = world.time
//Called when we bump onto a mob
/mob/living/proc/MobBump(mob/M)
//Even if we don't push/swap places, we "touched" them, so spread fire
spreadFire(M)
if(now_pushing)
return TRUE
var/they_can_move = TRUE
if(isliving(M))
var/mob/living/L = M
they_can_move = L.mobility_flags & MOBILITY_MOVE
//Also spread diseases
for(var/thing in diseases)
var/datum/disease/D = thing
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
L.ContactContractDisease(D)
for(var/thing in L.diseases)
var/datum/disease/D = thing
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
ContactContractDisease(D)
//Should stop you pushing a restrained person out of the way
if(L.pulledby && L.pulledby != src && L.restrained())
if(!(world.time % 5))
to_chat(src, span_warning("[L] is restrained, you cannot push past."))
return TRUE
if(L.pulling)
if(ismob(L.pulling))
var/mob/P = L.pulling
if(P.restrained())
if(!(world.time % 5))
to_chat(src, span_warning("[L] is restraining [P], you cannot push past."))
return TRUE
if(moving_diagonally)//no mob swap during diagonal moves.
return TRUE
if(!M.buckled && !M.has_buckled_mobs())
var/mob_swap = FALSE
var/too_strong = (M.move_resist > move_force) //can't swap with immovable objects unless they help us
if(!they_can_move) //we have to physically move them
if(!too_strong)
mob_swap = TRUE
else
//You can swap with the person you are dragging on grab intent, and restrained people in most cases
if(M.pulledby == src && a_intent == INTENT_GRAB && !too_strong)
mob_swap = TRUE
else if(
!(HAS_TRAIT(M, TRAIT_NOMOBSWAP) || HAS_TRAIT(src, TRAIT_NOMOBSWAP))&&\
((M.restrained() && !too_strong) || M.a_intent == INTENT_HELP) &&\
(restrained() || a_intent == INTENT_HELP)
)
mob_swap = TRUE
if(mob_swap)
//switch our position with M
if(loc && !loc.Adjacent(M.loc))
return TRUE
now_pushing = 1
var/oldloc = loc
var/oldMloc = M.loc
var/M_passmob = (M.pass_flags & PASSMOB) // we give PASSMOB to both mobs to avoid bumping other mobs during swap.
var/src_passmob = (pass_flags & PASSMOB)
M.pass_flags |= PASSMOB
pass_flags |= PASSMOB
var/move_failed = FALSE
if(!M.Move(oldloc) || !Move(oldMloc))
M.forceMove(oldMloc)
forceMove(oldloc)
move_failed = TRUE
if(!src_passmob)
pass_flags &= ~PASSMOB
if(!M_passmob)
M.pass_flags &= ~PASSMOB
now_pushing = 0
if(!move_failed)
return TRUE
//okay, so we didn't switch. but should we push?
//not if he's not CANPUSH of course
if(!(M.status_flags & CANPUSH))
return TRUE
if(isliving(M))
var/mob/living/L = M
if(HAS_TRAIT(L, TRAIT_PUSHIMMUNE))
return TRUE
//If they're a human, and they're not in help intent, block pushing
if(ishuman(M) && (M.a_intent != INTENT_HELP))
return TRUE
//anti-riot equipment is also anti-push
for(var/obj/item/I in M.held_items)
if(!istype(M, /obj/item/clothing))
if(prob(I.block_chance*2))
return
/mob/living/get_photo_description(obj/item/camera/camera)
var/list/mob_details = list()
var/list/holding = list()
var/len = length(held_items)
if(len)
for(var/obj/item/I in held_items)
if(!holding.len)
holding += "They are holding \a [I]"
else if(held_items.Find(I) == len)
holding += ", and \a [I]."
else
holding += ", \a [I]"
holding += "."
mob_details += "You can also see [src] on the photo[health < (maxHealth * 0.75) ? ", looking a bit hurt":""][holding ? ". [holding.Join("")]":"."]."
return mob_details.Join("")
//Called when we bump onto an obj
/mob/living/proc/ObjBump(obj/O)
return
//Called when we want to push an atom/movable
/mob/living/proc/PushAM(atom/movable/AM, force = move_force)
if(now_pushing)
return TRUE
if(moving_diagonally)// no pushing during diagonal moves.
return TRUE
if(!client && (mob_size < MOB_SIZE_SMALL))
return
now_pushing = TRUE
var/t = get_dir(src, AM)
var/push_anchored = FALSE
if((AM.move_resist * MOVE_FORCE_CRUSH_RATIO) <= force)
if(move_crush(AM, move_force, t))
push_anchored = TRUE
if((AM.move_resist * MOVE_FORCE_FORCEPUSH_RATIO) <= force) //trigger move_crush and/or force_push regardless of if we can push it normally
if(force_push(AM, move_force, t, push_anchored))
push_anchored = TRUE
if((AM.anchored && !push_anchored) || (force < (AM.move_resist * MOVE_FORCE_PUSH_RATIO)))
now_pushing = FALSE
return
if (istype(AM, /obj/structure/window))
var/obj/structure/window/W = AM
if(W.fulltile)
for(var/obj/structure/window/win in get_step(W,t))
now_pushing = FALSE
return
if(pulling == AM)
stop_pulling()
var/current_dir
if(isliving(AM))
current_dir = AM.dir
if(AM.Move(get_step(AM.loc, t), t, glide_size))
Move(get_step(loc, t), t)
if(current_dir)
AM.setDir(current_dir)
now_pushing = FALSE
/mob/living/start_pulling(atom/movable/AM, state, force = pull_force, supress_message = FALSE)
if(!AM || !src)
return FALSE
if(!(AM.can_be_pulled(src, state, force)))
return FALSE
if(throwing || !(mobility_flags & MOBILITY_PULL))
return FALSE
AM.add_fingerprint(src)
// If we're pulling something then drop what we're currently pulling and pull this instead.
if(pulling)
// Are we trying to pull something we are already pulling? Then just stop here, no need to continue.
if(AM == pulling)
return
stop_pulling()
changeNext_move(CLICK_CD_GRABBING)
if(AM.pulledby)
if(!supress_message)
visible_message(span_danger("[src] has pulled [AM] from [AM.pulledby]'s grip."))
log_combat(AM, AM.pulledby, "pulled from", src)
AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once.
pulling = AM
AM.pulledby = src
if(!supress_message)
var/sound_to_play = 'sound/weapons/thudswoosh.ogg'
if(ishuman(src))
var/mob/living/carbon/human/H = src
if(H.dna.species.grab_sound)
sound_to_play = H.dna.species.grab_sound
if(HAS_TRAIT(H, TRAIT_STRONG_GRABBER))
sound_to_play = null
playsound(src.loc, sound_to_play, 50, 1, -1)
update_pull_hud_icon()
if(ismob(AM))
var/mob/M = AM
log_combat(src, M, "grabbed", addition="passive grab")
if(!supress_message && !(iscarbon(AM) && HAS_TRAIT(src, TRAIT_STRONG_GRABBER)))
visible_message(span_warning("[src] has grabbed [M] passively!"))
if(!iscarbon(src))
M.LAssailant = null
else
M.LAssailant = WEAKREF(usr)
if(isliving(M))
var/mob/living/L = M
//Share diseases that are spread by touch
for(var/thing in diseases)
var/datum/disease/D = thing
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
L.ContactContractDisease(D)
for(var/thing in L.diseases)
var/datum/disease/D = thing
if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
ContactContractDisease(D)
if(iscarbon(L))
var/mob/living/carbon/C = L
if(HAS_TRAIT(src, TRAIT_STRONG_GRABBER))
C.grippedby(src)
update_pull_movespeed()
set_pull_offsets(M, state)
/mob/living/proc/set_pull_offsets(mob/living/M, grab_state = GRAB_PASSIVE)
if(M.buckled)
return //don't make them change direction or offset them if they're buckled into something.
var/offset = 0
switch(grab_state)
if(GRAB_PASSIVE)
offset = GRAB_PIXEL_SHIFT_PASSIVE
if(GRAB_AGGRESSIVE)
offset = GRAB_PIXEL_SHIFT_AGGRESSIVE
if(GRAB_NECK)
offset = GRAB_PIXEL_SHIFT_NECK
if(GRAB_KILL)
offset = GRAB_PIXEL_SHIFT_NECK
M.setDir(get_dir(M, src))
switch(M.dir)
if(NORTH)
animate(M, pixel_x = 0, pixel_y = offset, 3)
if(SOUTH)
animate(M, pixel_x = 0, pixel_y = -offset, 3)
if(EAST)
if(M.lying == 270) //update the dragged dude's direction if we've turned
M.lying = 90
M.update_transform() //force a transformation update, otherwise it'll take a few ticks for update_mobility() to do so
M.lying_prev = M.lying
animate(M, pixel_x = offset, pixel_y = 0, 3)
if(WEST)
if(M.lying == 90)
M.lying = 270
M.update_transform()
M.lying_prev = M.lying
animate(M, pixel_x = -offset, pixel_y = 0, 3)
/mob/living/proc/reset_pull_offsets(mob/living/M, override)
if(!override && M.buckled)
return
animate(M, pixel_x = 0, pixel_y = 0, 1)
//mob verbs are a lot faster than object verbs
//for more info on why this is not atom/pull, see examinate() in mob.dm
/mob/living/verb/pulled(atom/movable/AM as mob|obj in oview(1))
set name = "Pull"
set category = "Object"
if(istype(AM) && Adjacent(AM))
start_pulling(AM)
else
stop_pulling()
/mob/living/stop_pulling()
if(ismob(pulling))
reset_pull_offsets(pulling)
..()
update_pull_movespeed()
update_pull_hud_icon()
/mob/living/verb/stop_pulling1()
set name = "Stop Pulling"
set category = "IC"
stop_pulling()
//same as above
/mob/living/pointed(atom/A as mob|obj|turf in view())
if(incapacitated())
return FALSE
if(HAS_TRAIT(src, TRAIT_DEATHCOMA))
return FALSE
if(!..())
return FALSE
visible_message("<b>[src]</b> points at [A].", span_notice("You point at [A]."))
return TRUE
/mob/living/verb/succumb(whispered as null)
set hidden = TRUE
if (InCritical())
log_message("Has [whispered ? "whispered his final words" : "succumbed to death"] while in [InFullCritical() ? "hard":"soft"] critical with [round(health, 0.1)] points of health!", LOG_ATTACK)
adjustOxyLoss(health - HEALTH_THRESHOLD_DEAD)
updatehealth()
if(!whispered)
to_chat(src, span_notice("You have given up life and succumbed to death."))
death()
/mob/living/incapacitated(ignore_restraints = FALSE, ignore_grab = FALSE, check_immobilized = FALSE, ignore_stasis = FALSE)
if(stat || IsUnconscious() || IsStun() || IsParalyzed() || (check_immobilized && IsImmobilized()) || (!ignore_restraints && restrained(ignore_grab)) || (!ignore_stasis && IS_IN_STASIS(src)))
return TRUE
/mob/living/canUseStorage()
if (get_num_arms() <= 0)
return FALSE
return TRUE
/mob/living/proc/InCritical()
return (health <= crit_threshold && (stat == SOFT_CRIT || stat == UNCONSCIOUS))
/mob/living/proc/InFullCritical()
return (health <= HEALTH_THRESHOLD_FULLCRIT && stat == UNCONSCIOUS)
//This proc is used for mobs which are affected by pressure to calculate the amount of pressure that actually
//affects them once clothing is factored in. ~Errorage
/mob/living/proc/calculate_affecting_pressure(pressure)
return pressure
/mob/living/proc/adjustBodyTemp(actual, desired, incrementboost)
var/temperature = actual
var/difference = abs(actual-desired) //get difference
var/increments = difference/10 //find how many increments apart they are
var/change = increments*incrementboost // Get the amount to change by (x per increment)
// Too cold
if(actual < desired)
temperature += change
if(actual > desired)
temperature = desired
// Too hot
if(actual > desired)
temperature -= change
if(actual < desired)
temperature = desired
return temperature
/mob/living/proc/getMaxHealth()
return maxHealth
/mob/living/proc/setMaxHealth(newMaxHealth)
maxHealth = newMaxHealth
// MOB PROCS //END
/mob/living/proc/mob_sleep()
set name = "Sleep"
set category = "IC"
if(IsSleeping())
to_chat(src, span_notice("You are already sleeping."))
return
else
if(tgui_alert(usr, "You sure you want to sleep for a while?", "Sleep", list("Yes", "No")) == "Yes")
SetSleeping(400) //Short nap
update_mobility()
/mob/proc/get_contents()
/mob/living/proc/lay_down()
set name = "Rest"
set category = "IC"
if(!resting)
set_resting(TRUE, FALSE)
else
if(do_after(src, 1 SECONDS, src))
set_resting(FALSE, FALSE)
else
to_chat(src, span_notice("You fail to get up."))
/mob/living/proc/set_resting(rest, silent = TRUE)
if(!silent)
if(rest)
to_chat(src, span_notice("You are now resting."))
else
to_chat(src, span_notice("You get up."))
resting = rest
update_resting()
/mob/living/proc/update_resting()
update_rest_hud_icon()
update_mobility()
//Recursive function to find everything a mob is holding. Really shitty proc tbh.
/mob/living/get_contents()
var/list/ret = list()
ret |= contents //add our contents
for(var/i in ret.Copy()) //iterate storage objects
var/atom/A = i
SEND_SIGNAL(A, COMSIG_TRY_STORAGE_RETURN_INVENTORY, ret)
for(var/obj/item/folder/F in ret.Copy()) //very snowflakey-ly iterate folders
ret |= F.contents
return ret
// Living mobs use can_inject() to make sure that the mob is not syringe-proof in general.
/mob/living/proc/can_inject()
return TRUE
/mob/living/is_injectable(mob/user, allowmobs = TRUE)
return (allowmobs && reagents && can_inject(user))
/mob/living/is_drawable(mob/user, allowmobs = TRUE)
return (allowmobs && reagents && can_inject(user))
/mob/living/proc/updatehealth()
if(status_flags & GODMODE)
return
health = maxHealth - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss()
staminaloss = getStaminaLoss()
update_stat()
med_hud_set_health()
med_hud_set_status()
update_health_hud()
/mob/living/update_health_hud()
var/severity = 0
var/healthpercent = (health/maxHealth) * 100
if(hud_used?.healthdoll) //to really put you in the boots of a simplemob
var/atom/movable/screen/healthdoll/living/livingdoll = hud_used.healthdoll
switch(healthpercent)
if(100 to INFINITY)
livingdoll.icon_state = "living0"
if(80 to 100)
livingdoll.icon_state = "living1"
severity = 1
if(60 to 80)
livingdoll.icon_state = "living2"
severity = 2
if(40 to 60)
livingdoll.icon_state = "living3"
severity = 3
if(20 to 40)
livingdoll.icon_state = "living4"
severity = 4
if(1 to 20)
livingdoll.icon_state = "living5"
severity = 5
else
livingdoll.icon_state = "living6"
severity = 6
if(!livingdoll.filtered)
livingdoll.filtered = TRUE
var/icon/mob_mask = icon(icon, icon_state)
if(mob_mask.Height() > world.icon_size || mob_mask.Width() > world.icon_size)
var/health_doll_icon_state = health_doll_icon ? health_doll_icon : "megasprite"
mob_mask = icon('icons/mob/screen_gen.dmi', health_doll_icon_state) //swap to something generic if they have no special doll
UNLINT(livingdoll.filters += filter(type="alpha", icon = mob_mask))
livingdoll.filters += filter(type="drop_shadow", size = -1)
if(severity > 0)
overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity)
else
clear_fullscreen("brute")
//proc used to ressuscitate a mob
/mob/living/proc/revive(full_heal = 0, admin_revive = 0)
if(full_heal)
fully_heal(admin_revive)
if(stat == DEAD && can_be_revived()) //in some cases you can't revive (e.g. no brain)
remove_from_dead_mob_list()
add_to_alive_mob_list()
set_suicide(FALSE)
stat = UNCONSCIOUS //the mob starts unconscious,
blind_eyes(1)
losebreath = 0 //losebreath stacks were persisting beyond death, immediately killing again after revival until they ran out natureally from time
updatehealth() //then we check if the mob should wake up.
update_mobility()
update_sight()
clear_alert("not_enough_oxy")
reload_fullscreen()
revive_guardian()
. = 1
if(mind)
for(var/S in mind.spell_list)
var/obj/effect/proc_holder/spell/spell = S
spell.updateButtonIcon()
/mob/living/proc/remove_CC(should_update_mobility = TRUE)
SetStun(0, FALSE)
SetKnockdown(0, FALSE)
SetImmobilized(0, FALSE)
SetParalyzed(0, FALSE)
SetSleeping(0, FALSE)
setStaminaLoss(0)
SetUnconscious(0, FALSE)
if(should_update_mobility)
update_mobility()
//proc used to completely heal a mob.
/mob/living/proc/fully_heal(admin_revive = 0)
restore_blood()
setToxLoss(0, 0) //zero as second argument not automatically call updatehealth().
setOxyLoss(0, 0)
setCloneLoss(0, 0)
remove_CC(FALSE)
set_disgust(0)
radiation = 0
set_nutrition(NUTRITION_LEVEL_FED + 50)
bodytemperature = BODYTEMP_NORMAL
set_blindness(0)
set_blurriness(0)
set_dizziness(0)
cure_nearsighted()
cure_blind()
cure_husk()
hallucination = 0
heal_overall_damage(INFINITY, INFINITY, INFINITY, null, TRUE) //heal brute and burn dmg on both organic and robotic limbs, and update health right away.
ExtinguishMob()
losebreath = 0
fire_stacks = 0
confused = 0
dizziness = 0
drowsyness = 0
stuttering = 0
slurring = 0
jitteriness = 0
var/datum/component/mood/mood = GetComponent(/datum/component/mood)
if (mood)
mood.remove_temp_moods(admin_revive)
update_mobility()
stop_sound_channel(CHANNEL_HEARTBEAT)
if(admin_revive)
cure_fakedeath()
//proc called by revive(), to check if we can actually ressuscitate the mob (we don't want to revive him and have him instantly die again)
/mob/living/proc/can_be_revived()
. = 1
if(health <= HEALTH_THRESHOLD_DEAD)
return 0
/mob/living/proc/update_damage_overlays()
return
/mob/living/Move(atom/newloc, direct, glide_size_override)
if (buckled && buckled.loc != newloc) //not updating position
if (!buckled.anchored)
return buckled.Move(newloc, direct, glide_size)
else
return 0
var/old_direction = dir
var/turf/T = loc
if(pulling)
update_pull_movespeed()
. = ..()
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1 && (pulledby != moving_from_pull))//separated from our puller and not in the middle of a diagonal move.
pulledby.stop_pulling()
else
if(isliving(pulledby))
var/mob/living/L = pulledby
L.set_pull_offsets(src, pulledby.grab_state)
if(active_storage && !(CanReach(active_storage.parent,view_only = TRUE)))
active_storage.close(src)
if(!(mobility_flags & MOBILITY_STAND) && !buckled && prob(getBruteLoss()*200/maxHealth))
makeTrail(newloc, T, old_direction)
/mob/living/proc/makeTrail(turf/target_turf, turf/start, direction)
if(!has_gravity() || !isturf(start) || !blood_volume)
return
var/blood_exists = locate(/obj/effect/decal/cleanable/trail_holder) in start
var/trail_type = getTrail()
if(!trail_type)
return
var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1)
if(blood_volume < max(BLOOD_VOLUME_NORMAL(src)*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold
return
var/bleed_amount = bleedDragAmount()
blood_volume = max(blood_volume - bleed_amount, 0) //that depends on our brute damage.
var/newdir = get_dir(target_turf, start)
if(newdir != direction)
newdir = newdir | direction
if(newdir == (NORTH|SOUTH))
newdir = NORTH
else if(newdir == (EAST|WEST))
newdir = EAST
if((newdir in GLOB.cardinals) && (prob(50)))
newdir = turn(get_dir(target_turf, start), 180)
if(!blood_exists)
new /obj/effect/decal/cleanable/trail_holder(start, get_static_viruses())
for(var/obj/effect/decal/cleanable/trail_holder/TH in start)
if((!(newdir in TH.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && TH.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled)
TH.existing_dirs += newdir
TH.add_overlay(image('icons/effects/blood.dmi', trail_type, dir = newdir))
TH.transfer_mob_blood_dna(src)
/mob/living/carbon/human/makeTrail(turf/T)
if((NOBLOOD in dna.species.species_traits) || !is_bleeding() || bleedsuppress)
return
..()
///Returns how much blood we're losing from being dragged a tile, from [mob/living/proc/makeTrail]
/mob/living/proc/bleedDragAmount()
var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1)
return max(1, brute_ratio * 2)
/mob/living/carbon/bleedDragAmount()
var/bleed_amount = 0
for(var/i in all_wounds)
var/datum/wound/iter_wound = i
bleed_amount += iter_wound.drag_bleed_amount()
return bleed_amount
/mob/living/proc/getTrail()
if(getBruteLoss() < 300)
if(ispolysmorph(src))
return pick("xltrails_1", "xltrails_2")
return pick("ltrails_1", "ltrails_2")
else
if(ispolysmorph(src))
return pick("xttrails_1", "xttrails_2")
return pick("trails_1", "trails_2")
/mob/living/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0)
if(buckled)
return
if(client && client.move_delay >= world.time + world.tick_lag*2)
pressure_resistance_prob_delta -= 10
var/list/turfs_to_check = list()
if(has_limbs)
var/turf/T = get_step(src, angle2dir(dir2angle(direction)+90))
if (T)
turfs_to_check += T
T = get_step(src, angle2dir(dir2angle(direction)-90))
if(T)
turfs_to_check += T
for(var/t in turfs_to_check)
T = t
if(T.density)
pressure_resistance_prob_delta -= 5
continue
for (var/atom/movable/AM in T)
if (AM.density && AM.anchored)
pressure_resistance_prob_delta -= 5
break
if(!force_moving)
..(pressure_difference, direction, pressure_resistance_prob_delta)
/mob/living/can_resist()
return !((next_move > world.time) || incapacitated(ignore_restraints = TRUE, ignore_stasis = TRUE))
/mob/living/verb/resist()
set name = "Resist"
set category = "IC"
if(!can_resist())
return
changeNext_move(CLICK_CD_RESIST)
SEND_SIGNAL(src, COMSIG_LIVING_RESIST, src)
//resisting grabs (as if it helps anyone...)
if(!restrained(ignore_grab = 1) && pulledby)
log_combat(src, pulledby, "resisted grab")
resist_grab()
return
//unbuckling yourself
if(buckled && last_special <= world.time)
resist_buckle()
//Breaking out of a container (Locker, sleeper, cryo...)
else if(isobj(loc))
var/obj/C = loc
C.container_resist(src)
else if(mobility_flags & MOBILITY_MOVE)
if(on_fire)
resist_fire() //stop, drop, and roll
else if(last_special <= world.time)
resist_restraints() //trying to remove cuffs.
/mob/proc/resist_grab(moving_resist)
return 1 //returning 0 means we successfully broke free
/mob/living/resist_grab(moving_resist)
. = TRUE
if(pulledby.grab_state || resting)
var/altered_grab_state = pulledby.grab_state
if(resting && pulledby.grab_state < GRAB_KILL) //If resting, resisting out of a grab is equivalent to 1 grab state higher. wont make the grab state exceed the normal max, however
altered_grab_state++
var/resist_chance = BASE_GRAB_RESIST_CHANCE // see defines/combat.dm
resist_chance = max((resist_chance/altered_grab_state)-sqrt((getBruteLoss()+getFireLoss()+getOxyLoss()+getToxLoss()+getCloneLoss())*0.5+getStaminaLoss()), 0) //stamina loss is weighted twice as heavily as the other damage types in this calculation
if(prob(resist_chance))
visible_message(span_danger("[src] has broken free of [pulledby]'s grip!"))
log_combat(pulledby, src, "broke grab")
pulledby.stop_pulling()
return FALSE
else
adjustStaminaLoss(rand(8,15))//8 is from 7.5 rounded up
visible_message(span_danger("[src] struggles as they fail to break free of [pulledby]'s grip!"))
if(moving_resist && client) //we resisted by trying to move
client.move_delay = world.time + 20
else
pulledby.stop_pulling()
return FALSE
/mob/living/proc/resist_buckle()
buckled.user_unbuckle_mob(src,src)
/mob/living/proc/resist_fire()
return
/mob/living/proc/resist_restraints()
return
/mob/living/proc/get_visible_name()
return name
/mob/living/update_gravity(has_gravity,override = 0)
if(!SSticker.HasRoundStarted())
return
if(has_gravity)
if(has_gravity == 1)
clear_alert("gravity")
else
if(has_gravity >= GRAVITY_DAMAGE_TRESHOLD)
throw_alert("gravity", /atom/movable/screen/alert/veryhighgravity)
else
throw_alert("gravity", /atom/movable/screen/alert/highgravity)
else
throw_alert("gravity", /atom/movable/screen/alert/weightless)
if(!override && !is_flying())
float(!has_gravity)
/mob/living/float(on)
if(throwing)
return
var/fixed = 0
if(anchored || (buckled && buckled.anchored))
fixed = 1
if(on && !(movement_type & FLOATING) && !fixed)
animate(src, pixel_y = pixel_y + 2, time = 1 SECONDS, loop = -1)
animate(pixel_y = pixel_y - 2, time = 1 SECONDS)
setMovetype(movement_type | FLOATING)
else if(((!on || fixed) && (movement_type & FLOATING)))
animate(src, pixel_y = get_standard_pixel_y_offset(lying), time = 1 SECONDS)
setMovetype(movement_type & ~FLOATING)
// The src mob is trying to strip an item from someone
// Override if a certain type of mob should be behave differently when stripping items (can't, for example)
/mob/living/stripPanelUnequip(obj/item/what, mob/who, where)
if(!what.canStrip(who))
to_chat(src, span_warning("You can't remove \the [what.name], it appears to be stuck!"))
return
who.visible_message(span_danger("[src] tries to remove [who]'s [what.name]."), \
span_userdanger("[src] tries to remove [who]'s [what.name]."))
what.add_fingerprint(src)
SEND_SIGNAL(what, COMSIG_ITEM_PRESTRIP)
if(do_mob(src, who, what.strip_delay))
if(what && Adjacent(who))
if(islist(where))
var/list/L = where
if(what == who.get_item_for_held_index(L[2]))
if(what.doStrip(src, who))
log_combat(src, who, "stripped [what] off")
if(what == who.get_item_by_slot(where))
if(what.doStrip(src, who))
log_combat(src, who, "stripped [what] off")
if(Adjacent(who)) //update inventory window
who.show_inv(src)
else
src << browse(null,"window=mob[REF(who)]")
// The src mob is trying to place an item on someone
// Override if a certain mob should be behave differently when placing items (can't, for example)
/mob/living/stripPanelEquip(obj/item/what, mob/who, where)
what = src.get_active_held_item()
if(what && (HAS_TRAIT(what, TRAIT_NODROP)))
to_chat(src, span_warning("You can't put \the [what.name] on [who], it's stuck to your hand!"))
return
if(what)
var/list/where_list
var/final_where
if(islist(where))
where_list = where
final_where = where[1]
else
final_where = where
if(!what.mob_can_equip(who, src, final_where, TRUE, TRUE))
to_chat(src, span_warning("\The [what.name] doesn't fit in that place!"))
return
visible_message(span_notice("[src] tries to put [what] on [who]."))
if(do_mob(src, who, what.equip_delay_other))
if(what && Adjacent(who) && what.mob_can_equip(who, src, final_where, TRUE, TRUE))
if(temporarilyRemoveItemFromInventory(what))
if(where_list)
if(!who.put_in_hand(what, where_list[2]))
what.forceMove(get_turf(who))
else
who.equip_to_slot(what, where, TRUE)
if(Adjacent(who)) //update inventory window
who.show_inv(src)
else
src << browse(null,"window=mob[REF(who)]")
/mob/living/singularity_pull(S, current_size)
..()
if(current_size >= STAGE_SIX) //your puny magboots/wings/whatever will not save you against supermatter singularity
throw_at(S, 14, 3, src, TRUE)
else if(!src.mob_negates_gravity())
step_towards(src,S)
/mob/living/proc/do_jitter_animation(jitteriness)
var/amplitude = min(4, (jitteriness/100) + 1)
var/pixel_x_diff = rand(-amplitude, amplitude)
var/pixel_y_diff = rand(-amplitude/3, amplitude/3)
var/final_pixel_x = get_standard_pixel_x_offset(lying)
var/final_pixel_y = get_standard_pixel_y_offset(lying)
animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff , time = 0.2 SECONDS, loop = 6)
animate(pixel_x = final_pixel_x , pixel_y = final_pixel_y , time = 0.2 SECONDS)
setMovetype(movement_type & ~FLOATING) // If we were without gravity, the bouncing animation got stopped, so we make sure to restart it in next life().
/mob/living/proc/get_temperature(datum/gas_mixture/environment)
var/loc_temp = environment ? environment.return_temperature() : T0C
if(isobj(loc))
var/obj/oloc = loc
var/obj_temp = oloc.return_temperature()
if(obj_temp != null)
loc_temp = obj_temp
else if(isspaceturf(get_turf(src)))
var/turf/heat_turf = get_turf(src)
loc_temp = heat_turf.temperature
return loc_temp
/mob/living/proc/get_standard_pixel_x_offset(lying = 0)
return initial(pixel_x)
/mob/living/proc/get_standard_pixel_y_offset(lying = 0)
return initial(pixel_y)
/mob/living/cancel_camera()
..()
cameraFollow = null
/mob/living/proc/can_track(mob/living/user)
//basic fast checks go first. When overriding this proc, I recommend calling ..() at the end.
var/turf/T = get_turf(src)
if(!T)
return 0
if(is_centcom_level(T.z)) //dont detect mobs on centcom
return 0
if(is_away_level(T.z))
return 0
if(user != null && src == user)
return 0
if(invisibility || alpha == 0)//cloaked
return 0
if(digitalcamo || digitalinvis)
return 0
// Now, are they viewable by a camera? (This is last because it's the most intensive check)
if(!near_camera(src))
return 0
return 1
//used in datum/reagents/reaction() proc
/mob/living/proc/get_permeability_protection(list/target_zones)
return 0
/mob/living/proc/harvest(mob/living/user) //used for extra objects etc. in butchering
return
// Hotkeys Exist, so this stops it from making runtimes
/mob/living/proc/give()
return
/mob/living/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE)
if(incapacitated())
to_chat(src, span_warning("You can't do that right now!"))
return FALSE
if(be_close && !in_range(M, src))
to_chat(src, span_warning("You are too far away!"))
return FALSE
if(!no_dextery)
to_chat(src, span_warning("You don't have the dexterity to do this!"))
return FALSE
return TRUE
/mob/living/proc/can_use_guns(obj/item/G)//actually used for more than guns!
if(G.trigger_guard != TRIGGER_GUARD_ALLOW_ALL && !IsAdvancedToolUser())
to_chat(src, span_warning("You don't have the dexterity to do this!"))
return FALSE
return TRUE
/mob/living/proc/update_stamina()
return
/mob/living/carbon/alien/update_stamina()
return
/mob/living/proc/owns_soul()
if(mind)
return mind.soulOwner == mind
return TRUE
/mob/living/proc/return_soul()
hellbound = 0
if(mind)
var/datum/antagonist/devil/devilInfo = mind.soulOwner.has_antag_datum(/datum/antagonist/devil)
if(devilInfo)//Not sure how this could be null, but let's just try anyway.
devilInfo.remove_soul(mind)
mind.soulOwner = mind
/mob/living/proc/has_bane(banetype)
var/datum/antagonist/devil/devilInfo = is_devil(src)
return devilInfo && banetype == devilInfo.bane
/mob/living/proc/check_weakness(obj/item/weapon, mob/living/attacker)
if(mind && mind.has_antag_datum(/datum/antagonist/devil))
return check_devil_bane_multiplier(weapon, attacker)
return 1 //This is not a boolean, it's the multiplier for the damage the weapon does.
/mob/living/proc/check_acedia()
if(mind && mind.has_objective(/datum/objective/sintouched/acedia))
return TRUE
return FALSE
/mob/living/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, quickstart = TRUE)
stop_pulling()
. = ..()
// Called when we are hit by a bolt of polymorph and changed
// Generally the mob we are currently in is about to be deleted
/mob/living/proc/wabbajack_act(mob/living/new_mob)
new_mob.name = real_name
new_mob.real_name = real_name
if(mind)
mind.transfer_to(new_mob)
else
new_mob.key = key
for(var/para in hasparasites())
var/mob/living/simple_animal/hostile/guardian/G = para
G.summoner = new_mob
G.Recall()
to_chat(G, span_holoparasite("Your summoner has changed form!"))
/mob/living/rad_act(amount)
. = ..()
if(!amount || (amount < RAD_MOB_SKIN_PROTECTION) || HAS_TRAIT(src, TRAIT_RADIMMUNE))
return
amount -= RAD_BACKGROUND_RADIATION // This will always be at least 1 because of how skin protection is calculated
var/blocked = getarmor(null, RAD)
if(amount > RAD_BURN_THRESHOLD)
apply_damage((amount-RAD_BURN_THRESHOLD)/RAD_BURN_THRESHOLD, BURN, null, blocked)
apply_effect((amount*RAD_MOB_COEFFICIENT)/max(1, (radiation**2)*RAD_OVERDOSE_REDUCTION), EFFECT_IRRADIATE, blocked)
///Return any anti magic atom on this mob that matches the magic type
/mob/living/anti_magic_check(magic = TRUE, holy = FALSE, tinfoil = FALSE, chargecost = 1, self = FALSE)
if(!magic && !holy && !tinfoil)
return
var/list/protection_sources = list()
if(SEND_SIGNAL(src, COMSIG_MOB_RECEIVE_MAGIC, src, magic, holy, tinfoil, chargecost, self, protection_sources) & COMPONENT_BLOCK_MAGIC)
if(protection_sources.len)
return pick(protection_sources)
else
return src
if((magic && HAS_TRAIT(src, TRAIT_ANTIMAGIC)) || (holy && HAS_TRAIT(src, TRAIT_HOLY)))
return src
/mob/living/proc/fakefireextinguish()
return
/mob/living/proc/fakefire()
return
/mob/living/proc/unfry_mob() //Callback proc to tone down spam from multiple sizzling frying oil dipping.
REMOVE_TRAIT(src, TRAIT_OIL_FRIED, "cooking_oil_react")
/**
* add_body_temperature_change Adds modifications to the body temperature
*
* This collects all body temperature changes that the mob is experiencing to the list body_temp_changes
* the aggrogate result is used to derive the new body temperature for the mob
*
* arguments:
* * key_name (str) The unique key for this change, if it already exist it will be overridden
* * amount (int) The amount of change from the base body temperature
*/
/mob/living/proc/add_body_temperature_change(key_name, amount)
body_temp_changes["[key_name]"] = amount
/**
* remove_body_temperature_change Removes the modifications to the body temperature
*
* This removes the recorded change to body temperature from the body_temp_changes list
*
* arguments:
* * key_name (str) The unique key for this change that will be removed
*/
/mob/living/proc/remove_body_temperature_change(key_name)
body_temp_changes -= key_name
/**
* get_body_temp_normal_change Returns the aggregate change to body temperature
*
* This aggregates all the changes in the body_temp_changes list and returns the result
*/
/mob/living/proc/get_body_temp_normal_change()
var/total_change = 0
if(body_temp_changes.len)
for(var/change in body_temp_changes)
total_change += body_temp_changes["[change]"]
return total_change
/**
* get_body_temp_normal Returns the mobs normal body temperature with any modifications applied
*
* This applies the result from proc/get_body_temp_normal_change() against the BODYTEMP_NORMAL and returns the result
*
* arguments:
* * apply_change (optional) Default True This applies the changes to body temperature normal
*/
/mob/living/proc/get_body_temp_normal(apply_change=TRUE)
if(!apply_change)
return BODYTEMP_NORMAL
return BODYTEMP_NORMAL + get_body_temp_normal_change()
//Mobs on Fire
/mob/living/proc/IgniteMob()
if(fire_stacks > 0 && !on_fire)
on_fire = 1
src.visible_message(span_warning("[src] catches fire!"), \
span_userdanger("You're set on fire!"))
new/obj/effect/dummy/lighting_obj/moblight/fire(src)
throw_alert("fire", /atom/movable/screen/alert/fire)
update_fire()
SEND_SIGNAL(src, COMSIG_LIVING_IGNITED,src)
return TRUE
return FALSE
/mob/living/proc/ExtinguishMob()
if(on_fire)
on_fire = 0
fire_stacks = 0
for(var/obj/effect/dummy/lighting_obj/moblight/fire/F in src)
qdel(F)
clear_alert("fire")
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "on_fire")
SEND_SIGNAL(src, COMSIG_LIVING_EXTINGUISHED, src)
update_fire()
/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person
if(fire_stacks > 0) //don't let people on fire instantly get -20 fire_stacks, but still let them extinguish themselves. Stops preternis from hurting themselves for trying to put out fire
fire_stacks = clamp(fire_stacks + add_fire_stacks, -1, 20)
else
fire_stacks = clamp(fire_stacks + add_fire_stacks, -20, 20)
if(on_fire && fire_stacks <= 0)
ExtinguishMob()
//Share fire evenly between the two mobs
//Called in MobBump() and Crossed()
/mob/living/proc/spreadFire(mob/living/L)
if(!istype(L))
return
if(on_fire)
if(L.on_fire) // If they were also on fire
var/firesplit = (fire_stacks + L.fire_stacks)/2
fire_stacks = firesplit
L.fire_stacks = firesplit
else // If they were not
fire_stacks /= 2
L.adjust_fire_stacks(fire_stacks)
if(L.IgniteMob()) // Ignite them
log_game("[key_name(src)] bumped into [key_name(L)] and set them on fire")
else if(L.on_fire) // If they were on fire and we were not
L.fire_stacks /= 2
adjust_fire_stacks(L.fire_stacks)
IgniteMob() // Ignite us
//Mobs on Fire end
// used by secbot and monkeys Crossed
/mob/living/proc/knockOver(var/mob/living/carbon/C)
if(C.key) //save us from monkey hordes
C.visible_message("<span class='warning'>[pick( \
"[C] dives out of [src]'s way!", \
"[C] stumbles over [src]!", \
"[C] jumps out of [src]'s path!", \
"[C] trips over [src] and falls!", \
"[C] topples over [src]!", \
"[C] leaps out of [src]'s way!")]</span>")
C.Paralyze(40)
/mob/living/can_be_pulled()
return ..() && !(buckled && buckled.buckle_prevents_pull)
//Updates canmove, lying and icons. Could perhaps do with a rename but I can't think of anything to describe it.
//Robots, animals and brains have their own version so don't worry about them
/mob/living/proc/update_mobility()
var/stat_softcrit = stat == SOFT_CRIT
var/stat_conscious = (stat == CONSCIOUS) || stat_softcrit
var/conscious = !IsUnconscious() && stat_conscious && !HAS_TRAIT(src, TRAIT_DEATHCOMA)
var/chokehold = pulledby && pulledby.grab_state >= GRAB_NECK
var/restrained = restrained()
var/has_legs = get_num_legs()
var/has_arms = get_num_arms()
var/paralyzed = IsParalyzed()
var/stun = IsStun()
var/knockdown = IsKnockdown()
var/ignore_legs = get_leg_ignore()
var/canmove = !IsImmobilized() && !stun && conscious && !paralyzed && !buckled && (!stat_softcrit || !pulledby) && !chokehold && !IsFrozen() && !IS_IN_STASIS(src) && (has_arms || ignore_legs || has_legs)
if(canmove)
mobility_flags |= MOBILITY_MOVE
else
mobility_flags &= ~MOBILITY_MOVE
var/canstand_involuntary = conscious && !stat_softcrit && !knockdown && !chokehold && !paralyzed && (ignore_legs || has_legs) && !(buckled && buckled.buckle_lying)
var/canstand = canstand_involuntary && !resting
var/should_be_lying = !canstand
if(buckled)
if(buckled.buckle_lying != -1)
should_be_lying = buckled.buckle_lying
if(should_be_lying)
mobility_flags &= ~MOBILITY_STAND
if(buckled)
if(buckled.buckle_lying != -1)
lying = buckled.buckle_lying
if(!lying) //force them on the ground
lying = pick(90, 270)
else
mobility_flags |= MOBILITY_STAND
lying = 0
if(should_be_lying || restrained || incapacitated())
mobility_flags &= ~(MOBILITY_UI|MOBILITY_PULL)
else
mobility_flags |= MOBILITY_UI|MOBILITY_PULL
var/canitem = !paralyzed && !stun && conscious && !chokehold && !restrained && has_arms
if(canitem)
mobility_flags |= (MOBILITY_USE | MOBILITY_PICKUP | MOBILITY_STORAGE)
else
mobility_flags &= ~(MOBILITY_USE | MOBILITY_PICKUP | MOBILITY_STORAGE)
if(!(mobility_flags & MOBILITY_USE))
drop_all_held_items()
if(!(mobility_flags & MOBILITY_PULL))
if(pulling)
stop_pulling()
if(!(mobility_flags & MOBILITY_UI))
unset_machine()
density = !lying
if(lying)
if(!lying_prev)
fall(!canstand_involuntary)
if(layer == initial(layer)) //to avoid special cases like hiding larvas.
layer = LYING_MOB_LAYER //so mob lying always appear behind standing mobs
else
if(layer == LYING_MOB_LAYER)
layer = initial(layer)
update_transform()
lying_prev = lying
/mob/living/proc/fall(forced)
if(!(mobility_flags & MOBILITY_USE))
drop_all_held_items()
/mob/living/proc/AddAbility(obj/effect/proc_holder/A)
abilities.Add(A)
A.on_gain(src)
if(A.has_action)
A.action.Grant(src)
/mob/living/proc/RemoveAbility(obj/effect/proc_holder/A)
abilities.Remove(A)
A.on_lose(src)
if(A.action)
A.action.Remove(src)
/mob/living/proc/add_abilities_to_panel()
var/list/L = list()
for(var/obj/effect/proc_holder/A in abilities)
L[++L.len] = list("[A.panel]",A.get_panel_text(),A.name,"[REF(A)]")
return L
/mob/living/lingcheck()
if(mind)
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling)
if(changeling.changeling_speak)
return LINGHIVE_LING
return LINGHIVE_OUTSIDER
if(mind && mind.linglink)
return LINGHIVE_LINK
return LINGHIVE_NONE
/mob/living/forceMove(atom/destination)
stop_pulling()
if(buckled)
buckled.unbuckle_mob(src, force = TRUE)
if(has_buckled_mobs())
unbuckle_all_mobs(force = TRUE)
. = ..()
if(.)
if(client)
reset_perspective()
update_mobility() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
/mob/living/proc/update_z(new_z) // 1+ to register, null to unregister
if (registered_z != new_z)
if (registered_z)
SSmobs.clients_by_zlevel[registered_z] -= src
if (client)
if (new_z)
SSmobs.clients_by_zlevel[new_z] += src
for (var/I in length(SSidlenpcpool.idle_mobs_by_zlevel[new_z]) to 1 step -1) //Backwards loop because we're removing (guarantees optimal rather than worst-case performance), it's fine to use .len here but doesn't compile on 511
var/mob/living/simple_animal/SA = SSidlenpcpool.idle_mobs_by_zlevel[new_z][I]
if (SA)
SA.toggle_ai(AI_ON) // Guarantees responsiveness for when appearing right next to mobs
else
SSidlenpcpool.idle_mobs_by_zlevel[new_z] -= SA
registered_z = new_z
else
registered_z = null
/mob/living/onTransitZ(old_z,new_z)
..()
update_z(new_z)
/mob/living/MouseDrop_T(atom/pickable, atom/user)
var/mob/living/U = user
if(isliving(pickable))
var/mob/living/M = pickable
if(M.can_be_held && U.pulling == M)
M.mob_try_pickup(U)
return //dont open the mobs inventory if you are picking them up
. = ..()
/mob/living/proc/mob_pickup(mob/living/L)
if(!held_state)
held_state = icon_state
var/obj/item/clothing/mob_holder/holder = new(get_turf(src), src, held_state, held_icon, held_lh, held_rh, worn_layer, mob_size, worn_slot_flags)
L.visible_message(span_warning("[L] scoops up [src]!"))
L.put_in_hands(holder)
/mob/living/proc/mob_try_pickup(mob/living/user)
if(!ishuman(user))
return
if(user.get_active_held_item())
to_chat(user, span_warning("Your hands are full!"))
return FALSE
if(buckled)
to_chat(user, span_warning("[src] is buckled to something!"))
return FALSE
user.visible_message(span_notice("[user] starts trying to scoop up [src]!"))
if(!do_after(user, 2 SECONDS, src))
return FALSE
mob_pickup(user)
return TRUE
/mob/living/proc/get_static_viruses() //used when creating blood and other infective objects
if(!LAZYLEN(diseases))
return
var/list/datum/disease/result = list()
for(var/datum/disease/D in diseases)
var/static_virus = D.Copy()
result += static_virus
return result
/mob/living/reset_perspective(atom/A)
if(..())
update_sight()
if(client.eye && client.eye != src)
var/atom/AT = client.eye
AT.get_remote_view_fullscreens(src)
else
clear_fullscreen("remote_view", 0)
update_pipe_vision()
/mob/living/update_mouse_pointer()
..()
if (client && ranged_ability && ranged_ability.ranged_mousepointer)
client.mouse_pointer_icon = ranged_ability.ranged_mousepointer
/mob/living/vv_edit_var(var_name, var_value)
switch(var_name)
if ("maxHealth")
if (!isnum(var_value) || var_value <= 0)
return FALSE
if("stat")
if((stat == DEAD) && (var_value < DEAD))//Bringing the dead back to life
remove_from_dead_mob_list()
add_to_alive_mob_list()
if((stat < DEAD) && (var_value == DEAD))//Kill he
remove_from_dead_mob_list()
add_to_alive_mob_list()
. = ..()
switch(var_name)
if("knockdown")
SetParalyzed(var_value)
if("stun")
SetStun(var_value)
if("unconscious")
SetUnconscious(var_value)
if("sleeping")
SetSleeping(var_value)
if("eye_blind")
set_blindness(var_value)
if("eye_damage")
var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
if(E)
E.setOrganDamage(var_value)
if("eye_blurry")
set_blurriness(var_value)
if("maxHealth")
updatehealth()
if("resize")
update_transform()
if("lighting_alpha")
sync_lighting_plane_alpha()
/mob/living/vv_get_header()
. = ..()
var/refid = REF(src)
. += {"
<br><font size='1'><a href='?_src_=vars;[HrefToken()];datumedit=[refid];varnameedit=ckey' id='ckey'>[ckey || "No ckey"]</a> / [VV_HREF_TARGETREF_1V(refid, VV_HK_BASIC_EDIT, "[real_name || "no real name"]", NAMEOF(src, real_name))]</font>
<br><font size='1'>
BRUTE:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=[BRUTE]' id='brute'>[getBruteLoss()]</a>
BURN:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=[BURN]' id='burn'>[getFireLoss()]</a>
TOXIN:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=[TOX]' id='toxin'>[getToxLoss()]</a>
OXY:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=[OXY]' id='oxygen'>[getOxyLoss()]</a>
CLONE:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=[CLONE]' id='clone'>[getCloneLoss()]</a>
BRAIN:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=[BRAIN]' id='brain'>[getOrganLoss(ORGAN_SLOT_BRAIN)]</a>
STAMINA:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=[STAMINA]' id='stamina'>[getStaminaLoss()]</a>
</font>
"}
/mob/living/proc/is_convert_antag()
var/list/bad_antags = list(
/datum/antagonist/clockcult,
/datum/antagonist/cult,
/datum/antagonist/darkspawn,
/datum/antagonist/rev,
/datum/antagonist/shadowling,
/datum/antagonist/veil
)
for(var/antagcheck in bad_antags)
if(mind?.has_antag_datum(antagcheck))
return TRUE
return FALSE
/// Only defined for carbons who can wear masks and helmets, we just assume other mobs have visible faces
/mob/living/proc/is_face_visible()
return isturf(loc) // Yogs -- forbids making eye contact with things hidden within objects