mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-21 03:51:49 +01:00
after ragebaiting all of coderbus with our 10 second sendmap ticks, i have slapped together this bandaid fix which should help decrease server load from all you nerds with 72,000 body markings i know what you are
1087 lines
30 KiB
Plaintext
1087 lines
30 KiB
Plaintext
//mob verbs are faster than object verbs. See mob/verb/examine.
|
|
/mob/living/verb/pulled(atom/movable/atom_movable as mob|obj in oview(1))
|
|
set name = "Pull"
|
|
set category = "Object"
|
|
|
|
if(atom_movable.Adjacent(src))
|
|
src.start_pulling(atom_movable)
|
|
|
|
return
|
|
|
|
/mob/living/_pointed(atom/pointing_at)
|
|
if(src.stat || src.restrained())
|
|
return FALSE
|
|
if(src.status_flags & FAKEDEATH)
|
|
return FALSE
|
|
|
|
. = ..()
|
|
|
|
if(.)
|
|
visible_message("<b>\The [src]</b> points to \the [pointing_at].")
|
|
|
|
/mob/living/drop_from_inventory(var/obj/item/item, var/atom/target, update_icons = TRUE, force = FALSE)
|
|
. = ..()
|
|
if(item?.GetID())
|
|
BITSET(hud_updateflag, ID_HUD) //If we drop our ID, update ID HUD
|
|
|
|
/mob/living/carbon/drop_from_inventory(obj/item/W, atom/target, update_icons = TRUE, force = FALSE)
|
|
if(!force && (W in internal_organs))
|
|
return
|
|
return ..()
|
|
|
|
/*one proc, four uses
|
|
swapping: if it's 1, the mobs are trying to switch, if 0, non-passive is pushing passive
|
|
default behaviour is:
|
|
- non-passive mob passes the passive version
|
|
- passive mob checks to see if its mob_bump_flag is in the non-passive's mob_bump_flags
|
|
- if si, the proc returns
|
|
*/
|
|
/mob/living/proc/can_move_mob(var/mob/living/swapped, swapping = 0, passive = 0)
|
|
if(!swapped)
|
|
return TRUE
|
|
if(!passive)
|
|
return swapped.can_move_mob(src, swapping, 1)
|
|
else
|
|
var/context_flags = 0
|
|
if(swapping)
|
|
context_flags = swapped.mob_swap_flags
|
|
else
|
|
context_flags = swapped.mob_push_flags
|
|
if(!mob_bump_flag) //nothing defined, go wild
|
|
return TRUE
|
|
if(mob_bump_flag & context_flags)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/mob/living
|
|
var/tmp/last_push_notif
|
|
|
|
/mob/living/Collide(atom/movable/target_movable_atom)
|
|
if(now_pushing || !loc)
|
|
return
|
|
|
|
now_pushing = TRUE
|
|
if(istype(target_movable_atom, /mob/living))
|
|
var/mob/living/target_mob = target_movable_atom
|
|
|
|
for(var/mob/living/nearby_mob in range(target_mob, 1))
|
|
if(target_mob.pinned.len || ((nearby_mob.pulling == target_mob && (target_mob.restrained() && !(nearby_mob.restrained()) && nearby_mob.stat == 0)) || locate(/obj/item/grab, target_mob.grabbed_by.len)))
|
|
if(last_push_notif + 0.5 SECONDS <= world.time)
|
|
to_chat(src, SPAN_WARNING("[target_mob] is restrained, you cannot push past"))
|
|
last_push_notif = world.time
|
|
|
|
now_pushing = FALSE
|
|
return
|
|
if(target_mob.pulling == nearby_mob && (nearby_mob.restrained() && !( target_mob.restrained()) && target_mob.stat == 0))
|
|
if(last_push_notif + 0.5 SECONDS <= world.time)
|
|
to_chat(src, SPAN_WARNING("[target_mob] is restraining [nearby_mob], you cannot push past"))
|
|
last_push_notif = world.time
|
|
|
|
now_pushing = FALSE
|
|
return
|
|
|
|
//Leaping mobs just land on the tile, no pushing, no anything.
|
|
if(status_flags & LEAPING)
|
|
forceMove(target_mob.loc)
|
|
status_flags &= ~LEAPING
|
|
now_pushing = FALSE
|
|
return
|
|
|
|
if(can_swap_with(target_mob)) // mutual brohugs all around!
|
|
var/turf/target_mob_oldloc = get_turf(target_mob)
|
|
var/turf/src_oldloc = get_turf(src)
|
|
if(pulling?.density)
|
|
target_mob.forceMove(pulling.loc)
|
|
forceMove(target_mob_oldloc)
|
|
pulling.forceMove(src_oldloc)
|
|
else if(target_mob.pulling?.density)
|
|
forceMove(target_mob.pulling.loc)
|
|
target_mob.forceMove(src_oldloc)
|
|
target_mob.pulling.forceMove(target_mob_oldloc)
|
|
else
|
|
forceMove(target_mob_oldloc)
|
|
if(pulling)
|
|
pulling.forceMove(src_oldloc)
|
|
target_mob.forceMove(src_oldloc)
|
|
if(target_mob.pulling)
|
|
target_mob.pulling.forceMove(target_mob_oldloc)
|
|
for(var/obj/item/grab/grab_item in list(l_hand, r_hand))
|
|
grab_item.affecting.forceMove(loc)
|
|
for(var/obj/item/grab/grab_item in list(target_mob.l_hand, target_mob.r_hand))
|
|
grab_item.affecting.forceMove(target_mob.loc)
|
|
now_pushing = FALSE
|
|
for(var/mob/living/carbon/slime/slime in view(2, target_mob))
|
|
if(slime.victim == target_mob)
|
|
slime.UpdateFeed()
|
|
return
|
|
|
|
if(!can_move_mob(target_mob, 0, 0))
|
|
now_pushing = FALSE
|
|
return
|
|
|
|
if(a_intent == I_HELP || src.restrained())
|
|
now_pushing = FALSE
|
|
return
|
|
|
|
if(istype(target_mob.r_hand, /obj/item/shield/riot))
|
|
if(prob(99))
|
|
now_pushing = FALSE
|
|
return
|
|
|
|
if(istype(target_mob.l_hand, /obj/item/shield/riot))
|
|
if(prob(99))
|
|
now_pushing = FALSE
|
|
return
|
|
|
|
if(!(target_mob.status_flags & CANPUSH))
|
|
now_pushing = FALSE
|
|
return
|
|
|
|
target_mob.LAssailant = WEAKREF(src)
|
|
|
|
now_pushing = FALSE
|
|
. = ..()
|
|
if(!istype(target_movable_atom, /atom/movable))
|
|
return
|
|
if(!now_pushing)
|
|
now_pushing = TRUE
|
|
|
|
if(!target_movable_atom.anchored)
|
|
if(isobj(target_movable_atom))
|
|
var/obj/object = target_movable_atom
|
|
if((can_pull_size == 0) || (can_pull_size < object.w_class))
|
|
now_pushing = FALSE
|
|
return
|
|
|
|
var/target_direction = get_dir(src, target_movable_atom)
|
|
if(istype(target_movable_atom, /obj/structure/window))
|
|
for(var/obj/structure/window/win in get_step(target_movable_atom,target_direction))
|
|
now_pushing = FALSE
|
|
return
|
|
|
|
if(target_movable_atom == src.pulling)
|
|
stop_pulling()
|
|
|
|
step(target_movable_atom, target_direction)
|
|
if(ishuman(target_movable_atom))
|
|
var/mob/living/carbon/human/target_human = target_movable_atom
|
|
if(target_human.grabbed_by)
|
|
for(var/obj/item/grab/grab_item in target_human.grabbed_by)
|
|
step(grab_item.assailant, get_dir(grab_item.assailant, target_human))
|
|
grab_item.adjust_position()
|
|
now_pushing = FALSE
|
|
|
|
/**
|
|
* Checks if two mobs can swap with each other based on the density
|
|
*
|
|
* Returns `TRUE` if the density allows them to swap, `FALSE` otherwise
|
|
*
|
|
* swapper - A `/mob`, the one trying to perform the swap
|
|
* swapee - A `/mob`, the one the `swapper` is trying to swap with
|
|
*/
|
|
/proc/swap_density_check(var/mob/swapper, var/mob/swapee)
|
|
SHOULD_NOT_SLEEP(TRUE)
|
|
SHOULD_BE_PURE(TRUE)
|
|
|
|
var/turf/T = get_turf(swapper)
|
|
|
|
if(!T)
|
|
return FALSE
|
|
|
|
if(T.density)
|
|
return TRUE
|
|
|
|
for(var/atom/movable/A in T)
|
|
|
|
if(A == swapper)
|
|
continue
|
|
|
|
if(!A.CanPass(swapee, T, 1))
|
|
return TRUE
|
|
|
|
/mob/living/proc/can_swap_with(var/mob/living/target_mob)
|
|
if(target_mob.buckled_to || buckled_to)
|
|
return FALSE
|
|
|
|
//BubbleWrap: people in handcuffs are always switched around as if they were on 'help' intent to prevent a person being pulled from being seperated from their puller
|
|
if(!(target_mob.mob_always_swap || (target_mob.a_intent == I_HELP || target_mob.restrained()) && (a_intent == I_HELP || src.restrained())))
|
|
return FALSE
|
|
|
|
if(!target_mob.canmove || !canmove)
|
|
return FALSE
|
|
|
|
if(swap_density_check(src, target_mob))
|
|
return FALSE
|
|
|
|
if(swap_density_check(target_mob, src))
|
|
return FALSE
|
|
|
|
if(pulling?.density && target_mob.pulling?.density) // if both are pulling, don't shuffle
|
|
return FALSE
|
|
|
|
return can_move_mob(target_mob, 1, 0)
|
|
|
|
/mob/living/verb/succumb()
|
|
set hidden = 1
|
|
if(health < maxHealth / 3)
|
|
adjustBrainLoss(health + maxHealth * 2) // Deal 2x health in BrainLoss damage, as before but variable.
|
|
to_chat(src, SPAN_NOTICE("You have given up life and succumbed to death."))
|
|
else
|
|
to_chat(src, SPAN_WARNING("You are not injured enough to succumb to death!"))
|
|
|
|
|
|
/mob/living/proc/updatehealth()
|
|
if(status_flags & GODMODE)
|
|
health = maxHealth
|
|
set_stat(CONSCIOUS)
|
|
else
|
|
health = maxHealth - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss()
|
|
|
|
//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(var/pressure)
|
|
return
|
|
|
|
|
|
//sort of a legacy burn method for /electrocute, /shock
|
|
/mob/living/proc/burn_skin(burn_amount)
|
|
take_overall_damage(0, burn_amount)
|
|
return TRUE
|
|
|
|
/mob/living/carbon/human/burn_skin(burn_amount)
|
|
if((mutations & mShock)) //shockproof
|
|
return FALSE
|
|
if((mutations & COLD_RESISTANCE)) //fireproof
|
|
return FALSE
|
|
. = ..()
|
|
updatehealth()
|
|
|
|
/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
|
|
|
|
|
|
// ++++ROCKDTBEN++++ MOB PROCS -- Ask me before touching.
|
|
// Stop! ... Hammertime! ~Carn
|
|
// I touched them without asking... I'm soooo edgy ~Erro (added nodamage checks)
|
|
|
|
/mob/living/proc/getBruteLoss()
|
|
return maxHealth - health
|
|
|
|
/mob/living/proc/adjustBruteLoss(var/amount)
|
|
if(status_flags & GODMODE)
|
|
return
|
|
health = clamp(health - amount, 0, maxHealth)
|
|
|
|
/mob/living/proc/getOxyLoss()
|
|
return 0
|
|
|
|
/mob/living/proc/adjustOxyLoss(var/amount)
|
|
return
|
|
|
|
/mob/living/proc/setOxyLoss(var/amount)
|
|
return
|
|
|
|
/mob/living/proc/getToxLoss()
|
|
return 0
|
|
|
|
/mob/living/proc/adjustToxLoss(var/amount)
|
|
adjustBruteLoss(amount * 0.5)
|
|
|
|
/mob/living/proc/setToxLoss(var/amount)
|
|
adjustBruteLoss((amount * 0.5)-getBruteLoss())
|
|
|
|
/mob/living/proc/getFireLoss()
|
|
return
|
|
|
|
/mob/living/proc/adjustFireLoss(var/amount)
|
|
adjustBruteLoss(amount * 0.5)
|
|
|
|
/mob/living/proc/setFireLoss(var/amount)
|
|
adjustBruteLoss((amount * 0.5)-getBruteLoss())
|
|
|
|
/mob/living/proc/getHalLoss()
|
|
return 0
|
|
|
|
/mob/living/proc/get_shock()
|
|
return getHalLoss()
|
|
|
|
/mob/living/proc/getCloneLoss()
|
|
return 0
|
|
|
|
/mob/living/proc/adjustCloneLoss(var/amount)
|
|
return
|
|
|
|
/mob/living/proc/setCloneLoss(var/amount)
|
|
return
|
|
|
|
/mob/living/proc/getBrainLoss()
|
|
return 0
|
|
|
|
/mob/living/proc/adjustBrainLoss(var/amount, var/maximum)
|
|
return
|
|
|
|
/mob/living/proc/setBrainLoss(var/amount)
|
|
return
|
|
|
|
/mob/living/proc/adjustHalLoss(var/amount)
|
|
adjustBruteLoss(amount * 0.5)
|
|
|
|
/mob/living/proc/setHalLoss(var/amount)
|
|
adjustBruteLoss((amount * 0.5)-getBruteLoss())
|
|
|
|
/mob/living/proc/getMaxHealth()
|
|
return maxHealth
|
|
|
|
/mob/living/proc/setMaxHealth(var/newMaxHealth)
|
|
maxHealth = newMaxHealth
|
|
|
|
// ++++ROCKDTBEN++++ MOB PROCS //END
|
|
|
|
/mob/proc/get_contents()
|
|
return list()
|
|
|
|
//Recursive function to find everything a mob is holding.
|
|
/mob/living/get_contents(var/obj/item/storage/Storage = null)
|
|
var/list/L = list()
|
|
|
|
if(Storage) //If it called itself
|
|
L += Storage.return_inv()
|
|
|
|
//Leave this commented out, it will cause storage items to exponentially add duplicate to the list
|
|
//for(var/obj/item/storage/S in Storage.return_inv()) //Check for storage items
|
|
// L += get_contents(S)
|
|
|
|
for(var/obj/item/gift/G in Storage.return_inv()) //Check for gift-wrapped items
|
|
L += G.gift
|
|
if(istype(G.gift, /obj/item/storage))
|
|
L += get_contents(G.gift)
|
|
|
|
for(var/obj/item/smallDelivery/D in Storage.return_inv()) //Check for package wrapped items
|
|
L += D.wrapped
|
|
if(istype(D.wrapped, /obj/item/storage)) //this should never happen
|
|
L += get_contents(D.wrapped)
|
|
return L
|
|
|
|
else
|
|
|
|
L += src.contents
|
|
for(var/obj/item/storage/S in src.contents) //Check for storage items
|
|
L += get_contents(S)
|
|
|
|
for(var/obj/item/gift/G in src.contents) //Check for gift-wrapped items
|
|
L += G.gift
|
|
if(istype(G.gift, /obj/item/storage))
|
|
L += get_contents(G.gift)
|
|
|
|
for(var/obj/item/smallDelivery/D in src.contents) //Check for package wrapped items
|
|
L += D.wrapped
|
|
if(istype(D.wrapped, /obj/item/storage)) //this should never happen
|
|
L += get_contents(D.wrapped)
|
|
return L
|
|
|
|
/// Returns TRUE if mob has obj of A type anywhere in its contents.
|
|
/mob/living/proc/check_contents_for(A)
|
|
var/list/L = src.get_contents()
|
|
|
|
for(var/obj/B in L)
|
|
if(B.type == A)
|
|
return 1
|
|
return 0
|
|
|
|
// Returns injection time modifier, if 0 then injection fails
|
|
/mob/living/proc/can_inject()
|
|
return 1
|
|
|
|
/mob/living/proc/get_organ_target()
|
|
var/mob/shooter = src
|
|
var/t = shooter.zone_sel?.selecting
|
|
if((t in list( BP_EYES, BP_MOUTH )))
|
|
t = BP_HEAD
|
|
var/obj/item/organ/external/def_zone = ran_zone(t)
|
|
return def_zone
|
|
|
|
|
|
// heal ONE external organ, organ gets randomly selected from damaged ones.
|
|
/mob/living/proc/heal_organ_damage(var/brute, var/burn)
|
|
adjustBruteLoss(-brute)
|
|
adjustFireLoss(-burn)
|
|
src.updatehealth()
|
|
|
|
// damage ONE external organ, organ gets randomly selected from damaged ones.
|
|
/mob/living/proc/take_organ_damage(var/brute, var/burn, var/emp=0)
|
|
if(status_flags & GODMODE) return 0 //godmode
|
|
adjustBruteLoss(brute)
|
|
adjustFireLoss(burn)
|
|
src.updatehealth()
|
|
|
|
// heal MANY external organs, in random order
|
|
/mob/living/proc/heal_overall_damage(var/brute, var/burn)
|
|
adjustBruteLoss(-brute)
|
|
adjustFireLoss(-burn)
|
|
src.updatehealth()
|
|
|
|
// damage MANY external organs, in random order
|
|
/mob/living/proc/take_overall_damage(var/brute, var/burn, var/used_weapon = null)
|
|
if(status_flags & GODMODE) return 0 //godmode
|
|
adjustBruteLoss(brute)
|
|
adjustFireLoss(burn)
|
|
src.updatehealth()
|
|
|
|
/mob/living/proc/restore_all_organs()
|
|
return
|
|
|
|
/mob/living/update_gravity(has_gravity)
|
|
if(!ROUND_IS_STARTED)
|
|
return
|
|
if(has_gravity)
|
|
stop_floating()
|
|
else
|
|
start_floating()
|
|
|
|
/mob/living/proc/revive(reset_to_roundstart = TRUE) // this param is only used in human regen.
|
|
// Stop killing yourself. Please.
|
|
// if(suiciding)
|
|
// suiciding = 0
|
|
|
|
rejuvenate()
|
|
if(buckled_to)
|
|
buckled_to.unbuckle()
|
|
if(iscarbon(src))
|
|
var/mob/living/carbon/C = src
|
|
|
|
if(C.handcuffed && !initial(C.handcuffed))
|
|
C.drop_from_inventory(C.handcuffed)
|
|
C.handcuffed = initial(C.handcuffed)
|
|
|
|
if(C.legcuffed && !initial(C.legcuffed))
|
|
C.drop_from_inventory(C.legcuffed)
|
|
C.legcuffed = initial(C.legcuffed)
|
|
BITSET(hud_updateflag, HEALTH_HUD)
|
|
BITSET(hud_updateflag, STATUS_HUD)
|
|
BITSET(hud_updateflag, LIFE_HUD)
|
|
ExtinguishMobCompletely()
|
|
|
|
/mob/living/proc/rejuvenate()
|
|
if(!isnull(reagents))
|
|
reagents.clear_reagents()
|
|
|
|
// shut down various types of badness
|
|
setToxLoss(0)
|
|
setOxyLoss(0)
|
|
setCloneLoss(0)
|
|
setBrainLoss(0)
|
|
SetParalysis(0)
|
|
SetStunned(0)
|
|
SetWeakened(0)
|
|
|
|
// shut down ongoing problems
|
|
stamina = max_stamina
|
|
total_radiation = 0
|
|
nutrition = 400
|
|
hydration = 400
|
|
bodytemperature = T20C
|
|
sdisabilities = 0
|
|
disabilities = 0
|
|
hallucination = 0
|
|
silent = 0
|
|
dizziness = 0
|
|
drowsiness = 0
|
|
stuttering = 0
|
|
confused = 0
|
|
jitteriness = 0
|
|
|
|
// fix blindness and deafness
|
|
blinded = 0
|
|
eye_blind = 0
|
|
eye_blurry = 0
|
|
ear_deaf = 0
|
|
ear_damage = 0
|
|
heal_overall_damage(getBruteLoss(), getFireLoss())
|
|
|
|
// fix all of our organs
|
|
restore_all_organs()
|
|
|
|
// remove the character from the list of the dead
|
|
if(stat == DEAD)
|
|
GLOB.dead_mob_list -= src
|
|
GLOB.living_mob_list += src
|
|
tod = null
|
|
timeofdeath = 0
|
|
|
|
// restore us to conciousness
|
|
set_stat(CONSCIOUS)
|
|
|
|
// make the icons look correct
|
|
regenerate_icons()
|
|
|
|
BITSET(hud_updateflag, HEALTH_HUD)
|
|
BITSET(hud_updateflag, STATUS_HUD)
|
|
BITSET(hud_updateflag, LIFE_HUD)
|
|
|
|
failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath.
|
|
|
|
return
|
|
|
|
/mob/living/proc/basic_revival(var/repair_brain = TRUE)
|
|
|
|
if(repair_brain && getBrainLoss() > 50)
|
|
repair_brain = FALSE
|
|
setBrainLoss(50)
|
|
|
|
if(stat == DEAD)
|
|
switch_from_dead_to_living_mob_list()
|
|
timeofdeath = 0
|
|
|
|
set_stat(CONSCIOUS)
|
|
regenerate_icons()
|
|
|
|
BITSET(hud_updateflag, HEALTH_HUD)
|
|
BITSET(hud_updateflag, STATUS_HUD)
|
|
BITSET(hud_updateflag, LIFE_HUD)
|
|
|
|
failed_last_breath = 0 //So mobs that died of oxyloss don't revive and have perpetual out of breath.
|
|
|
|
/mob/living/carbon/basic_revival(var/repair_brain = TRUE)
|
|
if(repair_brain && should_have_organ(BP_BRAIN))
|
|
repair_brain = FALSE
|
|
var/obj/item/organ/internal/brain/brain = internal_organs_by_name[BP_BRAIN]
|
|
if(brain.damage > (brain.max_damage/2))
|
|
brain.damage = (brain.max_damage/2)
|
|
if(brain.status & ORGAN_DEAD)
|
|
brain.status &= ~ORGAN_DEAD
|
|
START_PROCESSING(SSprocessing, brain)
|
|
brain.update_icon()
|
|
..(repair_brain)
|
|
|
|
/mob/living/proc/UpdateDamageIcon()
|
|
return
|
|
|
|
/mob/living/Move(atom/newloc, direct)
|
|
if(buckled_to)
|
|
return
|
|
|
|
if(restrained())
|
|
stop_pulling()
|
|
|
|
|
|
var/t7 = 1
|
|
if(restrained())
|
|
for(var/mob/living/M in range(src, 1))
|
|
if((M.pulling == src && M.stat == 0 && !( M.restrained() )))
|
|
t7 = null
|
|
if((t7 && (pulling && ((get_dist(src, pulling) <= 1 || pulling.loc == loc) && (client && client.moving)))))
|
|
var/turf/T = loc
|
|
. = ..()
|
|
|
|
if(pulling && pulling.loc)
|
|
if(!( isturf(pulling.loc) ))
|
|
stop_pulling()
|
|
return
|
|
|
|
/////
|
|
if(pulling && pulling.anchored)
|
|
stop_pulling()
|
|
return
|
|
|
|
if(!restrained())
|
|
var/diag = get_dir(src, pulling)
|
|
if(!((diag - 1) & diag))
|
|
diag = null
|
|
if((get_dist(src, pulling) > 1 || diag))
|
|
if(isliving(pulling))
|
|
var/mob/living/M = pulling
|
|
var/ok = 1
|
|
if(locate(/obj/item/grab, M.grabbed_by))
|
|
if(prob(75))
|
|
var/obj/item/grab/G = pick(M.grabbed_by)
|
|
if(istype(G, /obj/item/grab))
|
|
for(var/mob/O in viewers(M, null))
|
|
O.show_message(SPAN_WARNING("[G.affecting] has been pulled from [G.assailant]'s grip by [src]"), 1)
|
|
//G = null
|
|
qdel(G)
|
|
else
|
|
ok = 0
|
|
if(locate(/obj/item/grab, M.grabbed_by.len))
|
|
ok = 0
|
|
if(ok)
|
|
var/atom/movable/t = M.pulling
|
|
M.stop_pulling()
|
|
|
|
if(!istype(M.loc, /turf/space))
|
|
var/area/A = get_area(M)
|
|
if(A.has_gravity())
|
|
//this is the gay blood on floor shit -- Added back -- Skie
|
|
if(M.lying && (prob(M.getBruteLoss() / 6)))
|
|
var/turf/location = M.loc
|
|
if(istype(location, /turf/simulated))
|
|
location.add_blood(M)
|
|
//pull damage with injured people
|
|
if(prob(25))
|
|
M.adjustBruteLoss(1)
|
|
visible_message(SPAN_DANGER("\The [M]'s [M.isSynthetic() ? "state worsens": "wounds open more"] from being dragged!"))
|
|
if(M.pull_damage())
|
|
if(prob(25))
|
|
M.adjustBruteLoss(2)
|
|
visible_message(SPAN_DANGER("\The [M]'s [M.isSynthetic() ? "state" : "wounds"] worsen terribly from being dragged!"))
|
|
var/turf/location = M.loc
|
|
if(istype(location, /turf/simulated))
|
|
location.add_blood(M)
|
|
if(ishuman(M))
|
|
var/mob/living/carbon/human/H = M
|
|
var/total_blood = round(REAGENT_VOLUME(H.vessel, /singleton/reagent/blood))
|
|
if(total_blood > 0)
|
|
H.vessel.remove_reagent(/singleton/reagent/blood, 1)
|
|
|
|
|
|
step(pulling, get_dir(pulling.loc, T))
|
|
if(t)
|
|
M.start_pulling(t)
|
|
else
|
|
if(pulling)
|
|
if(istype(pulling, /obj/structure/window))
|
|
var/obj/structure/window/W = pulling
|
|
if(W.is_full_window())
|
|
for(var/obj/structure/window/win in get_step(pulling,get_dir(pulling.loc, T)))
|
|
stop_pulling()
|
|
if(pulling)
|
|
step(pulling, get_dir(pulling.loc, T))
|
|
else
|
|
stop_pulling()
|
|
. = ..()
|
|
|
|
if(s_active && !s_active.Adjacent(src)) //check !( s_active in contents ) first so we hopefully don't have to call get_turf() so much.
|
|
s_active.close(src)
|
|
|
|
if(update_slimes)
|
|
for(var/mob/living/carbon/slime/M in view(1,src))
|
|
M.UpdateFeed(src)
|
|
|
|
/mob/living/verb/resist()
|
|
set name = "Resist"
|
|
set category = "IC"
|
|
|
|
DEFAULT_QUEUE_OR_CALL_VERB(VERB_CALLBACK(src, PROC_REF(execute_resist)))
|
|
|
|
///proc extender of [/mob/living/verb/resist] meant to make the process queable if the server is overloaded when the verb is called
|
|
/mob/living/proc/execute_resist()
|
|
|
|
if(!incapacitated(INCAPACITATION_KNOCKOUT) && canClick())
|
|
SEND_SIGNAL(src, COMSIG_MOB_RESISTED)
|
|
resist_grab()
|
|
if(!weakened)
|
|
process_resist()
|
|
|
|
/mob/living/proc/process_resist()
|
|
//Getting out of someone's inventory.
|
|
if(istype(src.loc, /obj/item/holder))
|
|
escape_inventory(src.loc)
|
|
return
|
|
|
|
//unbuckling yourself
|
|
if(buckled_to)
|
|
spawn() escape_buckle()
|
|
|
|
//Breaking out of a locker?
|
|
if( src.loc && istype(src.loc, /obj/structure/closet) )
|
|
var/obj/structure/closet/C = loc
|
|
spawn() C.mob_breakout(src)
|
|
|
|
/mob/living/proc/escape_inventory(obj/item/holder/H)
|
|
if(H != src.loc)
|
|
return
|
|
if(health < maxHealth * 0.6)
|
|
to_chat(src, SPAN_WARNING("You're too injured to escape..."))
|
|
return
|
|
|
|
var/mob/M = H.loc //Get our mob holder (if any).
|
|
|
|
if(istype(M))
|
|
M.drop_from_inventory(H)
|
|
to_chat(M, SPAN_WARNING("\The [H] wriggles out of your grip!"))
|
|
to_chat(src, SPAN_WARNING("You wriggle out of \the [M]'s grip!"))
|
|
|
|
// Update whether or not this mob needs to pass emotes to contents.
|
|
for(var/atom/A in M.contents)
|
|
if(istype(A,/mob/living/simple_animal/borer) || istype(A,/obj/item/holder))
|
|
return
|
|
M.status_flags &= ~PASSEMOTES
|
|
|
|
else if(istype(H.loc,/obj/item/clothing/accessory/holster))
|
|
var/obj/item/clothing/accessory/holster/holster = H.loc
|
|
if(holster.holstered == H)
|
|
holster.clear_holster()
|
|
to_chat(src, SPAN_WARNING("You extricate yourself from \the [holster]."))
|
|
H.forceMove(get_turf(H))
|
|
else if(istype(H.loc,/obj/item))
|
|
to_chat(src, SPAN_WARNING("You struggle free of \the [H.loc]."))
|
|
H.forceMove(get_turf(H))
|
|
|
|
/mob/living/proc/escape_buckle()
|
|
if(buckled_to)
|
|
buckled_to.user_unbuckle(src)
|
|
|
|
/mob/living/var/last_resist
|
|
|
|
/mob/living/proc/resist_grab()
|
|
if(last_resist + 10 > world.time)
|
|
return
|
|
last_resist = world.time
|
|
if(stunned > 10)
|
|
to_chat(src, SPAN_NOTICE("You can't move..."))
|
|
return
|
|
var/resisting = 0
|
|
for(var/obj/O in requests)
|
|
requests.Remove(O)
|
|
qdel(O)
|
|
resisting++
|
|
var/resist_power = get_resist_power() // How easily the mob can break out of a grab
|
|
for(var/obj/item/grab/G in grabbed_by)
|
|
resisting++
|
|
var/resist_chance
|
|
var/resist_msg
|
|
switch(G.state)
|
|
if(GRAB_PASSIVE)
|
|
if(incapacitated(INCAPACITATION_DISABLED) || src.lying)
|
|
resist_chance = 30 * resist_power
|
|
else
|
|
resist_chance = 70 * resist_power //only a bit difficult to break out of a passive grab
|
|
resist_msg = SPAN_WARNING("[src] pulls away from [G.assailant]'s grip!")
|
|
if(GRAB_AGGRESSIVE)
|
|
if(incapacitated(INCAPACITATION_DISABLED) || src.lying)
|
|
resist_chance = 15 * resist_power
|
|
else
|
|
resist_chance = 50 * resist_power
|
|
resist_msg = SPAN_WARNING("[src] has broken free of [G.assailant]'s grip!")
|
|
if(GRAB_NECK)
|
|
//If the you move when grabbing someone then it's easier for them to break free. Same if the affected mob is immune to stun.
|
|
if(world.time - G.assailant.l_move_time < 30 || !stunned || !src.lying || incapacitated(INCAPACITATION_DISABLED))
|
|
resist_chance = 15 * resist_power
|
|
else
|
|
resist_chance = 3 * resist_power
|
|
resist_msg = SPAN_DANGER("[src] has broken free of [G.assailant]'s headlock!")
|
|
|
|
if(prob(resist_chance))
|
|
visible_message(resist_msg)
|
|
qdel(G)
|
|
break
|
|
|
|
if(resisting)
|
|
visible_message(SPAN_WARNING("[src] resists!"))
|
|
setClickCooldown(2.5 SECONDS)
|
|
|
|
/mob/living/verb/lay_down()
|
|
set name = "Rest"
|
|
set category = "IC.Maneuver"
|
|
|
|
if(last_special + 1 SECOND > world.time)
|
|
to_chat(src, SPAN_WARNING("You're too tired to do this now!"))
|
|
return
|
|
if(in_neck_grab())
|
|
to_chat(src, SPAN_WARNING("You are being restrained!"))
|
|
return
|
|
last_special = world.time
|
|
resting = !resting
|
|
to_chat(src, SPAN_NOTICE("You are now [resting ? "resting" : "getting up"]."))
|
|
update_canmove()
|
|
update_icon()
|
|
|
|
/mob/living/proc/cannot_use_vents()
|
|
return "You can't fit into that vent."
|
|
|
|
/mob/living/proc/has_brain()
|
|
return 1
|
|
|
|
/mob/living/proc/has_eyes()
|
|
return 1
|
|
|
|
/mob/living/proc/eyes_protected(var/obj/stab_item, var/stabbed = FALSE) // if stabbed is set to true if we're being stabbed and not just checking
|
|
if(!has_eyes())
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/mob/living/proc/slip(var/slipped_on,stun_duration=8)
|
|
return 0
|
|
|
|
/mob/living/proc/under_door()
|
|
//This function puts a silicon on a layer that makes it draw under doors, then periodically checks if its still standing on a door
|
|
if(layer > UNDERDOOR)//Don't toggle it if we're hiding
|
|
layer = UNDERDOOR
|
|
underdoor = 1
|
|
|
|
/mob/living/touch_map_edge()
|
|
|
|
//check for nuke disks
|
|
if(client && stat != DEAD) //if they are clientless and dead don't bother, the parent will treat them as any other container
|
|
if(istype(SSticker.mode, /datum/game_mode/nuclear)) //only really care if the game mode is nuclear
|
|
var/datum/game_mode/nuclear/G = SSticker.mode
|
|
if(G.check_mob(src))
|
|
if(x <= TRANSITIONEDGE)
|
|
inertia_dir = 4
|
|
else if(x >= world.maxx -TRANSITIONEDGE)
|
|
inertia_dir = 8
|
|
else if(y <= TRANSITIONEDGE)
|
|
inertia_dir = 1
|
|
else if(y >= world.maxy -TRANSITIONEDGE)
|
|
inertia_dir = 2
|
|
to_chat(src, SPAN_WARNING("Something you are carrying is preventing you from leaving."))
|
|
return
|
|
|
|
..()
|
|
|
|
//damage/heal the mob ears and adjust the deaf amount
|
|
/mob/living/adjustEarDamage(var/damage, var/deaf, var/ringing = FALSE)
|
|
var/alreadydeaf = FALSE
|
|
if(ear_deaf)
|
|
alreadydeaf = TRUE
|
|
|
|
ear_damage = max(0, ear_damage + damage)
|
|
ear_deaf = max(0, ear_deaf + deaf)
|
|
|
|
if(ringing && !alreadydeaf)
|
|
if(ear_damage >= 5)
|
|
if(ear_damage >= 15)
|
|
to_chat(src, SPAN_DANGER("Your ears start to ring badly!"))
|
|
else
|
|
to_chat(src, SPAN_DANGER("Your ears start to ring!"))
|
|
|
|
|
|
//pass a negative argument to skip one of the variable
|
|
|
|
/mob/living/setEarDamage(var/damage, var/deaf)
|
|
if(damage >= 0)
|
|
ear_damage = damage
|
|
if(deaf >= 0)
|
|
ear_deaf = deaf
|
|
|
|
/mob/proc/can_be_possessed_by(var/mob/abstract/ghost/observer/possessor)
|
|
return istype(possessor) && possessor.client
|
|
|
|
/mob/living/can_be_possessed_by(var/mob/abstract/ghost/observer/possessor)
|
|
if(!..())
|
|
return 0
|
|
if(!possession_candidate)
|
|
to_chat(possessor, SPAN_WARNING("That animal cannot be possessed."))
|
|
return 0
|
|
if(jobban_isbanned(possessor, "Animal"))
|
|
to_chat(possessor, SPAN_WARNING("You are banned from animal roles."))
|
|
return 0
|
|
if(!possessor.MayRespawn(1,ANIMAL))
|
|
return 0
|
|
return 1
|
|
|
|
/mob/living/proc/do_possession(var/mob/abstract/ghost/observer/possessor)
|
|
|
|
if(!(istype(possessor) && possessor.ckey))
|
|
return 0
|
|
|
|
if(src.ckey || src.client)
|
|
to_chat(possessor, SPAN_WARNING("\The [src] already has a player."))
|
|
return 0
|
|
|
|
message_admins("<span class='adminnotice'>[key_name_admin(possessor)] has taken control of \the [src].</span>")
|
|
log_admin("[key_name(possessor)] took control of \the [src].")
|
|
src.ckey = possessor.ckey
|
|
qdel(possessor)
|
|
|
|
if(round_is_spooky(6)) // Six or more active cultists.
|
|
to_chat(src, SPAN_NOTICE("You reach out with tendrils of ectoplasm and invade the mind of \the [src]..."))
|
|
to_chat(src, "<b>You have assumed direct control of \the [src].</b>")
|
|
to_chat(src, SPAN_NOTICE("Due to the spookiness of the round, you have taken control of the poor animal as an invading, possessing spirit - roleplay accordingly."))
|
|
src.universal_speak = 1
|
|
src.universal_understand = 1
|
|
//src.cultify() // Maybe another time.
|
|
return
|
|
|
|
to_chat(src, "<b>You are now \the [src]!</b>")
|
|
to_chat(src, SPAN_NOTICE("Remember to stay in character for a mob of this type!"))
|
|
return 1
|
|
|
|
/mob/living/Initialize()
|
|
. = ..()
|
|
add_to_target_grid()
|
|
ability_master = new /atom/movable/screen/movable/ability_master(FALSE, src)
|
|
|
|
var/static/list/loc_connections = list(
|
|
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
|
|
)
|
|
|
|
register_init_signals()
|
|
|
|
AddElement(/datum/element/connect_loc, loc_connections)
|
|
|
|
/mob/living/Destroy()
|
|
|
|
//Aiming overlay
|
|
QDEL_NULL(aiming)
|
|
QDEL_LIST(aimed_at_by)
|
|
|
|
//Psi complexus
|
|
QDEL_NULL(psi)
|
|
|
|
if(vr_mob)
|
|
vr_mob = null
|
|
if(old_mob)
|
|
old_mob = null
|
|
|
|
//Remove contained mobs
|
|
if(loc)
|
|
for(var/mob/M in contents)
|
|
M.dropInto(loc)
|
|
else
|
|
for(var/mob/M in contents)
|
|
qdel(M)
|
|
|
|
QDEL_NULL(reagents)
|
|
|
|
if(auras)
|
|
for(var/a in auras)
|
|
remove_aura(a)
|
|
|
|
return ..()
|
|
|
|
/mob/living/proc/nervous_system_failure()
|
|
return FALSE
|
|
|
|
/mob/living/proc/get_digestion_product()
|
|
return null
|
|
|
|
/proc/is_valid_for_devour(var/mob/living/test, var/eat_types)
|
|
//eat_types must contain all types that the mob has. For example we need both humanoid and synthetic to eat an IPC.
|
|
var/test_types = test.find_type()
|
|
. = (eat_types & test_types) == test_types
|
|
|
|
/mob/living/proc/on_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs)
|
|
SIGNAL_HANDLER
|
|
|
|
if(istype(arrived, /mob/living/heavy_vehicle))
|
|
var/mob/living/heavy_vehicle/MB = arrived
|
|
MB.trample(src)
|
|
|
|
#define PPM 9 //Protein per meat, used for calculating the quantity of protein in an animal
|
|
/mob/living/proc/calculate_composition()
|
|
if(!composition_reagent)//if no reagent has been set, then we'll set one
|
|
var/type = find_type(src)
|
|
if(type & TYPE_SYNTHETIC)
|
|
src.composition_reagent = /singleton/reagent/iron
|
|
else
|
|
src.composition_reagent = /singleton/reagent/nutriment/protein
|
|
|
|
//if the mob is a simple animal with a defined meat quantity
|
|
if(istype(src, /mob/living/simple_animal))
|
|
var/mob/living/simple_animal/SA = src
|
|
if(SA.meat_amount)
|
|
src.composition_reagent_quantity = SA.meat_amount*2*PPM
|
|
|
|
//The quantity of protein is based on the meat_amount, but multiplied by 2
|
|
|
|
var/size_reagent = (src.mob_size * src.mob_size) * 3//The quantity of protein is set to 3x mob size squared
|
|
if(size_reagent > src.composition_reagent_quantity)//We take the larger of the two
|
|
src.composition_reagent_quantity = size_reagent
|
|
#undef PPM
|
|
|
|
/mob/living/proc/get_resist_power()
|
|
return 1
|
|
|
|
/mob/living/proc/seizure(var/severity_multiplier = 1)
|
|
if(!paralysis && stat == CONSCIOUS)
|
|
visible_message(SPAN_HIGHDANGER("\The [src] starts having a seizure!"))
|
|
Paralyse(24*severity_multiplier)
|
|
make_jittery(200*severity_multiplier)
|
|
adjustHalLoss(60*severity_multiplier)
|
|
|
|
/mob/living/proc/InStasis()
|
|
return FALSE
|
|
|
|
/mob/living/update_icon()
|
|
for(var/aura in auras)
|
|
var/obj/aura/A = aura
|
|
var/icon/aura_overlay = icon(A.icon, icon_state = A.icon_state)
|
|
AddOverlays(aura_overlay)
|
|
|
|
/mob/living/proc/add_aura(var/obj/aura/aura)
|
|
LAZYDISTINCTADD(auras, aura)
|
|
update_icon()
|
|
return TRUE
|
|
|
|
/mob/living/proc/remove_aura(var/obj/aura/aura)
|
|
LAZYREMOVE(auras, aura)
|
|
update_icon()
|
|
return TRUE
|
|
|
|
/mob/living/proc/needs_wheelchair()
|
|
return FALSE
|
|
|
|
/mob/living/verb/toggle_run_intent()
|
|
set hidden = 1
|
|
set name = "mov_intent"
|
|
if(hud_used?.move_intent)
|
|
hud_used.move_intent.Click()
|
|
|
|
/mob/living/verb/toggle_intentionally_lying()
|
|
set hidden = 1
|
|
set name = "lie_down"
|
|
if(hud_used?.move_intent)
|
|
hud_used.move_intent.Click(params="button=middle")
|
|
|
|
/**
|
|
* Used by a macro in skin.dmf to toggle the throw
|
|
*/
|
|
/mob/living/verb/throw_intent_keyDown()
|
|
set hidden = 1
|
|
set name = "throw_intent"
|
|
if(!(src.in_throw_mode))
|
|
toggle_throw_mode()
|
|
|
|
/mob/living/verb/throw_intent_keyUp()
|
|
set hidden = 1
|
|
set name = "throw_intent_up"
|
|
if(src.in_throw_mode)
|
|
toggle_throw_mode()
|
|
|
|
/mob/living/verb/throw_intent_toggle()
|
|
set hidden = 1
|
|
set name = "throw_intent_toggle"
|
|
toggle_throw_mode()
|
|
|
|
/mob/living/proc/add_hallucinate(var/amount)
|
|
hallucination += amount
|
|
hallucination += amount
|
|
|
|
/mob/living/set_respawn_time()
|
|
set_death_time(CREW, world.time)
|
|
//Used by simple animals and monkey species for renaming. M is the one doing the renaming
|
|
/mob/living/proc/can_name(var/mob/living/M)
|
|
return FALSE
|
|
|
|
/mob/living/proc/is_anti_materiel_vulnerable()
|
|
return FALSE
|
|
|
|
/mob/living/get_speech_bubble_state_modifier()
|
|
return isSynthetic() ? "robot" : ..()
|
|
|
|
///Performs the aftereffects of blocking a projectile.
|
|
/mob/living/proc/block_projectile_effects()
|
|
return
|
|
|
|
/// Uses presence of [TRAIT_UNDENSE] to figure out what is the correct density state for the mob. Triggered by trait signal.
|
|
/mob/living/proc/update_density()
|
|
if(HAS_TRAIT(src, TRAIT_UNDENSE))
|
|
set_density(FALSE)
|
|
else
|
|
set_density(TRUE)
|