mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-09 16:07:40 +00:00
* sync (#3) * shuttle auto call * Merge /vore into /master (#39) * progress * Compile errors fixed No idea if it's test worthy tho as conflicts with race overhaul and narky removal. * Update admins.txt * efforts continue Fuck grab code, seriously * grab code is cancer * Execute the Narkism Do not hesitate. Show no mercy. * holy shit grab code is awful * have I bitched about grab code My bitching, let me show you it * código de agarre es una mierda No really it is * yeah I don't even know anymore. * Lolnope. Fuck grab code * I'm not even sure what to fix anymore * Self eating is not an acceptable fate * Taste the void, son. * My code doesn't pass it's own sanity check. Maybe it's a sign of things to come. * uncommented and notes * It Works and I Don't Know Why (#38) * shuttle auto call * it works and I don't know why * pixel issue resolved Damnifino. It seems to work. * fixes attack runtime * Sleeper UI refresh Also has tgui framework TBF
1049 lines
30 KiB
Plaintext
1049 lines
30 KiB
Plaintext
/* I am informed this was added by Giacom to reduce mob-stacking in escape pods.
|
|
It's sorta problematic atm due to the shuttle changes I am trying to do
|
|
Sorry Giacom. Please don't be mad :(
|
|
/mob/living/Life()
|
|
..()
|
|
var/area/A = get_area(loc)
|
|
if(A && A.push_dir)
|
|
push_mob_back(src, A.push_dir)
|
|
*/
|
|
|
|
/mob/living/New()
|
|
. = ..()
|
|
generateStaticOverlay()
|
|
if(staticOverlays.len)
|
|
for(var/mob/living/simple_animal/drone/D in player_list)
|
|
if(D && D.seeStatic)
|
|
if(D.staticChoice in staticOverlays)
|
|
D.staticOverlays |= staticOverlays[D.staticChoice]
|
|
D.client.images |= staticOverlays[D.staticChoice]
|
|
else //no choice? force static
|
|
D.staticOverlays |= staticOverlays["static"]
|
|
D.client.images |= staticOverlays["static"]
|
|
if(unique_name)
|
|
name = "[name] ([rand(1, 1000)])"
|
|
real_name = name
|
|
var/datum/atom_hud/data/human/medical/advanced/medhud = huds[DATA_HUD_MEDICAL_ADVANCED]
|
|
medhud.add_to_hud(src)
|
|
faction |= "\ref[src]"
|
|
|
|
|
|
/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/mob/living/simple_animal/drone/D in player_list)
|
|
for(var/image/I in staticOverlays)
|
|
D.staticOverlays.Remove(I)
|
|
D.client.images.Remove(I)
|
|
qdel(I)
|
|
staticOverlays.len = 0
|
|
remove_from_all_data_huds()
|
|
return QDEL_HINT_HARDDEL
|
|
|
|
|
|
/mob/living/proc/OpenCraftingMenu()
|
|
return
|
|
|
|
/mob/living/proc/generateStaticOverlay()
|
|
staticOverlays.Add(list("static", "blank", "letter", "animal"))
|
|
var/image/staticOverlay = image(getStaticIcon(new/icon(icon,icon_state)), loc = src)
|
|
staticOverlay.override = 1
|
|
staticOverlays["static"] = staticOverlay
|
|
|
|
staticOverlay = image(getBlankIcon(new/icon(icon, icon_state)), loc = src)
|
|
staticOverlay.override = 1
|
|
staticOverlays["blank"] = staticOverlay
|
|
|
|
staticOverlay = getLetterImage(src)
|
|
staticOverlay.override = 1
|
|
staticOverlays["letter"] = staticOverlay
|
|
|
|
staticOverlay = getRandomAnimalImage(src)
|
|
staticOverlay.override = 1
|
|
staticOverlays["animal"] = staticOverlay
|
|
|
|
|
|
//Generic Bump(). Override MobBump() and ObjBump() instead of this.
|
|
/mob/living/Bump(atom/A, yes)
|
|
if(..()) //we are thrown onto something
|
|
return
|
|
if (buckled || !yes || 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(istype(A, /atom/movable))
|
|
var/atom/movable/AM = A
|
|
if(PushAM(AM))
|
|
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 1
|
|
|
|
//Should stop you pushing a restrained person out of the way
|
|
if(isliving(M))
|
|
var/mob/living/L = M
|
|
if(L.pulledby && L.pulledby != src && L.restrained())
|
|
if(!(world.time % 5))
|
|
src << "<span class='warning'>[L] is restrained, you cannot push past.</span>"
|
|
return 1
|
|
|
|
if(L.pulling)
|
|
if(ismob(L.pulling))
|
|
var/mob/P = L.pulling
|
|
if(P.restrained())
|
|
if(!(world.time % 5))
|
|
src << "<span class='warning'>[L] is restraining [P], you cannot push past.</span>"
|
|
return 1
|
|
|
|
if(moving_diagonally)//no mob swap during diagonal moves.
|
|
return 1
|
|
|
|
if(!M.buckled && !M.has_buckled_mobs())
|
|
var/mob_swap
|
|
//the puller can always swap with its victim if on grab intent
|
|
if(M.pulledby == src && a_intent == "grab")
|
|
mob_swap = 1
|
|
//restrained people act if they were on 'help' intent to prevent a person being pulled from being seperated from their puller
|
|
else if((M.restrained() || M.a_intent == "help") && (restrained() || a_intent == "help"))
|
|
mob_swap = 1
|
|
if(mob_swap)
|
|
//switch our position with M
|
|
if(loc && !loc.Adjacent(M.loc))
|
|
return 1
|
|
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
|
|
|
|
M.Move(oldloc)
|
|
Move(oldMloc)
|
|
|
|
if(!src_passmob)
|
|
pass_flags &= ~PASSMOB
|
|
if(!M_passmob)
|
|
M.pass_flags &= ~PASSMOB
|
|
|
|
now_pushing = 0
|
|
return 1
|
|
|
|
//okay, so we didn't switch. but should we push?
|
|
//not if he's not CANPUSH of course
|
|
if(!(M.status_flags & CANPUSH))
|
|
return 1
|
|
//anti-riot equipment is also anti-push
|
|
if(M.r_hand && (prob(M.r_hand.block_chance * 2)) && !istype(M.r_hand, /obj/item/clothing))
|
|
return 1
|
|
if(M.l_hand && (prob(M.l_hand.block_chance * 2)) && !istype(M.l_hand, /obj/item/clothing))
|
|
return 1
|
|
|
|
//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)
|
|
if(now_pushing)
|
|
return 1
|
|
if(moving_diagonally)// no pushing during diagonal moves.
|
|
return 1
|
|
if(!client && (mob_size < MOB_SIZE_SMALL))
|
|
return
|
|
if(!AM.anchored)
|
|
now_pushing = 1
|
|
var/t = get_dir(src, AM)
|
|
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 = 0
|
|
return
|
|
if(pulling == AM)
|
|
stop_pulling()
|
|
step(AM, t)
|
|
now_pushing = 0
|
|
|
|
//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) && AM.Adjacent(src))
|
|
start_pulling(AM)
|
|
else
|
|
stop_pulling()
|
|
|
|
//same as above
|
|
/mob/living/pointed(atom/A as mob|obj|turf in view())
|
|
if(incapacitated())
|
|
return 0
|
|
if(src.status_flags & FAKEDEATH)
|
|
return 0
|
|
if(!..())
|
|
return 0
|
|
visible_message("<b>[src]</b> points to [A]")
|
|
return 1
|
|
|
|
/mob/living/verb/succumb(whispered as null)
|
|
set hidden = 1
|
|
if (InCritical())
|
|
src.attack_log += "[src] has [whispered ? "whispered his final words" : "succumbed to death"] with [round(health, 0.1)] points of health!"
|
|
src.adjustOxyLoss(src.health - config.health_threshold_dead)
|
|
updatehealth()
|
|
if(!whispered)
|
|
src << "<span class='notice'>You have given up life and succumbed to death.</span>"
|
|
death()
|
|
|
|
/mob/living/proc/InCritical()
|
|
return (src.health < 0 && src.health > -95 && stat == UNCONSCIOUS)
|
|
|
|
/mob/living/ex_act(severity, target)
|
|
..()
|
|
flash_eyes()
|
|
|
|
/mob/living/proc/updatehealth()
|
|
if(status_flags & GODMODE)
|
|
return
|
|
health = maxHealth - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss()
|
|
update_stat()
|
|
med_hud_set_health()
|
|
|
|
//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
|
|
// if(istype(src, /mob/living/carbon/human))
|
|
// world << "[src] ~ [src.bodytemperature] ~ [temperature]"
|
|
return temperature
|
|
|
|
|
|
// MOB PROCS
|
|
/mob/living/proc/getBruteLoss()
|
|
return bruteloss
|
|
|
|
/mob/living/proc/adjustBruteLoss(amount, updating_health=1)
|
|
if(status_flags & GODMODE)
|
|
return 0
|
|
bruteloss = Clamp(bruteloss + amount, 0, maxHealth*2)
|
|
if(updating_health)
|
|
updatehealth()
|
|
|
|
/mob/living/proc/getOxyLoss()
|
|
return oxyloss
|
|
|
|
/mob/living/proc/adjustOxyLoss(amount, updating_health=1)
|
|
if(status_flags & GODMODE)
|
|
return 0
|
|
oxyloss = Clamp(oxyloss + amount, 0, maxHealth*2)
|
|
if(updating_health)
|
|
updatehealth()
|
|
|
|
/mob/living/proc/setOxyLoss(amount, updating_health=1)
|
|
if(status_flags & GODMODE)
|
|
return 0
|
|
oxyloss = amount
|
|
if(updating_health)
|
|
updatehealth()
|
|
|
|
/mob/living/proc/getToxLoss()
|
|
return toxloss
|
|
|
|
/mob/living/proc/adjustToxLoss(amount, updating_health=1)
|
|
if(status_flags & GODMODE)
|
|
return 0
|
|
toxloss = Clamp(toxloss + amount, 0, maxHealth*2)
|
|
if(updating_health)
|
|
updatehealth()
|
|
return amount
|
|
|
|
/mob/living/proc/setToxLoss(amount, updating_health=1)
|
|
if(status_flags & GODMODE)
|
|
return 0
|
|
toxloss = amount
|
|
if(updating_health)
|
|
updatehealth()
|
|
|
|
/mob/living/proc/getFireLoss()
|
|
return fireloss
|
|
|
|
/mob/living/proc/adjustFireLoss(amount, updating_health=1)
|
|
if(status_flags & GODMODE)
|
|
return 0
|
|
fireloss = Clamp(fireloss + amount, 0, maxHealth*2)
|
|
if(updating_health)
|
|
updatehealth()
|
|
|
|
/mob/living/proc/getCloneLoss()
|
|
return cloneloss
|
|
|
|
/mob/living/proc/adjustCloneLoss(amount, updating_health=1)
|
|
if(status_flags & GODMODE)
|
|
return 0
|
|
cloneloss = Clamp(cloneloss + amount, 0, maxHealth*2)
|
|
if(updating_health)
|
|
updatehealth()
|
|
|
|
/mob/living/proc/setCloneLoss(amount, updating_health=1)
|
|
if(status_flags & GODMODE)
|
|
return 0
|
|
cloneloss = amount
|
|
if(updating_health)
|
|
updatehealth()
|
|
|
|
/mob/living/proc/getBrainLoss()
|
|
return brainloss
|
|
|
|
/mob/living/proc/adjustBrainLoss(amount)
|
|
if(status_flags & GODMODE)
|
|
return 0
|
|
brainloss = Clamp(brainloss + amount, 0, maxHealth*2)
|
|
|
|
/mob/living/proc/setBrainLoss(amount)
|
|
if(status_flags & GODMODE)
|
|
return 0
|
|
brainloss = amount
|
|
|
|
/mob/living/proc/getStaminaLoss()
|
|
return staminaloss
|
|
|
|
/mob/living/proc/adjustStaminaLoss(amount, updating_stamina = 1)
|
|
return
|
|
|
|
/mob/living/carbon/adjustStaminaLoss(amount, updating_stamina = 1)
|
|
if(status_flags & GODMODE)
|
|
return 0
|
|
staminaloss = Clamp(staminaloss + amount, 0, maxHealth*2)
|
|
if(updating_stamina)
|
|
update_stamina()
|
|
|
|
/mob/living/carbon/alien/adjustStaminaLoss(amount, updating_stamina = 1)
|
|
return
|
|
|
|
/mob/living/proc/setStaminaLoss(amount, updating_stamina = 1)
|
|
return
|
|
|
|
/mob/living/carbon/setStaminaLoss(amount, updating_stamina = 1)
|
|
if(status_flags & GODMODE)
|
|
return 0
|
|
staminaloss = amount
|
|
if(updating_stamina)
|
|
update_stamina()
|
|
|
|
/mob/living/carbon/alien/setStaminaLoss(amount, updating_stamina = 1)
|
|
return
|
|
|
|
/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(sleeping)
|
|
src << "<span class='notice'>You are already sleeping.</span>"
|
|
return
|
|
else
|
|
if(alert(src, "You sure you want to sleep for a while?", "Sleep", "Yes", "No") == "Yes")
|
|
SetSleeping(20) //Short nap
|
|
update_canmove()
|
|
|
|
/mob/proc/get_contents()
|
|
|
|
/mob/living/proc/lay_down()
|
|
set name = "Rest"
|
|
set category = "IC"
|
|
|
|
resting = !resting
|
|
src << "<span class='notice'>You are now [resting ? "resting" : "getting up"].</span>"
|
|
update_canmove()
|
|
|
|
//Recursive function to find everything a mob is holding.
|
|
/mob/living/get_contents(obj/item/weapon/storage/Storage = null)
|
|
var/list/L = list()
|
|
|
|
if(Storage) //If it called itself
|
|
L += Storage.return_inv()
|
|
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/clothing/under/U in src.contents) //Check for jumpsuit accessories
|
|
L += U.contents
|
|
for(var/obj/item/weapon/folder/F in src.contents) //Check for folders
|
|
L += F.contents
|
|
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/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0)
|
|
return 0 //only carbon liveforms have this proc
|
|
|
|
/mob/living/emp_act(severity)
|
|
var/list/L = src.get_contents()
|
|
for(var/obj/O in L)
|
|
O.emp_act(severity)
|
|
..()
|
|
|
|
/mob/living/proc/can_inject()
|
|
return 1
|
|
|
|
/mob/living/proc/get_organ_target()
|
|
var/mob/shooter = src
|
|
var/t = shooter.zone_selected
|
|
if ((t in list( "eyes", "mouth" )))
|
|
t = "head"
|
|
var/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(brute, burn, updating_health=1)
|
|
adjustBruteLoss(-brute, updating_health)
|
|
adjustFireLoss(-burn, updating_health)
|
|
if(updating_health)
|
|
updatehealth()
|
|
|
|
// damage ONE external organ, organ gets randomly selected from damaged ones.
|
|
/mob/living/proc/take_organ_damage(brute, burn, updating_health=1)
|
|
adjustBruteLoss(brute)
|
|
adjustFireLoss(burn)
|
|
if(updating_health)
|
|
updatehealth()
|
|
|
|
// heal MANY bodyparts, in random order
|
|
/mob/living/proc/heal_overall_damage(brute, burn, updating_health=1)
|
|
adjustBruteLoss(-brute, updating_health)
|
|
adjustFireLoss(-burn, updating_health)
|
|
if(updating_health)
|
|
updatehealth()
|
|
|
|
// damage MANY bodyparts, in random order
|
|
/mob/living/proc/take_overall_damage(brute, burn, updating_health=1)
|
|
adjustBruteLoss(brute, updating_health)
|
|
adjustFireLoss(burn, updating_health)
|
|
if(updating_health)
|
|
updatehealth()
|
|
|
|
//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)
|
|
dead_mob_list -= src
|
|
living_mob_list += src
|
|
suiciding = 0
|
|
stat = UNCONSCIOUS //the mob starts unconscious,
|
|
blind_eyes(1)
|
|
updatehealth() //then we check if the mob should wake up.
|
|
update_canmove()
|
|
update_sight()
|
|
reload_fullscreen()
|
|
. = 1
|
|
|
|
//proc used to completely heal a mob.
|
|
/mob/living/proc/fully_heal(admin_revive = 0)
|
|
restore_blood()
|
|
setToxLoss(0, 0)
|
|
setOxyLoss(0, 0)
|
|
setCloneLoss(0, 0)
|
|
setBrainLoss(0)
|
|
setStaminaLoss(0, 0)
|
|
SetParalysis(0, 0)
|
|
SetStunned(0, 0)
|
|
SetWeakened(0, 0)
|
|
SetSleeping(0, 0)
|
|
radiation = 0
|
|
nutrition = NUTRITION_LEVEL_FED + 50
|
|
bodytemperature = 310
|
|
set_blindness(0)
|
|
set_blurriness(0)
|
|
set_eye_damage(0)
|
|
cure_nearsighted()
|
|
cure_blind()
|
|
disabilities = 0
|
|
ear_deaf = 0
|
|
ear_damage = 0
|
|
hallucination = 0
|
|
heal_overall_damage(100000, 100000)
|
|
ExtinguishMob()
|
|
fire_stacks = 0
|
|
updatehealth()
|
|
update_canmove()
|
|
|
|
|
|
//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 <= config.health_threshold_dead)
|
|
return 0
|
|
|
|
/mob/living/proc/update_damage_overlays()
|
|
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)
|
|
src << "[src]'s Metainfo:<br>[client.prefs.metadata]"
|
|
else
|
|
src << "[src] does not have any stored infomation!"
|
|
else
|
|
src << "OOC Metadata is not supported by this server!"
|
|
|
|
return
|
|
*/
|
|
|
|
/mob/living/Move(atom/newloc, direct)
|
|
if (buckled && buckled.loc != newloc) //not updating position
|
|
if (!buckled.anchored)
|
|
return buckled.Move(newloc, direct)
|
|
else
|
|
return 0
|
|
|
|
var/atom/movable/pullee = pulling
|
|
if(pullee && get_dist(src, pullee) > 1)
|
|
stop_pulling()
|
|
if(pullee && !isturf(pullee.loc) && pullee.loc != loc) //to be removed once all code that changes an object's loc uses forceMove().
|
|
log_game("DEBUG:[src]'s pull on [pullee] wasn't broken despite [pullee] being in [pullee.loc]. Pull stopped manually.")
|
|
stop_pulling()
|
|
var/turf/T = loc
|
|
. = ..()
|
|
if(. && pulling && pulling == pullee) //we were pulling a thing and didn't lose it during our move.
|
|
if(pulling.anchored)
|
|
stop_pulling()
|
|
return
|
|
|
|
var/pull_dir = get_dir(src, pulling)
|
|
if(get_dist(src, pulling) > 1 || ((pull_dir - 1) & pull_dir)) //puller and pullee more than one tile away or in diagonal position
|
|
if(isliving(pulling))
|
|
var/mob/living/M = pulling
|
|
if(M.lying && !M.buckled && (prob(M.getBruteLoss()*200/M.maxHealth)))
|
|
M.makeTrail(T)
|
|
pulling.Move(T, get_dir(pulling, T)) //the pullee tries to reach our previous position
|
|
if(pulling && get_dist(src, pulling) > 1) //the pullee couldn't keep up
|
|
stop_pulling()
|
|
|
|
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1)//separated from our puller and not in the middle of a diagonal move.
|
|
pulledby.stop_pulling()
|
|
|
|
if (s_active && !(s_active in contents) && !(s_active.loc in contents))
|
|
// It's ugly. But everything related to inventory/storage is. -- c0
|
|
s_active.close(src)
|
|
|
|
/mob/living/movement_delay()
|
|
. = ..()
|
|
if(isturf(loc, /turf/open))
|
|
var/turf/open/T = loc
|
|
. += T.slowdown
|
|
switch(m_intent)
|
|
if("run")
|
|
if(drowsyness > 0)
|
|
. += 6
|
|
. += config.run_speed
|
|
if("walk")
|
|
. += config.walk_speed
|
|
|
|
/mob/living/proc/makeTrail(turf/T)
|
|
if(!has_gravity(src))
|
|
return
|
|
var/blood_exists = 0
|
|
|
|
for(var/obj/effect/decal/cleanable/trail_holder/C in src.loc) //checks for blood splatter already on the floor
|
|
blood_exists = 1
|
|
if (isturf(src.loc))
|
|
var/trail_type = getTrail()
|
|
if(trail_type)
|
|
var/brute_ratio = round(getBruteLoss()/maxHealth, 0.1)
|
|
if(blood_volume && blood_volume > max(BLOOD_VOLUME_NORMAL*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold
|
|
blood_volume = max(blood_volume - max(1, brute_ratio * 2), 0) //that depends on our brute damage.
|
|
var/newdir = get_dir(T, src.loc)
|
|
if(newdir != src.dir)
|
|
newdir = newdir | src.dir
|
|
if(newdir == 3) //N + S
|
|
newdir = NORTH
|
|
else if(newdir == 12) //E + W
|
|
newdir = EAST
|
|
if((newdir in cardinal) && (prob(50)))
|
|
newdir = turn(get_dir(T, src.loc), 180)
|
|
if(!blood_exists)
|
|
new /obj/effect/decal/cleanable/trail_holder(src.loc)
|
|
for(var/obj/effect/decal/cleanable/trail_holder/TH in src.loc)
|
|
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.overlays.Add(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.specflags) || !bleed_rate || bleedsuppress)
|
|
return
|
|
..()
|
|
|
|
/mob/living/proc/getTrail()
|
|
if(getBruteLoss() < 300)
|
|
return pick("ltrails_1", "ltrails_2")
|
|
else
|
|
return pick("trails_1", "trails_2")
|
|
|
|
/mob/living/verb/resist()
|
|
set name = "Resist"
|
|
set category = "IC"
|
|
|
|
if(!isliving(src) || next_move > world.time || incapacitated(ignore_restraints = 1))
|
|
return
|
|
changeNext_move(CLICK_CD_RESIST)
|
|
|
|
//resisting grabs (as if it helps anyone...)
|
|
if(!restrained(ignore_grab = 1) && pulledby)
|
|
visible_message("<span class='danger'>[src] resists against [pulledby]'s grip!</span>")
|
|
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(canmove)
|
|
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)
|
|
. = 1
|
|
if(pulledby.grab_state)
|
|
if(prob(30/pulledby.grab_state))
|
|
visible_message("<span class='danger'>[src] has broken free of [pulledby]'s grip!</span>")
|
|
pulledby.stop_pulling()
|
|
return 0
|
|
if(moving_resist && client) //we resisted by trying to move
|
|
client.move_delay = world.time + 20
|
|
else
|
|
pulledby.stop_pulling()
|
|
return 0
|
|
|
|
/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(!ticker || !ticker.mode)
|
|
return
|
|
if(has_gravity)
|
|
clear_alert("weightless")
|
|
else
|
|
throw_alert("weightless", /obj/screen/alert/weightless)
|
|
if(!override)
|
|
float(!has_gravity)
|
|
|
|
/mob/living/proc/float(on)
|
|
if(throwing)
|
|
return
|
|
var/fixed = 0
|
|
if(anchored || (buckled && buckled.anchored))
|
|
fixed = 1
|
|
if(on && !floating && !fixed)
|
|
animate(src, pixel_y = pixel_y + 2, time = 10, loop = -1)
|
|
floating = 1
|
|
else if(((!on || fixed) && floating))
|
|
animate(src, pixel_y = get_standard_pixel_y_offset(lying), time = 10)
|
|
floating = 0
|
|
|
|
//called when the mob receives a bright flash
|
|
/mob/living/proc/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash)
|
|
if(check_eye_prot() < intensity && (override_blindness_check || !(disabilities & BLIND)))
|
|
overlay_fullscreen("flash", type)
|
|
addtimer(src, "clear_fullscreen", 25, FALSE, "flash", 25)
|
|
return 1
|
|
|
|
//this returns the mob's protection against eye damage (number between -1 and 2)
|
|
/mob/living/proc/check_eye_prot()
|
|
return 0
|
|
|
|
//this returns the mob's protection against ear damage (0 or 1)
|
|
/mob/living/proc/check_ear_prot()
|
|
return 0
|
|
|
|
// 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.flags & NODROP)
|
|
src << "<span class='warning'>You can't remove \the [what.name], it appears to be stuck!</span>"
|
|
return
|
|
who.visible_message("<span class='danger'>[src] tries to remove [who]'s [what.name].</span>", \
|
|
"<span class='userdanger'>[src] tries to remove [who]'s [what.name].</span>")
|
|
what.add_fingerprint(src)
|
|
if(do_mob(src, who, what.strip_delay))
|
|
if(what && what == who.get_item_by_slot(where) && Adjacent(who))
|
|
who.unEquip(what)
|
|
add_logs(src, who, "stripped", addition="of [what]")
|
|
|
|
// 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_hand()
|
|
if(what && (what.flags & NODROP))
|
|
src << "<span class='warning'>You can't put \the [what.name] on [who], it's stuck to your hand!</span>"
|
|
return
|
|
if(what)
|
|
if(!what.mob_can_equip(who, where, 1))
|
|
src << "<span class='warning'>\The [what.name] doesn't fit in that place!</span>"
|
|
return
|
|
visible_message("<span class='notice'>[src] tries to put [what] on [who].</span>")
|
|
if(do_mob(src, who, what.put_on_delay))
|
|
if(what && Adjacent(who))
|
|
unEquip(what)
|
|
who.equip_to_slot_if_possible(what, where, 0, 1)
|
|
add_logs(src, who, "equipped", what)
|
|
|
|
/mob/living/singularity_act()
|
|
var/gain = 20
|
|
investigate_log("([key_name(src)]) has been consumed by the singularity.","singulo") //Oh that's where the clown ended up!
|
|
gib()
|
|
return(gain)
|
|
|
|
/mob/living/singularity_pull(S, current_size)
|
|
if(current_size >= STAGE_SIX)
|
|
throw_at_fast(S,14,3, spin=1)
|
|
else
|
|
step_towards(src,S)
|
|
|
|
/mob/living/narsie_act()
|
|
if(is_servant_of_ratvar(src) && !stat)
|
|
src << "<span class='userdanger'>You resist Nar-Sie's influence... but not all of it. <i>Run!</i></span>"
|
|
adjustBruteLoss(35)
|
|
if(src && reagents)
|
|
reagents.add_reagent("heparin", 5)
|
|
return 0
|
|
if(client)
|
|
makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, null, 0)
|
|
else
|
|
new /mob/living/simple_animal/hostile/construct/harvester/hostile(get_turf(src))
|
|
spawn_dust()
|
|
gib()
|
|
return
|
|
|
|
/mob/living/ratvar_act()
|
|
if(!add_servant_of_ratvar(src) && !is_servant_of_ratvar(src))
|
|
src << "<span class='userdanger'>A blinding light boils you alive! <i>Run!</i></span>"
|
|
adjustFireLoss(35)
|
|
if(src)
|
|
adjust_fire_stacks(1)
|
|
IgniteMob()
|
|
|
|
/atom/movable/proc/do_attack_animation(atom/A, final_pixel_y, final_pixel_x)
|
|
var/pixel_x_diff = 0
|
|
var/pixel_y_diff = 0
|
|
if(!final_pixel_y)
|
|
final_pixel_y = initial(pixel_y)
|
|
|
|
if(!final_pixel_x)
|
|
final_pixel_x = initial(pixel_x) //lol copypasta
|
|
|
|
var/direction = get_dir(src, A)
|
|
if(direction & NORTH)
|
|
pixel_y_diff = 8
|
|
else if(direction & SOUTH)
|
|
pixel_y_diff = -8
|
|
|
|
if(direction & EAST)
|
|
pixel_x_diff = 8
|
|
else if(direction & WEST)
|
|
pixel_x_diff = -8
|
|
|
|
animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, time = 2)
|
|
//animate(pixel_x = initial(pixel_x), pixel_y = final_pixel_y, time = 2)
|
|
animate(pixel_x = pixel_x - pixel_x_diff, pixel_y = final_pixel_y, time = 2) //Why reset when you can just reverse? 99% less shit-breaking.
|
|
|
|
/mob/living/do_attack_animation(atom/A)
|
|
var/final_pixel_y = get_standard_pixel_y_offset(lying)
|
|
..(A, final_pixel_y)
|
|
floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement.
|
|
|
|
// What icon do we use for the attack?
|
|
var/image/I
|
|
if(hand && l_hand) // Attacked with item in left hand.
|
|
I = image(l_hand.icon, A, l_hand.icon_state, A.layer + 0.1)
|
|
else if(!hand && r_hand) // Attacked with item in right hand.
|
|
I = image(r_hand.icon, A, r_hand.icon_state, A.layer + 0.1)
|
|
else // Attacked with a fist?
|
|
return
|
|
|
|
// Who can see the attack?
|
|
var/list/viewing = list()
|
|
for(var/mob/M in viewers(A))
|
|
if(M.client)
|
|
viewing |= M.client
|
|
flick_overlay(I, viewing, 5) // 5 ticks/half a second
|
|
|
|
// Scale the icon.
|
|
I.transform *= 0.75
|
|
// The icon should not rotate.
|
|
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
|
|
|
|
// Set the direction of the icon animation.
|
|
var/direction = get_dir(src, A)
|
|
if(direction & NORTH)
|
|
I.pixel_y = -16
|
|
else if(direction & SOUTH)
|
|
I.pixel_y = 16
|
|
|
|
if(direction & EAST)
|
|
I.pixel_x = -16
|
|
else if(direction & WEST)
|
|
I.pixel_x = 16
|
|
|
|
if(!direction) // Attacked self?!
|
|
I.pixel_z = 16
|
|
|
|
// And animate the attack!
|
|
animate(I, alpha = 175, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3)
|
|
|
|
/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 = 2, loop = 6)
|
|
animate(pixel_x = final_pixel_x , pixel_y = final_pixel_y , time = 2)
|
|
floating = 0 // 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 = T0C
|
|
if(istype(loc, /obj/mecha))
|
|
var/obj/mecha/M = loc
|
|
loc_temp = M.return_temperature()
|
|
|
|
else if(istype(loc, /obj/structure/transit_tube_pod))
|
|
loc_temp = environment.temperature
|
|
|
|
else if(istype(get_turf(src), /turf/open/space))
|
|
var/turf/heat_turf = get_turf(src)
|
|
loc_temp = heat_turf.temperature
|
|
|
|
else if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
|
|
var/obj/machinery/atmospherics/components/unary/cryo_cell/C = loc
|
|
var/datum/gas_mixture/G = C.AIR1
|
|
|
|
if(G.total_moles() < 10)
|
|
loc_temp = environment.temperature
|
|
else
|
|
loc_temp = G.temperature
|
|
|
|
else
|
|
loc_temp = environment.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/Stat()
|
|
..()
|
|
if(statpanel("Status"))
|
|
if(ticker)
|
|
if(ticker.mode)
|
|
for(var/datum/gang/G in ticker.mode.gangs)
|
|
if(G.is_dominating)
|
|
stat(null, "[G.name] Gang Takeover: [max(G.domination_time_remaining(), 0)]")
|
|
|
|
/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(T.z == ZLEVEL_CENTCOM) //dont detect mobs on centcomm
|
|
return 0
|
|
if(T.z >= ZLEVEL_SPACEMAX)
|
|
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()
|
|
return 0
|
|
|
|
/mob/living/proc/harvest(mob/living/user)
|
|
if(qdeleted(src))
|
|
return
|
|
if(butcher_results)
|
|
for(var/path in butcher_results)
|
|
for(var/i = 1; i <= butcher_results[path];i++)
|
|
new path(src.loc)
|
|
butcher_results.Remove(path) //In case you want to have things like simple_animals drop their butcher results on gib, so it won't double up below.
|
|
visible_message("<span class='notice'>[user] butchers [src].</span>")
|
|
gib()
|
|
|
|
/mob/living/canUseTopic(atom/movable/M, be_close = 0, no_dextery = 0)
|
|
if(incapacitated())
|
|
return
|
|
if(no_dextery)
|
|
if(be_close && in_range(M, src))
|
|
return 1
|
|
else
|
|
src << "<span class='warning'>You don't have the dexterity to do this!</span>"
|
|
return
|
|
/mob/living/proc/can_use_guns(var/obj/item/weapon/gun/G)
|
|
if (G.trigger_guard != TRIGGER_GUARD_ALLOW_ALL && !IsAdvancedToolUser())
|
|
src << "<span class='warning'>You don't have the dexterity to do this!</span>"
|
|
return 0
|
|
return 1
|
|
|
|
/mob/living/carbon/proc/update_stamina()
|
|
return
|
|
|
|
/mob/living/carbon/human/update_stamina()
|
|
if(staminaloss)
|
|
var/total_health = (health - staminaloss)
|
|
if(total_health <= config.health_threshold_crit && !stat)
|
|
src << "<span class='notice'>You're too exhausted to keep going...</span>"
|
|
Weaken(5)
|
|
setStaminaLoss(health - 2)
|
|
update_health_hud()
|
|
|
|
/mob/proc/update_sight()
|
|
return
|
|
|
|
/mob/living/proc/owns_soul()
|
|
if(mind)
|
|
return mind.soulOwner == mind
|
|
return 1
|
|
|
|
/mob/living/proc/return_soul()
|
|
if(mind)
|
|
mind.soulOwner = mind
|
|
|
|
/mob/living/proc/has_bane(banetype)
|
|
if(mind)
|
|
if(mind.devilinfo)
|
|
return mind.devilinfo.bane == banetype
|
|
return 0
|
|
|
|
/mob/living/proc/check_weakness(obj/item/weapon, mob/living/attacker)
|
|
if(mind && mind.devilinfo)
|
|
return check_devil_bane_multiplier(weapon, attacker)
|
|
return 1
|
|
|
|
/mob/living/proc/check_acedia()
|
|
if(src.mind && src.mind.objectives)
|
|
for(var/datum/objective/sintouched/acedia/A in src.mind.objectives)
|
|
return 1
|
|
return 0
|
|
|
|
/mob/living/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0)
|
|
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 = 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()
|
|
G << "<span class='holoparasite'>Your summoner has changed \
|
|
form!</span>"
|