Files
Aurora.3/code/modules/mob/mob_helpers.dm
Erki 7b1bcdc8f3 October Bugfix Bonanza (#3767)
Fixes #3742 - someone unfucked the fix again.
Resolves #3740 and resolves #3739.
Fixes #1558 - a 10 month long meme is dead.
Resolves #3720 by making robo-eyes immune only to the eye stinging effects of pepperspray. Let there be equality amongst the synths.
Fixes #3676 - tested, shouldn't break. It was double-calling set_death_timer.
Fixes #3672 and fixes #3658 - that was my bad on not noticing the diff around hologram.icon = icon vs add_overlay(icon).
Fixes #3762 - I'm surprised this didn't fuck over more.
2017-10-29 19:03:24 +02:00

1155 lines
32 KiB
Plaintext

// fun if you want to typecast humans/monkeys/etc without writing long path-filled lines.
/proc/isxenomorph(A)
if(istype(A, /mob/living/carbon/human))
var/mob/living/carbon/human/H = A
return istype(H.species, /datum/species/xenos)
return 0
/proc/issmall(A)
if(A && istype(A, /mob/living))
var/mob/living/L = A
return L.mob_size <= MOB_SMALL
return 0
/mob/living/proc/isSynthetic()
return 0
/mob/living/carbon/human/isSynthetic()
// If they are 100% robotic, they count as synthetic.
for(var/obj/item/organ/external/E in organs)
if(!(E.status & ORGAN_ROBOT))
return 0
return 1
/mob/living/silicon/isSynthetic()
return 1
/mob/proc/isMonkey()
return 0
/mob/living/carbon/human/isMonkey()
return istype(species, /datum/species/monkey)
/proc/ishuman_species(A)
if(istype(A, /mob/living/carbon/human) && (A:get_species() == "Human"))
return 1
return 0
/proc/isunathi(A)
if(istype(A, /mob/living/carbon/human) && (A:get_species() == "Unathi"))
return 1
return 0
/proc/istajara(A)
if(istype(A, /mob/living/carbon/human))
switch(A:get_species())
if ("Tajara")
return 1
if("Zhan-Khazan Tajara")
return 1
if("M'sai Tajara")
return 1
return 0
/proc/isskrell(A)
if(istype(A, /mob/living/carbon/human) && (A:get_species() == "Skrell"))
return 1
return 0
/proc/isvaurca(A)
if(istype(A, /mob/living/carbon/human))
switch(A:get_species())
if ("Vaurca Worker")
return 1
if("Vaurca Warrior")
return 1
if("Vaurca Breeder")
return 1
if("V'krexi")
return 1
return 0
/proc/isipc(A)
. = 0
if(istype(A, /mob/living/carbon/human))
var/mob/living/carbon/human/H = A
. = !!global.mechanical_species[H.get_species()]
/proc/isvox(A)
if(istype(A, /mob/living/carbon/human))
switch(A:get_species())
if ("Vox")
return 1
if ("Vox Pariah")
return 1
if ("Vox Armalis")
return 1
return 0
/mob/proc/is_diona()
//returns which type of diona we are, or zero
if (istype(src, /mob/living/carbon/human))
var/mob/living/carbon/human/T = src
if (istype(T.species, /datum/species/diona) || istype(src, /mob/living/carbon/human/diona))
return DIONA_WORKER
if (istype(src, /mob/living/carbon/alien/diona))
return DIONA_NYMPH
return 0
/proc/isskeleton(A)
if(istype(A, /mob/living/carbon/human) && (A:get_species() == "Skeleton"))
return 1
return 0
/proc/islesserform(A)
if(istype(A, /mob/living/carbon/human))
switch(A:get_species())
if ("Monkey")
return 1
if ("Farwa")
return 1
if ("Neaera")
return 1
if ("Stok")
return 1
if ("V'krexi")
return 1
return 0
proc/isdeaf(A)
if(istype(A, /mob))
var/mob/M = A
return (M.sdisabilities & DEAF) || M.ear_deaf
return 0
proc/hasorgans(A) // Fucking really??
return ishuman(A)
proc/iscuffed(A)
if(istype(A, /mob/living/carbon))
var/mob/living/carbon/C = A
if(C.handcuffed)
return 1
return 0
proc/hassensorlevel(A, var/level)
var/mob/living/carbon/human/H = A
if(istype(H) && istype(H.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/U = H.w_uniform
return U.sensor_mode >= level
return 0
proc/getsensorlevel(A)
var/mob/living/carbon/human/H = A
if(istype(H) && istype(H.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/U = H.w_uniform
return U.sensor_mode
return SUIT_SENSOR_OFF
/proc/is_admin(var/mob/user)
return check_rights(R_ADMIN, 0, user) != 0
/proc/hsl2rgb(h, s, l)
return //TODO: Implement
/mob/living/proc/is_wizard(exclude_apprentice = FALSE)
if(exclude_apprentice)
return mind && mind.assigned_role == "Space Wizard"
else
return mind && (mind.assigned_role == "Space Wizard" || mind.assigned_role == "Apprentice")
/*
Miss Chance
*/
//TODO: Integrate defence zones and targeting body parts with the actual organ system, move these into organ definitions.
//The base miss chance for the different defence zones
var/list/global/base_miss_chance = list(
"head" = 40,
"chest" = 10,
"groin" = 20,
"l_leg" = 20,
"r_leg" = 20,
"l_arm" = 20,
"r_arm" = 20,
"l_hand" = 50,
"r_hand" = 50,
"l_foot" = 50,
"r_foot" = 50
)
//Used to weight organs when an organ is hit randomly (i.e. not a directed, aimed attack).
//Also used to weight the protection value that armour provides for covering that body part when calculating protection from full-body effects.
var/list/global/organ_rel_size = list(
"head" = 25,
"chest" = 70,
"groin" = 30,
"l_leg" = 25,
"r_leg" = 25,
"l_arm" = 25,
"r_arm" = 25,
"l_hand" = 10,
"r_hand" = 10,
"l_foot" = 10,
"r_foot" = 10
)
/proc/check_zone(zone)
if(!zone) return "chest"
switch(zone)
if("eyes")
zone = "head"
if("mouth")
zone = "head"
return zone
// Returns zone with a certain probability. If the probability fails, or no zone is specified, then a random body part is chosen.
// Do not use this if someone is intentionally trying to hit a specific body part.
// Use get_zone_with_miss_chance() for that.
/proc/ran_zone(zone, probability)
if (zone)
zone = check_zone(zone)
if (prob(probability))
return zone
var/ran_zone = zone
while (ran_zone == zone)
ran_zone = pick (
organ_rel_size["head"]; "head",
organ_rel_size["chest"]; "chest",
organ_rel_size["groin"]; "groin",
organ_rel_size["l_arm"]; "l_arm",
organ_rel_size["r_arm"]; "r_arm",
organ_rel_size["l_leg"]; "l_leg",
organ_rel_size["r_leg"]; "r_leg",
organ_rel_size["l_hand"]; "l_hand",
organ_rel_size["r_hand"]; "r_hand",
organ_rel_size["l_foot"]; "l_foot",
organ_rel_size["r_foot"]; "r_foot"
)
return ran_zone
// Emulates targetting a specific body part, and miss chances
// May return null if missed
// miss_chance_mod may be negative.
/proc/get_zone_with_miss_chance(zone, var/mob/target, var/miss_chance_mod = 0, var/ranged_attack=0)
zone = check_zone(zone)
if(!ranged_attack)
// you cannot miss if your target is prone or restrained
if(target.buckled || target.lying)
return zone
// if your target is being grabbed aggressively by someone you cannot miss either
for(var/obj/item/weapon/grab/G in target.grabbed_by)
if(G.state >= GRAB_AGGRESSIVE)
return zone
var/miss_chance = 10
if (zone in base_miss_chance)
miss_chance = base_miss_chance[zone]
miss_chance = max(miss_chance + miss_chance_mod, 0)
if(prob(miss_chance))
if(prob(70))
return null
return pick(base_miss_chance)
return zone
/proc/stars(n, pr)
if (pr == null)
pr = 25
if (pr <= 0)
return null
else
if (pr >= 100)
return n
var/te = n
var/t = ""
n = length(n)
var/p = null
p = 1
var/intag = 0
while(p <= n)
var/char = copytext(te, p, p + 1)
if (char == "<") //let's try to not break tags
intag = !intag
if (intag || char == " " || prob(pr))
t = text("[][]", t, char)
else
t = text("[]*", t)
if (char == ">")
intag = !intag
p++
return t
proc/slur(phrase)
phrase = html_decode(phrase)
var/leng=lentext(phrase)
var/counter=lentext(phrase)
var/newphrase=""
var/newletter=""
while(counter>=1)
newletter=copytext(phrase,(leng-counter)+1,(leng-counter)+2)
if(rand(1,3)==3)
if(lowertext(newletter)=="o") newletter="u"
if(lowertext(newletter)=="s") newletter="ch"
if(lowertext(newletter)=="a") newletter="ah"
if(lowertext(newletter)=="c") newletter="k"
switch(rand(1,15))
if(1,3,5,8) newletter="[lowertext(newletter)]"
if(2,4,6,15) newletter="[uppertext(newletter)]"
if(7) newletter+="'"
//if(9,10) newletter="<b>[newletter]</b>"
//if(11,12) newletter="<big>[newletter]</big>"
//if(13) newletter="<small>[newletter]</small>"
newphrase+="[newletter]";counter-=1
return newphrase
/proc/stutter(n)
var/te = html_decode(n)
var/t = ""//placed before the message. Not really sure what it's for.
n = length(n)//length of the entire word
var/p = null
p = 1//1 is the start of any word
while(p <= n)//while P, which starts at 1 is less or equal to N which is the length.
var/n_letter = copytext(te, p, p + 1)//copies text from a certain distance. In this case, only one letter at a time.
if (prob(80) && (ckey(n_letter) in list("b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z")))
if (prob(10))
n_letter = text("[n_letter]-[n_letter]-[n_letter]-[n_letter]")//replaces the current letter with this instead.
else
if (prob(20))
n_letter = text("[n_letter]-[n_letter]-[n_letter]")
else
if (prob(5))
n_letter = null
else
n_letter = text("[n_letter]-[n_letter]")
t = text("[t][n_letter]")//since the above is ran through for each letter, the text just adds up back to the original word.
p++//for each letter p is increased to find where the next letter will be.
return sanitize(t)
proc/Gibberish(t, p)//t is the inputted message, and any value higher than 70 for p will cause letters to be replaced instead of added
/* Turn text into complete gibberish! */
var/returntext = ""
for(var/i = 1, i <= length(t), i++)
var/letter = copytext(t, i, i+1)
if(prob(50))
if(p >= 70)
letter = ""
for(var/j = 1, j <= rand(0, 2), j++)
letter += pick("#","@","*","&","%","$","/", "<", ">", ";","*","*","*","*","*","*","*")
returntext += letter
return returntext
/proc/ninjaspeak(n)
/*
The difference with stutter is that this proc can stutter more than 1 letter
The issue here is that anything that does not have a space is treated as one word (in many instances). For instance, "LOOKING," is a word, including the comma.
It's fairly easy to fix if dealing with single letters but not so much with compounds of letters./N
*/
var/te = html_decode(n)
var/t = ""
n = length(n)
var/p = 1
while(p <= n)
var/n_letter
var/n_mod = rand(1,4)
if(p+n_mod>n+1)
n_letter = copytext(te, p, n+1)
else
n_letter = copytext(te, p, p+n_mod)
if (prob(50))
if (prob(30))
n_letter = text("[n_letter]-[n_letter]-[n_letter]")
else
n_letter = text("[n_letter]-[n_letter]")
else
n_letter = text("[n_letter]")
t = text("[t][n_letter]")
p=p+n_mod
return sanitize(t)
/proc/shake_camera(mob/M, duration, strength=1, var/taper = 0)
if(!M || !M.client || M.shakecamera || M.stat || isEye(M) || isAI(M))
return
M.shakecamera = 1
spawn(2)
if(!M.client)
return
var/atom/oldeye=M.client.eye
var/aiEyeFlag = 0
if(istype(oldeye, /mob/eye/aiEye))
aiEyeFlag = 1
var/x
for(x=0; x<duration, x++)
if(aiEyeFlag)
M.client.eye = locate(dd_range(1,oldeye.loc.x+rand(-strength,strength),world.maxx),dd_range(1,oldeye.loc.y+rand(-strength,strength),world.maxy),oldeye.loc.z)
else
M.client.eye = locate(dd_range(1,M.loc.x+rand(-strength,strength),world.maxx),dd_range(1,M.loc.y+rand(-strength,strength),world.maxy),M.loc.z)
sleep(1)
//Taper code added by nanako.
//Will make the strength falloff after the duration.
//This helps to reduce jarring effects of major screenshaking suddenly returning to stability
//Recommended taper values are 0.05-0.1
if (taper > 0)
while (strength > 0)
strength -= taper
if(aiEyeFlag)
M.client.eye = locate(dd_range(1,oldeye.loc.x+rand(-strength,strength),world.maxx),dd_range(1,oldeye.loc.y+rand(-strength,strength),world.maxy),oldeye.loc.z)
else
M.client.eye = locate(dd_range(1,M.loc.x+rand(-strength,strength),world.maxx),dd_range(1,M.loc.y+rand(-strength,strength),world.maxy),M.loc.z)
sleep(1)
M.client.eye=oldeye
M.shakecamera = 0
/proc/findname(msg)
for(var/mob/M in mob_list)
if (M.real_name == text("[msg]"))
return 1
return 0
/mob/proc/abiotic(var/full_body = 0)
if(full_body && ((src.l_hand && !( src.l_hand.abstract )) || (src.r_hand && !( src.r_hand.abstract )) || (src.back || src.wear_mask)))
return 1
if((src.l_hand && !( src.l_hand.abstract )) || (src.r_hand && !( src.r_hand.abstract )))
return 1
return 0
//converts intent-strings into numbers and back
var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HURT)
/proc/intent_numeric(argument)
if(istext(argument))
switch(argument)
if(I_HELP) return 0
if(I_DISARM) return 1
if(I_GRAB) return 2
else return 3
else
switch(argument)
if(0) return I_HELP
if(1) return I_DISARM
if(2) return I_GRAB
else return I_HURT
//change a mob's act-intent. Input the intent as a string such as "help" or use "right"/"left
/mob/verb/a_intent_change(input as text)
set name = "a-intent"
set hidden = 1
if(ishuman(src) || isbrain(src) || isslime(src))
switch(input)
if(I_HELP,I_DISARM,I_GRAB,I_HURT)
a_intent = input
if("right")
a_intent = intent_numeric((intent_numeric(a_intent)+1) % 4)
if("left")
a_intent = intent_numeric((intent_numeric(a_intent)+3) % 4)
if(hud_used && hud_used.action_intent)
hud_used.action_intent.icon_state = "intent_[a_intent]"
else if(isrobot(src))
switch(input)
if(I_HELP)
a_intent = I_HELP
if(I_HURT)
a_intent = I_HURT
if("right","left")
a_intent = intent_numeric(intent_numeric(a_intent) - 3)
if(hud_used && hud_used.action_intent)
if(a_intent == I_HURT)
hud_used.action_intent.icon_state = I_HURT
else
hud_used.action_intent.icon_state = I_HELP
proc/is_blind(A)
if(istype(A, /mob/living/carbon))
var/mob/living/carbon/C = A
if(C.sdisabilities & BLIND || C.blinded)
return 1
return 0
/proc/broadcast_security_hud_message(var/message, var/broadcast_source)
broadcast_hud_message(message, broadcast_source, sec_hud_users, /obj/item/clothing/glasses/hud/security)
/proc/broadcast_medical_hud_message(var/message, var/broadcast_source)
broadcast_hud_message(message, broadcast_source, med_hud_users, /obj/item/clothing/glasses/hud/health)
/proc/broadcast_hud_message(var/message, var/broadcast_source, var/list/targets, var/icon)
var/turf/sourceturf = get_turf(broadcast_source)
for(var/mob/M in targets)
var/turf/targetturf = get_turf(M)
if((targetturf.z == sourceturf.z))
M.show_message("<span class='info'>\icon[icon] [message]</span>", 1)
/proc/mobs_in_area(var/area/A)
var/list/mobs = new
for(var/mob/living/M in mob_list)
if(get_area(M) == A)
mobs += M
return mobs
//Direct dead say used both by emote and say
//It is somewhat messy. I don't know what to do.
//I know you can't see the change, but I rewrote the name code. It is significantly less messy now
/proc/say_dead_direct(var/message, var/mob/subject = null)
var/name
var/keyname
if(subject && subject.client)
var/client/C = subject.client
keyname = (C.holder && C.holder.fakekey) ? C.holder.fakekey : C.key
if(C.mob) //Most of the time this is the dead/observer mob; we can totally use him if there is no better name
var/mindname
var/realname = C.mob.real_name
if(C.mob.mind)
mindname = C.mob.mind.name
if(C.mob.mind.original && C.mob.mind.original.real_name)
realname = C.mob.mind.original.real_name
if(mindname && mindname != realname)
name = "[realname] died as [mindname]"
else
name = realname
for(var/mob/M in player_list)
if(M.client && ((!istype(M, /mob/new_player) && M.stat == DEAD) || (M.client.holder && check_rights(R_DEV|R_MOD|R_ADMIN, 0, M))) && (M.client.prefs.toggles & CHAT_DEAD))
var/follow
var/lname
if(subject)
if(subject != M)
follow = "[ghost_follow_link(subject, M)] "
if(M.stat != DEAD && M.client.holder)
follow = "([admin_jump_link(subject, M.client.holder)]) "
var/mob/dead/observer/DM
if(istype(subject, /mob/dead/observer))
DM = subject
if(M.client.holder) // What admins see
lname = "[keyname][(DM && DM.anonsay) ? "*" : (DM ? "" : "^")] ([name])"
else
if(DM && DM.anonsay) // If the person is actually observer they have the option to be anonymous
lname = "Ghost of [name]"
else if(DM) // Non-anons
lname = "[keyname] ([name])"
else // Everyone else (dead people who didn't ghost yet, etc.)
lname = name
lname = "<span class='name'>[lname]</span> "
M << "[follow] <span class='deadsay'>" + create_text_tag("dead", "DEAD:", M.client) + " [lname][message]</span>"
//Announces that a ghost has joined/left, mainly for use with wizards
/proc/announce_ghost_joinleave(O, var/joined_ghosts = 1, var/message = "")
var/client/C
//Accept any type, sort what we want here
if(istype(O, /mob))
var/mob/M = O
if(M.client)
C = M.client
else if(istype(O, /client))
C = O
else if(istype(O, /datum/mind))
var/datum/mind/M = O
if(M.current && M.current.client)
C = M.current.client
else if(M.original && M.original.client)
C = M.original.client
if(C)
var/name
if(C.mob)
var/mob/M = C.mob
if(M.mind && M.mind.name)
name = M.mind.name
if(M.real_name && M.real_name != name)
if(name)
name += " ([M.real_name])"
else
name = M.real_name
if(!name)
name = (C.holder && C.holder.fakekey) ? C.holder.fakekey : C.key
if(joined_ghosts)
say_dead_direct("The ghost of <span class='name'>[name]</span> now [pick("skulks","lurks","prowls","creeps","stalks")] among the dead. [message]")
else
say_dead_direct("<span class='name'>[name]</span> no longer [pick("skulks","lurks","prowls","creeps","stalks")] in the realm of the dead. [message]")
/mob/proc/switch_to_camera(var/obj/machinery/camera/C)
if (!C.can_use() || stat || (get_dist(C, src) > 1 || machine != src || blinded || !canmove))
return 0
check_eye(src)
return 1
/mob/living/silicon/ai/switch_to_camera(var/obj/machinery/camera/C)
if(!C.can_use() || !is_in_chassis())
return 0
eyeobj.setLoc(C)
return 1
// Returns true if the mob has a client which has been active in the last given X minutes.
/mob/proc/is_client_active(var/active = 1)
return client && client.inactivity < active MINUTES
/mob/proc/can_eat()
return 1
/mob/proc/can_force_feed()
return 1
#define SAFE_PERP -50
/mob/living/proc/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest)
if(stat == DEAD)
return SAFE_PERP
return 0
/mob/living/carbon/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest)
if(handcuffed)
return SAFE_PERP
return ..()
/mob/living/carbon/human/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest)
var/threatcount = ..()
if(. == SAFE_PERP)
return SAFE_PERP
//Agent cards lower threatlevel.
var/obj/item/weapon/card/id/id = GetIdCard()
if(id && istype(id, /obj/item/weapon/card/id/syndicate))
threatcount -= 2
// A proper CentCom id is hard currency.
else if(id && istype(id, /obj/item/weapon/card/id/centcom))
return SAFE_PERP
if(check_access && !access_obj.allowed(src))
threatcount += 4
if(auth_weapons && !access_obj.allowed(src))
if(istype(l_hand, /obj/item/weapon/gun) || istype(l_hand, /obj/item/weapon/melee))
threatcount += 4
if(istype(r_hand, /obj/item/weapon/gun) || istype(r_hand, /obj/item/weapon/melee))
threatcount += 4
if(istype(belt, /obj/item/weapon/gun) || istype(belt, /obj/item/weapon/melee))
threatcount += 2
if(species.name != "Human")
threatcount += 2
if(check_records || check_arrest)
var/perpname = name
if(id)
perpname = id.registered_name
var/datum/data/record/R = find_security_record("name", perpname)
if(check_records && !R)
threatcount += 4
if(check_arrest && R && (R.fields["criminal"] == "*Arrest*"))
threatcount += 4
return threatcount
/mob/living/simple_animal/hostile/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest)
var/threatcount = ..()
if(. == SAFE_PERP)
return SAFE_PERP
if(!istype(src, /mob/living/simple_animal/hostile/retaliate/goat))
threatcount += 4
return threatcount
/mob/living/proc/bucklecheck(var/mob/living/user)
if (buckled && istype(buckled, /obj/structure))
if (istype(user,/mob/living/silicon/robot))
return 2
else
user << "You must unbuckle the subject first"
return 0
return 1
/mob/living/carbon/proc/vomit()
var/canVomit = 0
var/mob/living/carbon/human/H
if (istype(src, /mob/living/carbon/human))
H = src
if (H.ingested.total_volume > 0)
canVomit = 1
if (nutrition > 0)
canVomit = 1
if(canVomit)
Stun(4)
src.visible_message("<span class='warning'>[src] vomits!</span>","<span class='warning'>You vomit!</span>")
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
var/turf/location = loc
if (istype(location, /turf/simulated))
location.add_vomit_floor(src, 1)
nutrition -= 60
if (intoxication)//The pain and system shock of vomiting, sobers you up a little
intoxication *= 0.8
if (istype(src, /mob/living/carbon/human))
ingested.trans_to_turf(location,30)//Vomiting empties the stomach, transferring 30u reagents to the floor where you vomited
else if (prob(50))
src.visible_message("<span class='warning'>[src] retches, attempting to vomit!</span>","<span class='warning'>You gag and collapse as you feel the urge to vomit, but there's nothing in your stomach!</span>")
Weaken(4)
/mob/living/carbon/human/proc/delayed_vomit()
if(!check_has_mouth())
return
if(stat == DEAD)
return
if(!lastpuke)
lastpuke = 1
src << "<span class='warning'>You feel nauseous...</span>"
spawn(150) //15 seconds until second warning
src << "<span class='warning'>You feel like you are about to throw up!</span>"
spawn(100) //and you have 10 more for mad dash to the bucket
vomit()//Vomit function is in mob helpers
spawn(350) //wait 35 seconds before next volley
lastpuke = 0
/obj/proc/get_equip_slot()
//This function is called by an object which is somewhere on a humanoid mob
//It will return the number of the equipment slot its in
if (!istype(loc, /mob/living/carbon/human))//This function is for finding where we are on a human. not valid otherwise
return null
var/mob/living/carbon/human/H = loc
//Now we check various slots on the mob, the order of these is optimised based on how likely we are to be in that slot
if (H.l_hand == src)
return slot_l_hand
else if (H.r_hand == src)
return slot_r_hand
else if (H.l_store == src)
return slot_l_store
else if (H.r_store == src)
return slot_r_store
else if (H.head == src)
return slot_head
else if (H.wear_suit == src)
return slot_wear_suit
else if (H.s_store == src)
return slot_s_store
else if (H.wear_mask == src)
return slot_wear_mask
else if (H.wear_id == src)
return slot_wear_id
else if (H.w_uniform == src)
return slot_w_uniform
else if (H.gloves == src)
return slot_gloves
else if (H.belt == src)
return slot_belt
else if (H.back == src)
return slot_back
else if (H.r_ear == src)
return slot_r_ear
else if (H.l_ear == src)
return slot_l_ear
else if (H.shoes == src)
return slot_shoes
else
return null//We failed to find the slot
/* Variables to check
l_hand
r_hand
head
l_store //Left and right pockets
r_store
s_store //Suit storage?
wear_mask,
wear_id
w_uniform //the uniform
wear_suit
gloves
belt
back
r_ear
l_ear
shoes
*/
/obj/proc/report_onmob_location(var/justmoved, var/slot = null, var/mob/reportto)
var/mob/living/carbon/human/H//The person who the item is on
var/newlocation
var/preposition= ""
var/action = ""
var/action3 = ""
if (!reportto)
return 0
if (istype(loc, /mob/living/carbon/human))//This function is for finding where we are on a human. not valid otherwise
H = loc
else
H = get_holding_mob()
if (slot != null)
if (slot_l_hand == slot)
if (justmoved)
action += "now "
preposition = "in"
action += "being held"
action3 = "holds"
newlocation = "left hand"
else if (slot_r_hand == slot)
if (justmoved)
action += "now "
preposition = "in"
action += "being held"
action3 = "holds"
newlocation = "right hand"
else if (slot_l_store == slot)
if (justmoved)
preposition = "into"
action = "placed"
action3 = "places"
else
preposition = "inside"
newlocation = "left pocket"
else if (slot_r_store == slot)
if (justmoved)
preposition = "into"
action = "placed"
action3 = "places"
else
preposition = "inside"
newlocation = "right pocket"
else if (slot_s_store == slot)
if (justmoved)
preposition = "into"
action = "placed"
action3 = "places"
else
preposition = "inside"
newlocation = "suit storage"
else
if (justmoved)
action += "now "
action += "being worn"
if (slot_head == slot)
preposition = "as"
action3 = "wears"
newlocation = "hat"
else if (slot_wear_suit == slot)
preposition = "over"
action3 = "wears"
newlocation = "uniform"
else if (slot_wear_mask == slot)
preposition = "on"
action3 = "wears"
newlocation = "face"
else if (slot_wear_id == slot)
preposition = "as"
action3 = "wears"
newlocation = "ID"
else if (slot_w_uniform == slot)
preposition = "on"
action3 = "wears"
newlocation = "body"
else if (slot_gloves == slot)
preposition = "on"
action3 = "wears"
newlocation = "hands"
else if (slot_belt == slot)
preposition = "around"
action3 = "wears"
newlocation = "waist"
else if (slot_back == slot)
preposition = "on"
action3 = "wears"
newlocation = "back"
else if (slot_r_ear == slot)
preposition = "on"
action3 = "wears"
newlocation = "right shoulder"//Ill use ear slots for wearing mobs on the shoulder in future
else if (slot_l_ear == slot)
preposition = "on"
action3 = "wears"
newlocation = "left shoulder"
else if (slot_shoes == slot)
preposition = "on"
action3 = "wears"
newlocation = "feet"
else if (istype(loc,/obj/item/device/pda))
var/obj/item/device/pda/S = loc
newlocation = S.name
if (justmoved)
preposition = "into"
action = "slotted"
action3 = "slots"
else
action = "installed"
preposition = "in"
else if (istype(loc,/obj/item/weapon/storage))
var/obj/item/weapon/storage/S = loc
newlocation = S.name
if (justmoved)
preposition = "into"
action = "placed"
action3 = "places"
else
action = "tucked"
preposition = "inside"
if (justmoved)
reportto.contained_visible_message(H, "<span class='notice'>[H] [action3] [reportto] [preposition] their [newlocation]</span>", "<span class='notice'>You are [action] [preposition] [H]'s [newlocation]</span>", "", 1)
else
reportto << "<span class='notice'>You are [action] [preposition] [H]'s [newlocation]</span>"
/atom/proc/get_holding_mob()
//This function will return the mob which is holding this holder, or null if it's not held
//It recurses up the hierarchy out of containers until it reaches a mob, or aturf, or hits the limit
var/x = 0//As a safety, we'll crawl up a maximum of five layers
var/atom/a = src
while (x < 5)
x++
if (isnull(a))
return null
a = a.loc
if (istype(a, /turf))
return null//We must be on a table or a floor, or maybe in a wall. Either way we're not held.
if (istype(a, /mob))
return a
//If none of the above are true, we must be inside a box or backpack or something. Keep recursing up.
return null//If we get here, the holder must be buried many layers deep in nested containers. Shouldn't happen
//This proc retrieves the relevant time of death from
/mob/proc/get_death_time(var/which)
var/datum/preferences/P
if (client)
P = client.prefs
else if (ckey)
// To avoid runtimes during adminghost.
if (copytext(ckey, 1, 2) == "@")
P = preferences_datums[copytext(ckey, 2)]
else
P = preferences_datums[ckey]
else
return null
if (!P)
return null
return P.time_of_death[which]
/mob/proc/set_death_time(var/which, var/value)
var/datum/preferences/P
if (client)
P = client.prefs
else if (ckey)
// To avoid runtimes during adminghost.
if (copytext(ckey, 1, 2) == "@")
P = preferences_datums[copytext(ckey, 2)]
else
P = preferences_datums[ckey]
else
return 0
if (!P)
return 0
P.time_of_death[which] = value
return 1
/**
* Resets death timers for a mob. Should only be called during new player creation.
*/
/mob/proc/reset_death_timers()
var/datum/preferences/P
if (client)
P = client.prefs
else if (ckey)
// To avoid runtimes during adminghost.
if (copytext(ckey, 1, 2) == "@")
P = preferences_datums[copytext(ckey, 2)]
else
P = preferences_datums[ckey]
else
return
if (!P)
return
P.time_of_death.Cut()
//Below here is stuff related to devouring, but which is generally helpful and thus placed here
//See Devour.dm for more info in how these are used
// Returns a bitfield representing the mob's type as relevant to the devour system.
/mob/proc/find_type()
return 0
/mob/living/carbon/human/find_type()
. = ..()
. |= isSynthetic() ? TYPE_SYNTHETIC : TYPE_ORGANIC
if (!islesserform(src))
. |= TYPE_HUMANOID
/mob/living/carbon/slime/find_type()
. = ..()
. |= TYPE_WEIRD
/mob/living/bot/find_type()
. = ..()
. |= TYPE_SYNTHETIC
// Yeah, I'm just going to cheat and do istype(src) checks here.
// It's not worth adding a proc for every single one of these types.
/mob/living/simple_animal/find_type()
. = ..()
if (is_type_in_typecache(src, global.mtl_synthetic))
. |= TYPE_SYNTHETIC
if (is_type_in_typecache(src, global.mtl_weird))
. |= TYPE_WEIRD
// If it's not TYPE_SYNTHETIC or TYPE_WEIRD, we can assume it's TYPE_ORGANIC.
if (!(. & (TYPE_SYNTHETIC|TYPE_WEIRD)))
. |= TYPE_ORGANIC
if (is_type_in_typecache(src, global.mtl_humanoid))
. |= TYPE_HUMANOID
/mob/living/proc/get_vessel(create = FALSE)
if (!create)
return
//we make a new vessel for whatever creature we're devouring. this allows blood to come from creatures that can't normally bleed
//We create an MD5 hash of the mob's reference to use as its DNA string.
//This creates unique DNA for each creature in a consistently repeatable process
var/datum/reagents/vessel = new/datum/reagents(600)
vessel.add_reagent("blood",560)
for(var/datum/reagent/blood/B in vessel.reagent_list)
if(B.id == "blood")
B.data = list(
"donor" = WEAKREF(src),
"viruses" = null,
"species" = name,
"blood_DNA" = md5("\ref[src]"),
"blood_colour" = "#a10808",
"blood_type" = null,
"resistances" = null,
"trace_chem" = null,
"virus2" = null,
"antibodies" = list()
)
B.color = B.data["blood_colour"]
return vessel
/mob/living/carbon/human/get_vessel(create = FALSE)
. = vessel
/mob/living/carbon/alien/diona/get_vessel(create = FALSE)
. = vessel
#define POSESSIVE_PRONOUN 0
#define POSESSIVE_ADJECTIVE 1
#define REFLEXIVE 2
#define SUBJECTIVE_PERSONAL 3
#define OBJECTIVE_PERSONAL 4
/mob/proc/get_pronoun(var/type)
switch (type)
if (POSESSIVE_PRONOUN)
switch(gender)
if (MALE)
return "his"
if (FEMALE)
return "hers"
else
return "theirs"
if (POSESSIVE_ADJECTIVE)
switch(gender)
if (MALE)
return "his"
if (FEMALE)
return "her"
else
return "their"
if (REFLEXIVE)
switch(gender)
if (MALE)
return "himself"
if (FEMALE)
return "herself"
else
return "themselves"
if (SUBJECTIVE_PERSONAL)
switch(gender)
if (MALE)
return "he"
if (FEMALE)
return "she"
else
return "they"
if (OBJECTIVE_PERSONAL)
switch(gender)
if (MALE)
return "him"
if (FEMALE)
return "her"
else
return "them"
else
return "its"//Something went wrong
#undef SAFE_PERP
/mob/proc/get_multitool(var/obj/item/device/multitool/P)
if(istype(P))
return P
mob/dead/observer/get_multitool()
return can_admin_interact() && ..(ghost_multitool)
/mob/living/carbon/human/get_multitool()
return ..(get_active_hand())
/mob/living/silicon/robot/get_multitool()
return ..(get_active_hand())
/mob/living/silicon/ai/get_multitool()
return ..(aiMulti)