diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index ef20b6e35e..7c57de74a4 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -515,10 +515,10 @@
step(src, AM.dir)
..()
-/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback)
- return throw_at(target, range, speed, thrower, spin, diagonals_first, callback)
+/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback, messy_throw = TRUE)
+ return throw_at(target, range, speed, thrower, spin, diagonals_first, callback, messy_throw)
-/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback) //If this returns FALSE then callback will not be called.
+/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback, messy_throw = TRUE) //If this returns FALSE then callback will not be called.
. = FALSE
if (!target || speed <= 0)
return
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index c5d198c05f..a410827347 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -578,21 +578,22 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
itempush = 0 //too light to push anything
return A.hitby(src, 0, itempush)
-/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
+/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, messy_throw = TRUE)
thrownby = thrower
- callback = CALLBACK(src, .proc/after_throw, callback) //replace their callback with our own
+ callback = CALLBACK(src, .proc/after_throw, callback, (spin && messy_throw)) //replace their callback with our own
. = ..(target, range, speed, thrower, spin, diagonals_first, callback)
-/obj/item/proc/after_throw(datum/callback/callback)
+/obj/item/proc/after_throw(datum/callback/callback, messy_throw)
if (callback) //call the original callback
. = callback.Invoke()
throw_speed = initial(throw_speed) //explosions change this.
item_flags &= ~IN_INVENTORY
- var/matrix/M = matrix(transform)
- M.Turn(rand(-170, 170))
- transform = M
- pixel_x = rand(-8, 8)
- pixel_y = rand(-8, 8)
+ if(messy_throw)
+ var/matrix/M = matrix(transform)
+ M.Turn(rand(-170, 170))
+ transform = M
+ pixel_x = rand(-8, 8)
+ pixel_y = rand(-8, 8)
/obj/item/proc/remove_item_from_storage(atom/newLoc) //please use this if you're going to snowflake an item out of a obj/item/storage
if(!newLoc)
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index f5dfa690db..14ac2f037e 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -80,13 +80,12 @@
SEND_SIGNAL(src, COMSIG_OBJ_SETANCHORED, anchorvalue)
anchored = anchorvalue
-/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
- ..()
+/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, messy_throw)
+ . = ..()
if(obj_flags & FROZEN)
visible_message("[src] shatters into a million pieces!")
qdel(src)
-
/obj/assume_air(datum/gas_mixture/giver)
if(loc)
return loc.assume_air(giver)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 52cf82a06a..102bc6fc3d 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -1,990 +1,991 @@
-/mob/living/carbon
- blood_volume = BLOOD_VOLUME_NORMAL
-
-/mob/living/carbon/Initialize()
- . = ..()
- create_reagents(1000)
- update_body_parts() //to update the carbon's new bodyparts appearance
- GLOB.carbon_list += src
- blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio)
-
-/mob/living/carbon/Destroy()
- //This must be done first, so the mob ghosts correctly before DNA etc is nulled
- . = ..()
-
- QDEL_LIST(internal_organs)
- QDEL_LIST(stomach_contents)
- QDEL_LIST(bodyparts)
- QDEL_LIST(implants)
- remove_from_all_data_huds()
- QDEL_NULL(dna)
- GLOB.carbon_list -= src
-
-/mob/living/carbon/initialize_footstep()
- AddComponent(/datum/component/footstep, 0.6, 2)
-
-/mob/living/carbon/relaymove(mob/user, direction)
- if(user in src.stomach_contents)
- if(prob(40))
- if(prob(25))
- audible_message("You hear something rumbling inside [src]'s stomach...", \
- "You hear something rumbling.", 4,\
- "Something is rumbling inside your stomach!")
- var/obj/item/I = user.get_active_held_item()
- if(I && I.force)
- var/d = rand(round(I.force / 4), I.force)
- var/obj/item/bodypart/BP = get_bodypart(BODY_ZONE_CHEST)
- if(BP.receive_damage(d, 0))
- update_damage_overlays()
- visible_message("[user] attacks [src]'s stomach wall with the [I.name]!", \
- "[user] attacks your stomach wall with the [I.name]!")
- playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1)
-
- if(prob(src.getBruteLoss() - 50))
- for(var/atom/movable/A in stomach_contents)
- A.forceMove(drop_location())
- stomach_contents.Remove(A)
- src.gib()
-
-
-/mob/living/carbon/swap_hand(held_index)
- if(!held_index)
- held_index = (active_hand_index % held_items.len)+1
-
- var/obj/item/item_in_hand = src.get_active_held_item()
- if(item_in_hand) //this segment checks if the item in your hand is twohanded.
- var/obj/item/twohanded/TH = item_in_hand
- if(istype(TH))
- if(TH.wielded == 1)
- to_chat(usr, "Your other hand is too busy holding [TH]")
- return
- var/oindex = active_hand_index
- active_hand_index = held_index
- if(hud_used)
- var/obj/screen/inventory/hand/H
- H = hud_used.hand_slots["[oindex]"]
- if(H)
- H.update_icon()
- H = hud_used.hand_slots["[held_index]"]
- if(H)
- H.update_icon()
-
-
-/mob/living/carbon/activate_hand(selhand) //l/r OR 1-held_items.len
- if(!selhand)
- selhand = (active_hand_index % held_items.len)+1
-
- if(istext(selhand))
- selhand = lowertext(selhand)
- if(selhand == "right" || selhand == "r")
- selhand = 2
- if(selhand == "left" || selhand == "l")
- selhand = 1
-
- if(selhand != active_hand_index)
- swap_hand(selhand)
- else
- mode() // Activate held item
-
-/mob/living/carbon/attackby(obj/item/I, mob/user, params)
- if(lying && surgeries.len)
- if(user != src && (user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM))
- for(var/datum/surgery/S in surgeries)
- if(S.next_step(user,user.a_intent))
- return 1
- return ..()
-
-/mob/living/carbon/throw_impact(atom/hit_atom, throwingdatum)
- . = ..()
- var/hurt = TRUE
- if(istype(throwingdatum, /datum/thrownthing))
- var/datum/thrownthing/D = throwingdatum
- if(iscyborg(D.thrower))
- var/mob/living/silicon/robot/R = D.thrower
- if(!R.emagged)
- hurt = FALSE
- if(hit_atom.density && isturf(hit_atom))
- if(hurt)
- Knockdown(20)
- take_bodypart_damage(10)
- if(iscarbon(hit_atom) && hit_atom != src)
- var/mob/living/carbon/victim = hit_atom
- if(victim.movement_type & FLYING)
- return
- if(hurt)
- victim.take_bodypart_damage(10)
- take_bodypart_damage(10)
- victim.Knockdown(20)
- Knockdown(20)
- visible_message("[src] crashes into [victim], knocking them both over!",\
- "You violently crash into [victim]!")
- playsound(src,'sound/weapons/punch1.ogg',50,1)
-
-
-//Throwing stuff
-/mob/living/carbon/proc/toggle_throw_mode()
- if(stat)
- return
- if(in_throw_mode)
- throw_mode_off()
- else
- throw_mode_on()
-
-
-/mob/living/carbon/proc/throw_mode_off()
- in_throw_mode = 0
- if(client && hud_used)
- hud_used.throw_icon.icon_state = "act_throw_off"
-
-
-/mob/living/carbon/proc/throw_mode_on()
- in_throw_mode = 1
- if(client && hud_used)
- hud_used.throw_icon.icon_state = "act_throw_on"
-
-/mob/proc/throw_item(atom/target)
- SEND_SIGNAL(src, COMSIG_MOB_THROW, target)
- return
-
-/mob/living/carbon/throw_item(atom/target)
- throw_mode_off()
- if(!target || !isturf(loc))
- return
- if(istype(target, /obj/screen))
- return
-
- //CIT CHANGES - makes it impossible to throw while in stamina softcrit
- if(getStaminaLoss() >= STAMINA_SOFTCRIT)
- to_chat(src, "You're too exhausted.")
- return
- //END OF CIT CHANGES
-
- var/obj/item/I = src.get_active_held_item()
-
- var/atom/movable/thrown_thing
- var/mob/living/throwable_mob
-
- if(istype(I, /obj/item/clothing/head/mob_holder))
- var/obj/item/clothing/head/mob_holder/holder = I
- if(holder.held_mob)
- throwable_mob = holder.held_mob
- holder.release()
-
- if(!I || throwable_mob)
- if(!throwable_mob && pulling && isliving(pulling) && grab_state >= GRAB_AGGRESSIVE)
- throwable_mob = pulling
-
- if(throwable_mob && !throwable_mob.buckled)
- thrown_thing = throwable_mob
- if(pulling)
- stop_pulling()
- if(HAS_TRAIT(src, TRAIT_PACIFISM))
- to_chat(src, "You gently let go of [throwable_mob].")
- return
-
- adjustStaminaLossBuffered(25)//CIT CHANGE - throwing an entire person shall be very tiring
- var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
- var/turf/end_T = get_turf(target)
- if(start_T && end_T)
- log_combat(src, throwable_mob, "thrown", addition="grab from tile in [AREACOORD(start_T)] towards tile at [AREACOORD(end_T)]")
-
- else if(!CHECK_BITFIELD(I.item_flags, ABSTRACT) && !HAS_TRAIT(I, TRAIT_NODROP))
- thrown_thing = I
- dropItemToGround(I)
-
- if(HAS_TRAIT(src, TRAIT_PACIFISM) && I.throwforce)
- to_chat(src, "You set [I] down gently on the ground.")
- return
-
- adjustStaminaLossBuffered(I.getweight()*2)//CIT CHANGE - throwing items shall be more tiring than swinging em. Doubly so.
-
- if(thrown_thing)
- visible_message("[src] has thrown [thrown_thing].")
- src.log_message("has thrown [thrown_thing]", LOG_ATTACK)
- do_attack_animation(target, no_effect = 1)
- playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1, -1)
- newtonian_move(get_dir(target, src))
- thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src)
-
-
-
-/mob/living/carbon/restrained(ignore_grab)
- . = (handcuffed || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE))
-
-/mob/living/carbon/proc/canBeHandcuffed()
- return 0
-
-
-/mob/living/carbon/show_inv(mob/user)
- user.set_machine(src)
- var/dat = {"
-
- [name]
-
-
Head: [(head && !(head.item_flags & ABSTRACT)) ? head : "Nothing"]
-
Mask: [(wear_mask && !(wear_mask.item_flags & ABSTRACT)) ? wear_mask : "Nothing"]
-
Neck: [(wear_neck && !(wear_neck.item_flags & ABSTRACT)) ? wear_neck : "Nothing"]"}
-
- for(var/i in 1 to held_items.len)
- var/obj/item/I = get_item_for_held_index(i)
- dat += "
[get_held_index_name(i)]:[(I && !(I.item_flags & ABSTRACT)) ? I : "Nothing"]"
-
- dat += " Back: [back ? back : "Nothing"]"
-
- if(istype(wear_mask, /obj/item/clothing/mask) && istype(back, /obj/item/tank))
- dat += " [internal ? "Disable Internals" : "Set Internals"]"
-
- if(handcuffed)
- dat += " Handcuffed"
- if(legcuffed)
- dat += " Legcuffed"
-
- dat += {"
-
- Close
- "}
- user << browse(dat, "window=mob[REF(src)];size=325x500")
- onclose(user, "mob[REF(src)]")
-
-/mob/living/carbon/Topic(href, href_list)
- ..()
- //strip panel
- if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
- 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) && wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS))
- visible_message("[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].", \
- "[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].")
- if(do_mob(usr, src, POCKET_STRIP_DELAY))
- if(internal)
- internal = null
- update_internals_hud_icon(0)
- else if(ITEM && istype(ITEM, /obj/item/tank))
- if((wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS)) || getorganslot(ORGAN_SLOT_BREATHING_TUBE))
- internal = ITEM
- update_internals_hud_icon(1)
-
- visible_message("[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].", \
- "[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].")
-
-
-/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/hallucinating()
- if(hallucination)
- return TRUE
- else
- return FALSE
-
-/mob/living/carbon/resist_buckle()
- if(restrained())
- changeNext_move(CLICK_CD_BREAKOUT)
- last_special = world.time + CLICK_CD_BREAKOUT
- var/buckle_cd = 600
- if(handcuffed)
- var/obj/item/restraints/O = src.get_item_by_slot(SLOT_HANDCUFFED)
- buckle_cd = O.breakouttime
- visible_message("[src] attempts to unbuckle [p_them()]self!", \
- "You attempt to unbuckle yourself... (This will take around [round(buckle_cd/600,1)] minute\s, and you need to stay still.)")
- if(do_after(src, buckle_cd, 0, target = src))
- if(!buckled)
- return
- buckled.user_unbuckle_mob(src,src)
- else
- if(src && buckled)
- to_chat(src, "You fail to unbuckle yourself!")
- else
- buckled.user_unbuckle_mob(src,src)
-
-/mob/living/carbon/resist_fire()
- fire_stacks -= 5
- Knockdown(60, TRUE, TRUE)
- spin(32,2)
- visible_message("[src] rolls on the floor, trying to put [p_them()]self out!", \
- "You stop, drop, and roll!")
- sleep(30)
- if(fire_stacks <= 0)
- visible_message("[src] has successfully extinguished [p_them()]self!", \
- "You extinguish yourself.")
- ExtinguishMob()
- return
-
-/mob/living/carbon/resist_restraints()
- var/obj/item/I = null
- var/type = 0
- if(handcuffed)
- I = handcuffed
- type = 1
- else if(legcuffed)
- I = legcuffed
- type = 2
- if(I)
- if(type == 1)
- changeNext_move(CLICK_CD_BREAKOUT)
- last_special = world.time + CLICK_CD_BREAKOUT
- if(type == 2)
- changeNext_move(CLICK_CD_RANGE)
- last_special = world.time + CLICK_CD_RANGE
- cuff_resist(I)
-
-
-/mob/living/carbon/proc/cuff_resist(obj/item/I, breakouttime = 600, cuff_break = 0)
- if(I.item_flags & BEING_REMOVED)
- to_chat(src, "You're already attempting to remove [I]!")
- return
- I.item_flags |= BEING_REMOVED
- breakouttime = I.breakouttime
- if(!cuff_break)
- visible_message("[src] attempts to remove [I]!")
- to_chat(src, "You attempt to remove [I]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)")
- if(do_after(src, breakouttime, 0, target = src))
- clear_cuffs(I, cuff_break)
- else
- to_chat(src, "You fail to remove [I]!")
-
- else if(cuff_break == FAST_CUFFBREAK)
- breakouttime = 50
- visible_message("[src] is trying to break [I]!")
- to_chat(src, "You attempt to break [I]... (This will take around 5 seconds and you need to stand still.)")
- if(do_after(src, breakouttime, 0, target = src))
- clear_cuffs(I, cuff_break)
- else
- to_chat(src, "You fail to break [I]!")
-
- else if(cuff_break == INSTANT_CUFFBREAK)
- clear_cuffs(I, cuff_break)
- I.item_flags &= ~BEING_REMOVED
-
-/mob/living/carbon/proc/uncuff()
- if (handcuffed)
- var/obj/item/W = handcuffed
- handcuffed = null
- if (buckled && buckled.buckle_requires_restraints)
- buckled.unbuckle_mob(src)
- update_handcuffed()
- if (client)
- client.screen -= W
- if (W)
- W.forceMove(drop_location())
- W.dropped(src)
- if (W)
- W.layer = initial(W.layer)
- W.plane = initial(W.plane)
- changeNext_move(0)
- if (legcuffed)
- var/obj/item/W = legcuffed
- legcuffed = null
- update_inv_legcuffed()
- if (client)
- client.screen -= W
- if (W)
- W.forceMove(drop_location())
- W.dropped(src)
- if (W)
- W.layer = initial(W.layer)
- W.plane = initial(W.plane)
- changeNext_move(0)
-
-/mob/living/carbon/proc/clear_cuffs(obj/item/I, cuff_break)
- if(!I.loc || buckled)
- return
- visible_message("[src] manages to [cuff_break ? "break" : "remove"] [I]!")
- to_chat(src, "You successfully [cuff_break ? "break" : "remove"] [I].")
-
- if(cuff_break)
- . = !((I == handcuffed) || (I == legcuffed))
- qdel(I)
- return
-
- else
- if(I == handcuffed)
- handcuffed.forceMove(drop_location())
- handcuffed.dropped(src)
- handcuffed = null
- if(buckled && buckled.buckle_requires_restraints)
- buckled.unbuckle_mob(src)
- update_handcuffed()
- return
- if(I == legcuffed)
- legcuffed.forceMove(drop_location())
- legcuffed.dropped()
- legcuffed = null
- update_inv_legcuffed()
- return
- else
- dropItemToGround(I)
- return
- return TRUE
-
-/mob/living/carbon/get_standard_pixel_y_offset(lying = 0)
- if(lying)
- return -6
- else
- return initial(pixel_y)
-
-/mob/living/carbon/proc/accident(obj/item/I)
- if(!I || (I.item_flags & ABSTRACT) || HAS_TRAIT(I, TRAIT_NODROP))
- return
-
- //dropItemToGround(I) CIT CHANGE - makes it so the item doesn't drop if the modifier rolls above 100
-
- var/modifier = 0
-
- if(HAS_TRAIT(src, TRAIT_CLUMSY))
- modifier -= 40 //Clumsy people are more likely to hit themselves -Honk!
-
- //CIT CHANGES START HERE
- else if(combatmode)
- modifier += 50
-
- if(modifier < 100)
- dropItemToGround(I)
- //END OF CIT CHANGES
-
- switch(rand(1,100)+modifier) //91-100=Nothing special happens
- if(-INFINITY to 0) //attack yourself
- I.attack(src,src)
- if(1 to 30) //throw it at yourself
- I.throw_impact(src)
- if(31 to 60) //Throw object in facing direction
- var/turf/target = get_turf(loc)
- var/range = rand(2,I.throw_range)
- for(var/i = 1; i < range; i++)
- var/turf/new_turf = get_step(target, dir)
- target = new_turf
- if(new_turf.density)
- break
- I.throw_at(target,I.throw_range,I.throw_speed,src)
- if(61 to 90) //throw it down to the floor
- var/turf/target = get_turf(loc)
- I.throw_at(target,I.throw_range,I.throw_speed,src)
-
-/mob/living/carbon/Stat()
- ..()
- if(statpanel("Status"))
- var/obj/item/organ/alien/plasmavessel/vessel = getorgan(/obj/item/organ/alien/plasmavessel)
- if(vessel)
- stat(null, "Plasma Stored: [vessel.storedPlasma]/[vessel.max_plasma]")
- if(locate(/obj/item/assembly/health) in src)
- stat(null, "Health: [health]")
-
- add_abilities_to_panel()
-
-/mob/living/carbon/attack_ui(slot)
- if(!has_hand_for_held_index(active_hand_index))
- return 0
- return ..()
-
-/mob/living/carbon/proc/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, toxic = FALSE)
- if(HAS_TRAIT(src, TRAIT_NOHUNGER))
- return 1
-
- if(nutrition < 100 && !blood)
- if(message)
- visible_message("[src] dry heaves!", \
- "You try to throw up, but there's nothing in your stomach!")
- if(stun)
- Knockdown(200)
- return 1
-
- if(is_mouth_covered()) //make this add a blood/vomit overlay later it'll be hilarious
- if(message)
- visible_message("[src] throws up all over [p_them()]self!", \
- "You throw up all over yourself!")
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomitself)
- distance = 0
- else
- if(message)
- visible_message("[src] throws up!", "You throw up!")
- if(!isflyperson(src))
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomit)
- if(stun)
- Stun(80)
-
- playsound(get_turf(src), 'sound/effects/splat.ogg', 50, 1)
- var/turf/T = get_turf(src)
- if(!blood)
- nutrition -= lost_nutrition
- adjustToxLoss(-3)
- for(var/i=0 to distance)
- if(blood)
- if(T)
- add_splatter_floor(T)
- if(stun)
- adjustBruteLoss(3)
- else if(src.reagents.has_reagent("blazaam"))
- if(T)
- T.add_vomit_floor(src, VOMIT_PURPLE)
- else
- if(T)
- T.add_vomit_floor(src, VOMIT_TOXIC)//toxic barf looks different
- T = get_step(T, dir)
- if (is_blocked_turf(T))
- break
- return 1
-
-/mob/living/carbon/proc/spew_organ(power = 5, amt = 1)
- for(var/i in 1 to amt)
- if(!internal_organs.len)
- break //Guess we're out of organs!
- var/obj/item/organ/guts = pick(internal_organs)
- var/turf/T = get_turf(src)
- guts.Remove(src)
- guts.forceMove(T)
- var/atom/throw_target = get_edge_target_turf(guts, dir)
- guts.throw_at(throw_target, power, 4, src)
-
-
-/mob/living/carbon/fully_replace_character_name(oldname,newname)
- ..()
- if(dna)
- dna.real_name = real_name
-
-//Updates the mob's health from bodyparts and mob damage variables
-/mob/living/carbon/updatehealth()
- if(status_flags & GODMODE)
- return
- var/total_burn = 0
- var/total_brute = 0
- var/total_stamina = 0
- for(var/X in bodyparts) //hardcoded to streamline things a bit
- var/obj/item/bodypart/BP = X
- total_brute += (BP.brute_dam * BP.body_damage_coeff)
- total_burn += (BP.burn_dam * BP.body_damage_coeff)
- total_stamina += (BP.stamina_dam * BP.stam_damage_coeff)
- health = round(maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute, DAMAGE_PRECISION)
- staminaloss = round(total_stamina, DAMAGE_PRECISION)
- update_stat()
- if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD )
- become_husk("burn")
- med_hud_set_health()
- if(stat == SOFT_CRIT)
- add_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE, multiplicative_slowdown = SOFTCRIT_ADD_SLOWDOWN)
- else
- remove_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE)
-
-/mob/living/carbon/update_stamina()
- var/stam = getStaminaLoss()
- if(stam > DAMAGE_PRECISION)
- var/total_health = (health - stam)
- if(total_health <= crit_threshold && !stat)
- if(!IsKnockdown())
- to_chat(src, "You're too exhausted to keep going...")
- Knockdown(100)
- update_health_hud()
-
-/mob/living/carbon/update_sight()
- if(!client)
- return
- if(stat == DEAD)
- sight = (SEE_TURFS|SEE_MOBS|SEE_OBJS)
- see_in_dark = 8
- see_invisible = SEE_INVISIBLE_OBSERVER
- return
-
- sight = initial(sight)
- lighting_alpha = initial(lighting_alpha)
- var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
- if(!E)
- update_tint()
- else
- see_invisible = E.see_invisible
- see_in_dark = E.see_in_dark
- sight |= E.sight_flags
- if(!isnull(E.lighting_alpha))
- lighting_alpha = E.lighting_alpha
- if(HAS_TRAIT(src, TRAIT_NIGHT_VISION))
- lighting_alpha = min(LIGHTING_PLANE_ALPHA_NV_TRAIT, lighting_alpha)
- see_in_dark = max(NIGHT_VISION_DARKSIGHT_RANGE, see_in_dark)
-
- if(client.eye && client.eye != src)
- var/atom/A = client.eye
- if(A.update_remote_sight(src)) //returns 1 if we override all other sight updates.
- return
-
- if(glasses)
- var/obj/item/clothing/glasses/G = glasses
- sight |= G.vision_flags
- see_in_dark = max(G.darkness_view, see_in_dark)
- if(G.invis_override)
- see_invisible = G.invis_override
- else
- see_invisible = min(G.invis_view, see_invisible)
- if(!isnull(G.lighting_alpha))
- lighting_alpha = min(lighting_alpha, G.lighting_alpha)
- if(dna)
- for(var/X in dna.mutations)
- var/datum/mutation/M = X
- if(M.name == XRAY)
- sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
- see_in_dark = max(see_in_dark, 8)
-
- if(see_override)
- see_invisible = see_override
- . = ..()
-
-
-//to recalculate and update the mob's total tint from tinted equipment it's wearing.
-/mob/living/carbon/proc/update_tint()
- if(!GLOB.tinted_weldhelh)
- return
- tinttotal = get_total_tint()
- if(tinttotal >= TINT_BLIND)
- become_blind(EYES_COVERED)
- else if(tinttotal >= TINT_DARKENED)
- cure_blind(EYES_COVERED)
- overlay_fullscreen("tint", /obj/screen/fullscreen/impaired, 2)
- else
- cure_blind(EYES_COVERED)
- 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
-
- var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
- if(E)
- . += E.tint
-
- else
- . += INFINITY
-
-/mob/living/carbon/get_permeability_protection(list/target_zones = list(HANDS,CHEST,GROIN,LEGS,FEET,ARMS,HEAD))
- var/list/tally = list()
- for(var/obj/item/I in get_equipped_items())
- for(var/zone in target_zones)
- if(I.body_parts_covered & zone)
- tally["[zone]"] = max(1 - I.permeability_coefficient, target_zones["[zone]"])
- var/protection = 0
- for(var/key in tally)
- protection += tally[key]
- protection *= INVERSE(target_zones.len)
- return protection
-
-//this handles hud updates
-/mob/living/carbon/update_damage_hud()
-
- if(!client)
- return
-
- if(health <= crit_threshold)
- var/severity = 0
- switch(health)
- if(-20 to -10)
- severity = 1
- if(-30 to -20)
- severity = 2
- if(-40 to -30)
- severity = 3
- if(-50 to -40)
- severity = 4
- if(-50 to -40)
- severity = 5
- if(-60 to -50)
- severity = 6
- if(-70 to -60)
- severity = 7
- if(-90 to -70)
- severity = 8
- if(-95 to -90)
- severity = 9
- if(-INFINITY to -95)
- severity = 10
- if(!InFullCritical())
- var/visionseverity = 4
- switch(health)
- if(-8 to -4)
- visionseverity = 5
- if(-12 to -8)
- visionseverity = 6
- if(-16 to -12)
- visionseverity = 7
- if(-20 to -16)
- visionseverity = 8
- if(-24 to -20)
- visionseverity = 9
- if(-INFINITY to -24)
- visionseverity = 10
- overlay_fullscreen("critvision", /obj/screen/fullscreen/crit/vision, visionseverity)
- else
- clear_fullscreen("critvision")
- overlay_fullscreen("crit", /obj/screen/fullscreen/crit, severity)
- else
- clear_fullscreen("crit")
- clear_fullscreen("critvision")
-
- //Oxygen damage overlay
- var/windedup = getOxyLoss() + getStaminaLoss() * 0.2
- if(windedup)
- var/severity = 0
- switch(windedup)
- if(10 to 20)
- severity = 1
- if(20 to 25)
- severity = 2
- if(25 to 30)
- severity = 3
- if(30 to 35)
- severity = 4
- if(35 to 40)
- severity = 5
- if(40 to 45)
- severity = 6
- if(45 to INFINITY)
- severity = 7
- overlay_fullscreen("oxy", /obj/screen/fullscreen/oxy, severity)
- else
- clear_fullscreen("oxy")
-
- //Fire and Brute damage overlay (BSSR)
- var/hurtdamage = getBruteLoss() + getFireLoss() + damageoverlaytemp
- if(hurtdamage)
- var/severity = 0
- switch(hurtdamage)
- if(5 to 15)
- severity = 1
- if(15 to 30)
- severity = 2
- if(30 to 45)
- severity = 3
- if(45 to 70)
- severity = 4
- if(70 to 85)
- severity = 5
- if(85 to INFINITY)
- severity = 6
- overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity)
- else
- clear_fullscreen("brute")
-
-/mob/living/carbon/update_health_hud(shown_health_amount)
- if(!client || !hud_used)
- return
- if(hud_used.healths)
- if(stat != DEAD)
- . = 1
- if(!shown_health_amount)
- shown_health_amount = health
- if(shown_health_amount >= maxHealth)
- hud_used.healths.icon_state = "health0"
- else if(shown_health_amount > maxHealth*0.8)
- hud_used.healths.icon_state = "health1"
- else if(shown_health_amount > maxHealth*0.6)
- hud_used.healths.icon_state = "health2"
- else if(shown_health_amount > maxHealth*0.4)
- hud_used.healths.icon_state = "health3"
- else if(shown_health_amount > maxHealth*0.2)
- hud_used.healths.icon_state = "health4"
- else if(shown_health_amount > 0)
- hud_used.healths.icon_state = "health5"
- else
- hud_used.healths.icon_state = "health6"
- else
- hud_used.healths.icon_state = "health7"
-
-/mob/living/carbon/proc/update_internals_hud_icon(internal_state = 0)
- if(hud_used && hud_used.internals)
- hud_used.internals.icon_state = "internal[internal_state]"
-
-/mob/living/carbon/update_stat()
- if(status_flags & GODMODE)
- return
- if(stat != DEAD)
- if(health <= HEALTH_THRESHOLD_DEAD && !HAS_TRAIT(src, TRAIT_NODEATH))
- death()
- return
- if(IsUnconscious() || IsSleeping() || getOxyLoss() > 50 || (HAS_TRAIT(src, TRAIT_DEATHCOMA)) || (health <= HEALTH_THRESHOLD_FULLCRIT && !HAS_TRAIT(src, TRAIT_NOHARDCRIT)))
- stat = UNCONSCIOUS
- blind_eyes(1)
- if(combatmode)
- toggle_combat_mode(TRUE, TRUE)
- else
- if(health <= crit_threshold && !HAS_TRAIT(src, TRAIT_NOSOFTCRIT))
- stat = SOFT_CRIT
- if(combatmode)
- toggle_combat_mode(TRUE, TRUE)
- else
- stat = CONSCIOUS
- adjust_blindness(-1)
- update_canmove()
- update_damage_hud()
- update_health_hud()
- med_hud_set_status()
-
-//called when we get cuffed/uncuffed
-/mob/living/carbon/proc/update_handcuffed()
- if(handcuffed)
- drop_all_held_items()
- stop_pulling()
- throw_alert("handcuffed", /obj/screen/alert/restrained/handcuffed, new_master = src.handcuffed)
- if(handcuffed.demoralize_criminals)
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "handcuffed", /datum/mood_event/handcuffed)
- else
- clear_alert("handcuffed")
- SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "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/fully_heal(admin_revive = FALSE)
- if(reagents)
- reagents.clear_reagents()
- var/obj/item/organ/brain/B = getorgan(/obj/item/organ/brain)
- if(B)
- B.brain_death = FALSE
- for(var/thing in diseases)
- var/datum/disease/D = thing
- if(D.severity != DISEASE_SEVERITY_POSITIVE)
- D.cure(FALSE)
- if(admin_revive)
- regenerate_limbs()
- regenerate_organs()
- handcuffed = initial(handcuffed)
- for(var/obj/item/restraints/R in contents) //actually remove cuffs from inventory
- qdel(R)
- update_handcuffed()
- if(reagents)
- reagents.addiction_list = list()
- cure_all_traumas(TRAUMA_RESILIENCE_MAGIC)
- ..()
- // heal ears after healing traits, since ears check TRAIT_DEAF trait
- // when healing.
- restoreEars()
-
-/mob/living/carbon/can_be_revived()
- . = ..()
- if(!getorgan(/obj/item/organ/brain) && (!mind || !mind.has_antag_datum(/datum/antagonist/changeling)))
- return 0
-
-/mob/living/carbon/harvest(mob/living/user)
- if(QDELETED(src))
- return
- var/organs_amt = 0
- for(var/X in internal_organs)
- var/obj/item/organ/O = X
- if(prob(50))
- organs_amt++
- O.Remove(src)
- O.forceMove(drop_location())
- if(organs_amt)
- to_chat(user, "You retrieve some of [src]\'s internal organs!")
-
-/mob/living/carbon/ExtinguishMob()
- for(var/X in get_equipped_items())
- var/obj/item/I = X
- I.acid_level = 0 //washes off the acid on our clothes
- I.extinguish() //extinguishes our clothes
- ..()
-
-/mob/living/carbon/fakefire(var/fire_icon = "Generic_mob_burning")
- var/mutable_appearance/new_fire_overlay = mutable_appearance('icons/mob/OnFire.dmi', fire_icon, -FIRE_LAYER)
- new_fire_overlay.appearance_flags = RESET_COLOR
- overlays_standing[FIRE_LAYER] = new_fire_overlay
- apply_overlay(FIRE_LAYER)
-
-/mob/living/carbon/fakefireextinguish()
- remove_overlay(FIRE_LAYER)
-
-
-/mob/living/carbon/proc/devour_mob(mob/living/carbon/C, devour_time = 130)
- C.visible_message("[src] is attempting to devour [C]!", \
- "[src] is attempting to devour you!")
- if(!do_mob(src, C, devour_time))
- return
- if(pulling && pulling == C && grab_state >= GRAB_AGGRESSIVE && a_intent == INTENT_GRAB)
- C.visible_message("[src] devours [C]!", \
- "[src] devours you!")
- C.forceMove(src)
- stomach_contents.Add(C)
- log_combat(src, C, "devoured")
-
-/mob/living/carbon/proc/create_bodyparts()
- var/l_arm_index_next = -1
- var/r_arm_index_next = 0
- for(var/X in bodyparts)
- var/obj/item/bodypart/O = new X()
- O.owner = src
- bodyparts.Remove(X)
- bodyparts.Add(O)
- if(O.body_part == ARM_LEFT)
- l_arm_index_next += 2
- O.held_index = l_arm_index_next //1, 3, 5, 7...
- hand_bodyparts += O
- else if(O.body_part == ARM_RIGHT)
- r_arm_index_next += 2
- O.held_index = r_arm_index_next //2, 4, 6, 8...
- hand_bodyparts += O
-
-/mob/living/carbon/do_after_coefficent()
- . = ..()
- var/datum/component/mood/mood = src.GetComponent(/datum/component/mood) //Currently, only carbons or higher use mood, move this once that changes.
- if(mood)
- switch(mood.sanity) //Alters do_after delay based on how sane you are
- if(SANITY_INSANE to SANITY_DISTURBED)
- . *= 1.25
- if(SANITY_NEUTRAL to SANITY_GREAT)
- . *= 0.90
-
-
-/mob/living/carbon/proc/create_internal_organs()
- for(var/X in internal_organs)
- var/obj/item/organ/I = X
- I.Insert(src)
-
-/mob/living/carbon/proc/update_disabled_bodyparts()
- for(var/B in bodyparts)
- var/obj/item/bodypart/BP = B
- BP.update_disabled()
-
-/mob/living/carbon/vv_get_dropdown()
- . = ..()
- . += "---"
- .["Make AI"] = "?_src_=vars;[HrefToken()];makeai=[REF(src)]"
- .["Modify bodypart"] = "?_src_=vars;[HrefToken()];editbodypart=[REF(src)]"
- .["Modify organs"] = "?_src_=vars;[HrefToken()];editorgans=[REF(src)]"
- .["Hallucinate"] = "?_src_=vars;[HrefToken()];hallucinate=[REF(src)]"
- .["Give martial arts"] = "?_src_=vars;[HrefToken()];givemartialart=[REF(src)]"
- .["Give brain trauma"] = "?_src_=vars;[HrefToken()];givetrauma=[REF(src)]"
- .["Cure brain traumas"] = "?_src_=vars;[HrefToken()];curetraumas=[REF(src)]"
-
-/mob/living/carbon/can_resist()
- return bodyparts.len > 2 && ..()
-
-/mob/living/carbon/proc/hypnosis_vulnerable()//unused atm, but added in case
- if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
- return FALSE
- if(hallucinating())
- return TRUE
- if(IsSleeping())
- return TRUE
- if(HAS_TRAIT(src, TRAIT_DUMB))
- return TRUE
- var/datum/component/mood/mood = src.GetComponent(/datum/component/mood)
- if(mood)
- if(mood.sanity < SANITY_UNSTABLE)
- return TRUE
-
-/mob/living/carbon/transfer_ckey(mob/new_mob, send_signal = TRUE)
- if(combatmode)
- toggle_combat_mode(TRUE, TRUE)
- return ..()
-
-/mob/living/carbon/can_see_reagents()
- . = ..()
- if(.) //No need to run through all of this if it's already true.
- return
- if(isclothing(head))
- var/obj/item/clothing/H = head
- if(H.clothing_flags & SCAN_REAGENTS)
- return TRUE
- if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_REAGENTS))
- return TRUE
+/mob/living/carbon
+ blood_volume = BLOOD_VOLUME_NORMAL
+
+/mob/living/carbon/Initialize()
+ . = ..()
+ create_reagents(1000)
+ update_body_parts() //to update the carbon's new bodyparts appearance
+ GLOB.carbon_list += src
+ blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio)
+
+/mob/living/carbon/Destroy()
+ //This must be done first, so the mob ghosts correctly before DNA etc is nulled
+ . = ..()
+
+ QDEL_LIST(internal_organs)
+ QDEL_LIST(stomach_contents)
+ QDEL_LIST(bodyparts)
+ QDEL_LIST(implants)
+ remove_from_all_data_huds()
+ QDEL_NULL(dna)
+ GLOB.carbon_list -= src
+
+/mob/living/carbon/initialize_footstep()
+ AddComponent(/datum/component/footstep, 0.6, 2)
+
+/mob/living/carbon/relaymove(mob/user, direction)
+ if(user in src.stomach_contents)
+ if(prob(40))
+ if(prob(25))
+ audible_message("You hear something rumbling inside [src]'s stomach...", \
+ "You hear something rumbling.", 4,\
+ "Something is rumbling inside your stomach!")
+ var/obj/item/I = user.get_active_held_item()
+ if(I && I.force)
+ var/d = rand(round(I.force / 4), I.force)
+ var/obj/item/bodypart/BP = get_bodypart(BODY_ZONE_CHEST)
+ if(BP.receive_damage(d, 0))
+ update_damage_overlays()
+ visible_message("[user] attacks [src]'s stomach wall with the [I.name]!", \
+ "[user] attacks your stomach wall with the [I.name]!")
+ playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1)
+
+ if(prob(src.getBruteLoss() - 50))
+ for(var/atom/movable/A in stomach_contents)
+ A.forceMove(drop_location())
+ stomach_contents.Remove(A)
+ src.gib()
+
+
+/mob/living/carbon/swap_hand(held_index)
+ if(!held_index)
+ held_index = (active_hand_index % held_items.len)+1
+
+ var/obj/item/item_in_hand = src.get_active_held_item()
+ if(item_in_hand) //this segment checks if the item in your hand is twohanded.
+ var/obj/item/twohanded/TH = item_in_hand
+ if(istype(TH))
+ if(TH.wielded == 1)
+ to_chat(usr, "Your other hand is too busy holding [TH]")
+ return
+ var/oindex = active_hand_index
+ active_hand_index = held_index
+ if(hud_used)
+ var/obj/screen/inventory/hand/H
+ H = hud_used.hand_slots["[oindex]"]
+ if(H)
+ H.update_icon()
+ H = hud_used.hand_slots["[held_index]"]
+ if(H)
+ H.update_icon()
+
+
+/mob/living/carbon/activate_hand(selhand) //l/r OR 1-held_items.len
+ if(!selhand)
+ selhand = (active_hand_index % held_items.len)+1
+
+ if(istext(selhand))
+ selhand = lowertext(selhand)
+ if(selhand == "right" || selhand == "r")
+ selhand = 2
+ if(selhand == "left" || selhand == "l")
+ selhand = 1
+
+ if(selhand != active_hand_index)
+ swap_hand(selhand)
+ else
+ mode() // Activate held item
+
+/mob/living/carbon/attackby(obj/item/I, mob/user, params)
+ if(lying && surgeries.len)
+ if(user != src && (user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM))
+ for(var/datum/surgery/S in surgeries)
+ if(S.next_step(user,user.a_intent))
+ return 1
+ return ..()
+
+/mob/living/carbon/throw_impact(atom/hit_atom, throwingdatum)
+ . = ..()
+ var/hurt = TRUE
+ if(istype(throwingdatum, /datum/thrownthing))
+ var/datum/thrownthing/D = throwingdatum
+ if(iscyborg(D.thrower))
+ var/mob/living/silicon/robot/R = D.thrower
+ if(!R.emagged)
+ hurt = FALSE
+ if(hit_atom.density && isturf(hit_atom))
+ if(hurt)
+ Knockdown(20)
+ take_bodypart_damage(10)
+ if(iscarbon(hit_atom) && hit_atom != src)
+ var/mob/living/carbon/victim = hit_atom
+ if(victim.movement_type & FLYING)
+ return
+ if(hurt)
+ victim.take_bodypart_damage(10)
+ take_bodypart_damage(10)
+ victim.Knockdown(20)
+ Knockdown(20)
+ visible_message("[src] crashes into [victim], knocking them both over!",\
+ "You violently crash into [victim]!")
+ playsound(src,'sound/weapons/punch1.ogg',50,1)
+
+
+//Throwing stuff
+/mob/living/carbon/proc/toggle_throw_mode()
+ if(stat)
+ return
+ if(in_throw_mode)
+ throw_mode_off()
+ else
+ throw_mode_on()
+
+
+/mob/living/carbon/proc/throw_mode_off()
+ in_throw_mode = 0
+ if(client && hud_used)
+ hud_used.throw_icon.icon_state = "act_throw_off"
+
+
+/mob/living/carbon/proc/throw_mode_on()
+ in_throw_mode = 1
+ if(client && hud_used)
+ hud_used.throw_icon.icon_state = "act_throw_on"
+
+/mob/proc/throw_item(atom/target)
+ SEND_SIGNAL(src, COMSIG_MOB_THROW, target)
+ return
+
+/mob/living/carbon/throw_item(atom/target)
+ throw_mode_off()
+ if(!target || !isturf(loc))
+ return
+ if(istype(target, /obj/screen))
+ return
+
+ //CIT CHANGES - makes it impossible to throw while in stamina softcrit
+ if(getStaminaLoss() >= STAMINA_SOFTCRIT)
+ to_chat(src, "You're too exhausted.")
+ return
+ var/random_turn = a_intent == INTENT_HARM
+ //END OF CIT CHANGES
+
+ var/obj/item/I = src.get_active_held_item()
+
+ var/atom/movable/thrown_thing
+ var/mob/living/throwable_mob
+
+ if(istype(I, /obj/item/clothing/head/mob_holder))
+ var/obj/item/clothing/head/mob_holder/holder = I
+ if(holder.held_mob)
+ throwable_mob = holder.held_mob
+ holder.release()
+
+ if(!I || throwable_mob)
+ if(!throwable_mob && pulling && isliving(pulling) && grab_state >= GRAB_AGGRESSIVE)
+ throwable_mob = pulling
+
+ if(throwable_mob && !throwable_mob.buckled)
+ thrown_thing = throwable_mob
+ if(pulling)
+ stop_pulling()
+ if(HAS_TRAIT(src, TRAIT_PACIFISM))
+ to_chat(src, "You gently let go of [throwable_mob].")
+ return
+
+ adjustStaminaLossBuffered(25)//CIT CHANGE - throwing an entire person shall be very tiring
+ var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
+ var/turf/end_T = get_turf(target)
+ if(start_T && end_T)
+ log_combat(src, throwable_mob, "thrown", addition="grab from tile in [AREACOORD(start_T)] towards tile at [AREACOORD(end_T)]")
+
+ else if(!CHECK_BITFIELD(I.item_flags, ABSTRACT) && !HAS_TRAIT(I, TRAIT_NODROP))
+ thrown_thing = I
+ dropItemToGround(I)
+
+ if(HAS_TRAIT(src, TRAIT_PACIFISM) && I.throwforce)
+ to_chat(src, "You set [I] down gently on the ground.")
+ return
+
+ adjustStaminaLossBuffered(I.getweight()*2)//CIT CHANGE - throwing items shall be more tiring than swinging em. Doubly so.
+
+ if(thrown_thing)
+ visible_message("[src] has thrown [thrown_thing].")
+ src.log_message("has thrown [thrown_thing]", LOG_ATTACK)
+ do_attack_animation(target, no_effect = 1)
+ playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1, -1)
+ newtonian_move(get_dir(target, src))
+ thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src, null, null, null, random_turn)
+
+
+
+/mob/living/carbon/restrained(ignore_grab)
+ . = (handcuffed || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE))
+
+/mob/living/carbon/proc/canBeHandcuffed()
+ return 0
+
+
+/mob/living/carbon/show_inv(mob/user)
+ user.set_machine(src)
+ var/dat = {"
+
+ [name]
+
+ Head: [(head && !(head.item_flags & ABSTRACT)) ? head : "Nothing"]
+ Mask: [(wear_mask && !(wear_mask.item_flags & ABSTRACT)) ? wear_mask : "Nothing"]
+ Neck: [(wear_neck && !(wear_neck.item_flags & ABSTRACT)) ? wear_neck : "Nothing"]"}
+
+ for(var/i in 1 to held_items.len)
+ var/obj/item/I = get_item_for_held_index(i)
+ dat += " [get_held_index_name(i)]: | [(I && !(I.item_flags & ABSTRACT)) ? I : "Nothing"]"
+
+ dat += " Back: [back ? back : "Nothing"]"
+
+ if(istype(wear_mask, /obj/item/clothing/mask) && istype(back, /obj/item/tank))
+ dat += " [internal ? "Disable Internals" : "Set Internals"]"
+
+ if(handcuffed)
+ dat += " Handcuffed"
+ if(legcuffed)
+ dat += " Legcuffed"
+
+ dat += {"
+
+ Close
+ "}
+ user << browse(dat, "window=mob[REF(src)];size=325x500")
+ onclose(user, "mob[REF(src)]")
+
+/mob/living/carbon/Topic(href, href_list)
+ ..()
+ //strip panel
+ if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
+ 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) && wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS))
+ visible_message("[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].", \
+ "[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].")
+ if(do_mob(usr, src, POCKET_STRIP_DELAY))
+ if(internal)
+ internal = null
+ update_internals_hud_icon(0)
+ else if(ITEM && istype(ITEM, /obj/item/tank))
+ if((wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS)) || getorganslot(ORGAN_SLOT_BREATHING_TUBE))
+ internal = ITEM
+ update_internals_hud_icon(1)
+
+ visible_message("[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].", \
+ "[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].")
+
+
+/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/hallucinating()
+ if(hallucination)
+ return TRUE
+ else
+ return FALSE
+
+/mob/living/carbon/resist_buckle()
+ if(restrained())
+ changeNext_move(CLICK_CD_BREAKOUT)
+ last_special = world.time + CLICK_CD_BREAKOUT
+ var/buckle_cd = 600
+ if(handcuffed)
+ var/obj/item/restraints/O = src.get_item_by_slot(SLOT_HANDCUFFED)
+ buckle_cd = O.breakouttime
+ visible_message("[src] attempts to unbuckle [p_them()]self!", \
+ "You attempt to unbuckle yourself... (This will take around [round(buckle_cd/600,1)] minute\s, and you need to stay still.)")
+ if(do_after(src, buckle_cd, 0, target = src))
+ if(!buckled)
+ return
+ buckled.user_unbuckle_mob(src,src)
+ else
+ if(src && buckled)
+ to_chat(src, "You fail to unbuckle yourself!")
+ else
+ buckled.user_unbuckle_mob(src,src)
+
+/mob/living/carbon/resist_fire()
+ fire_stacks -= 5
+ Knockdown(60, TRUE, TRUE)
+ spin(32,2)
+ visible_message("[src] rolls on the floor, trying to put [p_them()]self out!", \
+ "You stop, drop, and roll!")
+ sleep(30)
+ if(fire_stacks <= 0)
+ visible_message("[src] has successfully extinguished [p_them()]self!", \
+ "You extinguish yourself.")
+ ExtinguishMob()
+ return
+
+/mob/living/carbon/resist_restraints()
+ var/obj/item/I = null
+ var/type = 0
+ if(handcuffed)
+ I = handcuffed
+ type = 1
+ else if(legcuffed)
+ I = legcuffed
+ type = 2
+ if(I)
+ if(type == 1)
+ changeNext_move(CLICK_CD_BREAKOUT)
+ last_special = world.time + CLICK_CD_BREAKOUT
+ if(type == 2)
+ changeNext_move(CLICK_CD_RANGE)
+ last_special = world.time + CLICK_CD_RANGE
+ cuff_resist(I)
+
+
+/mob/living/carbon/proc/cuff_resist(obj/item/I, breakouttime = 600, cuff_break = 0)
+ if(I.item_flags & BEING_REMOVED)
+ to_chat(src, "You're already attempting to remove [I]!")
+ return
+ I.item_flags |= BEING_REMOVED
+ breakouttime = I.breakouttime
+ if(!cuff_break)
+ visible_message("[src] attempts to remove [I]!")
+ to_chat(src, "You attempt to remove [I]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)")
+ if(do_after(src, breakouttime, 0, target = src))
+ clear_cuffs(I, cuff_break)
+ else
+ to_chat(src, "You fail to remove [I]!")
+
+ else if(cuff_break == FAST_CUFFBREAK)
+ breakouttime = 50
+ visible_message("[src] is trying to break [I]!")
+ to_chat(src, "You attempt to break [I]... (This will take around 5 seconds and you need to stand still.)")
+ if(do_after(src, breakouttime, 0, target = src))
+ clear_cuffs(I, cuff_break)
+ else
+ to_chat(src, "You fail to break [I]!")
+
+ else if(cuff_break == INSTANT_CUFFBREAK)
+ clear_cuffs(I, cuff_break)
+ I.item_flags &= ~BEING_REMOVED
+
+/mob/living/carbon/proc/uncuff()
+ if (handcuffed)
+ var/obj/item/W = handcuffed
+ handcuffed = null
+ if (buckled && buckled.buckle_requires_restraints)
+ buckled.unbuckle_mob(src)
+ update_handcuffed()
+ if (client)
+ client.screen -= W
+ if (W)
+ W.forceMove(drop_location())
+ W.dropped(src)
+ if (W)
+ W.layer = initial(W.layer)
+ W.plane = initial(W.plane)
+ changeNext_move(0)
+ if (legcuffed)
+ var/obj/item/W = legcuffed
+ legcuffed = null
+ update_inv_legcuffed()
+ if (client)
+ client.screen -= W
+ if (W)
+ W.forceMove(drop_location())
+ W.dropped(src)
+ if (W)
+ W.layer = initial(W.layer)
+ W.plane = initial(W.plane)
+ changeNext_move(0)
+
+/mob/living/carbon/proc/clear_cuffs(obj/item/I, cuff_break)
+ if(!I.loc || buckled)
+ return
+ visible_message("[src] manages to [cuff_break ? "break" : "remove"] [I]!")
+ to_chat(src, "You successfully [cuff_break ? "break" : "remove"] [I].")
+
+ if(cuff_break)
+ . = !((I == handcuffed) || (I == legcuffed))
+ qdel(I)
+ return
+
+ else
+ if(I == handcuffed)
+ handcuffed.forceMove(drop_location())
+ handcuffed.dropped(src)
+ handcuffed = null
+ if(buckled && buckled.buckle_requires_restraints)
+ buckled.unbuckle_mob(src)
+ update_handcuffed()
+ return
+ if(I == legcuffed)
+ legcuffed.forceMove(drop_location())
+ legcuffed.dropped()
+ legcuffed = null
+ update_inv_legcuffed()
+ return
+ else
+ dropItemToGround(I)
+ return
+ return TRUE
+
+/mob/living/carbon/get_standard_pixel_y_offset(lying = 0)
+ if(lying)
+ return -6
+ else
+ return initial(pixel_y)
+
+/mob/living/carbon/proc/accident(obj/item/I)
+ if(!I || (I.item_flags & ABSTRACT) || HAS_TRAIT(I, TRAIT_NODROP))
+ return
+
+ //dropItemToGround(I) CIT CHANGE - makes it so the item doesn't drop if the modifier rolls above 100
+
+ var/modifier = 0
+
+ if(HAS_TRAIT(src, TRAIT_CLUMSY))
+ modifier -= 40 //Clumsy people are more likely to hit themselves -Honk!
+
+ //CIT CHANGES START HERE
+ else if(combatmode)
+ modifier += 50
+
+ if(modifier < 100)
+ dropItemToGround(I)
+ //END OF CIT CHANGES
+
+ switch(rand(1,100)+modifier) //91-100=Nothing special happens
+ if(-INFINITY to 0) //attack yourself
+ I.attack(src,src)
+ if(1 to 30) //throw it at yourself
+ I.throw_impact(src)
+ if(31 to 60) //Throw object in facing direction
+ var/turf/target = get_turf(loc)
+ var/range = rand(2,I.throw_range)
+ for(var/i = 1; i < range; i++)
+ var/turf/new_turf = get_step(target, dir)
+ target = new_turf
+ if(new_turf.density)
+ break
+ I.throw_at(target,I.throw_range,I.throw_speed,src)
+ if(61 to 90) //throw it down to the floor
+ var/turf/target = get_turf(loc)
+ I.throw_at(target,I.throw_range,I.throw_speed,src)
+
+/mob/living/carbon/Stat()
+ ..()
+ if(statpanel("Status"))
+ var/obj/item/organ/alien/plasmavessel/vessel = getorgan(/obj/item/organ/alien/plasmavessel)
+ if(vessel)
+ stat(null, "Plasma Stored: [vessel.storedPlasma]/[vessel.max_plasma]")
+ if(locate(/obj/item/assembly/health) in src)
+ stat(null, "Health: [health]")
+
+ add_abilities_to_panel()
+
+/mob/living/carbon/attack_ui(slot)
+ if(!has_hand_for_held_index(active_hand_index))
+ return 0
+ return ..()
+
+/mob/living/carbon/proc/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, toxic = FALSE)
+ if(HAS_TRAIT(src, TRAIT_NOHUNGER))
+ return 1
+
+ if(nutrition < 100 && !blood)
+ if(message)
+ visible_message("[src] dry heaves!", \
+ "You try to throw up, but there's nothing in your stomach!")
+ if(stun)
+ Knockdown(200)
+ return 1
+
+ if(is_mouth_covered()) //make this add a blood/vomit overlay later it'll be hilarious
+ if(message)
+ visible_message("[src] throws up all over [p_them()]self!", \
+ "You throw up all over yourself!")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomitself)
+ distance = 0
+ else
+ if(message)
+ visible_message("[src] throws up!", "You throw up!")
+ if(!isflyperson(src))
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomit)
+ if(stun)
+ Stun(80)
+
+ playsound(get_turf(src), 'sound/effects/splat.ogg', 50, 1)
+ var/turf/T = get_turf(src)
+ if(!blood)
+ nutrition -= lost_nutrition
+ adjustToxLoss(-3)
+ for(var/i=0 to distance)
+ if(blood)
+ if(T)
+ add_splatter_floor(T)
+ if(stun)
+ adjustBruteLoss(3)
+ else if(src.reagents.has_reagent("blazaam"))
+ if(T)
+ T.add_vomit_floor(src, VOMIT_PURPLE)
+ else
+ if(T)
+ T.add_vomit_floor(src, VOMIT_TOXIC)//toxic barf looks different
+ T = get_step(T, dir)
+ if (is_blocked_turf(T))
+ break
+ return 1
+
+/mob/living/carbon/proc/spew_organ(power = 5, amt = 1)
+ for(var/i in 1 to amt)
+ if(!internal_organs.len)
+ break //Guess we're out of organs!
+ var/obj/item/organ/guts = pick(internal_organs)
+ var/turf/T = get_turf(src)
+ guts.Remove(src)
+ guts.forceMove(T)
+ var/atom/throw_target = get_edge_target_turf(guts, dir)
+ guts.throw_at(throw_target, power, 4, src)
+
+
+/mob/living/carbon/fully_replace_character_name(oldname,newname)
+ ..()
+ if(dna)
+ dna.real_name = real_name
+
+//Updates the mob's health from bodyparts and mob damage variables
+/mob/living/carbon/updatehealth()
+ if(status_flags & GODMODE)
+ return
+ var/total_burn = 0
+ var/total_brute = 0
+ var/total_stamina = 0
+ for(var/X in bodyparts) //hardcoded to streamline things a bit
+ var/obj/item/bodypart/BP = X
+ total_brute += (BP.brute_dam * BP.body_damage_coeff)
+ total_burn += (BP.burn_dam * BP.body_damage_coeff)
+ total_stamina += (BP.stamina_dam * BP.stam_damage_coeff)
+ health = round(maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute, DAMAGE_PRECISION)
+ staminaloss = round(total_stamina, DAMAGE_PRECISION)
+ update_stat()
+ if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD )
+ become_husk("burn")
+ med_hud_set_health()
+ if(stat == SOFT_CRIT)
+ add_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE, multiplicative_slowdown = SOFTCRIT_ADD_SLOWDOWN)
+ else
+ remove_movespeed_modifier(MOVESPEED_ID_CARBON_SOFTCRIT, TRUE)
+
+/mob/living/carbon/update_stamina()
+ var/stam = getStaminaLoss()
+ if(stam > DAMAGE_PRECISION)
+ var/total_health = (health - stam)
+ if(total_health <= crit_threshold && !stat)
+ if(!IsKnockdown())
+ to_chat(src, "You're too exhausted to keep going...")
+ Knockdown(100)
+ update_health_hud()
+
+/mob/living/carbon/update_sight()
+ if(!client)
+ return
+ if(stat == DEAD)
+ sight = (SEE_TURFS|SEE_MOBS|SEE_OBJS)
+ see_in_dark = 8
+ see_invisible = SEE_INVISIBLE_OBSERVER
+ return
+
+ sight = initial(sight)
+ lighting_alpha = initial(lighting_alpha)
+ var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
+ if(!E)
+ update_tint()
+ else
+ see_invisible = E.see_invisible
+ see_in_dark = E.see_in_dark
+ sight |= E.sight_flags
+ if(!isnull(E.lighting_alpha))
+ lighting_alpha = E.lighting_alpha
+ if(HAS_TRAIT(src, TRAIT_NIGHT_VISION))
+ lighting_alpha = min(LIGHTING_PLANE_ALPHA_NV_TRAIT, lighting_alpha)
+ see_in_dark = max(NIGHT_VISION_DARKSIGHT_RANGE, see_in_dark)
+
+ if(client.eye && client.eye != src)
+ var/atom/A = client.eye
+ if(A.update_remote_sight(src)) //returns 1 if we override all other sight updates.
+ return
+
+ if(glasses)
+ var/obj/item/clothing/glasses/G = glasses
+ sight |= G.vision_flags
+ see_in_dark = max(G.darkness_view, see_in_dark)
+ if(G.invis_override)
+ see_invisible = G.invis_override
+ else
+ see_invisible = min(G.invis_view, see_invisible)
+ if(!isnull(G.lighting_alpha))
+ lighting_alpha = min(lighting_alpha, G.lighting_alpha)
+ if(dna)
+ for(var/X in dna.mutations)
+ var/datum/mutation/M = X
+ if(M.name == XRAY)
+ sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
+ see_in_dark = max(see_in_dark, 8)
+
+ if(see_override)
+ see_invisible = see_override
+ . = ..()
+
+
+//to recalculate and update the mob's total tint from tinted equipment it's wearing.
+/mob/living/carbon/proc/update_tint()
+ if(!GLOB.tinted_weldhelh)
+ return
+ tinttotal = get_total_tint()
+ if(tinttotal >= TINT_BLIND)
+ become_blind(EYES_COVERED)
+ else if(tinttotal >= TINT_DARKENED)
+ cure_blind(EYES_COVERED)
+ overlay_fullscreen("tint", /obj/screen/fullscreen/impaired, 2)
+ else
+ cure_blind(EYES_COVERED)
+ 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
+
+ var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
+ if(E)
+ . += E.tint
+
+ else
+ . += INFINITY
+
+/mob/living/carbon/get_permeability_protection(list/target_zones = list(HANDS,CHEST,GROIN,LEGS,FEET,ARMS,HEAD))
+ var/list/tally = list()
+ for(var/obj/item/I in get_equipped_items())
+ for(var/zone in target_zones)
+ if(I.body_parts_covered & zone)
+ tally["[zone]"] = max(1 - I.permeability_coefficient, target_zones["[zone]"])
+ var/protection = 0
+ for(var/key in tally)
+ protection += tally[key]
+ protection *= INVERSE(target_zones.len)
+ return protection
+
+//this handles hud updates
+/mob/living/carbon/update_damage_hud()
+
+ if(!client)
+ return
+
+ if(health <= crit_threshold)
+ var/severity = 0
+ switch(health)
+ if(-20 to -10)
+ severity = 1
+ if(-30 to -20)
+ severity = 2
+ if(-40 to -30)
+ severity = 3
+ if(-50 to -40)
+ severity = 4
+ if(-50 to -40)
+ severity = 5
+ if(-60 to -50)
+ severity = 6
+ if(-70 to -60)
+ severity = 7
+ if(-90 to -70)
+ severity = 8
+ if(-95 to -90)
+ severity = 9
+ if(-INFINITY to -95)
+ severity = 10
+ if(!InFullCritical())
+ var/visionseverity = 4
+ switch(health)
+ if(-8 to -4)
+ visionseverity = 5
+ if(-12 to -8)
+ visionseverity = 6
+ if(-16 to -12)
+ visionseverity = 7
+ if(-20 to -16)
+ visionseverity = 8
+ if(-24 to -20)
+ visionseverity = 9
+ if(-INFINITY to -24)
+ visionseverity = 10
+ overlay_fullscreen("critvision", /obj/screen/fullscreen/crit/vision, visionseverity)
+ else
+ clear_fullscreen("critvision")
+ overlay_fullscreen("crit", /obj/screen/fullscreen/crit, severity)
+ else
+ clear_fullscreen("crit")
+ clear_fullscreen("critvision")
+
+ //Oxygen damage overlay
+ var/windedup = getOxyLoss() + getStaminaLoss() * 0.2
+ if(windedup)
+ var/severity = 0
+ switch(windedup)
+ if(10 to 20)
+ severity = 1
+ if(20 to 25)
+ severity = 2
+ if(25 to 30)
+ severity = 3
+ if(30 to 35)
+ severity = 4
+ if(35 to 40)
+ severity = 5
+ if(40 to 45)
+ severity = 6
+ if(45 to INFINITY)
+ severity = 7
+ overlay_fullscreen("oxy", /obj/screen/fullscreen/oxy, severity)
+ else
+ clear_fullscreen("oxy")
+
+ //Fire and Brute damage overlay (BSSR)
+ var/hurtdamage = getBruteLoss() + getFireLoss() + damageoverlaytemp
+ if(hurtdamage)
+ var/severity = 0
+ switch(hurtdamage)
+ if(5 to 15)
+ severity = 1
+ if(15 to 30)
+ severity = 2
+ if(30 to 45)
+ severity = 3
+ if(45 to 70)
+ severity = 4
+ if(70 to 85)
+ severity = 5
+ if(85 to INFINITY)
+ severity = 6
+ overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity)
+ else
+ clear_fullscreen("brute")
+
+/mob/living/carbon/update_health_hud(shown_health_amount)
+ if(!client || !hud_used)
+ return
+ if(hud_used.healths)
+ if(stat != DEAD)
+ . = 1
+ if(!shown_health_amount)
+ shown_health_amount = health
+ if(shown_health_amount >= maxHealth)
+ hud_used.healths.icon_state = "health0"
+ else if(shown_health_amount > maxHealth*0.8)
+ hud_used.healths.icon_state = "health1"
+ else if(shown_health_amount > maxHealth*0.6)
+ hud_used.healths.icon_state = "health2"
+ else if(shown_health_amount > maxHealth*0.4)
+ hud_used.healths.icon_state = "health3"
+ else if(shown_health_amount > maxHealth*0.2)
+ hud_used.healths.icon_state = "health4"
+ else if(shown_health_amount > 0)
+ hud_used.healths.icon_state = "health5"
+ else
+ hud_used.healths.icon_state = "health6"
+ else
+ hud_used.healths.icon_state = "health7"
+
+/mob/living/carbon/proc/update_internals_hud_icon(internal_state = 0)
+ if(hud_used && hud_used.internals)
+ hud_used.internals.icon_state = "internal[internal_state]"
+
+/mob/living/carbon/update_stat()
+ if(status_flags & GODMODE)
+ return
+ if(stat != DEAD)
+ if(health <= HEALTH_THRESHOLD_DEAD && !HAS_TRAIT(src, TRAIT_NODEATH))
+ death()
+ return
+ if(IsUnconscious() || IsSleeping() || getOxyLoss() > 50 || (HAS_TRAIT(src, TRAIT_DEATHCOMA)) || (health <= HEALTH_THRESHOLD_FULLCRIT && !HAS_TRAIT(src, TRAIT_NOHARDCRIT)))
+ stat = UNCONSCIOUS
+ blind_eyes(1)
+ if(combatmode)
+ toggle_combat_mode(TRUE, TRUE)
+ else
+ if(health <= crit_threshold && !HAS_TRAIT(src, TRAIT_NOSOFTCRIT))
+ stat = SOFT_CRIT
+ if(combatmode)
+ toggle_combat_mode(TRUE, TRUE)
+ else
+ stat = CONSCIOUS
+ adjust_blindness(-1)
+ update_canmove()
+ update_damage_hud()
+ update_health_hud()
+ med_hud_set_status()
+
+//called when we get cuffed/uncuffed
+/mob/living/carbon/proc/update_handcuffed()
+ if(handcuffed)
+ drop_all_held_items()
+ stop_pulling()
+ throw_alert("handcuffed", /obj/screen/alert/restrained/handcuffed, new_master = src.handcuffed)
+ if(handcuffed.demoralize_criminals)
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "handcuffed", /datum/mood_event/handcuffed)
+ else
+ clear_alert("handcuffed")
+ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "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/fully_heal(admin_revive = FALSE)
+ if(reagents)
+ reagents.clear_reagents()
+ var/obj/item/organ/brain/B = getorgan(/obj/item/organ/brain)
+ if(B)
+ B.brain_death = FALSE
+ for(var/thing in diseases)
+ var/datum/disease/D = thing
+ if(D.severity != DISEASE_SEVERITY_POSITIVE)
+ D.cure(FALSE)
+ if(admin_revive)
+ regenerate_limbs()
+ regenerate_organs()
+ handcuffed = initial(handcuffed)
+ for(var/obj/item/restraints/R in contents) //actually remove cuffs from inventory
+ qdel(R)
+ update_handcuffed()
+ if(reagents)
+ reagents.addiction_list = list()
+ cure_all_traumas(TRAUMA_RESILIENCE_MAGIC)
+ ..()
+ // heal ears after healing traits, since ears check TRAIT_DEAF trait
+ // when healing.
+ restoreEars()
+
+/mob/living/carbon/can_be_revived()
+ . = ..()
+ if(!getorgan(/obj/item/organ/brain) && (!mind || !mind.has_antag_datum(/datum/antagonist/changeling)))
+ return 0
+
+/mob/living/carbon/harvest(mob/living/user)
+ if(QDELETED(src))
+ return
+ var/organs_amt = 0
+ for(var/X in internal_organs)
+ var/obj/item/organ/O = X
+ if(prob(50))
+ organs_amt++
+ O.Remove(src)
+ O.forceMove(drop_location())
+ if(organs_amt)
+ to_chat(user, "You retrieve some of [src]\'s internal organs!")
+
+/mob/living/carbon/ExtinguishMob()
+ for(var/X in get_equipped_items())
+ var/obj/item/I = X
+ I.acid_level = 0 //washes off the acid on our clothes
+ I.extinguish() //extinguishes our clothes
+ ..()
+
+/mob/living/carbon/fakefire(var/fire_icon = "Generic_mob_burning")
+ var/mutable_appearance/new_fire_overlay = mutable_appearance('icons/mob/OnFire.dmi', fire_icon, -FIRE_LAYER)
+ new_fire_overlay.appearance_flags = RESET_COLOR
+ overlays_standing[FIRE_LAYER] = new_fire_overlay
+ apply_overlay(FIRE_LAYER)
+
+/mob/living/carbon/fakefireextinguish()
+ remove_overlay(FIRE_LAYER)
+
+
+/mob/living/carbon/proc/devour_mob(mob/living/carbon/C, devour_time = 130)
+ C.visible_message("[src] is attempting to devour [C]!", \
+ "[src] is attempting to devour you!")
+ if(!do_mob(src, C, devour_time))
+ return
+ if(pulling && pulling == C && grab_state >= GRAB_AGGRESSIVE && a_intent == INTENT_GRAB)
+ C.visible_message("[src] devours [C]!", \
+ "[src] devours you!")
+ C.forceMove(src)
+ stomach_contents.Add(C)
+ log_combat(src, C, "devoured")
+
+/mob/living/carbon/proc/create_bodyparts()
+ var/l_arm_index_next = -1
+ var/r_arm_index_next = 0
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/O = new X()
+ O.owner = src
+ bodyparts.Remove(X)
+ bodyparts.Add(O)
+ if(O.body_part == ARM_LEFT)
+ l_arm_index_next += 2
+ O.held_index = l_arm_index_next //1, 3, 5, 7...
+ hand_bodyparts += O
+ else if(O.body_part == ARM_RIGHT)
+ r_arm_index_next += 2
+ O.held_index = r_arm_index_next //2, 4, 6, 8...
+ hand_bodyparts += O
+
+/mob/living/carbon/do_after_coefficent()
+ . = ..()
+ var/datum/component/mood/mood = src.GetComponent(/datum/component/mood) //Currently, only carbons or higher use mood, move this once that changes.
+ if(mood)
+ switch(mood.sanity) //Alters do_after delay based on how sane you are
+ if(SANITY_INSANE to SANITY_DISTURBED)
+ . *= 1.25
+ if(SANITY_NEUTRAL to SANITY_GREAT)
+ . *= 0.90
+
+
+/mob/living/carbon/proc/create_internal_organs()
+ for(var/X in internal_organs)
+ var/obj/item/organ/I = X
+ I.Insert(src)
+
+/mob/living/carbon/proc/update_disabled_bodyparts()
+ for(var/B in bodyparts)
+ var/obj/item/bodypart/BP = B
+ BP.update_disabled()
+
+/mob/living/carbon/vv_get_dropdown()
+ . = ..()
+ . += "---"
+ .["Make AI"] = "?_src_=vars;[HrefToken()];makeai=[REF(src)]"
+ .["Modify bodypart"] = "?_src_=vars;[HrefToken()];editbodypart=[REF(src)]"
+ .["Modify organs"] = "?_src_=vars;[HrefToken()];editorgans=[REF(src)]"
+ .["Hallucinate"] = "?_src_=vars;[HrefToken()];hallucinate=[REF(src)]"
+ .["Give martial arts"] = "?_src_=vars;[HrefToken()];givemartialart=[REF(src)]"
+ .["Give brain trauma"] = "?_src_=vars;[HrefToken()];givetrauma=[REF(src)]"
+ .["Cure brain traumas"] = "?_src_=vars;[HrefToken()];curetraumas=[REF(src)]"
+
+/mob/living/carbon/can_resist()
+ return bodyparts.len > 2 && ..()
+
+/mob/living/carbon/proc/hypnosis_vulnerable()//unused atm, but added in case
+ if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
+ return FALSE
+ if(hallucinating())
+ return TRUE
+ if(IsSleeping())
+ return TRUE
+ if(HAS_TRAIT(src, TRAIT_DUMB))
+ return TRUE
+ var/datum/component/mood/mood = src.GetComponent(/datum/component/mood)
+ if(mood)
+ if(mood.sanity < SANITY_UNSTABLE)
+ return TRUE
+
+/mob/living/carbon/transfer_ckey(mob/new_mob, send_signal = TRUE)
+ if(combatmode)
+ toggle_combat_mode(TRUE, TRUE)
+ return ..()
+
+/mob/living/carbon/can_see_reagents()
+ . = ..()
+ if(.) //No need to run through all of this if it's already true.
+ return
+ if(isclothing(head))
+ var/obj/item/clothing/H = head
+ if(H.clothing_flags & SCAN_REAGENTS)
+ return TRUE
+ if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_REAGENTS))
+ return TRUE
|