/mob/Initialize(mapload) add_to_mob_list() if(stat == DEAD) add_to_dead_mob_list() else add_to_alive_mob_list() set_focus(src) prepare_huds() for(var/v in GLOB.active_alternate_appearances) if(!v) continue var/datum/atom_hud/alternate_appearance/AA = v AA.onNewMob(src) set_nutrition(rand(NUTRITION_LEVEL_START_MIN, NUTRITION_LEVEL_START_MAX)) set_thirst(rand(THIRST_LEVEL_START_MIN, THIRST_LEVEL_START_MAX)) . = ..() update_config_movespeed() update_movespeed(TRUE) initialize_actionspeed() init_rendering() hook_vr("mob_new",list(src)) /mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game. remove_from_mob_list() remove_from_dead_mob_list() remove_from_alive_mob_list() QDEL_LIST(mob_spell_list) GLOB.all_clockwork_mobs -= src focus = null LAssailant = null movespeed_modification = null for (var/alert in alerts) clear_alert(alert, TRUE) if(observers && observers.len) for(var/M in observers) var/mob/dead/observe = M observe.reset_perspective(null) dispose_rendering() qdel(hud_used) for(var/cc in client_colours) qdel(cc) client_colours = null ghostize() if(mind?.current == src) //Let's just be safe yeah? This will occasionally be cleared, but not always. Can't do it with ghostize without changing behavior mind.set_current(null) ..() return QDEL_HINT_HARDDEL /mob/GenerateTag() tag = "mob_[next_mob_id++]" /atom/proc/prepare_huds() hud_list = list() for(var/hud in hud_possible) var/hint = hud_possible[hud] switch(hint) if(HUD_LIST_LIST) hud_list[hud] = list() else var/image/I = image('icons/mob/hud.dmi', src, "") I.appearance_flags = RESET_COLOR|RESET_TRANSFORM hud_list[hud] = I /mob/proc/Cell() set category = "Admin" set hidden = 1 if(!loc) return 0 var/datum/gas_mixture/environment = loc.return_air() var/t = "Coordinates: [x],[y] \n" t += "Temperature: [environment.return_temperature()] \n" for(var/id in environment.get_gases()) if(environment.get_moles(id)) t+="[GLOB.gas_data.names[id]]: [environment.get_moles(id)] \n" to_chat(usr, t) /mob/proc/get_photo_description(obj/item/camera/camera) return "a ... thing?" /mob/proc/show_message(msg, type, alt_msg, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2) if(audiovisual_redirect) audiovisual_redirect.show_message(msg ? "[msg]" : null, type, alt_msg ? "[alt_msg]" : null, alt_type) if(!client) return msg = copytext_char(msg, 1, MAX_MESSAGE_LEN) if(type) if(type & MSG_VISUAL && eye_blind )//Vision related if(!alt_msg) return else msg = alt_msg type = alt_type if(type & MSG_AUDIBLE && !can_hear())//Hearing related if(!alt_msg) return else msg = alt_msg type = alt_type if(type & MSG_VISUAL && eye_blind) return // voice muffling if(stat == UNCONSCIOUS) if(type & MSG_AUDIBLE) //audio to_chat(src, "... You can almost hear something ...") return to_chat(src, msg) /** * Generate a visible message from this atom * * Show a message to all player mobs who sees this atom * * Show a message to the src mob (if the src is a mob) * * Use for atoms performing visible actions * * message is output to anyone who can see, e.g. "The [src] does something!" * * Vars: * * 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!" * * vision_distance (optional) define how many tiles away the message can be seen. * * ignored_mobs (optional) doesn't show any message to any given mob in the list. * * target (optional) is the other mob involved with the visible message. For example, the attacker in many combat messages. * * target_message (optional) is what the target mob will see e.g. "[src] does something to you!" * * omni (optional) if TRUE, will show to users no matter what. * * runechat_popup (optional) if TRUE, will display a runechat popup using rune_msg if set otherwise it will use message and self_message accordingly. * * rune_msg (optional) is the message to display in the runechat popup. */ /atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, ignored_mobs, mob/target, target_message, omni = FALSE, runechat_popup, rune_msg) var/turf/T = get_turf(src) if(!T) return var/list/hearers = get_hearers_in_view(vision_distance, src) //caches the hearers and then removes ignored mobs. if(!length(hearers)) return hearers -= ignored_mobs if(target_message && target && istype(target) && (target.client || target.audiovisual_redirect)) hearers -= target if(omni) target.show_message(target_message) else //This entire if/else chain could be in two lines but isn't for readibilties sake. var/msg = target_message if(target.see_invisible LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE && T.is_softly_lit() && !in_range(T,target)) msg = blind_message if(msg) target.show_message(msg, MSG_VISUAL,blind_message, MSG_AUDIBLE) if(self_message) hearers -= src for(var/mob/M in hearers) if(!M.client && !M.audiovisual_redirect) continue if(omni) M.show_message(message) continue //This entire if/else chain could be in two lines but isn't for readibilties sake. var/msg = message //CITADEL EDIT, required for vore code to remove (T != loc && T != src)) as a check if(M.see_invisible LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE && T.is_softly_lit() && !in_range(T,M)) //the light object is dark and not invisible to us, darkness does not matter if you're directly next to the target msg = blind_message else if(SEND_SIGNAL(M, COMSIG_MOB_GET_VISIBLE_MESSAGE, src, message, vision_distance, ignored_mobs) & COMPONENT_NO_VISIBLE_MESSAGE) msg = blind_message if(!msg) continue if(runechat_popup && M.client?.prefs.chat_on_map && (M.client.prefs.see_chat_non_mob || ismob(src)) && M.client.prefs.see_chat_emotes) //SKYRAT CHANGE M.create_chat_message(src, null, rune_msg ? rune_msg : msg, list("emote", "italics"), null) //Skyrat change M.show_message(msg, MSG_VISUAL, blind_message, MSG_AUDIBLE) //SKYRAT CHANGE ///Adds the functionality to self_message. /mob/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, mob/target, target_message, omni = FALSE, runechat_popup, rune_msg) . = ..() if(self_message && target != src) if(!omni) show_message(self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE) if(runechat_popup && client?.prefs.chat_on_map && client.prefs.see_chat_emotes) //SKYRAT CHANGE create_chat_message(src, null, rune_msg ? rune_msg : self_message, list("emote", "italics"), null) //Skyrat change else show_message(self_message) if(runechat_popup && client?.prefs.chat_on_map && client.prefs.see_chat_emotes) //SKYRAT CHANGE create_chat_message(src, null, rune_msg ? rune_msg : self_message, list("emote", "italics"), null) //Skyrat change /** * Show a message to all mobs in earshot of this atom * * Use for objects performing audible actions * * vars: * * 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. * * ignored_mobs (optional) doesn't show any message to any given mob in the list. * * runechat_popup (optional) if TRUE, will display a runechat popup using rune_msg if set otherwise it will use message and self_message accordingly. * * rune_msg (optional) is the message to display in the runechat popup. */ /atom/proc/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, ignored_mobs, runechat_popup, rune_msg) //SKYRAT CHANGE var/turf/T = get_turf(src) if(!T) return var/list/hearers = get_hearers_in_view(hearing_distance, src) if(!length(hearers)) return hearers -= ignored_mobs if(self_message) hearers -= src for(var/mob/M in hearers) if(runechat_popup && M.client?.prefs.chat_on_map && (M.client.prefs.see_chat_non_mob || ismob(src)) && M.client.prefs.see_chat_emotes) //SKYRAT CHANGE M.create_chat_message(src, null, rune_msg ? rune_msg : message, list("emote", "italics"), null) //Skyrat change M.show_message(message, MSG_AUDIBLE, deaf_message, MSG_VISUAL) //SKYRAT CHANGE /** * Show a message to all mobs in earshot of this one * * This would be for audible actions by the src mob * * vars: * * 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. * * ignored_mobs (optional) doesn't show any message to any given mob in the list. */ /mob/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, list/ignored_mobs, runechat_popup, rune_msg) //SKYRAT CHANGE . = ..() if(self_message) if(runechat_popup && client?.prefs.chat_on_map && client.prefs.see_chat_emotes) //SKYRAT CHANGE create_chat_message(src, null, rune_msg ? rune_msg : self_message, list("emote", "italics"), null) //Skyrat change show_message(self_message, MSG_AUDIBLE, deaf_message, MSG_VISUAL) /mob/proc/get_item_by_slot(slot_id) return null /mob/proc/restrained(ignore_grab) return /mob/proc/incapacitated(ignore_restraints, ignore_grab) return //This proc is called whenever someone clicks an inventory ui slot. /mob/proc/attack_ui(slot) var/obj/item/W = get_active_held_item() if(istype(W)) if(equip_to_slot_if_possible(W, slot, FALSE, FALSE, FALSE, FALSE, TRUE)) W.apply_outline() return TRUE if(!W) // Activate the item var/obj/item/I = get_item_by_slot(slot) if(istype(I)) if(slot in check_obscured_slots()) to_chat(src, "You are unable to unequip that while wearing other garments over it!") return FALSE I.attack_hand(src) return FALSE /// Checks for slots that are currently obscured by other garments. /mob/proc/check_obscured_slots() return // reset_perspective(thing) set the eye to the thing (if it's equal to current default reset to mob perspective) // reset_perspective() set eye to common default : mob on turf, loc otherwise /mob/proc/reset_perspective(atom/A) if(!client) return if(A) if(ismovable(A)) //Set the the thing unless it's us if(A != src) client.perspective = EYE_PERSPECTIVE client.eye = A else client.eye = client.mob client.perspective = MOB_PERSPECTIVE else if(isturf(A)) //Set to the turf unless it's our current turf if(A != loc) client.perspective = EYE_PERSPECTIVE client.eye = A else client.eye = client.mob client.perspective = MOB_PERSPECTIVE else //Do nothing else //Reset to common defaults: mob if on turf, otherwise current loc if(isturf(loc)) client.eye = client.mob client.perspective = MOB_PERSPECTIVE else client.perspective = EYE_PERSPECTIVE client.eye = loc SEND_SIGNAL(src, COMSIG_MOB_RESET_PERSPECTIVE, A) return TRUE //view() but with a signal, to allow blacklisting some of the otherwise visible atoms. /mob/proc/fov_view(dist = world.view) . = view(dist, src) SEND_SIGNAL(src, COMSIG_MOB_FOV_VIEW, .) /** * Examine a mob * * mob verbs are faster than object verbs. See * [this byond forum post](https://secure.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()) //It used to be oview(12), but I can't really say why set name = "Examine" set category = "IC" if(isturf(A) && !(sight & SEE_TURFS) && !(A in view(client ? client.view : world.view, src))) // shift-click catcher may issue examinate() calls for out-of-sight turfs return if(is_blind()) to_chat(src, "Something is there but you can't see it!") return face_atom(A) var/list/result if(client) LAZYINITLIST(client.recent_examines) if(isnull(client.recent_examines[A]) || client.recent_examines[A] < world.time) result = A.examine(src) client.recent_examines[A] = world.time + EXAMINE_MORE_TIME // set the value to when the examine cooldown ends RegisterSignal(A, COMSIG_PARENT_QDELETING, .proc/clear_from_recent_examines, override=TRUE) // to flush the value if deleted early addtimer(CALLBACK(src, .proc/clear_from_recent_examines, A), EXAMINE_MORE_TIME) handle_eye_contact(A) else result = A.examine_more(src) else result = A.examine(src) // if a tree is examined but no client is there to see it, did the tree ever really exist? if(result.len) for(var/i = 1, i <= result.len, i++) if(!findtext(result[i], "
")) result[i] += "\n" else result = list("You examine \the [A], seems like noone really cares about it.") to_chat(src, examine_block("[result.Join()]")) SEND_SIGNAL(src, COMSIG_MOB_EXAMINATE, A) /mob/proc/clear_from_recent_examines(atom/A) if(!client) return UnregisterSignal(A, COMSIG_PARENT_QDELETING) LAZYREMOVE(client.recent_examines, A) /** * handle_eye_contact() is called when we examine() something. If we examine an alive mob with a mind who has examined us in the last second within 5 tiles, we make eye contact! * * Note that if either party has their face obscured, the other won't get the notice about the eye contact * Also note that examine_more() doesn't proc this or extend the timer, just because it's simpler this way and doesn't lose much. * The nice part about relying on examining is that we don't bother checking visibility, because we already know they were both visible to each other within the last second, and the one who triggers it is currently seeing them */ /mob/proc/handle_eye_contact(mob/living/examined_mob) return /mob/living/handle_eye_contact(mob/living/examined_mob) if(!istype(examined_mob) || src == examined_mob || examined_mob.stat >= UNCONSCIOUS || !client || !examined_mob.client?.recent_examines || !(src in examined_mob.client.recent_examines)) return if(get_dist(src, examined_mob) > EYE_CONTACT_RANGE) return var/mob/living/carbon/examined_carbon = examined_mob // check to see if their face is blocked (or if they're not a carbon, in which case they can't block their face anyway) if(!istype(examined_carbon) || (!(examined_carbon.wear_mask && examined_carbon.wear_mask.flags_inv & HIDEFACE) && !(examined_carbon.head && examined_carbon.head.flags_inv & HIDEFACE))) if(SEND_SIGNAL(src, COMSIG_MOB_EYECONTACT, examined_mob, TRUE) != COMSIG_BLOCK_EYECONTACT) var/msg = "You make eye contact with [examined_mob]." addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, src, msg), 3) // so the examine signal has time to fire and this will print after var/mob/living/carbon/us_as_carbon = src // i know >casting as subtype, but this isn't really an inheritable check if(!istype(us_as_carbon) || (!(us_as_carbon.wear_mask && us_as_carbon.wear_mask.flags_inv & HIDEFACE) && !(us_as_carbon.head && us_as_carbon.head.flags_inv & HIDEFACE))) if(SEND_SIGNAL(examined_mob, COMSIG_MOB_EYECONTACT, src, FALSE) != COMSIG_BLOCK_EYECONTACT) var/msg = "[src] makes eye contact with you." addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, examined_mob, msg), 3) /** * Point at an atom * * mob verbs are faster than object verbs. See * [this byond forum post](https://secure.byond.com/forum/?post=1326139&page=2#comment8198716) * for why this isn't atom/verb/pointed() * * note: ghosts can point, this is intended * * visible_message will handle invisibility properly * * overridden here and in /mob/dead/observer for different point span classes and sanity checks */ /mob/verb/pointed(atom/A as mob|obj|turf in fov_view(), params = "" as text) set name = "Point To" set category = "Object" if(!src || !isturf(src.loc) || !(A in view(src.loc))) return FALSE if(istype(A, /obj/effect/temp_visual/point)) return FALSE var/turf/tile = get_turf(A) if (!tile) return FALSE var/turf/our_tile = get_turf(src) var/obj/visual = new /obj/effect/temp_visual/point(our_tile, invisibility) /// Set position var/final_x = (tile.x - our_tile.x) * world.icon_size + A.pixel_x var/final_y = (tile.y - our_tile.y) * world.icon_size + A.pixel_y var/list/click_params = params2list(params) if(length(click_params) && click_params["screen-loc"]) var/list/actual_view = getviewsize(client ? client.view : world.view) var/list/split_coords = splittext(click_params["screen-loc"], ",") final_x = (text2num(splittext(split_coords[1], ":")[1]) - actual_view[1] / 2) * world.icon_size + (text2num(splittext(split_coords[1], ":")[2]) - world.icon_size) final_y = (text2num(splittext(split_coords[2], ":")[1]) - actual_view[2] / 2) * world.icon_size + (text2num(splittext(split_coords[2], ":")[2]) - world.icon_size) // /// Set rotation var/matrix/rotated_matrix = new() rotated_matrix.TurnTo(0, Get_Pixel_Angle(-final_y, -final_x)) visual.transform = rotated_matrix // animate(visual, pixel_x = final_x, pixel_y = final_y, time = 1.7, easing = EASE_OUT) SEND_SIGNAL(src, COMSIG_MOB_POINTED, A) return TRUE /mob/proc/can_resist() return FALSE //overridden in living.dm /mob/proc/spin(spintime, speed) set waitfor = 0 var/D = dir if((spintime < 1)||(speed < 1)||!spintime||!speed) return while(spintime >= speed) sleep(speed) switch(D) if(NORTH) D = EAST if(SOUTH) D = WEST if(EAST) D = SOUTH if(WEST) D = NORTH setDir(D) spintime -= speed /mob/proc/update_pull_hud_icon() hud_used?.pull_icon?.update_icon() /mob/proc/update_rest_hud_icon() hud_used?.rest_icon?.update_icon() /mob/verb/mode() set name = "Activate Held Object" set category = "Object" set src = usr if(ismecha(loc)) return if(incapacitated()) return var/obj/item/I = get_active_held_item() if(I) I.attack_self(src) update_inv_hands() /mob/verb/memory() set name = "Notes" set category = "IC" set desc = "View your character's notes memory." if(mind) //ambition start var/datum/browser/popup = new(src, "memory", "Memory and Notes") popup.set_content(mind.show_memory()) popup.open() //ambition end else to_chat(src, "You don't have a mind datum for some reason, so you can't look at your notes, if you had any.") /mob/verb/add_memory(msg as message) set name = "Add Note" set category = "IC" msg = copytext_char(msg, 1, MAX_MESSAGE_LEN) msg = sanitize(msg) if(mind) mind.store_memory(msg) else to_chat(src, "You don't have a mind datum for some reason, so you can't add a note to it.") /mob/proc/transfer_ckey(mob/new_mob, send_signal = TRUE) if(!new_mob || (!ckey && new_mob.ckey)) CRASH("transfer_ckey() called [new_mob ? "on ckey-less mob with a player mob as target" : "without a valid mob target"]!") if(!ckey) return SEND_SIGNAL(new_mob, COMSIG_MOB_PRE_PLAYER_CHANGE, new_mob, src) if (client) if(client.prefs?.auto_ooc) if (client.prefs.chat_toggles & CHAT_OOC && isliving(new_mob)) client.prefs.chat_toggles ^= CHAT_OOC if (!(client.prefs.chat_toggles & CHAT_OOC) && isdead(new_mob)) client.prefs.chat_toggles ^= CHAT_OOC new_mob.ckey = ckey if(send_signal) SEND_SIGNAL(src, COMSIG_MOB_KEY_CHANGE, new_mob, src) //splurt changeh INVOKE_ASYNC(GLOBAL_PROC, .proc/_paci_check, new_mob, src) // return TRUE /proc/_paci_check(mob/new_mob, mob/old_mob) if(jobban_isbanned(new_mob, "pacifist")) if(!QDELETED(old_mob)) REMOVE_TRAIT(old_mob, TRAIT_PACIFISM, "pacification ban") ADD_TRAIT(new_mob, TRAIT_PACIFISM, "pacification ban") /mob/verb/cancel_camera() set name = "Cancel Camera View" set category = "OOC" reset_perspective(null) unset_machine() GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0) //suppress the .click/dblclick macros so people can't use them to identify the location of items or aimbot /mob/verb/DisClick(argu = null as anything, sec = "" as text, number1 = 0 as num , number2 = 0 as num) set name = ".click" set hidden = TRUE set category = null if(GLOB.exploit_warn_spam_prevention < world.time) var/msg = "[key_name_admin(src)]([ADMIN_KICK(src)]) attempted to use the .click macro!" log_admin(msg) message_admins(msg) GLOB.exploit_warn_spam_prevention = world.time + 10 /mob/verb/DisDblClick(argu = null as anything, sec = "" as text, number1 = 0 as num , number2 = 0 as num) set name = ".dblclick" set hidden = TRUE set category = null if(GLOB.exploit_warn_spam_prevention < world.time) var/msg = "[key_name_admin(src)]([ADMIN_KICK(src)]) attempted to use the .dblclick macro!" log_admin(msg) message_admins(msg) GLOB.exploit_warn_spam_prevention = world.time + 10 /mob/Topic(href, href_list) if(href_list["mach_close"]) var/t1 = text("window=[href_list["mach_close"]]") unset_machine() src << browse(null, t1) if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY)) if(href_list["item"]) var/slot = text2num(href_list["item"]) var/hand_index = text2num(href_list["hand_index"]) var/obj/item/what if(hand_index) what = get_item_for_held_index(hand_index) slot = list(slot,hand_index) else what = get_item_by_slot(slot) if(what) if(!(what.item_flags & ABSTRACT)) usr.stripPanelUnequip(what,src,slot) else usr.stripPanelEquip(what,src,slot) // 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) . = ..() if(M != usr) return if(usr == src) return if(!Adjacent(usr)) return if(isAI(M)) return /mob/proc/is_muzzled() return FALSE /// Adds this list to the output to the stat browser /mob/proc/get_status_tab_items() . = list() /// Gets all relevant proc holders for the browser statpenl /mob/proc/get_proc_holders() . = list() if(mind) . += get_spells_for_statpanel(mind.spell_list) . += get_spells_for_statpanel(mob_spell_list) /** * Convert a list of spells into a displyable list for the statpanel * * Shows charge and other important info */ /mob/proc/get_spells_for_statpanel(list/spells) var/list/L = list() for(var/obj/effect/proc_holder/spell/S in spells) if((!S.mobs_blacklist || !S.mobs_blacklist[src]) && (!S.mobs_whitelist || S.mobs_whitelist[src])) switch(S.charge_type) if("recharge") L[++L.len] = list("[S.panel]", "[S.charge_counter/10.0]/[S.charge_max/10]", S.name, REF(S)) if("charges") L[++L.len] = list("[S.panel]", "[S.charge_counter]/[S.charge_max]", S.name, REF(S)) if("holdervar") L[++L.len] = list("[S.panel]", "[S.holder_var_type] [S.holder_var_amount]", S.name, REF(S)) return L #define MOB_FACE_DIRECTION_DELAY 1 // facing verbs /mob/proc/canface() if(world.time < client.last_turn) return FALSE if(stat == DEAD || stat == UNCONSCIOUS) return FALSE if(anchored) return FALSE if(mob_transforming) return FALSE if(restrained()) return FALSE return TRUE /mob/proc/fall(forced) drop_all_held_items() /mob/verb/eastface() set hidden = TRUE if(!canface()) return FALSE setDir(EAST) client.last_turn = world.time + MOB_FACE_DIRECTION_DELAY return TRUE /mob/verb/westface() set hidden = TRUE if(!canface()) return FALSE setDir(WEST) client.last_turn = world.time + MOB_FACE_DIRECTION_DELAY return TRUE /mob/verb/northface() set hidden = TRUE if(!canface()) return FALSE setDir(NORTH) client.last_turn = world.time + MOB_FACE_DIRECTION_DELAY return TRUE /mob/verb/southface() set hidden = TRUE if(!canface()) return FALSE setDir(SOUTH) client.last_turn = world.time + MOB_FACE_DIRECTION_DELAY return TRUE /mob/verb/eastshift() set hidden = TRUE if(!canface()) return FALSE if(pixel_x <= PIXEL_SHIFT_MAXIMUM + base_pixel_x) pixel_x++ is_shifted = TRUE /mob/verb/westshift() set hidden = TRUE if(!canface()) return FALSE if(pixel_x >= -PIXEL_SHIFT_MAXIMUM + base_pixel_x) pixel_x-- is_shifted = TRUE /mob/verb/northshift() set hidden = TRUE if(!canface()) return FALSE if(pixel_y <= PIXEL_SHIFT_MAXIMUM + base_pixel_y) pixel_y++ is_shifted = TRUE /mob/verb/southshift() set hidden = TRUE if(!canface()) return FALSE if(pixel_y >= -PIXEL_SHIFT_MAXIMUM + base_pixel_y) pixel_y-- is_shifted = TRUE /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() var/obj/item/held_item = get_active_held_item() if(SEND_SIGNAL(src, COMSIG_MOB_SWAP_HANDS, held_item) & COMPONENT_BLOCK_SWAP) to_chat(src, "Your other hand is too busy holding [held_item].") return FALSE return TRUE /mob/proc/activate_hand(selhand) return /mob/proc/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) //For sec bot threat assessment return 0 /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(var/message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", var/sound = 'sound/effects/genetics.ogg', var/atom/source = null, flashwindow) var/mob/dead/observer/ghost = get_ghost() if(ghost) ghost.notify_cloning(message, sound, source, flashwindow) return ghost /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) if(!spell) return for(var/X in mob_spell_list) var/obj/effect/proc_holder/spell/S = X if(istype(S, spell)) mob_spell_list -= S qdel(S) if(client) client << output(null, "statbrowser:check_spells") /mob/proc/anti_magic_check(magic = TRUE, holy = FALSE, tinfoil = FALSE, chargecost = 1, self = FALSE) if(!magic && !holy && !tinfoil) return var/list/protection_sources = list() if(SEND_SIGNAL(src, COMSIG_MOB_RECEIVE_MAGIC, src, magic, holy, tinfoil, chargecost, self, protection_sources) & COMPONENT_BLOCK_MAGIC) if(protection_sources.len) return pick(protection_sources) else return src if((magic && HAS_TRAIT(src, TRAIT_ANTIMAGIC)) || (!self && magic && HAS_TRAIT(src, TRAIT_ANTIMAGIC_NO_SELFBLOCK)) || (holy && HAS_TRAIT(src, TRAIT_HOLY))) return src //You can buckle on mobs if you're next to them since most are dense /mob/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) if(M.buckled) return FALSE 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 FALSE return ..() //Default buckling shift visual for mobs /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 /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 /mob/proc/can_buckle_others(mob/living/target, atom/buckle_to) return TRUE //Can the mob interact() with an atom? /mob/proc/can_interact_with(atom/A) return IsAdminGhost(src) || Adjacent(A) || A.hasSiliconAccessInArea(src) //Can the mob use Topic to interact with machines /mob/proc/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE) return /mob/proc/canUseStorage() return FALSE /mob/proc/faction_check_mob(mob/target, exact_match) 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 //This will update a mob's name, real_name, mind.name, GLOB.data_core records, pda, id and traitor text //Calling this proc without an oldname will only update the mob and skip updating the pda, id and records ~Carn /mob/proc/fully_replace_character_name(oldname,newname) log_message("[src] name changed from [oldname] to [newname]", LOG_OWNERSHIP) if(!newname) return 0 real_name = newname name = newname if(mind) mind.name = newname if(oldname) //update the datacore records! This is goig to be a bit costly. replace_records_name(oldname,newname) //update our pda and id if we have them on our person replace_identification_name(oldname,newname) for(var/datum/mind/T in SSticker.minds) for(var/datum/objective/obj in T.get_all_objectives()) // Only update if this player is a target if(obj.target && obj.target.current && obj.target.current.real_name == name) obj.update_explanation_text() return 1 //Updates GLOB.data_core records with new name , see mob/living/carbon/human /mob/proc/replace_records_name(oldname,newname) return /mob/proc/replace_identification_name(oldname,newname) var/list/searching = GetAllContents() var/search_id = 1 var/search_pda = 1 for(var/A in searching) if( search_id && istype(A, /obj/item/card/id) ) var/obj/item/card/id/ID = A if(ID.registered_name == oldname) ID.registered_name = newname ID.update_label() if(!search_pda) break search_id = 0 else if( search_pda && istype(A, /obj/item/pda) ) var/obj/item/pda/PDA = A if(PDA.owner == oldname) PDA.owner = newname PDA.update_label() if(!search_id) break search_pda = 0 /mob/proc/update_stat() return /mob/proc/update_health_hud() return /mob/proc/update_sight() SEND_SIGNAL(src, COMSIG_MOB_UPDATE_SIGHT) sync_lighting_plane_alpha() /mob/proc/sync_lighting_plane_alpha() if(hud_used) var/atom/movable/screen/plane_master/lighting/L = hud_used.plane_masters["[LIGHTING_PLANE]"] if (L) L.alpha = lighting_alpha /mob/proc/update_mouse_pointer() if (!client) return client.mouse_pointer_icon = initial(client.mouse_pointer_icon) // Consider using mouse override icon or snapping this section. if(pull_cursor_icon && client.keys_held["Ctrl"]) client.mouse_pointer_icon = pull_cursor_icon else if(throw_cursor_icon && in_throw_mode != 0) client.mouse_pointer_icon = throw_cursor_icon else if(combat_cursor_icon && SEND_SIGNAL(usr, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) if(!client.prefs || !client.prefs.disable_combat_cursor) // Don't show the combat cursor for people who have it disabled in prefs. client.mouse_pointer_icon = combat_cursor_icon else if(examine_cursor_icon && client.keys_held["Shift"]) //mouse shit is hardcoded, make this non hard-coded once we make mouse modifiers bindable client.mouse_pointer_icon = examine_cursor_icon // else if(istype(loc, /obj/vehicle/sealed)) var/obj/vehicle/sealed/mecha/E = loc if(E.mouse_pointer) client.mouse_pointer_icon = E.mouse_pointer if(client.mouse_override_icon) client.mouse_pointer_icon = client.mouse_override_icon /mob/proc/is_literate() return 0 /mob/proc/can_hold_items() return FALSE /mob/vv_get_dropdown() . = ..() VV_DROPDOWN_OPTION("", "---------") VV_DROPDOWN_OPTION(VV_HK_GIB, "Gib") VV_DROPDOWN_OPTION(VV_HK_GIVE_SPELL, "Give Spell") VV_DROPDOWN_OPTION(VV_HK_REMOVE_SPELL, "Remove Spell") VV_DROPDOWN_OPTION(VV_HK_GIVE_DISEASE, "Give Disease") VV_DROPDOWN_OPTION(VV_HK_GODMODE, "Toggle Godmode") VV_DROPDOWN_OPTION(VV_HK_DROP_ALL, "Drop Everything") VV_DROPDOWN_OPTION(VV_HK_REGEN_ICONS, "Regenerate Icons") VV_DROPDOWN_OPTION(VV_HK_PLAYER_PANEL, "Show player panel") VV_DROPDOWN_OPTION(VV_HK_BUILDMODE, "Toggle Buildmode") VV_DROPDOWN_OPTION(VV_HK_DIRECT_CONTROL, "Assume Direct Control") VV_DROPDOWN_OPTION(VV_HK_OFFER_GHOSTS, "Offer Control to Ghosts") /mob/vv_do_topic(list/href_list) . = ..() if(href_list[VV_HK_REGEN_ICONS]) if(!check_rights(NONE)) return regenerate_icons() if(href_list[VV_HK_PLAYER_PANEL]) if(!check_rights(NONE)) return usr.client.holder.show_player_panel(src) if(href_list[VV_HK_GODMODE]) if(!check_rights(R_ADMIN)) return usr.client.cmd_admin_godmode(src) if(href_list[VV_HK_GIVE_SPELL]) if(!check_rights(NONE)) return usr.client.give_spell(src) if(href_list[VV_HK_REMOVE_SPELL]) if(!check_rights(NONE)) return usr.client.remove_spell(src) if(href_list[VV_HK_GIVE_DISEASE]) if(!check_rights(NONE)) return usr.client.give_disease(src) if(href_list[VV_HK_GIB]) if(!check_rights(R_FUN)) return usr.client.cmd_admin_gib(src) if(href_list[VV_HK_BUILDMODE]) if(!check_rights(R_BUILDMODE)) return togglebuildmode(src) if(href_list[VV_HK_DROP_ALL]) if(!check_rights(NONE)) return usr.client.cmd_admin_drop_everything(src) if(href_list[VV_HK_DIRECT_CONTROL]) if(!check_rights(NONE)) return usr.client.cmd_assume_direct_control(src) if(href_list[VV_HK_OFFER_GHOSTS]) if(!check_rights(NONE)) return offer_control(src) /mob/vv_get_var(var_name) switch(var_name) if("logging") return debug_variable(var_name, logging, 0, src, FALSE) if(NAMEOF(src, lastKnownIP)) if(!check_rights(R_SENSITIVE, FALSE)) return "SENSITIVE" if(NAMEOF(src, computer_id)) if(!check_rights(R_SENSITIVE, FALSE)) return "SENSITIVE" . = ..() /mob/vv_auto_rename(new_name) //Do not do parent's actions, as we *usually* do this differently. fully_replace_character_name(real_name, new_name) /mob/verb/open_language_menu() set name = "Open Language Menu" set category = "IC" var/datum/language_holder/H = get_language_holder() H.open_language_menu(usr) ///Adjust the nutrition of a mob /mob/proc/adjust_nutrition(change, max = INFINITY) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks nutrition = clamp(nutrition + change, 0, max) ///Force set the mob nutrition /mob/proc/set_nutrition(var/change) //Seriously fuck you oldcoders. nutrition = max(0, change) /mob/setMovetype(newval) . = ..() update_movespeed(FALSE) /mob/proc/getLAssailant() return LAssailant?.resolve() /// Updates the grab state of the mob and updates movespeed /mob/setGrabState(newstate) . = ..() switch(grab_state) if(GRAB_PASSIVE) remove_movespeed_modifier(MOVESPEED_ID_MOB_GRAB_STATE) if(GRAB_AGGRESSIVE) add_movespeed_modifier(/datum/movespeed_modifier/grab_slowdown/aggressive) if(GRAB_NECK) add_movespeed_modifier(/datum/movespeed_modifier/grab_slowdown/neck) if(GRAB_KILL) add_movespeed_modifier(/datum/movespeed_modifier/grab_slowdown/kill) /mob/proc/update_equipment_speed_mods() var/speedies = equipped_speed_mods() if(!speedies) remove_movespeed_modifier(/datum/movespeed_modifier/equipment_speedmod, update=TRUE) else add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/equipment_speedmod, multiplicative_slowdown = speedies) /// Gets the combined speed modification of all worn items /// Except base mob type doesnt really wear items /mob/proc/equipped_speed_mods() for(var/obj/item/I in held_items) if(I.item_flags & SLOWS_WHILE_IN_HAND) . += I.slowdown /** * Mostly called by doUnEquip() * Like item dropped() on mob side. */ /mob/proc/on_item_dropped(obj/item/I) return