/mob/living/Initialize() . = ..() if(unique_name) name = "[name] ([rand(1, 1000)])" real_name = name var/datum/atom_hud/data/human/medical/advanced/medhud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] medhud.add_to_hud(src) for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds) diag_hud.add_to_hud(src) faction += "[REF(src)]" GLOB.mob_living_list += src initialize_footstep() /mob/living/proc/initialize_footstep() AddComponent(/datum/component/footstep) /mob/living/prepare_huds() ..() prepare_data_huds() /mob/living/proc/prepare_data_huds() med_hud_set_health() med_hud_set_status() /mob/living/Destroy() if(LAZYLEN(status_effects)) for(var/s in status_effects) var/datum/status_effect/S = s if(S.on_remove_on_mob_delete) //the status effect calls on_remove when its mob is deleted qdel(S) else S.be_replaced() if(ranged_ability) ranged_ability.remove_ranged_ability(src) if(buckled) buckled.unbuckle_mob(src,force=1) remove_from_all_data_huds() GLOB.mob_living_list -= src QDEL_LIST(diseases) return ..() /mob/living/onZImpact(turf/T, levels) if(!isgroundlessturf(T)) ZImpactDamage(T, levels) return ..() /mob/living/proc/ZImpactDamage(turf/T, levels) visible_message("[src] crashes into [T] with a sickening noise!") adjustBruteLoss((levels * 5) ** 1.5) Knockdown(levels * 50) /mob/living/proc/OpenCraftingMenu() return //Generic Bump(). Override MobBump() and ObjBump() instead of this. /mob/living/Bump(atom/A) if(..()) //we are thrown onto something return if (buckled || now_pushing) return if(ismob(A)) var/mob/M = A if(MobBump(M)) return if(isobj(A)) var/obj/O = A if(ObjBump(O)) return if(ismovableatom(A)) var/atom/movable/AM = A if(PushAM(AM, move_force)) return /mob/living/Bumped(atom/movable/AM) ..() last_bumped = world.time //Called when we bump onto a mob /mob/living/proc/MobBump(mob/M) //Even if we don't push/swap places, we "touched" them, so spread fire spreadFire(M) if(now_pushing) return TRUE if(isliving(M)) var/mob/living/L = M //Also spread diseases for(var/thing in diseases) var/datum/disease/D = thing if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) L.ContactContractDisease(D) for(var/thing in L.diseases) var/datum/disease/D = thing if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) ContactContractDisease(D) //Should stop you pushing a restrained person out of the way if(L.pulledby && L.pulledby != src && L.restrained()) if(!(world.time % 5)) to_chat(src, "[L] is restrained, you cannot push past.") return 1 if(L.pulling) if(ismob(L.pulling)) var/mob/P = L.pulling if(P.restrained()) if(!(world.time % 5)) to_chat(src, "[L] is restraining [P], you cannot push past.") return 1 //CIT CHANGES START HERE - makes it so resting stops you from moving through standing folks without a short delay if(resting && !L.resting) var/origtargetloc = L.loc if(!pulledby) if(attemptingcrawl) return TRUE if(getStaminaLoss() >= STAMINA_SOFTCRIT) to_chat(src, "You're too exhausted to crawl under [L].") return TRUE attemptingcrawl = TRUE visible_message("[src] is attempting to crawl under [L].", "You are now attempting to crawl under [L].") if(!do_after(src, CRAWLUNDER_DELAY, target = src) || !resting) attemptingcrawl = FALSE return TRUE var/src_passmob = (pass_flags & PASSMOB) pass_flags |= PASSMOB Move(origtargetloc) if(!src_passmob) pass_flags &= ~PASSMOB attemptingcrawl = FALSE return TRUE //END OF CIT CHANGES if(moving_diagonally)//no mob swap during diagonal moves. return 1 if(!M.buckled && !M.has_buckled_mobs()) var/mob_swap //the puller can always swap with its victim if on grab intent if(M.pulledby == src && a_intent == INTENT_GRAB) mob_swap = 1 //restrained people act if they were on 'help' intent to prevent a person being pulled from being separated from their puller else if((M.restrained() || M.a_intent == INTENT_HELP) && (restrained() || a_intent == INTENT_HELP)) mob_swap = 1 if(mob_swap) //handle micro bumping on help intent if(handle_micro_bump_helping(M)) return 1 //switch our position with M if(loc && !loc.Adjacent(M.loc)) return 1 now_pushing = 1 var/oldloc = loc var/oldMloc = M.loc var/M_passmob = (M.pass_flags & PASSMOB) // we give PASSMOB to both mobs to avoid bumping other mobs during swap. var/src_passmob = (pass_flags & PASSMOB) M.pass_flags |= PASSMOB pass_flags |= PASSMOB var/move_failed = FALSE if(!M.Move(oldloc) || !Move(oldMloc)) M.forceMove(oldMloc) forceMove(oldloc) move_failed = TRUE if(!src_passmob) pass_flags &= ~PASSMOB if(!M_passmob) M.pass_flags &= ~PASSMOB now_pushing = 0 if(!move_failed) return 1 //okay, so we didn't switch. but should we push? //not if he's not CANPUSH of course if(!(M.status_flags & CANPUSH)) return 1 //handle micro bumping on other intents if(handle_micro_bump_other(M)) return 1 if(isliving(M)) var/mob/living/L = M if(HAS_TRAIT(L, TRAIT_PUSHIMMUNE)) return 1 //If they're a human, and they're not in help intent, block pushing if(ishuman(M) && (M.a_intent != INTENT_HELP)) return TRUE //anti-riot equipment is also anti-push for(var/obj/item/I in M.held_items) if(!istype(M, /obj/item/clothing)) if(prob(I.block_chance*2)) return 1 /mob/living/get_photo_description(obj/item/camera/camera) var/list/mob_details = list() var/list/holding = list() var/len = length(held_items) if(len) for(var/obj/item/I in held_items) if(!holding.len) holding += "They are holding \a [I]" else if(held_items.Find(I) == len) holding += ", and \a [I]." else holding += ", \a [I]" holding += "." mob_details += "You can also see [src] on the photo[health < (maxHealth * 0.75) ? ", looking a bit hurt":""][holding ? ". [holding.Join("")]":"."]." return mob_details.Join("") //Called when we bump onto an obj /mob/living/proc/ObjBump(obj/O) return //Called when we want to push an atom/movable /mob/living/proc/PushAM(atom/movable/AM, force = move_force) if(now_pushing) return TRUE if(moving_diagonally)// no pushing during diagonal moves. return TRUE if(!client && (mob_size < MOB_SIZE_SMALL)) return now_pushing = TRUE var/t = get_dir(src, AM) var/push_anchored = FALSE if((AM.move_resist * MOVE_FORCE_CRUSH_RATIO) <= force) if(move_crush(AM, move_force, t)) push_anchored = TRUE if((AM.move_resist * MOVE_FORCE_FORCEPUSH_RATIO) <= force) //trigger move_crush and/or force_push regardless of if we can push it normally if(force_push(AM, move_force, t, push_anchored)) push_anchored = TRUE if((AM.anchored && !push_anchored) || (force < (AM.move_resist * MOVE_FORCE_PUSH_RATIO))) now_pushing = FALSE return if (istype(AM, /obj/structure/window)) var/obj/structure/window/W = AM if(W.fulltile) for(var/obj/structure/window/win in get_step(W,t)) now_pushing = FALSE return if(pulling == AM) stop_pulling() var/current_dir if(isliving(AM)) current_dir = AM.dir if(AM.Move(get_step(AM.loc, t), t, glide_size)) Move(get_step(loc, t), t) if(current_dir) AM.setDir(current_dir) now_pushing = FALSE /mob/living/start_pulling(atom/movable/AM, state, force = pull_force, supress_message = FALSE) if(!AM || !src) return FALSE if(!(AM.can_be_pulled(src, state, force))) return FALSE if(throwing || incapacitated()) return FALSE AM.add_fingerprint(src) // If we're pulling something then drop what we're currently pulling and pull this instead. if(pulling) // Are we trying to pull something we are already pulling? Then just stop here, no need to continue. if(AM == pulling) return stop_pulling() changeNext_move(CLICK_CD_GRABBING) if(AM.pulledby) if(!supress_message) visible_message("[src] has pulled [AM] from [AM.pulledby]'s grip.") log_combat(AM, AM.pulledby, "pulled from", src) AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once. pulling = AM AM.pulledby = src if(!supress_message) playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) update_pull_hud_icon() if(ismob(AM)) var/mob/M = AM log_combat(src, M, "grabbed", addition="passive grab") if(!supress_message && !(iscarbon(AM) && HAS_TRAIT(src, TRAIT_STRONG_GRABBER))) visible_message("[src] has grabbed [M][(zone_selected == "l_arm" || zone_selected == "r_arm")? " by their hands":" passively"].") //Cit change - And they thought ERP was bad. if(!iscarbon(src)) M.LAssailant = null else M.LAssailant = usr if(isliving(M)) var/mob/living/L = M //Share diseases that are spread by touch for(var/thing in diseases) var/datum/disease/D = thing if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) L.ContactContractDisease(D) for(var/thing in L.diseases) var/datum/disease/D = thing if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) ContactContractDisease(D) if(iscarbon(L)) var/mob/living/carbon/C = L if(HAS_TRAIT(src, TRAIT_STRONG_GRABBER)) C.grippedby(src) //mob verbs are a lot faster than object verbs //for more info on why this is not atom/pull, see examinate() in mob.dm /mob/living/verb/pulled(atom/movable/AM as mob|obj in oview(1)) set name = "Pull" set category = "Object" if(istype(AM) && Adjacent(AM)) start_pulling(AM) else stop_pulling() /mob/living/stop_pulling() ..() update_pull_hud_icon() /mob/living/verb/stop_pulling1() set name = "Stop Pulling" set category = "IC" stop_pulling() //same as above /mob/living/pointed(atom/A as mob|obj|turf in view()) if(incapacitated()) return FALSE if(HAS_TRAIT(src, TRAIT_DEATHCOMA)) return FALSE if(!..()) return FALSE visible_message("[src] points at [A].", "You point at [A].") return TRUE /mob/living/verb/succumb() set name = "Succumb" set category = "IC" if(src.has_status_effect(/datum/status_effect/chem/enthrall)) var/datum/status_effect/chem/enthrall/E = src.has_status_effect(/datum/status_effect/chem/enthrall) if(E.phase < 3) if(HAS_TRAIT(src, TRAIT_MINDSHIELD)) to_chat(src, "Your mindshield prevents your mind from giving in!") else if(src.mind.assigned_role in GLOB.command_positions) to_chat(src, "Your dedication to your department prevents you from giving in!") else E.enthrallTally += 20 to_chat(src, "You give into [E.master]'s influence.") if (InCritical()) log_message("Has succumbed to death while in [InFullCritical() ? "hard":"soft"] critical with [round(health, 0.1)] points of health!", LOG_ATTACK) adjustOxyLoss(health - HEALTH_THRESHOLD_DEAD) updatehealth() to_chat(src, "You have given up life and succumbed to death.") death() /mob/living/incapacitated(ignore_restraints, ignore_grab) if(stat || IsUnconscious() || IsStun() || IsKnockdown() || recoveringstam || (!ignore_restraints && restrained(ignore_grab))) // CIT CHANGE - adds recoveringstam check here return TRUE /mob/living/canUseStorage() if (get_num_arms() <= 0) return FALSE return TRUE /mob/living/proc/InCritical() return (health <= crit_threshold && (stat == SOFT_CRIT || stat == UNCONSCIOUS)) /mob/living/proc/InFullCritical() return (health <= HEALTH_THRESHOLD_FULLCRIT && stat == UNCONSCIOUS) //This proc is used for mobs which are affected by pressure to calculate the amount of pressure that actually //affects them once clothing is factored in. ~Errorage /mob/living/proc/calculate_affecting_pressure(pressure) return pressure /mob/living/proc/adjustBodyTemp(actual, desired, incrementboost) var/temperature = actual var/difference = abs(actual-desired) //get difference var/increments = difference/10 //find how many increments apart they are var/change = increments*incrementboost // Get the amount to change by (x per increment) // Too cold if(actual < desired) temperature += change if(actual > desired) temperature = desired // Too hot if(actual > desired) temperature -= change if(actual < desired) temperature = desired return temperature /mob/living/proc/getMaxHealth() return maxHealth /mob/living/proc/setMaxHealth(newMaxHealth) maxHealth = newMaxHealth // MOB PROCS //END /mob/living/proc/mob_sleep() set name = "Sleep" set category = "IC" if(IsSleeping()) to_chat(src, "You are already sleeping.") return else if(alert(src, "You sure you want to sleep for a while?", "Sleep", "Yes", "No") == "Yes") SetSleeping(400) //Short nap update_canmove() /mob/proc/get_contents() /*CIT CHANGE - comments out lay_down proc to be modified in modular_citadel /mob/living/proc/lay_down() set name = "Rest" set category = "IC" resting = !resting to_chat(src, "You are now [resting ? "resting" : "getting up"].") update_canmove() */ //Recursive function to find everything a mob is holding. Really shitty proc tbh. /mob/living/get_contents() var/list/ret = list() ret |= contents //add our contents for(var/i in ret.Copy()) //iterate storage objects var/atom/A = i SEND_SIGNAL(A, COMSIG_TRY_STORAGE_RETURN_INVENTORY, ret) for(var/obj/item/folder/F in ret.Copy()) //very snowflakey-ly iterate folders ret |= F.contents return ret // Living mobs use can_inject() to make sure that the mob is not syringe-proof in general. /mob/living/proc/can_inject() return TRUE /mob/living/is_injectable(allowmobs = TRUE) return (allowmobs && reagents && can_inject()) /mob/living/is_drawable(allowmobs = TRUE) return (allowmobs && reagents && can_inject()) /mob/living/proc/get_organ_target() var/mob/shooter = src var/t = shooter.zone_selected if ((t in list( BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH ))) t = BODY_ZONE_HEAD var/def_zone = ran_zone(t) return def_zone /mob/living/proc/updatehealth() if(status_flags & GODMODE) return health = maxHealth - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss() staminaloss = getStaminaLoss() update_stat() med_hud_set_health() med_hud_set_status() //proc used to ressuscitate a mob /mob/living/proc/revive(full_heal = 0, admin_revive = 0) if(full_heal) fully_heal(admin_revive) if(stat == DEAD && can_be_revived()) //in some cases you can't revive (e.g. no brain) GLOB.dead_mob_list -= src GLOB.alive_mob_list += src suiciding = 0 stat = UNCONSCIOUS //the mob starts unconscious, blind_eyes(1) updatehealth() //then we check if the mob should wake up. update_canmove() update_sight() clear_alert("not_enough_oxy") reload_fullscreen() . = 1 if(mind) for(var/S in mind.spell_list) var/obj/effect/proc_holder/spell/spell = S spell.updateButtonIcon() //proc used to completely heal a mob. /mob/living/proc/fully_heal(admin_revive = 0) restore_blood() setToxLoss(0, 0) //zero as second argument not automatically call updatehealth(). setOxyLoss(0, 0) setCloneLoss(0, 0) setStaminaLoss(0, 0) SetUnconscious(0, FALSE) set_disgust(0) SetStun(0, FALSE) SetKnockdown(0, FALSE) SetSleeping(0, FALSE) radiation = 0 nutrition = NUTRITION_LEVEL_FED + 50 fullness = FULLNESS_LEVEL_HALF_FULL // GS13 thirst = THIRST_LEVEL_QUENCHED + 50 bodytemperature = BODYTEMP_NORMAL set_blindness(0) set_blurriness(0) set_eye_damage(0) cure_nearsighted() cure_blind() cure_husk() hallucination = 0 heal_overall_damage(INFINITY, INFINITY, INFINITY, FALSE, FALSE, TRUE) //heal brute and burn dmg on both organic and robotic limbs, and update health right away. ExtinguishMob() fire_stacks = 0 confused = 0 update_canmove() var/datum/component/mood/mood = GetComponent(/datum/component/mood) if (mood) QDEL_LIST_ASSOC_VAL(mood.mood_events) mood.sanity = SANITY_GREAT mood.update_mood() //Heal all organs if(iscarbon(src)) var/mob/living/carbon/C = src if(C.internal_organs) for(var/organ in C.internal_organs) var/obj/item/organ/O = organ O.setOrganDamage(0) SEND_SIGNAL(src, COMSIG_LIVING_FULLY_HEAL, admin_revive) //fuck shitcode I hate shitcode /mob/living/proc/legion_heal() restore_blood() setStaminaLoss(0, 0) SetUnconscious(0, FALSE) SetStun(0, FALSE) SetKnockdown(0, FALSE) SetSleeping(0, FALSE) bodytemperature = BODYTEMP_NORMAL heal_overall_damage(INFINITY, INFINITY, INFINITY, FALSE, FALSE, TRUE) //heal brute and burn dmg on both organic and robotic limbs, and update health right away. ExtinguishMob() fire_stacks = 0 update_canmove() SEND_SIGNAL(src, COMSIG_LIVING_FULLY_HEAL) //proc called by revive(), to check if we can actually ressuscitate the mob (we don't want to revive him and have him instantly die again) /mob/living/proc/can_be_revived() . = 1 if(health <= HEALTH_THRESHOLD_DEAD) return 0 /mob/living/proc/update_damage_overlays() return /mob/living/Move(atom/newloc, direct, glide_size_override) if (buckled && buckled.loc != newloc) //not updating position if (!buckled.anchored) return buckled.Move(newloc, direct, glide_size) else return 0 var/old_direction = dir var/turf/T = loc . = ..() if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1)//separated from our puller and not in the middle of a diagonal move. pulledby.stop_pulling() if(active_storage && !(CanReach(active_storage.parent,view_only = TRUE))) active_storage.close(src) if(lying && !buckled && prob(getBruteLoss()*200/maxHealth)) makeTrail(newloc, T, old_direction) /mob/living/proc/makeTrail(turf/target_turf, turf/start, direction) if(!has_gravity()) return var/blood_exists = FALSE for(var/obj/effect/decal/cleanable/trail_holder/C in start) //checks for blood splatter already on the floor blood_exists = TRUE if(isturf(start)) var/trail_type = getTrail() if(trail_type) var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1) if(blood_volume && blood_volume > max((BLOOD_VOLUME_NORMAL*blood_ratio)*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold blood_volume = max(blood_volume - max(1, brute_ratio * 2), 0) //that depends on our brute damage. var/newdir = get_dir(target_turf, start) if(newdir != direction) newdir = newdir | direction if(newdir == 3) //N + S newdir = NORTH else if(newdir == 12) //E + W newdir = EAST if((newdir in GLOB.cardinals) && (prob(50))) newdir = turn(get_dir(target_turf, start), 180) if(!blood_exists) new /obj/effect/decal/cleanable/trail_holder(start, get_static_viruses()) for(var/obj/effect/decal/cleanable/trail_holder/TH in start) if((!(newdir in TH.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && TH.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled) TH.existing_dirs += newdir TH.add_overlay(image('icons/effects/blood.dmi', trail_type, dir = newdir)) TH.transfer_mob_blood_dna(src) /mob/living/carbon/human/makeTrail(turf/T) if((NOBLOOD in dna.species.species_traits) || !bleed_rate || bleedsuppress) return ..() /mob/living/proc/getTrail() if(getBruteLoss() < 300) return pick("ltrails_1", "ltrails_2") else return pick("trails_1", "trails_2") /mob/living/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0) if(buckled) return if(client && client.move_delay >= world.time + world.tick_lag*2) pressure_resistance_prob_delta -= 30 var/list/turfs_to_check = list() if(has_limbs) var/turf/T = get_step(src, angle2dir(dir2angle(direction)+90)) if (T) turfs_to_check += T T = get_step(src, angle2dir(dir2angle(direction)-90)) if(T) turfs_to_check += T for(var/t in turfs_to_check) T = t if(T.density) pressure_resistance_prob_delta -= 20 continue for (var/atom/movable/AM in T) if (AM.density && AM.anchored) pressure_resistance_prob_delta -= 20 break if(!force_moving) ..(pressure_difference, direction, pressure_resistance_prob_delta) /mob/living/can_resist() return !((next_move > world.time) || incapacitated(ignore_restraints = TRUE)) /mob/living/verb/resist() set name = "Resist" set category = "IC" if(!can_resist()) return changeNext_move(CLICK_CD_RESIST) SEND_SIGNAL(src, COMSIG_LIVING_RESIST, src) //resisting grabs (as if it helps anyone...) if(!restrained(ignore_grab = 1) && pulledby) visible_message("[src] resists against [pulledby]'s grip!") log_combat(src, pulledby, "resisted grab") resist_grab() return //unbuckling yourself if(buckled && last_special <= world.time) resist_buckle() // CIT CHANGE - climbing out of a gut if(attempt_vr(src,"vore_process_resist",args)) return TRUE //Breaking out of a container (Locker, sleeper, cryo...) else if(isobj(loc)) var/obj/C = loc C.container_resist(src) else if(canmove) if(on_fire) resist_fire() //stop, drop, and roll return if(resting) //cit change - allows resisting out of resting resist_a_rest() // ditto return if(resist_embedded()) //Citadel Change for embedded removal memes return if(last_special <= world.time) resist_restraints() //trying to remove cuffs. return /mob/proc/resist_grab(moving_resist) return 1 //returning 0 means we successfully broke free /mob/living/resist_grab(moving_resist) . = 1 if(pulledby.grab_state) if(!resting && prob(30/pulledby.grab_state)) visible_message("[src] has broken free of [pulledby]'s grip!") log_combat(pulledby, src, "broke grab") pulledby.stop_pulling() return 0 if(moving_resist && client) //we resisted by trying to move client.move_delay = world.time + 20 else pulledby.stop_pulling() return 0 /mob/living/proc/resist_buckle() buckled.user_unbuckle_mob(src,src) /mob/living/proc/resist_fire() return /mob/living/proc/resist_restraints() return /mob/living/proc/get_visible_name() return name /mob/living/update_gravity(has_gravity,override = 0) if(!SSticker.HasRoundStarted()) return if(has_gravity) if(has_gravity == 1) clear_alert("gravity") else if(has_gravity >= GRAVITY_DAMAGE_TRESHOLD) throw_alert("gravity", /obj/screen/alert/veryhighgravity) else throw_alert("gravity", /obj/screen/alert/highgravity) else throw_alert("gravity", /obj/screen/alert/weightless) if(!override && !is_flying()) float(!has_gravity) /mob/living/float(on) if(throwing) return var/fixed = 0 if(anchored || (buckled && buckled.anchored)) fixed = 1 if(on && !floating && !fixed) animate(src, pixel_y = pixel_y + 2, time = 10, loop = -1) sleep(10) animate(src, pixel_y = pixel_y - 2, time = 10, loop = -1) floating = TRUE else if(((!on || fixed) && floating)) animate(src, pixel_y = get_standard_pixel_y_offset(lying), time = 10) floating = FALSE // The src mob is trying to strip an item from someone // Override if a certain type of mob should be behave differently when stripping items (can't, for example) /mob/living/stripPanelUnequip(obj/item/what, mob/who, where) if(HAS_TRAIT(what, TRAIT_NODROP)) to_chat(src, "You can't remove \the [what.name], it appears to be stuck!") return who.visible_message("[src] tries to remove [who]'s [what.name].", \ "[src] tries to remove [who]'s [what.name].") what.add_fingerprint(src) if(do_mob(src, who, what.strip_delay, ignorehelditem = TRUE)) if(what && Adjacent(who)) if(islist(where)) var/list/L = where if(what == who.get_item_for_held_index(L[2])) if(who.dropItemToGround(what)) if(!put_in_hands(what)) what.forceMove(drop_location()) log_combat(src, who, "stripped [what] off") if(what == who.get_item_by_slot(where)) if(who.dropItemToGround(what)) if(!can_hold_items() || !put_in_hands(what)) what.forceMove(drop_location()) log_combat(src, who, "stripped [what] off") // The src mob is trying to place an item on someone // Override if a certain mob should be behave differently when placing items (can't, for example) /mob/living/stripPanelEquip(obj/item/what, mob/who, where) what = src.get_active_held_item() if(what && HAS_TRAIT(what, TRAIT_NODROP)) to_chat(src, "You can't put \the [what.name] on [who], it's stuck to your hand!") return if(what) var/list/where_list var/final_where if(islist(where)) where_list = where final_where = where[1] else final_where = where if(!what.mob_can_equip(who, src, final_where, TRUE, TRUE)) to_chat(src, "\The [what.name] doesn't fit in that place!") return visible_message("[src] tries to put [what] on [who].") if(do_mob(src, who, what.equip_delay_other)) if(what && Adjacent(who) && what.mob_can_equip(who, src, final_where, TRUE, TRUE)) if(temporarilyRemoveItemFromInventory(what)) if(where_list) if(!who.put_in_hand(what, where_list[2])) what.forceMove(get_turf(who)) else who.equip_to_slot(what, where, TRUE) /mob/living/singularity_pull(S, current_size) ..() if(current_size >= STAGE_SIX) throw_at(S, 14, 3, src, TRUE) else step_towards(src,S) /mob/living/proc/do_jitter_animation(jitteriness) var/amplitude = min(4, (jitteriness/100) + 1) var/pixel_x_diff = rand(-amplitude, amplitude) var/pixel_y_diff = rand(-amplitude/3, amplitude/3) var/final_pixel_x = get_standard_pixel_x_offset(lying) var/final_pixel_y = get_standard_pixel_y_offset(lying) animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff , time = 2, loop = 6) animate(pixel_x = final_pixel_x , pixel_y = final_pixel_y , time = 2) floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure to restart it in next life(). /mob/living/proc/get_temperature(datum/gas_mixture/environment) var/loc_temp = environment ? environment.temperature : T0C if(isobj(loc)) var/obj/oloc = loc var/obj_temp = oloc.return_temperature() if(obj_temp != null) loc_temp = obj_temp else if(isspaceturf(get_turf(src))) var/turf/heat_turf = get_turf(src) loc_temp = heat_turf.temperature return loc_temp /mob/living/proc/get_standard_pixel_x_offset(lying = 0) return initial(pixel_x) /mob/living/proc/get_standard_pixel_y_offset(lying = 0) return initial(pixel_y) /mob/living/cancel_camera() ..() cameraFollow = null /mob/living/proc/can_track(mob/living/user) //basic fast checks go first. When overriding this proc, I recommend calling ..() at the end. var/turf/T = get_turf(src) if(!T) return 0 if(is_centcom_level(T.z)) //dont detect mobs on centcom return 0 if(is_away_level(T.z)) return 0 if(user != null && src == user) return 0 if(invisibility || alpha == 0)//cloaked return 0 if(digitalcamo || digitalinvis) return 0 if(ismimic(src)) // Are we a mimic? Mimics should not be tracked to prevent AI camera cheese. return 0 // Now, are they viewable by a camera? (This is last because it's the most intensive check) if(!near_camera(src)) return 0 return 1 //used in datum/reagents/reaction() proc /mob/living/proc/get_permeability_protection(list/target_zones) return 0 /mob/living/proc/harvest(mob/living/user) //used for extra objects etc. in butchering return /mob/living/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE) if(incapacitated()) to_chat(src, "You can't do that right now!") return FALSE if(be_close && !in_range(M, src)) to_chat(src, "You are too far away!") return FALSE if(!no_dextery) to_chat(src, "You don't have the dexterity to do this!") return FALSE return TRUE /mob/living/proc/can_use_guns(obj/item/G)//actually used for more than guns! if(G.trigger_guard != TRIGGER_GUARD_ALLOW_ALL && !IsAdvancedToolUser()) to_chat(src, "You don't have the dexterity to do this!") return FALSE return TRUE /mob/living/proc/update_stamina() return /mob/living/carbon/alien/update_stamina() return /mob/living/proc/owns_soul() if(mind) return mind.soulOwner == mind return TRUE /mob/living/proc/return_soul() hellbound = 0 if(mind) var/datum/antagonist/devil/devilInfo = mind.soulOwner.has_antag_datum(/datum/antagonist/devil) if(devilInfo)//Not sure how this could be null, but let's just try anyway. devilInfo.remove_soul(mind) mind.soulOwner = mind /mob/living/proc/has_bane(banetype) var/datum/antagonist/devil/devilInfo = is_devil(src) return devilInfo && banetype == devilInfo.bane /mob/living/proc/check_weakness(obj/item/weapon, mob/living/attacker) if(mind && mind.has_antag_datum(/datum/antagonist/devil)) return check_devil_bane_multiplier(weapon, attacker) return 1 /mob/living/proc/check_acedia() if(mind && mind.has_objective(/datum/objective/sintouched/acedia)) return TRUE return FALSE /mob/living/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) stop_pulling() . = ..() // Called when we are hit by a bolt of polymorph and changed // Generally the mob we are currently in is about to be deleted /mob/living/proc/wabbajack_act(mob/living/new_mob) new_mob.name = real_name new_mob.real_name = real_name if(mind) mind.transfer_to(new_mob) else new_mob.key = key for(var/para in hasparasites()) var/mob/living/simple_animal/hostile/guardian/G = para G.summoner = new_mob G.Recall() to_chat(G, "Your summoner has changed form!") /mob/living/rad_act(amount) . = ..() if(!amount || (amount < RAD_MOB_SKIN_PROTECTION) || HAS_TRAIT(src, TRAIT_RADIMMUNE)) return amount -= RAD_BACKGROUND_RADIATION // This will always be at least 1 because of how skin protection is calculated var/blocked = getarmor(null, "rad") if(amount > RAD_BURN_THRESHOLD) apply_damage(log(amount)*2, BURN, null, blocked) apply_effect((amount*RAD_MOB_COEFFICIENT)/max(1, (radiation**2)*RAD_OVERDOSE_REDUCTION), EFFECT_IRRADIATE, blocked) /mob/living/anti_magic_check(magic = TRUE, holy = FALSE, chargecost = 1, self = FALSE) . = ..() if(.) return if((magic && HAS_TRAIT(src, TRAIT_ANTIMAGIC)) || (holy && HAS_TRAIT(src, TRAIT_HOLY))) return src /mob/living/proc/fakefireextinguish() return /mob/living/proc/fakefire() return //Mobs on Fire /mob/living/proc/IgniteMob() if(fire_stacks > 0 && !on_fire) on_fire = 1 src.visible_message("[src] catches fire!", \ "You're set on fire!") new/obj/effect/dummy/lighting_obj/moblight/fire(src) throw_alert("fire", /obj/screen/alert/fire) update_fire() SEND_SIGNAL(src, COMSIG_LIVING_IGNITED,src) return TRUE return FALSE /mob/living/proc/ExtinguishMob() if(on_fire) on_fire = 0 fire_stacks = 0 for(var/obj/effect/dummy/lighting_obj/moblight/fire/F in src) qdel(F) clear_alert("fire") SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "on_fire") SEND_SIGNAL(src, COMSIG_LIVING_EXTINGUISHED, src) update_fire() /mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person fire_stacks = CLAMP(fire_stacks + add_fire_stacks, -20, 20) if(on_fire && fire_stacks <= 0) ExtinguishMob() //Share fire evenly between the two mobs //Called in MobBump() and Crossed() /mob/living/proc/spreadFire(mob/living/L) if(!istype(L)) return var/L_old_on_fire = L.on_fire if(on_fire) //Only spread fire stacks if we're on fire fire_stacks /= 2 L.fire_stacks += fire_stacks if(L.IgniteMob()) log_game("[key_name(src)] bumped into [key_name(L)] and set them on fire") if(L_old_on_fire) //Only ignite us and gain their stacks if they were onfire before we bumped them L.fire_stacks /= 2 fire_stacks += L.fire_stacks IgniteMob() //Mobs on Fire end // used by secbot and monkeys Crossed /mob/living/proc/knockOver(var/mob/living/carbon/C) if(C.key) //save us from monkey hordes C.visible_message("[pick( \ "[C] dives out of [src]'s way!", \ "[C] stumbles over [src]!", \ "[C] jumps out of [src]'s path!", \ "[C] trips over [src] and falls!", \ "[C] topples over [src]!", \ "[C] leaps out of [src]'s way!")]") C.Knockdown(40) /mob/living/can_be_pulled() return ..() && !(buckled && buckled.buckle_prevents_pull) //Updates canmove, lying and icons. Could perhaps do with a rename but I can't think of anything to describe it. //Robots, animals and brains have their own version so don't worry about them /mob/living/proc/update_canmove() var/ko = IsKnockdown() || IsUnconscious() || (stat && (stat != SOFT_CRIT || pulledby)) || (HAS_TRAIT(src, TRAIT_DEATHCOMA)) var/move_and_fall = stat == SOFT_CRIT && !pulledby var/chokehold = pulledby && pulledby.grab_state >= GRAB_NECK var/buckle_lying = !(buckled && !buckled.buckle_lying) var/has_legs = get_num_legs() var/has_arms = get_num_arms() var/ignore_legs = get_leg_ignore() var/pinned = resting && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE // Cit change - adds pinning for aggressive-grabbing people on the ground if(ko || move_and_fall || IsStun() || chokehold) // Cit change - makes resting not force you to drop everything drop_all_held_items() unset_machine() if(pulling) stop_pulling() else if(resting) //CIT CHANGE - makes resting make you stop pulling and interacting with machines unset_machine() //CIT CHANGE - Ditto! if(pulling) //CIT CHANGE - Ditto. stop_pulling() //CIT CHANGE - Ditto... else if(has_legs || ignore_legs) lying = 0 if(buckled) lying = 90*buckle_lying else if(!lying) if(resting) lying = pick(90, 270) // Cit change - makes resting not force you to drop your held items if(has_gravity()) // Cit change - Ditto playsound(src, "bodyfall", 50, 1) // Cit change - Ditto! else if(ko || move_and_fall || (!has_legs && !ignore_legs) || chokehold) fall(forced = 1) canmove = !(ko || recoveringstam || pinned || IsStun() || IsFrozen() || chokehold || buckled || (!has_legs && !ignore_legs && !has_arms)) //Cit change - makes it plausible to move while resting, adds pinning and stamina crit density = !lying if(lying) if(layer == initial(layer)) //to avoid special cases like hiding larvas. layer = LYING_MOB_LAYER //so mob lying always appear behind standing mobs else if(layer == LYING_MOB_LAYER) layer = initial(layer) update_transform() if(!lying && lying_prev) if(client) client.move_delay = world.time + movement_delay() lying_prev = lying if(canmove && !intentionalresting && iscarbon(src) && client && client.prefs && client?.prefs?.autostand)//CIT CHANGE - adds autostanding as a preference addtimer(CALLBACK(src,PROC_REF(resist_a_rest), TRUE), 0) //CIT CHANGE - ditto return canmove /mob/living/proc/AddAbility(obj/effect/proc_holder/A) abilities.Add(A) A.on_gain(src) if(A.has_action) A.action.Grant(src) /mob/living/proc/RemoveAbility(obj/effect/proc_holder/A) abilities.Remove(A) A.on_lose(src) if(A.action) A.action.Remove(src) /mob/living/proc/add_abilities_to_panel() var/list/L = list() for(var/obj/effect/proc_holder/A in abilities) L[++L.len] = list("[A.panel]",A.get_panel_text(),A.name,"[REF(A)]") return L /mob/living/lingcheck() if(mind) var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling) if(changeling) if(changeling.changeling_speak) return LINGHIVE_LING return LINGHIVE_OUTSIDER if(mind && mind.linglink) return LINGHIVE_LINK return LINGHIVE_NONE /mob/living/forceMove(atom/destination) stop_pulling() if(buckled) buckled.unbuckle_mob(src, force = TRUE) if(has_buckled_mobs()) unbuckle_all_mobs(force = TRUE) . = ..() if(.) if(client) reset_perspective() update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall. /mob/living/proc/update_z(new_z) // 1+ to register, null to unregister if(isnull(new_z) && audiovisual_redirect) return if (registered_z != new_z) if (registered_z) SSmobs.clients_by_zlevel[registered_z] -= src if (client || audiovisual_redirect) if (new_z) SSmobs.clients_by_zlevel[new_z] += src for (var/I in length(SSidlenpcpool.idle_mobs_by_zlevel[new_z]) to 1 step -1) //Backwards loop because we're removing (guarantees optimal rather than worst-case performance), it's fine to use .len here but doesn't compile on 511 var/mob/living/simple_animal/SA = SSidlenpcpool.idle_mobs_by_zlevel[new_z][I] if (SA) SA.toggle_ai(AI_ON) // Guarantees responsiveness for when appearing right next to mobs else SSidlenpcpool.idle_mobs_by_zlevel[new_z] -= SA registered_z = new_z else registered_z = null /mob/living/onTransitZ(old_z,new_z) ..() update_z(new_z) /mob/living/MouseDrop(mob/over) . = ..() var/mob/living/user = usr if(!istype(over) || !istype(user)) return if(!over.Adjacent(src) || (user != src) || !canUseTopic(over)) return /mob/living/proc/get_static_viruses() //used when creating blood and other infective objects if(!LAZYLEN(diseases)) return var/list/datum/disease/result = list() for(var/datum/disease/D in diseases) var/static_virus = D.Copy() result += static_virus return result /mob/living/reset_perspective(atom/A) if(..()) update_sight() if(client.eye && client.eye != src) var/atom/AT = client.eye AT.get_remote_view_fullscreens(src) else clear_fullscreen("remote_view", 0) update_pipe_vision() /mob/living/update_mouse_pointer() ..() if (client && ranged_ability && ranged_ability.ranged_mousepointer) client.mouse_pointer_icon = ranged_ability.ranged_mousepointer /mob/living/vv_edit_var(var_name, var_value) switch(var_name) if ("maxHealth") if (!isnum(var_value) || var_value <= 0) return FALSE if("stat") if((stat == DEAD) && (var_value < DEAD))//Bringing the dead back to life GLOB.dead_mob_list -= src GLOB.alive_mob_list += src if((stat < DEAD) && (var_value == DEAD))//Kill he GLOB.alive_mob_list -= src GLOB.dead_mob_list += src . = ..() switch(var_name) if("knockdown") SetKnockdown(var_value) if("stun") SetStun(var_value) if("unconscious") SetUnconscious(var_value) if("sleeping") SetSleeping(var_value) if("eye_blind") set_blindness(var_value) if("eye_damage") set_eye_damage(var_value) if("eye_blurry") set_blurriness(var_value) if("maxHealth") updatehealth() if("resize") update_transform() if("lighting_alpha") sync_lighting_plane_alpha() /mob/living/proc/do_adrenaline( stamina_boost = 150, put_on_feet = TRUE, clamp_unconscious_to = 0, clamp_immobility_to = 0, reset_misc = TRUE, healing_chems = list(/datum/reagent/medicine/inaprovaline = 3, /datum/reagent/medicine/synaptizine = 10, /datum/reagent/medicine/regen_jelly = 10, /datum/reagent/medicine/stimulants = 10), message = "You feel a surge of energy!", stamina_buffer_boost = 0, //restores stamina buffer rather than just health scale_stamina_loss_recovery, //defaults to null. if this is set, restores loss * this stamina. make sure it's a fraction. stamina_loss_recovery_bypass = 0 //amount of stamina loss to ignore during calculation ) to_chat(src, message) if(AmountSleeping() > clamp_unconscious_to) SetSleeping(clamp_unconscious_to) if(AmountUnconscious() > clamp_unconscious_to) SetUnconscious(clamp_unconscious_to) if(AmountStun() > clamp_immobility_to) SetStun(clamp_immobility_to) if(AmountKnockdown() > clamp_immobility_to) SetKnockdown(clamp_immobility_to) adjustStaminaLoss(min(0, -stamina_boost)) adjustStaminaLossBuffered(min(0, -stamina_buffer_boost)) if(scale_stamina_loss_recovery) adjustStaminaLoss(min(-((getStaminaLoss() - stamina_loss_recovery_bypass) * scale_stamina_loss_recovery), 0)) if(put_on_feet) resting = FALSE lying = FALSE if(reset_misc) stuttering = 0 updatehealth() update_stamina() update_canmove() if(healing_chems) reagents.add_reagent_list(healing_chems) /mob/living/vv_get_header() . = ..() var/refid = REF(src) . += {"
[VV_HREF_TARGETREF_1V(refid, VV_HK_BASIC_EDIT, "[ckey || "no ckey"]", NAMEOF(src, ckey))] / [VV_HREF_TARGETREF_1V(refid, VV_HK_BASIC_EDIT, "[real_name || "no real name"]", NAMEOF(src, real_name))]
BRUTE:[getBruteLoss()] FIRE:[getFireLoss()] TOXIN:[getToxLoss()] OXY:[getOxyLoss()] CLONE:[getCloneLoss()] BRAIN:[getOrganLoss(ORGAN_SLOT_BRAIN)] STAMINA:[getStaminaLoss()] "}