Files
Paradise/code/modules/mob/mob.dm
GDN 82b863cefd Converts over the missing TGUI input lists (#23859)
* Converts over the missing TGUI input lists

* last fixes

* num revert
2024-02-14 21:17:29 +00:00

1643 lines
48 KiB
Plaintext

/mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game.
GLOB.mob_list -= src
GLOB.dead_mob_list -= src
GLOB.alive_mob_list -= src
input_focus = null
if(s_active)
s_active.close(src)
QDEL_NULL(hud_used)
if(mind && mind.current == src)
spellremove(src)
mobspellremove(src)
QDEL_LIST_CONTENTS(viruses)
QDEL_LIST_CONTENTS(actions)
for(var/alert in alerts)
clear_alert(alert)
ghostize()
QDEL_LIST_ASSOC_VAL(tkgrabbed_objects)
for(var/I in tkgrabbed_objects)
qdel(tkgrabbed_objects[I])
tkgrabbed_objects = null
if(buckled)
buckled.unbuckle_mob(src, force = TRUE)
if(viewing_alternate_appearances)
for(var/datum/alternate_appearance/AA in viewing_alternate_appearances)
AA.viewers -= src
viewing_alternate_appearances = null
LAssailant = null
runechat_msg_location = null
return ..()
/mob/Initialize(mapload)
GLOB.mob_list += src
if(stat == DEAD)
GLOB.dead_mob_list += src
else
GLOB.alive_mob_list += src
input_focus = src
reset_perspective(src)
prepare_huds()
update_runechat_msg_location()
. = ..()
/atom/proc/prepare_huds()
hud_list = list()
var/static/list/hud_dmis = list(
SPECIALROLE_HUD = 'icons/mob/hud/antaghud.dmi',
DIAG_TRACK_HUD = 'icons/mob/hud/diaghud.dmi',
DIAG_AIRLOCK_HUD = 'icons/mob/hud/diaghud.dmi',
DIAG_STAT_HUD = 'icons/mob/hud/diaghud.dmi',
DIAG_HUD = 'icons/mob/hud/diaghud.dmi',
DIAG_BATT_HUD = 'icons/mob/hud/diaghud.dmi',
DIAG_MECH_HUD = 'icons/mob/hud/diaghud.dmi',
DIAG_BOT_HUD = 'icons/mob/hud/diaghud.dmi',
PLANT_NUTRIENT_HUD = 'icons/mob/hud/hydrohud.dmi',
PLANT_WATER_HUD = 'icons/mob/hud/hydrohud.dmi',
PLANT_STATUS_HUD = 'icons/mob/hud/hydrohud.dmi',
PLANT_HEALTH_HUD = 'icons/mob/hud/hydrohud.dmi',
PLANT_TOXIN_HUD = 'icons/mob/hud/hydrohud.dmi',
PLANT_PEST_HUD = 'icons/mob/hud/hydrohud.dmi',
PLANT_WEED_HUD = 'icons/mob/hud/hydrohud.dmi',
HEALTH_HUD = 'icons/mob/hud/medhud.dmi',
STATUS_HUD = 'icons/mob/hud/medhud.dmi',
ID_HUD = 'icons/mob/hud/sechud.dmi',
WANTED_HUD = 'icons/mob/hud/sechud.dmi',
IMPMINDSHIELD_HUD = 'icons/mob/hud/sechud.dmi',
IMPCHEM_HUD = 'icons/mob/hud/sechud.dmi',
IMPTRACK_HUD = 'icons/mob/hud/sechud.dmi',
)
for(var/hud in hud_possible)
var/use_this_dmi = hud_dmis[hud]
if(!use_this_dmi)
use_this_dmi = 'icons/mob/hud/hud_misc.dmi'
var/image/I = image(use_this_dmi, src, "")
I.appearance_flags = RESET_COLOR | RESET_TRANSFORM
hud_list[hud] = I
/mob/proc/generate_name()
return name
/mob/proc/GetAltName()
return ""
/mob/proc/Cell()
set category = "Admin"
set hidden = 1
if(!loc) return 0
var/datum/gas_mixture/environment = loc.return_air()
var/t = "<span class='notice'>Coordinates: [x],[y] \n</span>"
t+= "<span class='warning'>Temperature: [environment.temperature] \n</span>"
t+= "<span class='notice'>Nitrogen: [environment.nitrogen] \n</span>"
t+= "<span class='notice'>Oxygen: [environment.oxygen] \n</span>"
t+= "<span class='notice'>Plasma : [environment.toxins] \n</span>"
t+= "<span class='notice'>Carbon Dioxide: [environment.carbon_dioxide] \n</span>"
t+= "<span class='notice'>N2O: [environment.sleeping_agent] \n</span>"
t+= "<span class='notice'>Agent B: [environment.agent_b] \n</span>"
usr.show_message(t, EMOTE_VISIBLE)
/mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2)
if(!client) return
if(type)
if(type & EMOTE_VISIBLE && !has_vision(information_only=TRUE))//Vision related
if(!alt)
return
else
msg = alt
type = alt_type
if(type & EMOTE_AUDIBLE && !can_hear())//Hearing related
if(!alt)
return
else
msg = alt
type = alt_type
if(type & EMOTE_VISIBLE && !has_vision(information_only=TRUE))
return
// Added voice muffling for Issue 41.
if(stat == UNCONSCIOUS)
to_chat(src, "<I>... You can almost hear someone talking ...</I>")
else
to_chat(src, msg)
return
// Show a message to all mobs in sight of this one
// This would be for visible actions by the src mob
// message is the message output to anyone who can see e.g. "[src] does something!"
// self_message (optional) is what the src mob sees e.g. "You do something!"
// blind_message (optional) is what blind people will hear e.g. "You hear something!"
/mob/visible_message(message, self_message, blind_message)
if(!isturf(loc)) // mobs inside objects (such as lockers) shouldn't have their actions visible to those outside the object
for(var/mob/M in get_mobs_in_view(3, src))
if(M.see_invisible < invisibility)
continue //can't view the invisible
var/msg = message
if(self_message && M == src)
msg = self_message
if(M.loc != loc)
if(!blind_message) // for some reason VISIBLE action has blind_message param so if we are not in the same object but next to it, lets show it
continue
msg = blind_message
M.show_message(msg, EMOTE_VISIBLE, blind_message, EMOTE_AUDIBLE)
return
for(var/mob/M in get_mobs_in_view(7, src))
if(M.see_invisible < invisibility)
continue //can't view the invisible
var/msg = message
if(self_message && M == src)
msg = self_message
M.show_message(msg, EMOTE_VISIBLE, blind_message, EMOTE_AUDIBLE)
// Show a message to all mobs in sight of this atom
// Use for objects performing visible actions
// message is output to anyone who can see, e.g. "The [src] does something!"
// blind_message (optional) is what blind people will hear e.g. "You hear something!"
/atom/proc/visible_message(message, blind_message)
for(var/mob/M in get_mobs_in_view(7, src))
if(!M.client)
continue
M.show_message(message, EMOTE_VISIBLE, blind_message, EMOTE_AUDIBLE)
// Show a message to all mobs in earshot of this one
// This would be for audible actions by the src mob
// message is the message output to anyone who can hear.
// self_message (optional) is what the src mob hears.
// deaf_message (optional) is what deaf people will see.
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
/mob/audible_message(message, deaf_message, hearing_distance)
var/range = 7
if(hearing_distance)
range = hearing_distance
var/msg = message
for(var/mob/M in get_mobs_in_view(range, src))
M.show_message(msg, EMOTE_AUDIBLE, deaf_message, EMOTE_VISIBLE)
// based on say code
var/omsg = replacetext(message, "<B>[src]</B> ", "")
var/list/listening_obj = new
for(var/atom/movable/A in view(range, src))
if(ismob(A))
var/mob/M = A
for(var/obj/O in M.contents)
listening_obj |= O
else if(isobj(A))
var/obj/O = A
listening_obj |= O
for(var/obj/O in listening_obj)
O.hear_message(src, omsg)
// Show a message to all mobs in earshot of this atom
// Use for objects performing audible actions
// message is the message output to anyone who can hear.
// deaf_message (optional) is what deaf people will see.
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
/atom/proc/audible_message(message, deaf_message, hearing_distance)
var/range = 7
if(hearing_distance)
range = hearing_distance
for(var/mob/M in get_mobs_in_view(range, src))
M.show_message(message, EMOTE_AUDIBLE, deaf_message, EMOTE_VISIBLE)
/mob/proc/findname(msg)
for(var/mob/M in GLOB.mob_list)
if(M.real_name == "[msg]")
return M
return 0
/mob/proc/movement_delay()
return 0
//This proc is called whenever someone clicks an inventory ui slot.
/mob/proc/attack_ui(slot)
var/obj/item/W = get_active_hand()
if(istype(W))
equip_to_slot_if_possible(W, slot)
else if(!restrained())
W = get_item_by_slot(slot)
if(W)
W.attack_hand(src)
if(ishuman(src) && W == src:head)
src:update_hair()
src:update_fhair()
/mob/proc/put_in_any_hand_if_possible(obj/item/W as obj, del_on_fail = 0, disable_warning = 1)
if(equip_to_slot_if_possible(W, SLOT_HUD_LEFT_HAND, del_on_fail, disable_warning))
return 1
else if(equip_to_slot_if_possible(W, SLOT_HUD_RIGHT_HAND, del_on_fail, disable_warning))
return 1
return 0
//This is a SAFE proc. Use this instead of equip_to_slot()!
//set del_on_fail to have it delete W if it fails to equip
//set disable_warning to disable the 'you are unable to equip that' warning.
/mob/proc/equip_to_slot_if_possible(obj/item/W, slot, del_on_fail = FALSE, disable_warning = FALSE, initial = FALSE)
if(!istype(W)) return 0
if(!W.mob_can_equip(src, slot, disable_warning))
if(del_on_fail)
qdel(W)
else
if(!disable_warning)
to_chat(src, "<span class='warning'>You are unable to equip that.</span>")//Only print if del_on_fail is false
return 0
equip_to_slot(W, slot, initial) //This proc should not ever fail.
return 1
//This is an UNSAFE proc. It merely handles the actual job of equipping. All the checks on whether you can or can't eqip need to be done before! Use mob_can_equip() for that task.
//In most cases you will want to use equip_to_slot_if_possible()
/mob/proc/equip_to_slot(obj/item/W, slot, initial = FALSE)
return
//This is just a commonly used configuration for the equip_to_slot_if_possible() proc, used to equip people when the rounds tarts and when events happen and such.
/mob/proc/equip_to_slot_or_del(obj/item/W, slot, initial = FALSE)
return equip_to_slot_if_possible(W, slot, TRUE, TRUE, initial)
// Convinience proc. Collects crap that fails to equip either onto the mob's back, or drops it.
// Used in job equipping so shit doesn't pile up at the start loc.
/mob/living/carbon/human/proc/equip_or_collect(obj/item/W, slot, initial = FALSE)
if(W.mob_can_equip(src, slot, 1))
//Mob can equip. Equip it.
equip_to_slot_or_del(W, slot, initial)
else
//Mob can't equip it. Put it their backpack or toss it on the floor
if(isstorage(back))
var/obj/item/storage/S = back
//Now, S represents a container we can insert W into.
S.handle_item_insertion(W, TRUE, TRUE)
return S
if(ismodcontrol(back))
var/obj/item/mod/control/C = back
if(C.bag)
C.bag.handle_item_insertion(W, TRUE, TRUE)
return C.bag
var/turf/T = get_turf(src)
if(istype(T))
W.forceMove(T)
return T
//The list of slots by priority. equip_to_appropriate_slot() uses this list. Doesn't matter if a mob type doesn't have a slot.
GLOBAL_LIST_INIT(slot_equipment_priority, list( \
SLOT_HUD_BACK,\
SLOT_HUD_WEAR_PDA,\
SLOT_HUD_WEAR_ID,\
SLOT_HUD_JUMPSUIT,\
SLOT_HUD_OUTER_SUIT,\
SLOT_HUD_WEAR_MASK,\
SLOT_HUD_HEAD,\
SLOT_HUD_SHOES,\
SLOT_HUD_GLOVES,\
SLOT_HUD_LEFT_EAR,\
SLOT_HUD_RIGHT_EAR,\
SLOT_HUD_GLASSES,\
SLOT_HUD_BELT,\
SLOT_HUD_SUIT_STORE,\
SLOT_HUD_TIE,\
SLOT_HUD_LEFT_STORE,\
SLOT_HUD_RIGHT_STORE\
))
//puts the item "W" into an appropriate slot in a human's inventory
//returns 0 if it cannot, 1 if successful
/mob/proc/equip_to_appropriate_slot(obj/item/W)
if(!istype(W)) return 0
for(var/slot in GLOB.slot_equipment_priority)
if(isstorage(W) && slot == SLOT_HUD_HEAD) // Storage items should be put on the belt before the head
continue
if(equip_to_slot_if_possible(W, slot, FALSE, TRUE)) //del_on_fail = 0; disable_warning = 0
return 1
return 0
/mob/proc/check_for_open_slot(obj/item/W)
if(!istype(W)) return 0
var/openslot = 0
for(var/slot in GLOB.slot_equipment_priority)
if(W.mob_check_equip(src, slot, 1) == 1)
openslot = 1
break
return openslot
/obj/item/proc/mob_check_equip(M as mob, slot, disable_warning = 0)
if(!M) return 0
if(!slot) return 0
if(ishuman(M))
//START HUMAN
var/mob/living/carbon/human/H = M
switch(slot)
if(SLOT_HUD_LEFT_HAND)
if(H.l_hand)
return 0
return 1
if(SLOT_HUD_RIGHT_HAND)
if(H.r_hand)
return 0
return 1
if(SLOT_HUD_WEAR_MASK)
if(!(slot_flags & SLOT_FLAG_MASK))
return 0
if(H.wear_mask)
return 0
return 1
if(SLOT_HUD_BACK)
if(!(slot_flags & SLOT_FLAG_BACK))
return 0
if(H.back)
if(!(H.back.flags & NODROP))
return 2
else
return 0
return 1
if(SLOT_HUD_OUTER_SUIT)
if(!(slot_flags & SLOT_FLAG_OCLOTHING))
return 0
if(H.wear_suit)
if(!(H.wear_suit.flags & NODROP))
return 2
else
return 0
return 1
if(SLOT_HUD_GLOVES)
if(!(slot_flags & SLOT_FLAG_GLOVES))
return 0
if(H.gloves)
if(!(H.gloves.flags & NODROP))
return 2
else
return 0
return 1
if(SLOT_HUD_SHOES)
if(!(slot_flags & SLOT_FLAG_FEET))
return 0
if(H.shoes)
if(!(H.shoes.flags & NODROP))
return 2
else
return 0
return 1
if(SLOT_HUD_BELT)
if(!H.w_uniform)
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [name].</span>")
return 0
if(!(slot_flags & SLOT_FLAG_BELT))
return 0
if(H.belt)
if(!(H.belt.flags & NODROP))
return 2
else
return 0
return 1
if(SLOT_HUD_GLASSES)
if(!(slot_flags & SLOT_FLAG_EYES))
return 0
if(H.glasses)
if(!(H.glasses.flags & NODROP))
return 2
else
return 0
return 1
if(SLOT_HUD_HEAD)
if(!(slot_flags & SLOT_FLAG_HEAD))
return 0
if(H.head)
if(!(H.head.flags & NODROP))
return 2
else
return 0
return 1
if(SLOT_HUD_LEFT_EAR)
if(!(slot_flags & SLOT_HUD_LEFT_EAR))
return 0
if(H.l_ear)
if(!(H.l_ear.flags & NODROP))
return 2
else
return 0
return 1
if(SLOT_HUD_RIGHT_EAR)
if(!(slot_flags & SLOT_HUD_RIGHT_EAR))
return 0
if(H.r_ear)
if(!(H.r_ear.flags & NODROP))
return 2
else
return 0
return 1
if(SLOT_HUD_JUMPSUIT)
if(!(slot_flags & SLOT_FLAG_ICLOTHING))
return 0
if(H.w_uniform)
if(!(H.w_uniform.flags & NODROP))
return 2
else
return 0
return 1
if(SLOT_HUD_WEAR_ID)
if(!H.w_uniform)
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [name].</span>")
return 0
if(!(slot_flags & SLOT_FLAG_ID))
return 0
if(H.wear_id)
if(!(H.wear_id.flags & NODROP))
return 2
else
return 0
return 1
if(SLOT_HUD_LEFT_STORE)
if(H.l_store)
return 0
if(!H.w_uniform)
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [name].</span>")
return 0
if(w_class <= WEIGHT_CLASS_SMALL || (slot_flags & SLOT_FLAG_POCKET))
return 1
if(SLOT_HUD_RIGHT_STORE)
if(H.r_store)
return 0
if(!H.w_uniform)
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [name].</span>")
return 0
if(w_class <= WEIGHT_CLASS_SMALL || (slot_flags & SLOT_FLAG_POCKET))
return 1
return 0
if(SLOT_HUD_SUIT_STORE)
if(!H.wear_suit)
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a suit before you can attach this [name].</span>")
return 0
if(!H.wear_suit.allowed)
if(!disable_warning)
to_chat(usr, "You somehow have a suit with no defined allowed items for suit storage, stop that.")
return 0
if(w_class > H.wear_suit.max_suit_w)
if(!disable_warning)
to_chat(usr, "The [name] is too big to attach.")
return 0
if(istype(src, /obj/item/pda) || is_pen(src) || is_type_in_list(src, H.wear_suit.allowed))
if(H.s_store)
if(!(H.s_store.flags & NODROP))
return 2
else
return 0
else
return 1
return 0
if(SLOT_HUD_HANDCUFFED)
if(H.handcuffed)
return 0
if(!istype(src, /obj/item/restraints/handcuffs))
return 0
return 1
if(SLOT_HUD_LEGCUFFED)
if(H.legcuffed)
return 0
if(!istype(src, /obj/item/restraints/legcuffs))
return 0
return 1
if(SLOT_HUD_IN_BACKPACK)
if(H.back && istype(H.back, /obj/item/storage/backpack))
var/obj/item/storage/backpack/B = H.back
if(B.contents.len < B.storage_slots && w_class <= B.max_w_class)
return 1
return 0
return 0 //Unsupported slot
//END HUMAN
/mob/proc/get_visible_mobs()
var/list/seen_mobs = list()
for(var/mob/M in view(src))
seen_mobs += M
return seen_mobs
/**
* Returns an assoc list which contains the mobs in range and their "visible" name.
* Mobs out of view but in range will be listed as unknown. Else they will have their visible name
*/
/mob/proc/get_telepathic_targets()
var/list/validtargets = new /list()
var/turf/T = get_turf(src)
var/list/mobs_in_view = get_visible_mobs()
for(var/mob/living/M in range(14, T))
if(M && M.mind)
if(M == src)
continue
var/mob_name
if(M in mobs_in_view)
mob_name = M.name
else
mob_name = "Unknown entity"
var/i = 0
var/result_name
do
result_name = mob_name
if(i++)
result_name += " ([i])" // Avoid dupes
while(validtargets[result_name])
validtargets[result_name] = M
return validtargets
// If you're looking for `reset_perspective`, that's a synonym for this proc.
/mob/proc/reset_perspective(atom/A)
if(client)
if(istype(A, /atom/movable))
if(is_ventcrawling(src))
client.eye = get_turf(A)
client.perspective = MOB_PERSPECTIVE
else
client.perspective = EYE_PERSPECTIVE
client.eye = A
else
if(isturf(loc))
client.eye = client.mob
client.perspective = MOB_PERSPECTIVE
else
client.perspective = EYE_PERSPECTIVE
client.eye = loc
return 1
/mob/living/reset_perspective(atom/A)
. = ..()
if(.)
// Above check means the mob has a client
update_sight()
if(client.eye != src)
var/atom/AT = client.eye
AT.get_remote_view_fullscreens(src)
else
clear_fullscreen("remote_view", 0)
update_pipe_vision()
/mob/dead/reset_perspective(atom/A)
. = ..()
if(.)
// Allows sharing HUDs with ghosts
if(hud_used)
client.screen = list()
hud_used.show_hud(hud_used.hud_version)
/mob/proc/show_inv(mob/user)
user.set_machine(src)
var/dat = {"<table>
<tr><td><B>Left Hand:</B></td><td><A href='?src=[UID()];item=[SLOT_HUD_LEFT_HAND]'>[(l_hand && !(l_hand.flags&ABSTRACT)) ? html_encode(l_hand) : "<font color=grey>Empty</font>"]</A></td></tr>
<tr><td><B>Right Hand:</B></td><td><A href='?src=[UID()];item=[SLOT_HUD_RIGHT_HAND]'>[(r_hand && !(r_hand.flags&ABSTRACT)) ? html_encode(r_hand) : "<font color=grey>Empty</font>"]</A></td></tr>
<tr><td>&nbsp;</td></tr>"}
dat += {"</table>
<A href='?src=[user.UID()];mach_close=mob\ref[src]'>Close</A>
"}
var/datum/browser/popup = new(user, "mob\ref[src]", "[src]", 440, 250)
popup.set_content(dat)
popup.open()
//mob verbs are faster than object verbs. See http://www.byond.com/forum/?post=1326139&page=2#comment8198716 for why this isn't atom/verb/examine()
/mob/verb/examinate(atom/A as mob|obj|turf in view())
set name = "Examine"
set category = "IC"
DEFAULT_QUEUE_OR_CALL_VERB(VERB_CALLBACK(src, PROC_REF(run_examinate), A))
/mob/proc/run_examinate(atom/A)
if(!has_vision(information_only = TRUE) && !isobserver(src))
to_chat(src, chat_box_regular("<span class='notice'>Something is there but you can't see it.</span>"), MESSAGE_TYPE_INFO, confidential = TRUE)
return TRUE
face_atom(A)
if(!client)
var/list/result = A.examine(src)
to_chat(src, chat_box_examine(result.Join("\n")))
return
var/list/result
LAZYINITLIST(client.recent_examines)
for(var/key in client.recent_examines)
if(client.recent_examines[key] < world.time)
client.recent_examines -= key
var/ref_to_atom = A.UID()
if(LAZYACCESS(client.recent_examines, ref_to_atom))
result = A.examine_more(src)
if(!length(result))
result += "<span class='notice'><i>You examine [A] closer, but find nothing of interest...</i></span>"
else
result = A.examine(src)
client.recent_examines[ref_to_atom] = world.time + EXAMINE_MORE_WINDOW // set to when we should not examine something
to_chat(src, chat_box_examine(result.Join("\n")), MESSAGE_TYPE_INFO, confidential = TRUE)
/mob/proc/ret_grab(obj/effect/list_container/mobl/L as obj, flag)
if((!istype(l_hand, /obj/item/grab) && !istype(r_hand, /obj/item/grab)))
if(!L)
return null
else
return L.container
else
if(!L)
L = new /obj/effect/list_container/mobl( null )
L.container += src
L.master = src
if(istype(l_hand, /obj/item/grab))
var/obj/item/grab/G = l_hand
if(!L.container.Find(G.affecting))
L.container += G.affecting
if(G.affecting)
G.affecting.ret_grab(L, 1)
if(istype(r_hand, /obj/item/grab))
var/obj/item/grab/G = r_hand
if(!L.container.Find(G.affecting))
L.container += G.affecting
if(G.affecting)
G.affecting.ret_grab(L, 1)
if(!flag)
if(L.master == src)
var/list/temp = list( )
temp += L.container
//L = null
qdel(L)
return temp
else
return L.container
return
/mob/verb/mode()
set name = "Activate Held Object"
set category = null
set src = usr
DEFAULT_QUEUE_OR_CALL_VERB(VERB_CALLBACK(src, PROC_REF(run_mode)))
///proc version to finish /mob/verb/mode() execution. used in case the proc needs to be queued for the tick after its first called
/mob/proc/run_mode()
if(ismecha(loc)) return
if(hand)
var/obj/item/W = l_hand
if(W)
W.attack_self(src)
update_inv_l_hand()
else
var/obj/item/W = r_hand
if(W)
W.attack_self(src)
update_inv_r_hand()
return
/*
/mob/verb/dump_source()
var/master = "<PRE>"
for(var/t in typesof(/area))
master += text("[]\n", t)
//Foreach goto(26)
src << browse(master)
return
*/
/mob/verb/memory()
set name = "Notes"
set category = "IC"
if(mind)
mind.show_memory(src)
else
to_chat(src, "The game appears to have misplaced your mind datum, so we can't show you your notes.")
/mob/verb/add_memory(msg as message)
set name = "Add Note"
set category = "IC"
msg = copytext(msg, 1, MAX_MESSAGE_LEN)
msg = sanitize_simple(html_encode(msg), list("\n" = "<BR>"))
var/combined = length(memory + msg)
if(mind && (combined < MAX_PAPER_MESSAGE_LEN))
mind.store_memory(msg)
else if(combined >= MAX_PAPER_MESSAGE_LEN)
to_chat(src, "Your brain can't hold that much information!")
return
else
to_chat(src, "The game appears to have misplaced your mind datum, so we can't show you your notes.")
/mob/proc/store_memory(msg as message, popup, sane = 1)
msg = copytext(msg, 1, MAX_MESSAGE_LEN)
if(sane)
msg = sanitize(msg)
if(length(memory) == 0)
memory += msg
else
memory += "<BR>[msg]"
if(popup)
memory()
/mob/proc/update_flavor_text()
set src in usr
if(usr != src)
to_chat(usr, "<span class='notice'>You can't change the flavor text of this mob</span>")
return
if(stat)
to_chat(usr, "<span class='notice'>You have to be conscious to change your flavor text</span>")
return
var/msg = input(usr,"Set the flavor text in your 'examine' verb. The flavor text should be a physical descriptor of your character at a glance.","Flavor Text",html_decode(flavor_text)) as message|null
if(msg != null)
if(stat)
to_chat(usr, "<span class='notice'>You have to be conscious to change your flavor text</span>")
return
msg = copytext(msg, 1, MAX_MESSAGE_LEN)
msg = html_encode(msg)
flavor_text = msg
/mob/proc/print_flavor_text(shrink = TRUE)
if(flavor_text && flavor_text != "")
var/msg = replacetext(flavor_text, "\n", " ")
if(length(msg) <= 40 || !shrink)
return "<span class='notice'>[html_encode(msg)]</span>" //Repeat after me, "I will not give players access to decoded HTML."
else
return "<span class='notice'>[copytext_preserve_html(msg, 1, 37)]... <a href='byond://?src=[UID()];flavor_more=1'>More...</a></span>"
/mob/proc/is_dead()
return stat == DEAD
// Nobody in their right mind will have this enabled on the production server, uncomment if you want this for some reason
/*
/mob/verb/abandon_mob()
set name = "Respawn"
set category = "OOC"
if(!GLOB.configuration.general.respawn_enabled)
to_chat(usr, "<span class='warning'>Respawning is disabled.</span>")
return
if(stat != DEAD || !SSticker)
to_chat(usr, "<span class='boldnotice'>You must be dead to use this!</span>")
return
log_game("[key_name(usr)] has respawned.")
to_chat(usr, "<span class='boldnotice'>Make sure to play a different character, and please roleplay correctly!</span>")
if(!client)
log_game("[key_name(usr)] respawn failed due to disconnect.")
return
client.screen.Cut()
client.screen += client.void
if(!client)
log_game("[key_name(usr)] respawn failed due to disconnect.")
return
var/mob/new_player/M = new /mob/new_player()
if(!client)
log_game("[key_name(usr)] respawn failed due to disconnect.")
qdel(M)
return
M.key = key
return
*/
/mob/verb/observe()
set name = "Observe"
set category = "OOC"
var/is_admin = 0
if(client.holder && (client.holder.rights & R_ADMIN))
is_admin = 1
else if(stat != DEAD || isnewplayer(src))
to_chat(usr, "<span class='notice'>You must be observing to use this!</span>")
return
if(is_admin && stat == DEAD)
is_admin = 0
var/list/names = list()
var/list/namecounts = list()
var/list/creatures = list()
for(var/obj/O in GLOB.poi_list)
if(!O.loc)
continue
if(istype(O, /obj/item/disk/nuclear))
var/name = "Nuclear Disk"
if(names.Find(name))
namecounts[name]++
name = "[name] ([namecounts[name]])"
else
names.Add(name)
namecounts[name] = 1
creatures[name] = O
if(istype(O, /obj/singularity))
var/name = "Singularity"
if(names.Find(name))
namecounts[name]++
name = "[name] ([namecounts[name]])"
else
names.Add(name)
namecounts[name] = 1
creatures[name] = O
for(var/mob/M in sortAtom(GLOB.mob_list))
var/name = M.name
if(names.Find(name))
namecounts[name]++
name = "[name] ([namecounts[name]])"
else
names.Add(name)
namecounts[name] = 1
creatures[name] = M
client.perspective = EYE_PERSPECTIVE
var/eye_name = null
var/ok = "[is_admin ? "Admin Observe" : "Observe"]"
eye_name = tgui_input_list(usr, "Please, select a player!", ok, creatures)
if(!eye_name)
return
var/mob/mob_eye = creatures[eye_name]
if(client && mob_eye)
client.eye = mob_eye
/mob/verb/cancel_camera()
set name = "Cancel Camera View"
set category = "OOC"
reset_perspective(null)
unset_machine()
if(isliving(src))
if(src:cameraFollow)
src:cameraFollow = null
/mob/Topic(href, href_list)
if(href_list["mach_close"])
var/t1 = "window=[href_list["mach_close"]]"
unset_machine()
src << browse(null, t1)
if(href_list["refresh"])
if(machine && in_range(src, usr))
show_inv(machine)
if(!usr.incapacitated() && in_range(src, usr))
if(href_list["item"])
var/slot = text2num(href_list["item"])
var/obj/item/what = get_item_by_slot(slot)
if(what)
usr.stripPanelUnequip(what,src,slot)
else
usr.stripPanelEquip(what,src,slot)
if(usr.machine == src)
if(Adjacent(usr))
show_inv(usr)
else
usr << browse(null,"window=mob\ref[src]")
if(href_list["flavor_more"])
usr << browse(text("<HTML><HEAD><TITLE>[]</TITLE></HEAD><BODY><TT>[]</TT></BODY></HTML>", name, replacetext(flavor_text, "\n", "<BR>")), "window=[name];size=500x200")
onclose(usr, "[name]")
if(href_list["flavor_change"])
update_flavor_text()
if(href_list["scoreboard"])
usr << browse(GLOB.scoreboard, "window=roundstats;size=500x600")
// The src mob is trying to strip an item from someone
// Defined in living.dm
/mob/proc/stripPanelUnequip(obj/item/what, mob/who)
return
// The src mob is trying to place an item on someone
// Defined in living.dm
/mob/proc/stripPanelEquip(obj/item/what, mob/who)
return
/mob/MouseDrop(mob/M as mob, src_location, over_location, src_control, over_control, params)
if((M != usr) || !istype(M))
..()
return
if(isliving(M))
var/mob/living/L = M
if(L.mob_size <= MOB_SIZE_SMALL)
return // Stops pAI drones and small mobs (parrots, crabs) from stripping people. --DZD
if(!M.can_strip)
return
if(usr == src)
return
if(!Adjacent(usr))
return
if(IsFrozen(src) && !is_admin(usr))
to_chat(usr, "<span class='boldannounceic'>Interacting with admin-frozen players is not permitted.</span>")
return
if(isLivingSSD(src) && M.client && M.client.send_ssd_warning(src))
return
show_inv(usr)
/mob/proc/can_use_hands()
return
/mob/proc/is_mechanical()
return mind && (mind.assigned_role == "Cyborg" || mind.assigned_role == "AI")
/mob/proc/is_ready()
return client && !!mind
/mob/proc/is_in_brig()
if(!loc || !loc.loc)
return 0
// They should be in a cell or the Brig portion of the shuttle.
var/area/A = loc.loc
if(!istype(A, /area/station/security/prison))
if(!istype(A, /area/shuttle/escape) || loc.name != "Brig floor")
return 0
// If they still have their ID they're not brigged.
for(var/obj/item/card/id/card in src)
return 0
for(var/obj/item/pda/P in src)
if(P.id)
return 0
return 1
/mob/proc/get_gender()
return gender
/mob/proc/is_muzzled()
return FALSE
/mob/Stat()
show_stat_turf_contents()
if(statpanel("Status"))
stat(null, "Round ID: [GLOB.round_id ? GLOB.round_id : "NULL"]")
stat(null, "Map: [SSmapping.map_datum.fluff_name]")
if(SSmapping.next_map)
stat(null, "Next Map: [SSmapping.next_map.fluff_name]")
if(SSticker)
show_stat_station_time()
stat(null, "Players Connected: [length(GLOB.clients)]")
if(length(mob_spell_list))
for(var/obj/effect/proc_holder/spell/S in mob_spell_list)
add_spell_to_statpanel(S)
if(length(mind.spell_list))
for(var/obj/effect/proc_holder/spell/S in mind.spell_list)
add_spell_to_statpanel(S)
// Allow admins + PR reviewers to VIEW the panel. Doesnt mean they can click things.
if((is_admin(src) || check_rights(R_VIEWRUNTIMES, FALSE)) && client?.prefs.toggles2 & PREFTOGGLE_2_MC_TABS)
// Below are checks to see which MC panel you are looking at
// Shows MC Metadata
if(statpanel("MC|M"))
stat("Info", "Showing MC metadata")
var/turf/T = get_turf(client.eye)
stat("Location:", COORD(T))
stat("CPU:", "[Master.formatcpu(world.cpu)]")
stat("Map CPU:", "[Master.formatcpu(world.map_cpu)]")
stat("Instances:", "[num2text(world.contents.len, 10)]")
GLOB.stat_entry()
stat("Server Time:", time_stamp())
if(Master)
Master.stat_entry()
else
stat("Master Controller:", "ERROR")
if(Failsafe)
Failsafe.stat_entry()
else
stat("Failsafe Controller:", "ERROR")
// Shows subsystems with SS_NO_FIRE
if(statpanel("MC|N"))
stat("Info", "Showing subsystems that do not fire")
if(Master)
for(var/datum/controller/subsystem/SS as anything in Master.subsystems)
if(SS.flags & SS_NO_FIRE)
SS.stat_entry()
// Shows subsystems with the SS_CPUDISPLAY_LOW flag
if(statpanel("MC|L"))
stat("Info", "Showing subsystems marked as low intensity")
if(Master)
for(var/datum/controller/subsystem/SS as anything in Master.subsystems)
if((SS.cpu_display == SS_CPUDISPLAY_LOW) && !(SS.flags & SS_NO_FIRE))
SS.stat_entry()
// Shows subsystems with the SS_CPUDISPLAY_DEFAULT flag
if(statpanel("MC|D"))
stat("Info", "Showing subsystems marked as default intensity")
if(Master)
for(var/datum/controller/subsystem/SS as anything in Master.subsystems)
if((SS.cpu_display == SS_CPUDISPLAY_DEFAULT) && !(SS.flags & SS_NO_FIRE))
SS.stat_entry()
// Shows subsystems with the SS_CPUDISPLAY_HIGH flag
if(statpanel("MC|H"))
stat("Info", "Showing subsystems marked as high intensity")
if(Master)
for(var/datum/controller/subsystem/SS as anything in Master.subsystems)
if((SS.cpu_display == SS_CPUDISPLAY_HIGH) && !(SS.flags & SS_NO_FIRE))
SS.stat_entry()
// this function displays the station time in the status panel
/mob/proc/show_stat_station_time()
stat(null, "Server Uptime: [worldtime2text()]")
stat(null, "Round Time: [ROUND_TIME ? time2text(ROUND_TIME, "hh:mm:ss") : "N/A"]")
stat(null, "Station Time: [station_time_timestamp()]")
stat(null, "Time Dilation: [round(SStime_track.time_dilation_current,1)]% " + \
"AVG:([round(SStime_track.time_dilation_avg_fast,1)]%, " + \
"[round(SStime_track.time_dilation_avg,1)]%, " + \
"[round(SStime_track.time_dilation_avg_slow,1)]%)")
// this function displays the shuttles ETA in the status panel if the shuttle has been called
/mob/proc/show_stat_emergency_shuttle_eta()
var/ETA = SSshuttle.emergency.getModeStr()
if(ETA)
stat(null, "[ETA] [SSshuttle.emergency.getTimerStr()]")
/mob/proc/show_stat_turf_contents()
if(listed_turf && client)
if(!TurfAdjacent(listed_turf))
listed_turf = null
else
statpanel(listed_turf.name, null, listed_turf)
var/list/statpanel_things = list()
for(var/foo in listed_turf)
var/atom/A = foo
if(A.invisibility > see_invisible)
continue
if(is_type_in_list(A, shouldnt_see) || !A.simulated)
continue
statpanel_things += A
statpanel(listed_turf.name, null, statpanel_things)
/mob/proc/add_spell_to_statpanel(obj/effect/proc_holder/spell/S)
statpanel(S.panel,"[S.cooldown_handler.statpanel_info()]", S)
// facing verbs
/mob/proc/canface()
if(client.moving)
return FALSE
if(stat == DEAD)
return FALSE
if(anchored)
return FALSE
if(notransform)
return FALSE
if(restrained())
return FALSE
return TRUE
/mob/living/canface()
if(!(mobility_flags & MOBILITY_MOVE))
return FALSE
. = ..()
/mob/proc/fall()
drop_l_hand()
drop_r_hand()
/mob/living/fall()
..()
set_body_position(LYING_DOWN)
/mob/proc/facedir(ndir)
if(!canface())
return FALSE
setDir(ndir)
return TRUE
/mob/verb/eastface()
set hidden = 1
return facedir(EAST)
/mob/verb/westface()
set hidden = 1
return facedir(WEST)
/mob/verb/northface()
set hidden = 1
return facedir(NORTH)
/mob/verb/southface()
set hidden = 1
return facedir(SOUTH)
/mob/proc/IsAdvancedToolUser()//This might need a rename but it should replace the can this mob use things check
return FALSE
/mob/proc/swap_hand()
return
/mob/proc/activate_hand(selhand)
return
/mob/dead/observer/verb/respawn()
set name = "Respawn as NPC"
set category = "Ghost"
if(jobban_isbanned(usr, ROLE_SENTIENT))
to_chat(usr, "<span class='warning'>You are banned from playing as sentient animals.</span>")
return
if(!SSticker || SSticker.current_state < 3)
to_chat(src, "<span class='warning'>You can't respawn as an NPC before the game starts!</span>")
return
if((HAS_TRAIT(usr, TRAIT_RESPAWNABLE)) && (stat == DEAD || isobserver(usr)))
var/list/creatures = list("Mouse")
for(var/mob/living/simple_animal/L in GLOB.alive_mob_list)
if(!(is_station_level(L.z) || is_admin_level(L.z))) // Prevents players from spawning in space
continue
if(L.npc_safe(src) && L.stat != DEAD && !L.key)
creatures += L
var/picked = tgui_input_list(usr, "Please select an NPC to respawn as", "Respawn as NPC", creatures)
switch(picked)
if("Mouse")
become_mouse()
else
var/mob/living/NPC = picked
if(istype(NPC) && !NPC.key)
NPC.key = key
else
to_chat(usr, "You are not dead or you have given up your right to be respawned!")
return
/**
* Returns true if the player successfully becomes a mouse
*/
/mob/proc/become_mouse()
var/timedifference = world.time - client.time_died_as_mouse
if(client.time_died_as_mouse && timedifference <= GLOB.mouse_respawn_time * 600)
var/timedifference_text = time2text(GLOB.mouse_respawn_time * 600 - timedifference,"mm:ss")
to_chat(src, "<span class='warning'>You may only spawn again as a mouse more than [GLOB.mouse_respawn_time] minutes after your death. You have [timedifference_text] left.</span>")
return FALSE
//find a viable mouse candidate
var/list/found_vents = get_valid_vent_spawns()
if(!length(found_vents))
found_vents = get_valid_vent_spawns(min_network_size = 0)
if(!length(found_vents))
to_chat(src, "<span class='warning'>Unable to find any unwelded vents to spawn mice at.</span>")
return FALSE
var/obj/vent_found = pick(found_vents)
var/mob/living/simple_animal/mouse/host = new(vent_found.loc)
host.ckey = src.ckey
to_chat(host, "<span class='info'>You are now a mouse. Try to avoid interaction with players, and do not give hints away that you are more than a simple rodent.</span>")
host.forceMove(vent_found)
host.add_ventcrawl(vent_found)
return TRUE
/mob/proc/assess_threat() //For sec bot threat assessment
return 5
/mob/proc/get_ghost(even_if_they_cant_reenter = 0)
if(mind)
return mind.get_ghost(even_if_they_cant_reenter)
/mob/proc/grab_ghost(force)
if(mind)
return mind.grab_ghost(force = force)
/mob/proc/notify_ghost_cloning(message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", sound = 'sound/effects/genetics.ogg', atom/source = null, flashwindow = TRUE)
var/mob/dead/observer/ghost = get_ghost()
if(ghost)
if(flashwindow)
window_flash(ghost.client)
ghost.notify_cloning(message, sound, source)
return ghost
/mob/proc/fakevomit(green = 0, no_text = 0) //for aesthetic vomits that need to be instant and do not stun. -Fox
if(stat==DEAD)
return
var/turf/location = loc
if(issimulatedturf(location))
if(green)
if(!no_text)
visible_message("<span class='warning'>[src] vomits up some green goo!</span>","<span class='warning'>You vomit up some green goo!</span>")
add_vomit_floor(FALSE, TRUE)
else
if(!no_text)
visible_message("<span class='warning'>[src] pukes all over [p_themselves()]!</span>","<span class='warning'>You puke all over yourself!</span>")
add_vomit_floor(TRUE)
/mob/proc/AddSpell(obj/effect/proc_holder/spell/S)
mob_spell_list += S
S.action.Grant(src)
/mob/proc/RemoveSpell(obj/effect/proc_holder/spell/spell) //To remove a specific spell from a mind
if(!spell)
return
for(var/obj/effect/proc_holder/spell/S in mob_spell_list)
if(istype(S, spell))
qdel(S)
mob_spell_list -= S
//override to avoid rotating pixel_xy on mobs
/mob/shuttleRotate(rotation)
dir = angle2dir(rotation+dir2angle(dir))
/mob/proc/handle_ventcrawl()
return // Only living mobs can ventcrawl
/**
* Buckle to another mob
*
* You can buckle on mobs if you're next to them since most are dense
*
* Turns you to face the other mob too
*/
/mob/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
if(M.buckled)
return 0
var/turf/T = get_turf(src)
if(M.loc != T)
var/old_density = density
density = FALSE
var/can_step = step_towards(M, T)
density = old_density
if(!can_step)
return 0
return ..()
///Call back post buckle to a mob to offset your visual height
/mob/post_buckle_mob(mob/living/M)
var/height = M.get_mob_buckling_height(src)
M.pixel_y = initial(M.pixel_y) + height
if(M.layer < layer)
M.layer = layer + 0.1
///Call back post unbuckle from a mob, (reset your visual height here)
/mob/post_unbuckle_mob(mob/living/M)
M.layer = initial(M.layer)
M.pixel_y = initial(M.pixel_y)
///returns the height in pixel the mob should have when buckled to another mob.
/mob/proc/get_mob_buckling_height(mob/seat)
if(isliving(seat))
var/mob/living/L = seat
if(L.mob_size <= MOB_SIZE_SMALL) //being on top of a small mob doesn't put you very high.
return 0
return 9
///can the mob be buckled to something by default?
/mob/proc/can_buckle()
return TRUE
///can the mob be unbuckled from something by default?
/mob/proc/can_unbuckle()
return TRUE
//Can the mob see reagents inside of containers?
/mob/proc/can_see_reagents()
return FALSE
//Can this mob leave its location without breaking things terrifically?
/mob/proc/can_safely_leave_loc()
return TRUE // Yes, you can
/mob/proc/IsVocal()
return TRUE
/mob/proc/cannot_speak_loudly()
return FALSE
/mob/proc/get_access()
return list() //must return list or IGNORE_ACCESS
/mob/proc/create_attack_log(text, collapse = TRUE)
LAZYINITLIST(attack_log_old)
create_log_in_list(attack_log_old, text, collapse, last_log)
last_log = world.timeofday
/mob/proc/create_debug_log(text, collapse = TRUE)
LAZYINITLIST(debug_log)
create_log_in_list(debug_log, text, collapse, world.timeofday)
/mob/proc/create_log(log_type, what, target = null, turf/where = get_turf(src))
if(!ckey)
return
var/real_ckey = ckey
if(ckey[1] == "@") // Admin aghosting will do this
real_ckey = copytext(ckey, 2)
var/datum/log_record/record = new(log_type, src, what, target, where, world.time)
GLOB.logging.add_log(real_ckey, record)
/proc/create_log_in_list(list/target, text, collapse = TRUE, last_log)//forgive me code gods for this shitcode proc
//this proc enables lovely stuff like an attack log that looks like this: "[18:20:29-18:20:45]21x John Smith attacked Andrew Jackson with a crowbar."
//That makes the logs easier to read, but because all of this is stored in strings, weird things have to be used to get it all out.
var/new_log = "\[[time_stamp()]] [text]"
if(target.len)//if there are other logs already present
var/previous_log = target[target.len]//get the latest log
var/last_log_is_range = (copytext(previous_log, 10, 11) == "-") //whether the last log is a time range or not. The "-" will be an indicator that it is.
var/x_sign_position = findtext(previous_log, "x")
if(world.timeofday - last_log > 100)//if more than 10 seconds from last log
collapse = 0//don't collapse anyway
//the following checks if the last log has the same contents as the new one
if(last_log_is_range)
if(!(copytext(previous_log, x_sign_position + 13) == text))//the 13 is there because of span classes; you won't see those normally in-game
collapse = 0
else
if(!(copytext(previous_log, 12) == text))
collapse = 0
if(collapse == 1)
var/rep = 0
var/old_timestamp = copytext(previous_log, 2, 10)//copy the first time value. This one doesn't move when it's a timespan, so no biggie
//An attack log entry can either be a time range with multiple occurences of an action or a single one, with just one time stamp
if(last_log_is_range)
rep = text2num(copytext(previous_log, 44, x_sign_position))//get whatever number is right before the 'x'
new_log = "\[[old_timestamp]-[time_stamp()]]<font color='purple'><b>[rep?rep+1:2]x</b></font> [text]"
target -= target[target.len]//remove the last log
target += new_log
/mob/vv_get_dropdown()
. = ..()
.["Show player panel"] = "?_src_=vars;mob_player_panel=[UID()]"
.["Give Spell"] = "?_src_=vars;give_spell=[UID()]"
.["Give Martial Art"] = "?_src_=vars;givemartialart=[UID()]"
.["Give Disease"] = "?_src_=vars;give_disease=[UID()]"
.["Toggle Godmode"] = "?_src_=vars;godmode=[UID()]"
.["Toggle Build Mode"] = "?_src_=vars;build_mode=[UID()]"
.["Make 2spooky"] = "?_src_=vars;make_skeleton=[UID()]"
.["Hallucinate"] = "?_src_=vars;hallucinate=[UID()]"
.["Assume Direct Control"] = "?_src_=vars;direct_control=[UID()]"
.["Offer Control to Ghosts"] = "?_src_=vars;offer_control=[UID()]"
.["Drop Everything"] = "?_src_=vars;drop_everything=[UID()]"
.["Regenerate Icons"] = "?_src_=vars;regenerateicons=[UID()]"
.["Add Language"] = "?_src_=vars;addlanguage=[UID()]"
.["Remove Language"] = "?_src_=vars;remlanguage=[UID()]"
.["Add Organ"] = "?_src_=vars;addorgan=[UID()]"
.["Remove Organ"] = "?_src_=vars;remorgan=[UID()]"
.["Add Verb"] = "?_src_=vars;addverb=[UID()]"
.["Remove Verb"] = "?_src_=vars;remverb=[UID()]"
.["Gib"] = "?_src_=vars;gib=[UID()]"
///Can this mob resist (default FALSE)
/mob/proc/can_resist()
return FALSE //overridden in living.dm
/mob/proc/spin(spintime, speed)
set waitfor = FALSE
if(!spintime || !speed || spintime > 100)
CRASH("Aborted attempted call of /mob/proc/spin with invalid args ([spintime],[speed]) which could have frozen the server.")
while(spintime >= speed)
sleep(speed)
switch(dir)
if(NORTH)
setDir(EAST)
if(SOUTH)
setDir(WEST)
if(EAST)
setDir(SOUTH)
if(WEST)
setDir(NORTH)
spintime -= speed
/mob/proc/is_literate()
return FALSE
/mob/proc/faction_check_mob(mob/target, exact_match)
if(!target)
return faction_check(faction, null, FALSE)
if(exact_match) //if we need an exact match, we need to do some bullfuckery.
var/list/faction_src = faction.Copy()
var/list/faction_target = target.faction.Copy()
if(!("\ref[src]" in faction_target)) //if they don't have our ref faction, remove it from our factions list.
faction_src -= "\ref[src]" //if we don't do this, we'll never have an exact match.
if(!("\ref[target]" in faction_src))
faction_target -= "\ref[target]" //same thing here.
return faction_check(faction_src, faction_target, TRUE)
return faction_check(faction, target.faction, FALSE)
/proc/faction_check(list/faction_A, list/faction_B, exact_match)
var/list/match_list
if(exact_match)
match_list = faction_A & faction_B //only items in both lists
var/length = LAZYLEN(match_list)
if(length)
return (length == LAZYLEN(faction_A)) //if they're not the same len(gth) or we don't have a len, then this isn't an exact match.
else
match_list = faction_A & faction_B
return LAZYLEN(match_list)
return FALSE
/mob/proc/update_sight()
SEND_SIGNAL(src, COMSIG_MOB_UPDATE_SIGHT)
sync_lighting_plane_alpha()
/mob/proc/set_sight(datum/vision_override/O)
QDEL_NULL(vision_type)
if(O) //in case of null
vision_type = new O
update_sight()
/mob/proc/sync_lighting_plane_alpha()
if(hud_used)
var/obj/screen/plane_master/lighting/L = hud_used.plane_masters["[LIGHTING_PLANE]"]
if(L)
L.alpha = lighting_alpha
sync_nightvision_screen() //Sync up the overlay used for nightvision to the amount of see_in_dark a mob has. This needs to be called everywhere sync_lighting_plane_alpha() is.
/mob/proc/sync_nightvision_screen()
var/obj/screen/fullscreen/see_through_darkness/S = screens["see_through_darkness"]
if(S)
var/suffix = ""
switch(see_in_dark)
if(3 to 8)
suffix = "_[see_in_dark]"
if(8 to INFINITY)
suffix = "_8"
S.icon_state = "[initial(S.icon_state)][suffix]"
///Adjust the nutrition of a mob
/mob/proc/adjust_nutrition(change)
nutrition = max(0, nutrition + change)
///Force set the mob nutrition
/mob/proc/set_nutrition(change)
nutrition = max(0, change)
/mob/clean_blood(radiation_clean = FALSE, clean_hands = TRUE, clean_mask = TRUE, clean_feet = TRUE)
. = ..()
if(bloody_hands && clean_hands)
bloody_hands = 0
update_inv_gloves()
if(l_hand)
if(l_hand.clean_blood(radiation_clean))
update_inv_l_hand()
if(r_hand)
if(r_hand.clean_blood(radiation_clean))
update_inv_r_hand()
if(back)
if(back.clean_blood(radiation_clean))
update_inv_back()
if(wear_mask && clean_mask)
if(wear_mask.clean_blood(radiation_clean))
update_inv_wear_mask()
if(clean_feet)
feet_blood_color = null
qdel(feet_blood_DNA)
bloody_feet = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_NOT_BLOODY = 0, BLOOD_BASE_ALPHA = BLOODY_FOOTPRINT_BASE_ALPHA)
blood_state = BLOOD_STATE_NOT_BLOODY
update_inv_shoes()
update_icons() //apply the now updated overlays to the mob
/**
* Updates the mob's runechat maptext display location.
*
* By default, we set this to the src mob's `UID()`.
*/
/mob/proc/update_runechat_msg_location()
runechat_msg_location = UID()
/**
* Show an overlay of radiation levels on radioactive objects.
*/
/mob/proc/show_rads(range)
for(var/turf/place in range(range, src))
var/rads = SSradiation.get_turf_radiation(place)
if(rads < RAD_BACKGROUND_RADIATION)
continue
var/strength = round(rads / 1000, 0.1)
var/image/pic = image(loc = place)
var/mutable_appearance/MA = new()
MA.maptext = MAPTEXT("[strength]k")
MA.color = "#04e604"
MA.layer = RAD_TEXT_LAYER
MA.plane = GAME_PLANE
pic.appearance = MA
flick_overlay(pic, list(client), 10)
GLOBAL_LIST_INIT(holy_areas, typecacheof(list(
/area/station/service/chapel
)))
/mob/proc/holy_check()
if(!is_type_in_typecache(loc.loc, GLOB.holy_areas))
return FALSE
if(!mind)
return FALSE
//Allows cult to bypass holy areas once they summon
var/datum/game_mode/gamemode = SSticker.mode
if(iscultist(src) && gamemode.cult_objs.cult_status == NARSIE_HAS_RISEN)
return FALSE
//Execption for Holy Constructs
if(isconstruct(src) && !iscultist(src))
return FALSE
to_chat(src, "<span class='warning'>Your powers are useless on this holy ground.</span>")
return TRUE
/mob/proc/reset_visibility()
invisibility = initial(invisibility)
alpha = initial(alpha)
add_to_all_human_data_huds()
/mob/proc/make_invisible()
invisibility = INVISIBILITY_LEVEL_TWO
alpha = 128
remove_from_all_data_huds()
/mob/proc/set_stat(new_stat)
if(new_stat == stat)
return
. = stat
stat = new_stat
SEND_SIGNAL(src, COMSIG_MOB_STATCHANGE, new_stat, .)
///Makes a call in the context of a different usr. Use sparingly
/world/proc/invoke_callback_with_usr(mob/user_mob, datum/callback/invoked_callback, ...)
var/temp = usr
usr = user_mob
if(length(args) > 2)
. = invoked_callback.Invoke(arglist(args.Copy(3)))
else
. = invoked_callback.Invoke()
usr = temp
/mob/verb/give_kudos(mob/living/target as mob in oview())
set category = null
set name = "Give Kudos (OOC)"
if(target == src)
to_chat(src, "<span class='warning'>You cannot give kudos to yourself!</span>")
return
to_chat(src, "<span class='notice'>You've given kudos to [target]!</span>")
// Pretend we've always succeeded when we might not have.
// This should prevent people from using it to suss anything out about mobs' states
if(!client || !target.mind)
return
target.mind.kudos_received_from |= ckey