Files
Paradise/code/modules/mob/living/carbon/carbon.dm
T

1127 lines
36 KiB
Plaintext

/mob/living
var/canEnterVentWith = "/obj/item/implant=0&/obj/item/clothing/mask/facehugger=0&/obj/item/radio/borg=0&/obj/machinery/camera=0"
var/datum/middleClickOverride/middleClickOverride = null
/mob/living/carbon/Destroy()
// This clause is here due to items falling off from limb deletion
for(var/obj/item in get_all_slots())
unEquip(item)
qdel(item)
QDEL_LIST(internal_organs)
QDEL_LIST(stomach_contents)
var/mob/living/simple_animal/borer/B = has_brain_worms()
if(B)
B.leave_host()
qdel(B)
return ..()
/mob/living/carbon/blob_act()
if(stat == DEAD)
return
else
show_message("<span class='userdanger'>The blob attacks!</span>")
adjustBruteLoss(10)
/mob/living/carbon/Move(NewLoc, direct)
. = ..()
if(.)
if(nutrition && stat != DEAD)
nutrition -= hunger_drain / 10
if(m_intent == MOVE_INTENT_RUN)
nutrition -= hunger_drain / 10
if((FAT in mutations) && m_intent == MOVE_INTENT_RUN && bodytemperature <= 360)
bodytemperature += 2
// Moving around increases germ_level faster
if(germ_level < GERM_LEVEL_MOVE_CAP && prob(8))
germ_level++
#define STOMACH_ATTACK_DELAY 4
/mob/living/carbon/var/last_stomach_attack //defining this here because no one would look in carbon_defines for it
/mob/living/carbon/relaymove(var/mob/user, direction)
if(user in src.stomach_contents)
if(last_stomach_attack + STOMACH_ATTACK_DELAY > world.time) return
last_stomach_attack = world.time
for(var/mob/M in hearers(4, src))
if(M.client)
M.show_message(text("<span class='warning'>You hear something rumbling inside [src]'s stomach...</span>"), 2)
var/obj/item/I = user.get_active_hand()
if(I && I.force)
var/d = rand(round(I.force / 4), I.force)
if(istype(src, /mob/living/carbon/human))
var/mob/living/carbon/human/H = src
var/obj/item/organ/external/organ = H.get_organ("chest")
if(istype(organ))
if(organ.receive_damage(d, 0))
H.UpdateDamageIcon()
H.updatehealth("stomach attack")
else
src.take_organ_damage(d)
for(var/mob/M in viewers(user, null))
if(M.client)
M.show_message(text("<span class='warning'><B>[user] attacks [src]'s stomach wall with the [I.name]!</span>"), 2)
playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1)
if(prob(src.getBruteLoss() - 50))
for(var/atom/movable/A in stomach_contents)
A.loc = loc
stomach_contents.Remove(A)
src.gib()
#undef STOMACH_ATTACK_DELAY
/mob/living/carbon/proc/has_mutated_organs()
return FALSE
/mob/living/carbon/proc/vomit(var/lost_nutrition = 10, var/blood = 0, var/stun = 1, var/distance = 0, var/message = 1)
if(src.is_muzzled())
if(message)
to_chat(src, "<span class='warning'>The muzzle prevents you from vomiting!</span>")
return 0
if(stun)
Stun(4)
if(nutrition < 100 && !blood)
if(message)
visible_message("<span class='warning'>[src] dry heaves!</span>", \
"<span class='userdanger'>You try to throw up, but there's nothing your stomach!</span>")
if(stun)
Weaken(10)
else
if(message)
visible_message("<span class='danger'>[src] throws up!</span>", \
"<span class='userdanger'>You throw up!</span>")
playsound(get_turf(src), 'sound/effects/splat.ogg', 50, 1)
var/turf/T = get_turf(src)
for(var/i=0 to distance)
if(blood)
if(T)
add_splatter_floor(T)
if(stun)
adjustBruteLoss(3)
else
if(T)
T.add_vomit_floor(src)
nutrition -= lost_nutrition
if(stun)
adjustToxLoss(-3)
T = get_step(T, dir)
if(is_blocked_turf(T))
break
return 1
/mob/living/carbon/gib()
. = death(1)
if(!.)
return
for(var/obj/item/organ/internal/I in internal_organs)
if(isturf(loc))
I.remove(src)
I.forceMove(get_turf(src))
I.throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5)
for(var/mob/M in src)
if(M in src.stomach_contents)
src.stomach_contents.Remove(M)
M.forceMove(get_turf(src))
visible_message("<span class='danger'>[M] bursts out of [src]!</span>")
/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, override = 0, tesla_shock = 0)
if(status_flags & GODMODE) //godmode
return 0
if(NO_SHOCK in mutations) //shockproof
return 0
if(tesla_shock && tesla_ignore)
return FALSE
shock_damage *= siemens_coeff
if(shock_damage<1 && !override)
return 0
if(reagents.has_reagent("teslium"))
shock_damage *= 1.5 //If the mob has teslium in their body, shocks are 50% more damaging!
take_overall_damage(0,shock_damage, TRUE, used_weapon = "Electrocution")
shock_internal_organs(shock_damage)
visible_message(
"<span class='danger'>[src] was shocked by \the [source]!</span>", \
"<span class='userdanger'>You feel a powerful shock coursing through your body!</span>", \
"<span class='italics'>You hear a heavy electrical crack.</span>" \
)
AdjustJitter(1000) //High numbers for violent convulsions
do_jitter_animation(jitteriness)
AdjustStuttering(2)
if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5))
Stun(2)
spawn(20)
AdjustJitter(-1000, bound_lower = 10) //Still jittery, but vastly less
if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5))
Stun(3)
Weaken(3)
if(shock_damage > 200)
src.visible_message(
"<span class='danger'>[src] was arc flashed by the [source]!</span>", \
"<span class='userdanger'>The [source] arc flashes and electrocutes you!</span>", \
"<span class='italics'>You hear a lightning-like crack!</span>" \
)
playsound(loc, 'sound/effects/eleczap.ogg', 50, 1, -1)
explosion(src.loc,-1,0,2,2)
if(override)
return override
else
return shock_damage
/mob/living/carbon/swap_hand()
var/obj/item/item_in_hand = src.get_active_hand()
if(item_in_hand) //this segment checks if the item in your hand is twohanded.
if(istype(item_in_hand,/obj/item/twohanded))
if(item_in_hand:wielded == 1)
to_chat(usr, "<span class='warning'>Your other hand is too busy holding the [item_in_hand.name]</span>")
return
src.hand = !( src.hand )
if(hud_used && hud_used.inv_slots[slot_l_hand] && hud_used.inv_slots[slot_r_hand])
var/obj/screen/inventory/hand/H
H = hud_used.inv_slots[slot_l_hand]
H.update_icon()
H = hud_used.inv_slots[slot_r_hand]
H.update_icon()
/mob/living/carbon/activate_hand(var/selhand) //0 or "r" or "right" for right hand; 1 or "l" or "left" for left hand.
if(istext(selhand))
selhand = lowertext(selhand)
if(selhand == "right" || selhand == "r")
selhand = 0
if(selhand == "left" || selhand == "l")
selhand = 1
if(selhand != src.hand)
swap_hand()
/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M)
add_attack_logs(M, src, "Shaked", ATKLOG_ALL)
if(health >= config.health_threshold_crit)
if(src == M && ishuman(src))
var/mob/living/carbon/human/H = src
visible_message( \
text("<span class='notice'>[src] examines [].</span>",gender==MALE?"himself":"herself"), \
"<span class='notice'>You check yourself for injuries.</span>" \
)
var/list/missing = list("head", "chest", "groin", "l_arm", "r_arm", "l_hand", "r_hand", "l_leg", "r_leg", "l_foot", "r_foot")
for(var/X in H.bodyparts)
var/obj/item/organ/external/LB = X
missing -= LB.limb_name
var/status = ""
var/brutedamage = LB.brute_dam
var/burndamage = LB.burn_dam
if(brutedamage > 0)
status = "bruised"
if(brutedamage > 20)
status = "battered"
if(brutedamage > 40)
status = "mangled"
if(brutedamage > 0 && burndamage > 0)
status += " and "
if(burndamage > 40)
status += "peeling away"
else if(burndamage > 10)
status += "blistered"
else if(burndamage > 0)
status += "numb"
if(LB.status & ORGAN_MUTATED)
status = "weirdly shapen."
if(status == "")
status = "OK"
to_chat(src, "\t <span class='[status == "OK" ? "notice" : "warning"]'>Your [LB.name] is [status].</span>")
for(var/obj/item/I in LB.embedded_objects)
to_chat(src, "\t <a href='byond://?src=[UID()];embedded_object=[I.UID()];embedded_limb=[LB.UID()]' class='warning'>There is \a [I] embedded in your [LB.name]!</a>")
for(var/t in missing)
to_chat(src, "<span class='boldannounce'>Your [parse_zone(t)] is missing!</span>")
if(H.bleed_rate)
to_chat(src, "<span class='danger'>You are bleeding!</span>")
if(staminaloss)
if(staminaloss > 30)
to_chat(src, "<span class='info'>You're completely exhausted.</span>")
else
to_chat(src, "<span class='info'>You feel fatigued.</span>")
if((SKELETON in H.mutations) && (!H.w_uniform) && (!H.wear_suit))
H.play_xylophone()
else
if(player_logged)
M.visible_message("<span class='notice'>[M] shakes [src], but [p_they()] [p_do()] not respond. Probably suffering from SSD.", \
"<span class='notice'>You shake [src], but [p_theyre()] unresponsive. Probably suffering from SSD.</span>")
if(lying) // /vg/: For hugs. This is how update_icon figgers it out, anyway. - N3X15
if(ishuman(src))
var/mob/living/carbon/human/H = src
if(H.w_uniform)
H.w_uniform.add_fingerprint(M)
AdjustSleeping(-5)
if(sleeping == 0)
StopResting()
AdjustParalysis(-3)
AdjustStunned(-3)
AdjustWeakened(-3)
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if(!player_logged)
M.visible_message( \
"<span class='notice'>[M] shakes [src] trying to wake [p_them()] up!</span>",\
"<span class='notice'>You shake [src] trying to wake [p_them()] up!</span>",\
)
// BEGIN HUGCODE - N3X
else
playsound(get_turf(src), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if(M.zone_sel.selecting == "head")
M.visible_message(\
"<span class='notice'>[M] pats [src] on the head.</span>",\
"<span class='notice'>You pat [src] on the head.</span>",\
)
else
M.visible_message(\
"<span class='notice'>[M] gives [src] a [pick("hug","warm embrace")].</span>",\
"<span class='notice'>You hug [src].</span>",\
)
if(ishuman(src))
var/mob/living/carbon/human/H = src
if(H.wear_suit)
H.wear_suit.add_fingerprint(M)
else if(H.w_uniform)
H.w_uniform.add_fingerprint(M)
/mob/living/carbon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
. = ..()
var/damage = intensity - check_eye_prot()
var/extra_damage = 0
if(.)
if(visual)
return
if(weakeyes)
Stun(2)
var/obj/item/organ/internal/eyes/E = get_int_organ(/obj/item/organ/internal/eyes)
if(!E || (E && E.weld_proof))
return
var/extra_darkview = 0
if(E.dark_view)
extra_darkview = max(E.dark_view - 2, 0)
extra_damage = extra_darkview
var/light_amount = 10 // assume full brightness
if(isturf(src.loc))
var/turf/T = src.loc
light_amount = round(T.get_lumcount() * 10)
// a dark view of 8, in full darkness, will result in maximum 1st tier damage
var/extra_prob = (10 - light_amount) * extra_darkview
switch(damage)
if(1)
to_chat(src, "<span class='warning'>Your eyes sting a little.</span>")
var/minor_damage_multiplier = min(40 + extra_prob, 100) / 100
var/minor_damage = minor_damage_multiplier * (1 + extra_damage)
E.receive_damage(minor_damage, 1)
if(2)
to_chat(src, "<span class='warning'>Your eyes burn.</span>")
E.receive_damage(rand(2, 4) + extra_damage, 1)
else
to_chat(src, "Your eyes itch and burn severely!</span>")
E.receive_damage(rand(12, 16) + extra_damage, 1)
if(E.damage > E.min_bruised_damage)
AdjustEyeBlind(damage)
AdjustEyeBlurry(damage * rand(3, 6))
if(E.damage > (E.min_bruised_damage + E.min_broken_damage) / 2)
if(!E.is_robotic())
to_chat(src, "<span class='warning'>Your eyes start to burn badly!</span>")
else //snowflake conditions piss me off for the record
to_chat(src, "<span class='warning'>The flash blinds you!</span>")
else if(E.damage >= E.min_broken_damage)
to_chat(src, "<span class='warning'>You can't see anything!</span>")
else
to_chat(src, "<span class='warning'>Your eyes are really starting to hurt. This can't be good for you!</span>")
if(mind && has_bane(BANE_LIGHT))
mind.disrupt_spells(-500)
return 1
else if(damage == 0) // just enough protection
if(prob(20))
to_chat(src, "<span class='notice'>Something bright flashes in the corner of your vision!</span>")
if(mind && has_bane(BANE_LIGHT))
mind.disrupt_spells(0)
/mob/living/carbon/proc/tintcheck()
return 0
/mob/living/carbon/proc/getDNA()
return dna
/mob/living/carbon/proc/setDNA(var/datum/dna/newDNA)
dna = newDNA
var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, /obj/machinery/atmospherics/unary/vent_scrubber)
/mob/living/handle_ventcrawl(var/atom/clicked_on) // -- TLE -- Merged by Carn
if(!Adjacent(clicked_on))
return
var/ventcrawlerlocal = 0
if(ventcrawler)
ventcrawlerlocal = ventcrawler
if(!ventcrawler)
if(ishuman(src))
var/mob/living/carbon/human/H = src
ventcrawlerlocal = H.dna.species.ventcrawler
if(!ventcrawlerlocal) return
if(stat)
to_chat(src, "You must be conscious to do this!")
return
if(lying)
to_chat(src, "You can't vent crawl while you're stunned!")
return
if(buckled_mob)
to_chat(src, "You can't vent crawl with [buckled_mob] on you!")
return
if(ishuman(src))
var/mob/living/carbon/human/H = src
if(H.w_uniform && istype(H.w_uniform, /obj/item/clothing/under/contortionist))//IMMA SPCHUL SNOWFLAKE
var/obj/item/clothing/under/contortionist/C = H.w_uniform
if(!C.check_clothing(src))//return values confuse me right now
return
var/obj/machinery/atmospherics/unary/vent_found
if(clicked_on)
vent_found = clicked_on
if(!istype(vent_found) || !vent_found.can_crawl_through())
vent_found = null
if(!vent_found)
for(var/obj/machinery/atmospherics/machine in range(1,src))
if(is_type_in_list(machine, ventcrawl_machinery))
vent_found = machine
if(!vent_found.can_crawl_through())
vent_found = null
if(vent_found)
break
if(vent_found)
if(vent_found.parent && (vent_found.parent.members.len || vent_found.parent.other_atmosmch))
visible_message("<span class='notice'>[src] begins climbing into the ventilation system...</span>", \
"<span class='notice'>You begin climbing into the ventilation system...</span>")
if(!do_after(src, 45, target = src))
return
if(buckled)
to_chat(src, "<span class='warning'>You cannot crawl into a vent while buckled to something!</span>")
return
if(!client)
return
if(iscarbon(src) && contents.len && ventcrawlerlocal < 2)//It must have atleast been 1 to get this far
for(var/obj/item/I in contents)
var/failed = 0
if(istype(I, /obj/item/implant))
continue
if(istype(I, /obj/item/organ))
continue
if(I.flags & ABSTRACT)
continue
else
failed++
if(failed)
to_chat(src, "<span class='warning'>You can't crawl around in the ventilation ducts with items!</span>")
return
visible_message("<b>[src] scrambles into the ventilation ducts!</b>", "You climb into the ventilation system.")
src.loc = vent_found
add_ventcrawl(vent_found)
else
to_chat(src, "<span class='warning'>This ventilation duct is not connected to anything!</span>")
/mob/living/proc/add_ventcrawl(obj/machinery/atmospherics/starting_machine)
if(!istype(starting_machine) || !starting_machine.returnPipenet())
return
var/datum/pipeline/pipeline = starting_machine.returnPipenet()
var/list/totalMembers = list()
totalMembers |= pipeline.members
totalMembers |= pipeline.other_atmosmch
for(var/obj/machinery/atmospherics/A in totalMembers)
if(!A.pipe_image)
A.update_pipe_image()
pipes_shown += A.pipe_image
client.images += A.pipe_image
/mob/living/proc/remove_ventcrawl()
if(client)
for(var/image/current_image in pipes_shown)
client.images -= current_image
client.eye = src
pipes_shown.len = 0
//OOP
/atom/proc/update_pipe_vision()
return
/mob/living/update_pipe_vision()
if(pipes_shown.len)
if(!istype(loc, /obj/machinery/atmospherics))
remove_ventcrawl()
else
if(istype(loc, /obj/machinery/atmospherics))
add_ventcrawl(loc)
//Throwing stuff
/mob/living/carbon/throw_impact(atom/hit_atom, throwingdatum)
. = ..()
var/hurt = TRUE
/*if(istype(throwingdatum, /datum/thrownthing))
var/datum/thrownthing/D = throwingdatum
if(isrobot(D.thrower))
var/mob/living/silicon/robot/R = D.thrower
if(!R.emagged)
hurt = FALSE*/
if(hit_atom.density && isturf(hit_atom))
if(hurt)
Weaken(1)
take_organ_damage(10)
if(iscarbon(hit_atom) && hit_atom != src)
var/mob/living/carbon/victim = hit_atom
if(hurt)
victim.take_organ_damage(10)
take_organ_damage(10)
victim.Weaken(1)
Weaken(1)
visible_message("<span class='danger'>[src] crashes into [victim], knocking them both over!</span>", "<span class='userdanger'>You violently crash into [victim]!</span>")
playsound(src, 'sound/weapons/punch1.ogg', 50, 1)
/mob/living/carbon/proc/toggle_throw_mode()
if(in_throw_mode)
throw_mode_off()
else
throw_mode_on()
/mob/living/carbon/proc/throw_mode_off()
src.in_throw_mode = 0
if(src.throw_icon) //in case we don't have the HUD and we use the hotkey
src.throw_icon.icon_state = "act_throw_off"
/mob/living/carbon/proc/throw_mode_on()
src.in_throw_mode = 1
if(src.throw_icon)
src.throw_icon.icon_state = "act_throw_on"
/mob/proc/throw_item(atom/target)
return
/mob/living/carbon/throw_item(atom/target)
if(!target || !isturf(loc) || istype(target, /obj/screen))
throw_mode_off()
return
var/obj/item/I = src.get_active_hand()
if(!I || I.override_throw(src, target) || (I.flags & NODROP))
throw_mode_off()
return
throw_mode_off()
var/atom/movable/thrown_thing
if(istype(I, /obj/item/grab))
var/obj/item/grab/G = I
var/mob/throwable_mob = G.get_mob_if_throwable() //throw the person instead of the grab
qdel(G) //We delete the grab.
if(throwable_mob)
thrown_thing = throwable_mob
var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
var/turf/end_T = get_turf(target)
throwable_mob.forceMove(start_T)
if(start_T && end_T)
var/start_T_descriptor = "<font color='#6b5d00'>tile at [start_T.x], [start_T.y], [start_T.z] in area [get_area(start_T)]</font>"
var/end_T_descriptor = "<font color='#6b4400'>tile at [end_T.x], [end_T.y], [end_T.z] in area [get_area(end_T)]</font>"
add_attack_logs(src, throwable_mob, "Thrown from [start_T_descriptor] with the target [end_T_descriptor]")
else if(!(I.flags & ABSTRACT)) //can't throw abstract items
thrown_thing = I
unEquip(I)
if(thrown_thing)
visible_message("<span class='danger'>[src] has thrown [thrown_thing].</span>")
newtonian_move(get_dir(target, src))
thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src, null, null, null, move_force)
/mob/living/carbon/can_use_hands()
if(handcuffed)
return FALSE
if(buckled && ! istype(buckled, /obj/structure/chair)) // buckling does not restrict hands
return FALSE
return TRUE
/mob/living/carbon/restrained()
if(handcuffed)
return TRUE
return
/mob/living/carbon/unEquip(obj/item/I) //THIS PROC DID NOT CALL ..()
. = ..() //Sets the default return value to what the parent returns.
if(!. || !I) //We don't want to set anything to null if the parent returned 0.
return
if(I == back)
back = null
update_inv_back()
else if(I == wear_mask)
if(istype(src, /mob/living/carbon/human)) //If we don't do this hair won't be properly rebuilt.
return
wear_mask = null
update_inv_wear_mask()
else if(I == handcuffed)
handcuffed = null
if(buckled && buckled.buckle_requires_restraints)
buckled.unbuckle_mob()
update_handcuffed()
else if(I == legcuffed)
legcuffed = null
update_inv_legcuffed()
/mob/living/carbon/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_l_hand]'>[(l_hand && !(l_hand.flags&ABSTRACT)) ? l_hand : "<font color=grey>Empty</font>"]</A></td></tr>
<tr><td><B>Right Hand:</B></td><td><A href='?src=[UID()];item=[slot_r_hand]'>[(r_hand && !(r_hand.flags&ABSTRACT)) ? r_hand : "<font color=grey>Empty</font>"]</A></td></tr>
<tr><td>&nbsp;</td></tr>"}
dat += "<tr><td><B>Back:</B></td><td><A href='?src=[UID()];item=[slot_back]'>[(back && !(back.flags&ABSTRACT)) ? back : "<font color=grey>Empty</font>"]</A>"
if(istype(wear_mask, /obj/item/clothing/mask) && istype(back, /obj/item/tank))
dat += "&nbsp;<A href='?src=[UID()];internal=[slot_back]'>[internal ? "Disable Internals" : "Set Internals"]</A>"
dat += "</td></tr><tr><td>&nbsp;</td></tr>"
dat += "<tr><td><B>Head:</B></td><td><A href='?src=[UID()];item=[slot_head]'>[(head && !(head.flags&ABSTRACT)) ? head : "<font color=grey>Empty</font>"]</A></td></tr>"
dat += "<tr><td><B>Mask:</B></td><td><A href='?src=[UID()];item=[slot_wear_mask]'>[(wear_mask && !(wear_mask.flags&ABSTRACT)) ? wear_mask : "<font color=grey>Empty</font>"]</A></td></tr>"
if(istype(wear_mask, /obj/item/clothing/mask/muzzle))
var/obj/item/clothing/mask/muzzle/M = wear_mask
if(M.security_lock)
dat += "&nbsp;<A href='?src=[M.UID()];locked=\ref[src]'>[M.locked ? "Disable Lock" : "Set Lock"]</A>"
dat += "</td></tr><tr><td>&nbsp;</td></tr>"
if(handcuffed)
dat += "<tr><td><B>Handcuffed:</B> <A href='?src=[UID()];item=[slot_handcuffed]'>Remove</A></td></tr>"
if(legcuffed)
dat += "<tr><td><A href='?src=[UID()];item=[slot_legcuffed]'>Legcuffed</A></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, 500)
popup.set_content(dat)
popup.open()
/mob/living/carbon/Topic(href, href_list)
..()
//strip panel
if(!usr.stat && usr.canmove && !usr.restrained() && in_range(src, usr))
if(href_list["internal"])
var/slot = text2num(href_list["internal"])
var/obj/item/ITEM = get_item_by_slot(slot)
if(ITEM && istype(ITEM, /obj/item/tank))
visible_message("<span class='danger'>[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM].</span>", \
"<span class='userdanger'>[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM].</span>")
var/no_mask
if(!get_organ_slot("breathing_tube"))
if(!(wear_mask && wear_mask.flags & AIRTIGHT))
if(!(head && head.flags & AIRTIGHT))
no_mask = 1
if(no_mask)
to_chat(usr, "<span class='warning'>[src] is not wearing a suitable mask or helmet!</span>")
return
if(do_mob(usr, src, POCKET_STRIP_DELAY))
if(internal)
internal = null
update_action_buttons_icon()
else
var/no_mask2
if(!get_organ_slot("breathing_tube"))
if(!(wear_mask && wear_mask.flags & AIRTIGHT))
if(!(head && head.flags & AIRTIGHT))
no_mask2 = 1
if(no_mask2)
to_chat(usr, "<span class='warning'>[src] is not wearing a suitable mask or helmet!</span>")
return
internal = ITEM
update_action_buttons_icon()
visible_message("<span class='danger'>[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM].</span>", \
"<span class='userdanger'>[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM].</span>")
/mob/living/carbon/get_item_by_slot(slot_id)
switch(slot_id)
if(slot_back)
return back
if(slot_wear_mask)
return wear_mask
if(slot_handcuffed)
return handcuffed
if(slot_legcuffed)
return legcuffed
if(slot_l_hand)
return l_hand
if(slot_r_hand)
return r_hand
return null
//generates realistic-ish pulse output based on preset levels
/mob/living/carbon/proc/get_pulse(var/method) //method 0 is for hands, 1 is for machines, more accurate
var/temp = 0 //see setup.dm:694
switch(src.pulse)
if(PULSE_NONE)
return "0"
if(PULSE_SLOW)
temp = rand(40, 60)
return num2text(method ? temp : temp + rand(-10, 10))
if(PULSE_NORM)
temp = rand(60, 90)
return num2text(method ? temp : temp + rand(-10, 10))
if(PULSE_FAST)
temp = rand(90, 120)
return num2text(method ? temp : temp + rand(-10, 10))
if(PULSE_2FAST)
temp = rand(120, 160)
return num2text(method ? temp : temp + rand(-10, 10))
if(PULSE_THREADY)
return method ? ">250" : "extremely weak and fast, patient's artery feels like a thread"
// output for machines^ ^^^^^^^output for people^^^^^^^^^
/mob/living/carbon/proc/canBeHandcuffed()
return 0
/mob/living/carbon/fall(forced)
loc.handle_fall(src, forced)//it's loc so it doesn't call the mob's handle_fall which does nothing
/mob/living/carbon/is_muzzled()
return(istype(src.wear_mask, /obj/item/clothing/mask/muzzle))
/mob/living/carbon/resist_buckle()
spawn(0)
resist_muzzle()
if(restrained())
changeNext_move(CLICK_CD_BREAKOUT)
last_special = world.time + CLICK_CD_BREAKOUT
visible_message("<span class='warning'>[src] attempts to unbuckle [p_them()]self!</span>", \
"<span class='notice'>You attempt to unbuckle yourself... (This will take around one minute and you need to stay still.)</span>")
if(do_after(src, 600, 0, target = src))
if(!buckled)
return
buckled.user_unbuckle_mob(src,src)
else
if(src && buckled)
to_chat(src, "<span class='warning'>You fail to unbuckle yourself!</span>")
else
buckled.user_unbuckle_mob(src,src)
/mob/living/carbon/resist_fire()
fire_stacks -= 5
Weaken(3, 1, 1) //We dont check for CANWEAKEN, I don't care how immune to weakening you are, if you're rolling on the ground, you're busy.
update_canmove()
spin(32,2)
visible_message("<span class='danger'>[src] rolls on the floor, trying to put [p_them()]self out!</span>", \
"<span class='notice'>You stop, drop, and roll!</span>")
sleep(30)
if(fire_stacks <= 0)
visible_message("<span class='danger'>[src] has successfully extinguished [p_them()]self!</span>", \
"<span class='notice'>You extinguish yourself.</span>")
ExtinguishMob()
/mob/living/carbon/resist_restraints()
spawn(0)
resist_muzzle()
var/obj/item/I = null
if(handcuffed)
I = handcuffed
else if(legcuffed)
I = legcuffed
if(I)
changeNext_move(CLICK_CD_BREAKOUT)
last_special = world.time + CLICK_CD_BREAKOUT
cuff_resist(I)
/mob/living/carbon/resist_muzzle()
if(!istype(wear_mask, /obj/item/clothing/mask/muzzle))
return
var/obj/item/clothing/mask/muzzle/I = wear_mask
var/time = I.resist_time
if(I.resist_time == 0)//if it's 0, you can't get out of it
to_chat(src, "[I] is too well made, you'll need hands for this one!")
else
visible_message("<span class='warning'>[src] gnaws on [I], trying to remove it!</span>")
to_chat(src, "<span class='notice'>You attempt to remove [I]... (This will take around [time/10] seconds and you need to stand still.)</span>")
if(do_after(src, time, 0, target = src))
visible_message("<span class='warning'>[src] removes [I]!</span>")
to_chat(src, "<span class='notice'>You get rid of [I]!</span>")
if(I.security_lock)
I.do_break()
unEquip(I)
/mob/living/carbon/proc/cuff_resist(obj/item/I, breakouttime = 600, cuff_break = 0)
breakouttime = I.breakouttime
var/displaytime = breakouttime / 600
if(!cuff_break)
visible_message("<span class='warning'>[src] attempts to remove [I]!</span>")
to_chat(src, "<span class='notice'>You attempt to remove [I]... (This will take around [displaytime] minutes and you need to stand still.)</span>")
if(do_after(src, breakouttime, 0, target = src))
if(I.loc != src || buckled)
return
visible_message("<span class='danger'>[src] manages to remove [I]!</span>")
to_chat(src, "<span class='notice'>You successfully remove [I].</span>")
if(I == handcuffed)
handcuffed.loc = loc
handcuffed.dropped(src)
handcuffed = null
if(buckled && buckled.buckle_requires_restraints)
buckled.unbuckle_mob(src)
update_handcuffed()
return
if(I == legcuffed)
legcuffed.loc = loc
legcuffed.dropped()
legcuffed = null
update_inv_legcuffed()
return
else
unEquip(I)
I.dropped()
return
return 1
else
to_chat(src, "<span class='warning'>You fail to remove [I]!</span>")
else
breakouttime = 50
visible_message("<span class='warning'>[src] is trying to break [I]!</span>")
to_chat(src, "<span class='notice'>You attempt to break [I]... (This will take around 5 seconds and you need to stand still.)</span>")
if(do_after(src, breakouttime, 0, target = src))
if(!I.loc || buckled)
return
visible_message("<span class='danger'>[src] manages to break [I]!</span>")
to_chat(src, "<span class='notice'>You successfully break [I].</span>")
qdel(I)
if(I == handcuffed)
handcuffed = null
update_handcuffed()
return
else if(I == legcuffed)
legcuffed = null
update_inv_legcuffed()
return
return 1
else
to_chat(src, "<span class='warning'>You fail to break [I]!</span>")
//called when we get cuffed/uncuffed
/mob/living/carbon/proc/update_handcuffed()
if(handcuffed)
//we don't want problems with nodrop shit if there ever is more than one nodrop twohanded
var/obj/item/I = get_active_hand()
if(istype(I, /obj/item/twohanded))
var/obj/item/twohanded/TH = I //FML
if(TH.wielded)
TH.unwield()
drop_r_hand()
drop_l_hand()
stop_pulling()
throw_alert("handcuffed", /obj/screen/alert/restrained/handcuffed, new_master = src.handcuffed)
else
clear_alert("handcuffed")
update_action_buttons_icon() //some of our action buttons might be unusable when we're handcuffed.
update_inv_handcuffed()
update_hud_handcuffed()
/mob/living/carbon/get_standard_pixel_y_offset(lying = 0)
if(lying)
if(buckled)
return buckled.buckle_offset //tg just has this whole block removed, always returning -6. Paradise is special.
else
return -6
else
return initial(pixel_y)
/mob/living/carbon/emp_act(severity)
for(var/obj/item/organ/internal/O in internal_organs)
O.emp_act(severity)
..()
/mob/living/carbon/Stat()
..()
if(statpanel("Status"))
var/obj/item/organ/internal/xenos/plasmavessel/vessel = get_int_organ(/obj/item/organ/internal/xenos/plasmavessel)
if(vessel)
stat(null, "Plasma Stored: [vessel.stored_plasma]/[vessel.max_plasma]")
/mob/living/carbon/get_all_slots()
return list(l_hand,
r_hand,
handcuffed,
legcuffed,
back,
wear_mask)
/mob/living/carbon/proc/uncuff()
if(handcuffed)
var/obj/item/W = handcuffed
handcuffed = null
if(buckled && buckled.buckle_requires_restraints)
buckled.unbuckle_mob()
update_handcuffed()
if(client)
client.screen -= W
if(W)
W.loc = loc
W.dropped(src)
if(W)
W.layer = initial(W.layer)
W.plane = initial(W.plane)
if(legcuffed)
var/obj/item/W = legcuffed
legcuffed = null
update_inv_legcuffed()
if(client)
client.screen -= W
if(W)
W.loc = loc
W.dropped(src)
if(W)
W.layer = initial(W.layer)
W.plane = initial(W.plane)
/mob/living/carbon/proc/slip(description, stun, weaken, tilesSlipped, walkSafely, slipAny, slipVerb = "slip")
if(flying || buckled || (walkSafely && m_intent == MOVE_INTENT_WALK))
return 0
if((lying) && (!(tilesSlipped)))
return 0
if(!(slipAny))
if(istype(src, /mob/living/carbon/human))
var/mob/living/carbon/human/H = src
if(isobj(H.shoes) && H.shoes.flags & NOSLIP)
return 0
if(tilesSlipped)
for(var/t = 0, t<=tilesSlipped, t++)
spawn (t) step(src, src.dir)
stop_pulling()
to_chat(src, "<span class='notice'>You [slipVerb]ped on [description]!</span>")
playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3)
// Something something don't run with scissors
Stun(stun)
Weaken(weaken)
return 1
/mob/living/carbon/proc/can_eat(flags = 255)
return 1
/mob/living/carbon/proc/eat(var/obj/item/reagent_containers/food/toEat, mob/user, var/bitesize_override)
if(!istype(toEat))
return 0
var/fullness = nutrition + 10
if(istype(toEat, /obj/item/reagent_containers/food/snacks))
for(var/datum/reagent/consumable/C in reagents.reagent_list) //we add the nutrition value of what we're currently digesting
fullness += C.nutriment_factor * C.volume / (C.metabolization_rate * metabolism_efficiency * digestion_ratio)
if(user == src)
if(istype(toEat, /obj/item/reagent_containers/food/drinks))
if(!selfDrink(toEat))
return 0
else
if(!selfFeed(toEat, fullness))
return 0
else
if(!forceFed(toEat, user, fullness))
return 0
consume(toEat, bitesize_override, taste = toEat.taste)
score_foodeaten++
return 1
/mob/living/carbon/proc/selfFeed(var/obj/item/reagent_containers/food/toEat, fullness)
if(ispill(toEat))
to_chat(src, "<span class='notify'>You [toEat.apply_method] [toEat].</span>")
else
if(toEat.junkiness && satiety < -150 && nutrition > NUTRITION_LEVEL_STARVING + 50 )
to_chat(src, "<span class='notice'>You don't feel like eating any more junk food at the moment.</span>")
return 0
if(fullness <= 50)
to_chat(src, "<span class='warning'>You hungrily chew out a piece of [toEat] and gobble it!</span>")
else if(fullness > 50 && fullness < 150)
to_chat(src, "<span class='notice'>You hungrily begin to eat [toEat].</span>")
else if(fullness > 150 && fullness < 500)
to_chat(src, "<span class='notice'>You take a bite of [toEat].</span>")
else if(fullness > 500 && fullness < 600)
to_chat(src, "<span class='notice'>You unwillingly chew a bit of [toEat].</span>")
else if(fullness > (600 * (1 + overeatduration / 2000))) // The more you eat - the more you can eat
to_chat(src, "<span class='warning'>You cannot force any more of [toEat] to go down your throat.</span>")
return 0
return 1
/mob/living/carbon/proc/selfDrink(var/obj/item/reagent_containers/food/drinks/toDrink, mob/user)
return 1
/mob/living/carbon/proc/forceFed(var/obj/item/reagent_containers/food/toEat, mob/user, fullness)
if(ispill(toEat) || fullness <= (600 * (1 + overeatduration / 1000)))
if(!toEat.instant_application)
visible_message("<span class='warning'>[user] attempts to force [src] to [toEat.apply_method] [toEat].</span>")
else
visible_message("<span class='warning'>[user] cannot force anymore of [toEat] down [src]'s throat.</span>")
return 0
if(!toEat.instant_application)
if(!do_mob(user, src))
return 0
forceFedAttackLog(toEat, user)
visible_message("<span class='warning'>[user] forces [src] to [toEat.apply_method] [toEat].</span>")
return 1
/mob/living/carbon/proc/forceFedAttackLog(var/obj/item/reagent_containers/food/toEat, mob/user)
add_attack_logs(user, src, "Fed [toEat]. Reagents: [toEat.reagents.log_list(toEat)]", ATKLOG_MOST)
if(!iscarbon(user))
LAssailant = null
else
LAssailant = user
/*TO DO - If/when stomach organs are introduced, override this at the human level sending the item to the stomach
so that different stomachs can handle things in different ways VB*/
/mob/living/carbon/proc/consume(var/obj/item/reagent_containers/food/toEat, var/bitesize_override, var/taste = TRUE)
var/this_bite = bitesize_override ? bitesize_override : toEat.bitesize
if(!toEat.reagents)
return
if(satiety > -200)
satiety -= toEat.junkiness
if(toEat.consume_sound)
playsound(loc, toEat.consume_sound, rand(10,50), 1)
if(toEat.reagents.total_volume)
if(taste)
taste_reagents(toEat.reagents)
var/fraction = min(this_bite/toEat.reagents.total_volume, 1)
toEat.reagents.reaction(src, toEat.apply_type, fraction)
toEat.reagents.trans_to(src, this_bite*toEat.transfer_efficiency)
/mob/living/carbon/get_access()
. = ..()
var/obj/item/RH = get_active_hand()
if(RH)
. |= RH.GetAccess()
var/obj/item/LH = get_inactive_hand()
if(LH)
. |= LH.GetAccess()
/mob/living/carbon/proc/can_breathe_gas()
if(!wear_mask)
return TRUE
if(!(wear_mask.flags & BLOCK_GAS_SMOKE_EFFECT) && internal == null)
return TRUE
return FALSE
//to recalculate and update the mob's total tint from tinted equipment it's wearing.
/mob/living/carbon/proc/update_tint()
if(!tinted_weldhelh)
return
var/tinttotal = get_total_tint()
if(tinttotal >= TINT_BLIND)
overlay_fullscreen("tint", /obj/screen/fullscreen/blind)
else if(tinttotal >= TINT_IMPAIR)
overlay_fullscreen("tint", /obj/screen/fullscreen/impaired, 2)
else
clear_fullscreen("tint", 0)
/mob/living/carbon/proc/get_total_tint()
. = 0
if(istype(head, /obj/item/clothing/head))
var/obj/item/clothing/head/HT = head
. += HT.tint
if(wear_mask)
. += wear_mask.tint
/mob/living/carbon/human/get_total_tint()
. = ..()
if(glasses)
var/obj/item/clothing/glasses/G = glasses
. += G.tint
//handle stuff to update when a mob equips/unequips a mask.
/mob/living/proc/wear_mask_update(obj/item/clothing/C, toggle_off = 1)
update_inv_wear_mask()
/mob/living/carbon/wear_mask_update(obj/item/clothing/C, toggle_off = 1)
if(C.tint || initial(C.tint))
update_tint()
update_inv_wear_mask()
//handle stuff to update when a mob equips/unequips a headgear.
/mob/living/carbon/proc/head_update(obj/item/I, forced)
if(istype(I, /obj/item/clothing))
var/obj/item/clothing/C = I
if(C.tint || initial(C.tint))
update_tint()
if(I.flags_inv & HIDEMASK || forced)
update_inv_wear_mask()
update_inv_head()
/mob/living/carbon/proc/shock_internal_organs(intensity)
for(var/obj/item/organ/O in internal_organs)
O.shock_organ(intensity)