Files
CHOMPStation2/code/modules/mob/living/living.dm

780 lines
22 KiB
Plaintext

//mob verbs are faster than object verbs. See mob/verb/examine.
/mob/living/verb/pulled(atom/movable/AM as mob|obj in oview(1))
set name = "Pull"
set category = "Object"
if(AM.Adjacent(src))
src.start_pulling(AM)
return
//mob verbs are faster than object verbs. See above.
/mob/living/pointed(atom/A as mob|obj|turf in view())
if(src.stat || !src.canmove || src.restrained())
return 0
if(src.status_flags & FAKEDEATH)
return 0
if(!..())
return 0
usr.visible_message("<b>[src]</b> points to [A]")
return 1
/*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 1
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 1
if(mob_bump_flag & context_flags)
return 1
return 0
/mob/living/Bump(atom/movable/AM, yes)
spawn(0)
if ((!( yes ) || now_pushing) || !loc)
return
now_pushing = 1
if (istype(AM, /mob/living))
var/mob/living/tmob = AM
for(var/mob/living/M in range(tmob, 1))
if(tmob.pinned.len || ((M.pulling == tmob && ( tmob.restrained() && !( M.restrained() ) && M.stat == 0)) || locate(/obj/item/weapon/grab, tmob.grabbed_by.len)) )
if ( !(world.time % 5) )
src << "<span class='warning'>[tmob] is restrained, you cannot push past</span>"
now_pushing = 0
return
if( tmob.pulling == M && ( M.restrained() && !( tmob.restrained() ) && tmob.stat == 0) )
if ( !(world.time % 5) )
src << "<span class='warning'>[tmob] is restraining [M], you cannot push past</span>"
now_pushing = 0
return
//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
var/dense = 0
if(loc.density)
dense = 1
for(var/atom/movable/A in loc)
if(A == src)
continue
if(A.density)
if(A.flags&ON_BORDER)
dense = !A.CanPass(src, src.loc)
else
dense = 1
if(dense) break
//Leaping mobs just land on the tile, no pushing, no anything.
if(status_flags & LEAPING)
loc = tmob.loc
status_flags &= ~LEAPING
now_pushing = 0
return
if((tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained())) && tmob.canmove && canmove && !dense && can_move_mob(tmob, 1, 0)) // mutual brohugs all around!
var/turf/oldloc = loc
loc = tmob.loc
tmob.loc = oldloc
now_pushing = 0
for(var/mob/living/carbon/slime/slime in view(1,tmob))
if(slime.Victim == tmob)
slime.UpdateFeed()
return
if(!can_move_mob(tmob, 0, 0))
now_pushing = 0
return
if(istype(tmob, /mob/living/carbon/human) && (FAT in tmob.mutations))
if(prob(40) && !(FAT in src.mutations))
src << "<span class='danger'>You fail to push [tmob]'s fat ass out of the way.</span>"
now_pushing = 0
return
if(tmob.r_hand && istype(tmob.r_hand, /obj/item/weapon/shield/riot))
if(prob(99))
now_pushing = 0
return
if(tmob.l_hand && istype(tmob.l_hand, /obj/item/weapon/shield/riot))
if(prob(99))
now_pushing = 0
return
if(!(tmob.status_flags & CANPUSH))
now_pushing = 0
return
tmob.LAssailant = src
now_pushing = 0
spawn(0)
..()
if (!istype(AM, /atom/movable))
return
if (!now_pushing)
now_pushing = 1
if (!AM.anchored)
var/t = get_dir(src, AM)
if (istype(AM, /obj/structure/window))
for(var/obj/structure/window/win in get_step(AM,t))
now_pushing = 0
return
step(AM, t)
if(ishuman(AM) && AM:grabbed_by)
for(var/obj/item/weapon/grab/G in AM:grabbed_by)
step(G:assailant, get_dir(G:assailant, AM))
G.adjust_position()
now_pushing = 0
return
return
/mob/living/verb/succumb()
set hidden = 1
if ((src.health < 0 && src.health > -95.0))
src.adjustOxyLoss(src.health + 200)
src.health = 100 - src.getOxyLoss() - src.getToxLoss() - src.getFireLoss() - src.getBruteLoss()
src << "\blue You have given up life and succumbed to death."
/mob/living/proc/updatehealth()
if(status_flags & GODMODE)
health = 100
stat = CONSCIOUS
else
health = maxHealth - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss() - halloss
//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, and the e_chair
/mob/living/proc/burn_skin(burn_amount)
if(istype(src, /mob/living/carbon/human))
//world << "DEBUG: burn_skin(), mutations=[mutations]"
if(mShock in src.mutations) //shockproof
return 0
if (COLD_RESISTANCE in src.mutations) //fireproof
return 0
var/mob/living/carbon/human/H = src //make this damage method divide the damage to be done among all the body parts, then burn each body part for that much damage. will have better effect then just randomly picking a body part
var/divided_damage = (burn_amount)/(H.organs.len)
var/extradam = 0 //added to when organ is at max dam
for(var/obj/item/organ/external/affecting in H.organs)
if(!affecting) continue
if(affecting.take_damage(0, divided_damage+extradam)) //TODO: fix the extradam stuff. Or, ebtter yet...rewrite this entire proc ~Carn
H.UpdateDamageIcon()
H.updatehealth()
return 1
else if(istype(src, /mob/living/silicon/ai))
return 0
/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
// if(istype(src, /mob/living/carbon/human))
// world << "[src] ~ [src.bodytemperature] ~ [temperature]"
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 bruteloss
/mob/living/proc/adjustBruteLoss(var/amount)
if(status_flags & GODMODE) return 0 //godmode
bruteloss = min(max(bruteloss + amount, 0),(maxHealth*2))
/mob/living/proc/getOxyLoss()
return oxyloss
/mob/living/proc/adjustOxyLoss(var/amount)
if(status_flags & GODMODE) return 0 //godmode
oxyloss = min(max(oxyloss + amount, 0),(maxHealth*2))
/mob/living/proc/setOxyLoss(var/amount)
if(status_flags & GODMODE) return 0 //godmode
oxyloss = amount
/mob/living/proc/getToxLoss()
return toxloss
/mob/living/proc/adjustToxLoss(var/amount)
if(status_flags & GODMODE) return 0 //godmode
toxloss = min(max(toxloss + amount, 0),(maxHealth*2))
/mob/living/proc/setToxLoss(var/amount)
if(status_flags & GODMODE) return 0 //godmode
toxloss = amount
/mob/living/proc/getFireLoss()
return fireloss
/mob/living/proc/adjustFireLoss(var/amount)
if(status_flags & GODMODE) return 0 //godmode
fireloss = min(max(fireloss + amount, 0),(maxHealth*2))
/mob/living/proc/getCloneLoss()
return cloneloss
/mob/living/proc/adjustCloneLoss(var/amount)
if(status_flags & GODMODE) return 0 //godmode
cloneloss = min(max(cloneloss + amount, 0),(maxHealth*2))
/mob/living/proc/setCloneLoss(var/amount)
if(status_flags & GODMODE) return 0 //godmode
cloneloss = amount
/mob/living/proc/getBrainLoss()
return brainloss
/mob/living/proc/adjustBrainLoss(var/amount)
if(status_flags & GODMODE) return 0 //godmode
brainloss = min(max(brainloss + amount, 0),(maxHealth*2))
/mob/living/proc/setBrainLoss(var/amount)
if(status_flags & GODMODE) return 0 //godmode
brainloss = amount
/mob/living/proc/getHalLoss()
return halloss
/mob/living/proc/adjustHalLoss(var/amount)
if(status_flags & GODMODE) return 0 //godmode
halloss = min(max(halloss + amount, 0),(maxHealth*2))
/mob/living/proc/setHalLoss(var/amount)
if(status_flags & GODMODE) return 0 //godmode
halloss = amount
/mob/living/proc/getMaxHealth()
return maxHealth
/mob/living/proc/setMaxHealth(var/newMaxHealth)
maxHealth = newMaxHealth
// ++++ROCKDTBEN++++ MOB PROCS //END
/mob/proc/get_contents()
//Recursive function to find everything a mob is holding.
/mob/living/get_contents(var/obj/item/weapon/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/weapon/storage/S in Storage.return_inv()) //Check for storage items
// L += get_contents(S)
for(var/obj/item/weapon/gift/G in Storage.return_inv()) //Check for gift-wrapped items
L += G.gift
if(istype(G.gift, /obj/item/weapon/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/weapon/storage)) //this should never happen
L += get_contents(D.wrapped)
return L
else
L += src.contents
for(var/obj/item/weapon/storage/S in src.contents) //Check for storage items
L += get_contents(S)
for(var/obj/item/weapon/gift/G in src.contents) //Check for gift-wrapped items
L += G.gift
if(istype(G.gift, /obj/item/weapon/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/weapon/storage)) //this should never happen
L += get_contents(D.wrapped)
return L
/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
/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( "eyes", "mouth" )))
t = "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/proc/revive()
rejuvenate()
if(buckled)
buckled.unbuckle_mob()
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)
ExtinguishMob()
fire_stacks = 0
/mob/living/proc/rejuvenate()
// shut down various types of badness
setToxLoss(0)
setOxyLoss(0)
setCloneLoss(0)
setBrainLoss(0)
SetParalysis(0)
SetStunned(0)
SetWeakened(0)
// shut down ongoing problems
radiation = 0
nutrition = 400
bodytemperature = T20C
sdisabilities = 0
disabilities = 0
// fix blindness and deafness
blinded = 0
eye_blind = 0
eye_blurry = 0
ear_deaf = 0
ear_damage = 0
heal_overall_damage(getBruteLoss(), getFireLoss())
// restore all of a human's blood
if(ishuman(src))
var/mob/living/carbon/human/human_mob = src
human_mob.restore_blood()
// fix all of our organs
restore_all_organs()
// remove the character from the list of the dead
if(stat == 2)
dead_mob_list -= src
living_mob_list += src
tod = null
timeofdeath = 0
// restore us to conciousness
stat = CONSCIOUS
// make the icons look correct
regenerate_icons()
BITSET(hud_updateflag, HEALTH_HUD)
BITSET(hud_updateflag, STATUS_HUD)
BITSET(hud_updateflag, LIFE_HUD)
return
/mob/living/proc/UpdateDamageIcon()
return
/mob/living/proc/Examine_OOC()
set name = "Examine Meta-Info (OOC)"
set category = "OOC"
set src in view()
if(config.allow_Metadata)
if(client)
usr << "[src]'s Metainfo:<br>[client.prefs.metadata]"
else
usr << "[src] does not have any stored infomation!"
else
usr << "OOC Metadata is not supported by this server!"
return
/mob/living/Move(a, b, flag)
if (buckled)
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
else
if(Debug)
log_debug("pulling disappeared? at [__LINE__] in mob.dm - pulling = [pulling]")
log_debug("REPORT THIS")
/////
if(pulling && pulling.anchored)
stop_pulling()
return
if (!restrained())
var/diag = get_dir(src, pulling)
if ((diag - 1) & diag)
else
diag = null
if ((get_dist(src, pulling) > 1 || diag))
if (isliving(pulling))
var/mob/living/M = pulling
var/ok = 1
if (locate(/obj/item/weapon/grab, M.grabbed_by))
if (prob(75))
var/obj/item/weapon/grab/G = pick(M.grabbed_by)
if (istype(G, /obj/item/weapon/grab))
for(var/mob/O in viewers(M, null))
O.show_message(text("\red [] has been pulled from []'s grip by []", G.affecting, G.assailant, src), 1)
//G = null
qdel(G)
else
ok = 0
if (locate(/obj/item/weapon/grab, M.grabbed_by.len))
ok = 0
if (ok)
var/atom/movable/t = M.pulling
M.stop_pulling()
//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 class='danger'>\The [M]'s [M.isSynthetic() ? "state worsens": "wounds open more"] from being dragged!</span>")
if(M.pull_damage())
if(prob(25))
M.adjustBruteLoss(2)
visible_message("<span class='danger'>\The [M]'s [M.isSynthetic() ? "state" : "wounds"] worsen terribly from being dragged!</span>")
var/turf/location = M.loc
if (istype(location, /turf/simulated))
location.add_blood(M)
if(ishuman(M))
var/mob/living/carbon/H = M
var/blood_volume = round(H:vessel.get_reagent_amount("blood"))
if(blood_volume > 0)
H:vessel.remove_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 in contents ) && get_turf(s_active) != get_turf(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"
if(can_resist())
next_move = world.time + 20
process_resist()
/mob/living/proc/can_resist()
//need to allow !canmove, or otherwise neck grabs can't be resisted
//so just check weakened instead.
if(stat || weakened)
return 0
if(next_move > world.time)
return 0
return 1
/mob/living/proc/process_resist()
//Getting out of someone's inventory.
if(istype(src.loc, /obj/item/weapon/holder))
escape_inventory(src.loc)
return
//resisting grabs (as if it helps anyone...)
if (!restrained())
resist_grab()
//unbuckling yourself
if(buckled)
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/weapon/holder/H)
if(H != src.loc) return
var/mob/M = H.loc //Get our mob holder (if any).
if(istype(M))
M.drop_from_inventory(H)
M << "<span class='warning'>[H] wriggles out of your grip!</span>"
src << "<span class='warning'>You wriggle out of [M]'s grip!</span>"
else if(istype(H.loc,/obj/item))
src << "<span class='warning'>You struggle free of [H.loc].</span>"
H.loc = get_turf(H)
if(istype(M))
for(var/atom/A in M.contents)
if(istype(A,/mob/living/simple_animal/borer) || istype(A,/obj/item/weapon/holder))
return
M.status_flags &= ~PASSEMOTES
/mob/living/proc/escape_buckle()
if(buckled)
buckled.user_unbuckle_mob(src)
/mob/living/proc/resist_grab()
var/resisting = 0
for(var/obj/O in requests)
requests.Remove(O)
qdel(O)
resisting++
for(var/obj/item/weapon/grab/G in grabbed_by)
resisting++
switch(G.state)
if(GRAB_PASSIVE)
qdel(G)
if(GRAB_AGGRESSIVE)
if(prob(60)) //same chance of breaking the grab as disarm
visible_message("<span class='warning'>[src] has broken free of [G.assailant]'s grip!</span>")
qdel(G)
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) && prob(15)) || prob(3))
visible_message("<span class='warning'>[src] has broken free of [G.assailant]'s headlock!</span>")
qdel(G)
if(resisting)
visible_message("<span class='danger'>[src] resists!</span>")
/mob/living/verb/lay_down()
set name = "Rest"
set category = "IC"
resting = !resting
src << "\blue You are now [resting ? "resting" : "getting up"]"
/mob/living/proc/handle_ventcrawl(var/obj/machinery/atmospherics/unary/vent_pump/vent_found = null, var/ignore_items = 0) // -- TLE -- Merged by Carn
if(stat)
src << "You must be conscious to do this!"
return
if(lying)
src << "You can't vent crawl while you're stunned!"
return
var/special_fail_msg = can_use_vents()
if(special_fail_msg)
src << "\red [special_fail_msg]"
return
if(vent_found) // one was passed in, probably from vent/AltClick()
if(vent_found.welded)
src << "That vent is welded shut."
return
if(!vent_found.Adjacent(src))
return // don't even acknowledge that
else
for(var/obj/machinery/atmospherics/unary/vent_pump/v in range(1,src))
if(!v.welded)
if(v.Adjacent(src))
vent_found = v
if(!vent_found)
src << "You'll need a non-welded vent to crawl into!"
return
if(!vent_found.network || !vent_found.network.normal_members.len)
src << "This vent is not connected to anything."
return
var/list/vents = list()
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in vent_found.network.normal_members)
if(temp_vent.welded)
continue
if(temp_vent in loc)
continue
var/turf/T = get_turf(temp_vent)
if(!T || T.z != loc.z)
continue
var/i = 1
var/index = "[T.loc.name]\[[i]\]"
while(index in vents)
i++
index = "[T.loc.name]\[[i]\]"
vents[index] = temp_vent
if(!vents.len)
src << "\red There are no available vents to travel to, they could be welded."
return
var/obj/selection = input("Select a destination.", "Duct System") as null|anything in sortAssoc(vents)
if(!selection) return
if(!vent_found.Adjacent(src))
src << "Never mind, you left."
return
if(!ignore_items)
for(var/obj/item/carried_item in contents)//If the monkey got on objects.
if( !istype(carried_item, /obj/item/weapon/implant) && !istype(carried_item, /obj/item/clothing/mask/facehugger) )//If it's not an implant or a facehugger
src << "\red You can't be carrying items or have items equipped when vent crawling!"
return
if(isslime(src))
var/mob/living/carbon/slime/S = src
if(S.Victim)
src << "\red You'll have to let [S.Victim] go or finish eating \him first."
return
var/obj/machinery/atmospherics/unary/vent_pump/target_vent = vents[selection]
if(!target_vent)
return
for(var/mob/O in viewers(src, null))
O.show_message(text("<B>[src] scrambles into the ventillation ducts!</B>"), 1)
loc = target_vent
var/travel_time = round(get_dist(loc, target_vent.loc) / 2)
spawn(travel_time)
if(!target_vent) return
for(var/mob/O in hearers(target_vent,null))
O.show_message("You hear something squeezing through the ventilation ducts.",2)
sleep(travel_time)
if(!target_vent) return
if(target_vent.welded) //the vent can be welded while alien scrolled through the list or travelled.
target_vent = vent_found //travel back. No additional time required.
src << "\red The vent you were heading to appears to be welded."
loc = target_vent.loc
var/area/new_area = get_area(loc)
if(new_area)
new_area.Entered(src)
/mob/living/proc/can_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/slip(var/slipped_on,stun_duration=8)
return 0
/mob/living/carbon/drop_from_inventory(var/obj/item/W, var/atom/Target = null)
if(W in internal_organs)
return
..()